Home | History | Annotate | Download | only in perfetto_cmd
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "src/perfetto_cmd/rate_limiter.h"
     18 
     19 #include <stdio.h>
     20 
     21 #include "perfetto/base/scoped_file.h"
     22 #include "perfetto/base/temp_file.h"
     23 #include "perfetto/base/utils.h"
     24 
     25 #include "gmock/gmock.h"
     26 #include "gtest/gtest.h"
     27 
     28 using testing::_;
     29 using testing::NiceMock;
     30 using testing::StrictMock;
     31 using testing::Invoke;
     32 using testing::Return;
     33 
     34 namespace perfetto {
     35 
     36 namespace {
     37 
     38 class MockRateLimiter : public RateLimiter {
     39  public:
     40   MockRateLimiter() : dir_(base::TempDir::Create()) {
     41     ON_CALL(*this, LoadState(_))
     42         .WillByDefault(Invoke(this, &MockRateLimiter::LoadStateConcrete));
     43     ON_CALL(*this, SaveState(_))
     44         .WillByDefault(Invoke(this, &MockRateLimiter::SaveStateConcrete));
     45   }
     46 
     47   virtual std::string GetStateFilePath() const {
     48     return std::string(dir_.path()) + "/.guardraildata";
     49   }
     50 
     51   virtual ~MockRateLimiter() override {
     52     if (StateFileExists())
     53       remove(GetStateFilePath().c_str());
     54   }
     55 
     56   bool LoadStateConcrete(PerfettoCmdState* state) {
     57     return RateLimiter::LoadState(state);
     58   }
     59 
     60   bool SaveStateConcrete(const PerfettoCmdState& state) {
     61     return RateLimiter::SaveState(state);
     62   }
     63 
     64   MOCK_METHOD1(LoadState, bool(PerfettoCmdState*));
     65   MOCK_METHOD1(SaveState, bool(const PerfettoCmdState&));
     66 
     67  private:
     68   base::TempDir dir_;
     69 };
     70 
     71 void WriteGarbageToFile(const std::string& path) {
     72   base::ScopedFile fd;
     73   fd.reset(open(path.c_str(), O_WRONLY | O_CREAT, 0600));
     74   constexpr char data[] = "Some random bytes.";
     75   if (write(fd.get(), data, sizeof(data)) != sizeof(data))
     76     ADD_FAILURE() << "Could not write garbage";
     77 }
     78 
     79 TEST(RateLimiterTest, RoundTripState) {
     80   NiceMock<MockRateLimiter> limiter;
     81 
     82   PerfettoCmdState input{};
     83   PerfettoCmdState output{};
     84 
     85   input.set_total_bytes_uploaded(42);
     86   ASSERT_TRUE(limiter.SaveState(input));
     87   ASSERT_TRUE(limiter.LoadState(&output));
     88   ASSERT_EQ(output.total_bytes_uploaded(), 42u);
     89 }
     90 
     91 TEST(RateLimiterTest, LoadFromEmpty) {
     92   NiceMock<MockRateLimiter> limiter;
     93 
     94   PerfettoCmdState input{};
     95   input.set_total_bytes_uploaded(0);
     96   input.set_last_trace_timestamp(0);
     97   input.set_first_trace_timestamp(0);
     98   PerfettoCmdState output{};
     99 
    100   ASSERT_TRUE(limiter.SaveState(input));
    101   ASSERT_TRUE(limiter.LoadState(&output));
    102   ASSERT_EQ(output.total_bytes_uploaded(), 0u);
    103 }
    104 
    105 TEST(RateLimiterTest, LoadFromNoFileFails) {
    106   NiceMock<MockRateLimiter> limiter;
    107   PerfettoCmdState output{};
    108   ASSERT_FALSE(limiter.LoadState(&output));
    109   ASSERT_EQ(output.total_bytes_uploaded(), 0u);
    110 }
    111 
    112 TEST(RateLimiterTest, LoadFromGarbageFails) {
    113   NiceMock<MockRateLimiter> limiter;
    114 
    115   WriteGarbageToFile(limiter.GetStateFilePath().c_str());
    116 
    117   PerfettoCmdState output{};
    118   ASSERT_FALSE(limiter.LoadState(&output));
    119   ASSERT_EQ(output.total_bytes_uploaded(), 0u);
    120 }
    121 
    122 TEST(RateLimiterTest, NotDropBox) {
    123   StrictMock<MockRateLimiter> limiter;
    124 
    125   ASSERT_TRUE(limiter.ShouldTrace({}));
    126   ASSERT_TRUE(limiter.OnTraceDone({}, true, 10000));
    127   ASSERT_FALSE(limiter.StateFileExists());
    128 }
    129 
    130 TEST(RateLimiterTest, NotDropBox_FailedToTrace) {
    131   StrictMock<MockRateLimiter> limiter;
    132 
    133   ASSERT_FALSE(limiter.OnTraceDone({}, false, 0));
    134   ASSERT_FALSE(limiter.StateFileExists());
    135 }
    136 
    137 TEST(RateLimiterTest, DropBox_IgnoreGuardrails) {
    138   StrictMock<MockRateLimiter> limiter;
    139   RateLimiter::Args args;
    140 
    141   args.is_dropbox = true;
    142   args.ignore_guardrails = true;
    143   args.current_time = base::TimeSeconds(41);
    144 
    145   EXPECT_CALL(limiter, SaveState(_));
    146   EXPECT_CALL(limiter, LoadState(_));
    147   ASSERT_TRUE(limiter.ShouldTrace(args));
    148 
    149   EXPECT_CALL(limiter, SaveState(_));
    150   ASSERT_TRUE(limiter.OnTraceDone(args, true, 42u));
    151 
    152   PerfettoCmdState output{};
    153   ASSERT_TRUE(limiter.LoadStateConcrete(&output));
    154   ASSERT_EQ(output.first_trace_timestamp(), 41u);
    155   ASSERT_EQ(output.last_trace_timestamp(), 41u);
    156   ASSERT_EQ(output.total_bytes_uploaded(), 42u);
    157 }
    158 
    159 TEST(RateLimiterTest, DropBox_EmptyState) {
    160   StrictMock<MockRateLimiter> limiter;
    161   RateLimiter::Args args;
    162 
    163   args.is_dropbox = true;
    164   args.current_time = base::TimeSeconds(10000);
    165 
    166   EXPECT_CALL(limiter, SaveState(_));
    167   EXPECT_CALL(limiter, LoadState(_));
    168   ASSERT_TRUE(limiter.ShouldTrace(args));
    169 
    170   EXPECT_CALL(limiter, SaveState(_));
    171   ASSERT_TRUE(limiter.OnTraceDone(args, true, 1024 * 1024));
    172 
    173   PerfettoCmdState output{};
    174   ASSERT_TRUE(limiter.LoadStateConcrete(&output));
    175   EXPECT_EQ(output.total_bytes_uploaded(), 1024u * 1024u);
    176   EXPECT_EQ(output.first_trace_timestamp(), 10000u);
    177   EXPECT_EQ(output.last_trace_timestamp(), 10000u);
    178 }
    179 
    180 TEST(RateLimiterTest, DropBox_NormalUpload) {
    181   StrictMock<MockRateLimiter> limiter;
    182   RateLimiter::Args args;
    183 
    184   PerfettoCmdState input{};
    185   input.set_first_trace_timestamp(10000);
    186   input.set_last_trace_timestamp(10000 + 60 * 10);
    187   input.set_total_bytes_uploaded(1024 * 1024 * 2);
    188   ASSERT_TRUE(limiter.SaveStateConcrete(input));
    189 
    190   args.is_dropbox = true;
    191   args.current_time = base::TimeSeconds(input.last_trace_timestamp() + 60 * 10);
    192 
    193   EXPECT_CALL(limiter, LoadState(_));
    194   ASSERT_TRUE(limiter.ShouldTrace(args));
    195 
    196   EXPECT_CALL(limiter, SaveState(_));
    197   ASSERT_TRUE(limiter.OnTraceDone(args, true, 1024 * 1024));
    198 
    199   PerfettoCmdState output{};
    200   ASSERT_TRUE(limiter.LoadStateConcrete(&output));
    201   EXPECT_EQ(output.total_bytes_uploaded(), 1024u * 1024u * 3);
    202   EXPECT_EQ(output.first_trace_timestamp(), input.first_trace_timestamp());
    203   EXPECT_EQ(output.last_trace_timestamp(),
    204             static_cast<uint64_t>(args.current_time.count()));
    205 }
    206 
    207 TEST(RateLimiterTest, DropBox_FailedToLoadState) {
    208   StrictMock<MockRateLimiter> limiter;
    209   RateLimiter::Args args;
    210 
    211   args.is_dropbox = true;
    212 
    213   WriteGarbageToFile(limiter.GetStateFilePath().c_str());
    214 
    215   EXPECT_CALL(limiter, LoadState(_));
    216   EXPECT_CALL(limiter, SaveState(_));
    217   ASSERT_FALSE(limiter.ShouldTrace(args));
    218 
    219   PerfettoCmdState output{};
    220   ASSERT_TRUE(limiter.LoadStateConcrete(&output));
    221   EXPECT_EQ(output.total_bytes_uploaded(), 0u);
    222   EXPECT_EQ(output.first_trace_timestamp(), 0u);
    223   EXPECT_EQ(output.last_trace_timestamp(), 0u);
    224 }
    225 
    226 TEST(RateLimiterTest, DropBox_NoTimeTravel) {
    227   StrictMock<MockRateLimiter> limiter;
    228   RateLimiter::Args args;
    229 
    230   PerfettoCmdState input{};
    231   input.set_first_trace_timestamp(100);
    232   input.set_last_trace_timestamp(100);
    233   ASSERT_TRUE(limiter.SaveStateConcrete(input));
    234 
    235   args.is_dropbox = true;
    236   args.current_time = base::TimeSeconds(99);
    237 
    238   EXPECT_CALL(limiter, LoadState(_));
    239   EXPECT_CALL(limiter, SaveState(_));
    240   ASSERT_FALSE(limiter.ShouldTrace(args));
    241 
    242   PerfettoCmdState output{};
    243   ASSERT_TRUE(limiter.LoadStateConcrete(&output));
    244   EXPECT_EQ(output.total_bytes_uploaded(), 0u);
    245   EXPECT_EQ(output.first_trace_timestamp(), 0u);
    246   EXPECT_EQ(output.last_trace_timestamp(), 0u);
    247 }
    248 
    249 TEST(RateLimiterTest, DropBox_TooSoon) {
    250   StrictMock<MockRateLimiter> limiter;
    251   RateLimiter::Args args;
    252 
    253   PerfettoCmdState input{};
    254   input.set_first_trace_timestamp(10000);
    255   input.set_last_trace_timestamp(10000);
    256   ASSERT_TRUE(limiter.SaveStateConcrete(input));
    257 
    258   args.is_dropbox = true;
    259   args.current_time = base::TimeSeconds(10000 + 60 * 4);
    260 
    261   EXPECT_CALL(limiter, LoadState(_));
    262   ASSERT_FALSE(limiter.ShouldTrace(args));
    263 }
    264 
    265 TEST(RateLimiterTest, DropBox_TooMuch) {
    266   StrictMock<MockRateLimiter> limiter;
    267   RateLimiter::Args args;
    268 
    269   PerfettoCmdState input{};
    270   input.set_total_bytes_uploaded(10 * 1024 * 1024 + 1);
    271   ASSERT_TRUE(limiter.SaveStateConcrete(input));
    272 
    273   args.is_dropbox = true;
    274   args.current_time = base::TimeSeconds(60 * 60);
    275 
    276   EXPECT_CALL(limiter, LoadState(_));
    277   ASSERT_FALSE(limiter.ShouldTrace(args));
    278 }
    279 
    280 TEST(RateLimiterTest, DropBox_TooMuch_Override) {
    281   StrictMock<MockRateLimiter> limiter;
    282   RateLimiter::Args args;
    283 
    284   PerfettoCmdState input{};
    285   input.set_total_bytes_uploaded(10 * 1024 * 1024 + 1);
    286   ASSERT_TRUE(limiter.SaveStateConcrete(input));
    287 
    288   args.is_dropbox = true;
    289   args.current_time = base::TimeSeconds(60 * 60);
    290   args.max_upload_bytes_override = 10 * 1024 * 1024 + 2;
    291 
    292   EXPECT_CALL(limiter, LoadState(_));
    293   ASSERT_TRUE(limiter.ShouldTrace(args));
    294 }
    295 
    296 TEST(RateLimiterTest, DropBox_TooMuchWasUploaded) {
    297   StrictMock<MockRateLimiter> limiter;
    298   RateLimiter::Args args;
    299 
    300   PerfettoCmdState input{};
    301   input.set_first_trace_timestamp(1);
    302   input.set_last_trace_timestamp(1);
    303   input.set_total_bytes_uploaded(10 * 1024 * 1024 + 1);
    304   ASSERT_TRUE(limiter.SaveStateConcrete(input));
    305 
    306   args.is_dropbox = true;
    307   args.current_time = base::TimeSeconds(60 * 60 * 24 + 2);
    308 
    309   EXPECT_CALL(limiter, LoadState(_));
    310   ASSERT_TRUE(limiter.ShouldTrace(args));
    311 
    312   EXPECT_CALL(limiter, SaveState(_));
    313   ASSERT_TRUE(limiter.OnTraceDone(args, true, 1024 * 1024));
    314 
    315   PerfettoCmdState output{};
    316   ASSERT_TRUE(limiter.LoadStateConcrete(&output));
    317   EXPECT_EQ(output.total_bytes_uploaded(), 1024u * 1024u);
    318   EXPECT_EQ(output.first_trace_timestamp(),
    319             static_cast<uint64_t>(args.current_time.count()));
    320   EXPECT_EQ(output.last_trace_timestamp(),
    321             static_cast<uint64_t>(args.current_time.count()));
    322 }
    323 
    324 TEST(RateLimiterTest, DropBox_FailedToUpload) {
    325   StrictMock<MockRateLimiter> limiter;
    326   RateLimiter::Args args;
    327 
    328   args.is_dropbox = true;
    329   args.current_time = base::TimeSeconds(10000);
    330 
    331   EXPECT_CALL(limiter, SaveState(_));
    332   EXPECT_CALL(limiter, LoadState(_));
    333   ASSERT_TRUE(limiter.ShouldTrace(args));
    334   ASSERT_FALSE(limiter.OnTraceDone(args, false, 1024 * 1024));
    335 }
    336 
    337 TEST(RateLimiterTest, DropBox_FailedToSave) {
    338   StrictMock<MockRateLimiter> limiter;
    339   RateLimiter::Args args;
    340 
    341   args.is_dropbox = true;
    342   args.current_time = base::TimeSeconds(10000);
    343 
    344   EXPECT_CALL(limiter, SaveState(_));
    345   EXPECT_CALL(limiter, LoadState(_));
    346   ASSERT_TRUE(limiter.ShouldTrace(args));
    347 
    348   EXPECT_CALL(limiter, SaveState(_)).WillOnce(Return(false));
    349   ASSERT_FALSE(limiter.OnTraceDone(args, true, 1024 * 1024));
    350 }
    351 
    352 }  // namespace
    353 
    354 }  // namespace perfetto
    355