Home | History | Annotate | Download | only in adb
      1 /*
      2  * Copyright (C) 2016 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 "bugreport.h"
     18 
     19 #include <gmock/gmock.h>
     20 #include <gtest/gtest.h>
     21 
     22 #include <android-base/strings.h>
     23 #include <android-base/test_utils.h>
     24 
     25 #include "sysdeps.h"
     26 #include "adb_utils.h"
     27 
     28 using ::testing::_;
     29 using ::testing::Action;
     30 using ::testing::ActionInterface;
     31 using ::testing::DoAll;
     32 using ::testing::ElementsAre;
     33 using ::testing::HasSubstr;
     34 using ::testing::MakeAction;
     35 using ::testing::Return;
     36 using ::testing::StrEq;
     37 using ::testing::WithArg;
     38 using ::testing::internal::CaptureStderr;
     39 using ::testing::internal::CaptureStdout;
     40 using ::testing::internal::GetCapturedStderr;
     41 using ::testing::internal::GetCapturedStdout;
     42 
     43 // Empty function so tests don't need to be linked against file_sync_service.cpp, which requires
     44 // SELinux and its transitive dependencies...
     45 bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
     46                   const char* name) {
     47     ADD_FAILURE() << "do_sync_pull() should have been mocked";
     48     return false;
     49 }
     50 
     51 // Empty functions so tests don't need to be linked against commandline.cpp
     52 DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK(nullptr, nullptr);
     53 
     54 int send_shell_command(const std::string& command, bool disable_shell_protocol,
     55                        StandardStreamsCallbackInterface* callback) {
     56     ADD_FAILURE() << "send_shell_command() should have been mocked";
     57     return -42;
     58 }
     59 
     60 enum StreamType {
     61     kStreamStdout,
     62     kStreamStderr,
     63 };
     64 
     65 // gmock black magic to provide a WithArg<2>(WriteOnStdout(output)) matcher
     66 typedef void OnStandardStreamsCallbackFunction(StandardStreamsCallbackInterface*);
     67 
     68 class OnStandardStreamsCallbackAction : public ActionInterface<OnStandardStreamsCallbackFunction> {
     69   public:
     70     explicit OnStandardStreamsCallbackAction(StreamType type, const std::string& output)
     71         : type_(type), output_(output) {
     72     }
     73     virtual Result Perform(const ArgumentTuple& args) {
     74         if (type_ == kStreamStdout) {
     75             ::std::tr1::get<0>(args)->OnStdout(output_.c_str(), output_.size());
     76         }
     77         if (type_ == kStreamStderr) {
     78             ::std::tr1::get<0>(args)->OnStderr(output_.c_str(), output_.size());
     79         }
     80     }
     81 
     82   private:
     83     StreamType type_;
     84     std::string output_;
     85 };
     86 
     87 // Matcher used to emulated StandardStreamsCallbackInterface.OnStdout(buffer,
     88 // length)
     89 Action<OnStandardStreamsCallbackFunction> WriteOnStdout(const std::string& output) {
     90     return MakeAction(new OnStandardStreamsCallbackAction(kStreamStdout, output));
     91 }
     92 
     93 // Matcher used to emulated StandardStreamsCallbackInterface.OnStderr(buffer,
     94 // length)
     95 Action<OnStandardStreamsCallbackFunction> WriteOnStderr(const std::string& output) {
     96     return MakeAction(new OnStandardStreamsCallbackAction(kStreamStderr, output));
     97 }
     98 
     99 typedef int CallbackDoneFunction(StandardStreamsCallbackInterface*);
    100 
    101 class CallbackDoneAction : public ActionInterface<CallbackDoneFunction> {
    102   public:
    103     explicit CallbackDoneAction(int status) : status_(status) {
    104     }
    105     virtual Result Perform(const ArgumentTuple& args) {
    106         int status = ::std::tr1::get<0>(args)->Done(status_);
    107         return status;
    108     }
    109 
    110   private:
    111     int status_;
    112 };
    113 
    114 // Matcher used to emulated StandardStreamsCallbackInterface.Done(status)
    115 Action<CallbackDoneFunction> ReturnCallbackDone(int status = -1337) {
    116     return MakeAction(new CallbackDoneAction(status));
    117 }
    118 
    119 class BugreportMock : public Bugreport {
    120   public:
    121     MOCK_METHOD3(SendShellCommand, int(const std::string& command, bool disable_shell_protocol,
    122                                        StandardStreamsCallbackInterface* callback));
    123     MOCK_METHOD4(DoSyncPull, bool(const std::vector<const char*>& srcs, const char* dst,
    124                                   bool copy_attrs, const char* name));
    125     MOCK_METHOD2(UpdateProgress, void(const std::string&, int));
    126 };
    127 
    128 class BugreportTest : public ::testing::Test {
    129   public:
    130     void SetUp() {
    131         if (!getcwd(&cwd_)) {
    132             ADD_FAILURE() << "getcwd failed: " << strerror(errno);
    133             return;
    134         }
    135     }
    136 
    137     void ExpectBugreportzVersion(const std::string& version) {
    138         EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
    139             .WillOnce(DoAll(WithArg<2>(WriteOnStderr(version.c_str())),
    140                             WithArg<2>(ReturnCallbackDone(0))));
    141     }
    142 
    143     void ExpectProgress(int progress_percentage, const std::string& file = "file.zip") {
    144         EXPECT_CALL(br_, UpdateProgress(StrEq("generating " + file), progress_percentage));
    145     }
    146 
    147     BugreportMock br_;
    148     std::string cwd_;  // TODO: make it static
    149 };
    150 
    151 // Tests when called with invalid number of arguments
    152 TEST_F(BugreportTest, InvalidNumberArgs) {
    153     const char* args[] = {"bugreport", "to", "principal"};
    154     ASSERT_EQ(1, br_.DoIt(3, args));
    155 }
    156 
    157 // Tests the 'adb bugreport' option when the device does not support 'bugreportz' - it falls back
    158 // to the flat-file format ('bugreport' binary on device)
    159 TEST_F(BugreportTest, NoArgumentsPreNDevice) {
    160     // clang-format off
    161     EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
    162         .WillOnce(DoAll(WithArg<2>(WriteOnStderr("")),
    163                         // Write some bogus output on stdout to make sure it's ignored
    164                         WithArg<2>(WriteOnStdout("Dude, where is my bugreportz?")),
    165                         WithArg<2>(ReturnCallbackDone(0))));
    166     // clang-format on
    167     std::string bugreport = "Reported the bug was.";
    168     CaptureStdout();
    169     EXPECT_CALL(br_, SendShellCommand("bugreport", false, _))
    170         .WillOnce(DoAll(WithArg<2>(WriteOnStdout(bugreport)), Return(0)));
    171 
    172     const char* args[] = {"bugreport"};
    173     ASSERT_EQ(0, br_.DoIt(1, args));
    174     ASSERT_THAT(GetCapturedStdout(), StrEq(bugreport));
    175 }
    176 
    177 // Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.0 - it will
    178 // save the bugreport in the current directory with the name provided by the device.
    179 TEST_F(BugreportTest, NoArgumentsNDevice) {
    180     ExpectBugreportzVersion("1.0");
    181 
    182     std::string dest_file =
    183         android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
    184     EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
    185         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
    186                         WithArg<2>(ReturnCallbackDone())));
    187     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    188                                 false, StrEq("pulling da_bugreport.zip")))
    189         .WillOnce(Return(true));
    190 
    191     const char* args[] = {"bugreport"};
    192     ASSERT_EQ(0, br_.DoIt(1, args));
    193 }
    194 
    195 // Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.1 - it will
    196 // save the bugreport in the current directory with the name provided by the device.
    197 TEST_F(BugreportTest, NoArgumentsPostNDevice) {
    198     ExpectBugreportzVersion("1.1");
    199     std::string dest_file =
    200         android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
    201     ExpectProgress(50, "da_bugreport.zip");
    202     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    203         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
    204                         WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")),
    205                         WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
    206                         WithArg<2>(ReturnCallbackDone())));
    207     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    208                                 false, StrEq("pulling da_bugreport.zip")))
    209         .WillOnce(Return(true));
    210 
    211     const char* args[] = {"bugreport"};
    212     ASSERT_EQ(0, br_.DoIt(1, args));
    213 }
    214 
    215 // Tests 'adb bugreport file.zip' when it succeeds and device does not support progress.
    216 TEST_F(BugreportTest, OkNDevice) {
    217     ExpectBugreportzVersion("1.0");
    218     EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
    219         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
    220                         WithArg<2>(ReturnCallbackDone())));
    221     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    222                                 false, StrEq("pulling file.zip")))
    223         .WillOnce(Return(true));
    224 
    225     const char* args[] = {"bugreport", "file.zip"};
    226     ASSERT_EQ(0, br_.DoIt(2, args));
    227 }
    228 
    229 // Tests 'adb bugreport file.zip' when it succeeds but response was sent in
    230 // multiple buffer writers and without progress updates.
    231 TEST_F(BugreportTest, OkNDeviceSplitBuffer) {
    232     ExpectBugreportzVersion("1.0");
    233     EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
    234         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device")),
    235                         WithArg<2>(WriteOnStdout("/bugreport.zip")),
    236                         WithArg<2>(ReturnCallbackDone())));
    237     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    238                                 false, StrEq("pulling file.zip")))
    239         .WillOnce(Return(true));
    240 
    241     const char* args[] = {"bugreport", "file.zip"};
    242     ASSERT_EQ(0, br_.DoIt(2, args));
    243 }
    244 
    245 // Tests 'adb bugreport file.zip' when it succeeds and displays progress.
    246 TEST_F(BugreportTest, OkProgress) {
    247     ExpectBugreportzVersion("1.1");
    248     ExpectProgress(1);
    249     ExpectProgress(10);
    250     ExpectProgress(50);
    251     ExpectProgress(99);
    252     // clang-format off
    253     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    254         // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
    255         .WillOnce(DoAll(
    256             // Name might change on OK, so make sure the right one is picked.
    257             WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport___NOT.zip\n")),
    258             // Progress line in one write
    259             WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")),
    260             // Add some bogus lines
    261             WithArg<2>(WriteOnStdout("\nDUDE:SWEET\n\nBLA\n\nBLA\nBLA\n\n")),
    262             // Multiple progress lines in one write
    263             WithArg<2>(WriteOnStdout("PROGRESS:10/100\nPROGRESS:50/100\n")),
    264             // Progress line in multiple writes
    265             WithArg<2>(WriteOnStdout("PROG")),
    266             WithArg<2>(WriteOnStdout("RESS:99")),
    267             WithArg<2>(WriteOnStdout("/100\n")),
    268             // Split last message as well, just in case
    269             WithArg<2>(WriteOnStdout("OK:/device/bugreport")),
    270             WithArg<2>(WriteOnStdout(".zip")),
    271             WithArg<2>(ReturnCallbackDone())));
    272     // clang-format on
    273     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    274                                 false, StrEq("pulling file.zip")))
    275         .WillOnce(Return(true));
    276 
    277     const char* args[] = {"bugreport", "file.zip"};
    278     ASSERT_EQ(0, br_.DoIt(2, args));
    279 }
    280 
    281 // Tests 'adb bugreport file.zip' when it succeeds and displays progress, even if progress recedes.
    282 TEST_F(BugreportTest, OkProgressAlwaysForward) {
    283     ExpectBugreportzVersion("1.1");
    284     ExpectProgress(1);
    285     ExpectProgress(50);
    286     ExpectProgress(75);
    287     // clang-format off
    288     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    289         // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
    290         .WillOnce(DoAll(
    291             WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
    292             WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
    293             WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")), // 50%
    294             // 25% should be ignored becaused it receded.
    295             WithArg<2>(WriteOnStdout("PROGRESS:25/100\n")), // 25%
    296             WithArg<2>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
    297             // 75% should be ignored becaused it didn't change.
    298             WithArg<2>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
    299             // Try a receeding percentage with a different max progress
    300             WithArg<2>(WriteOnStdout("PROGRESS:700/1000\n")), // 70%
    301             WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
    302             WithArg<2>(ReturnCallbackDone())));
    303     // clang-format on
    304     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    305                                 false, StrEq("pulling file.zip")))
    306         .WillOnce(Return(true));
    307 
    308     const char* args[] = {"bugreport", "file.zip"};
    309     ASSERT_EQ(0, br_.DoIt(2, args));
    310 }
    311 
    312 // Tests 'adb bugreport file.zip' when it succeeds and displays the initial progress of 0%
    313 TEST_F(BugreportTest, OkProgressZeroPercentIsNotIgnored) {
    314     ExpectBugreportzVersion("1.1");
    315     ExpectProgress(0);
    316     ExpectProgress(1);
    317     // clang-format off
    318     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    319         // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
    320         .WillOnce(DoAll(
    321             WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
    322             WithArg<2>(WriteOnStdout("PROGRESS:1/100000\n")),
    323             WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
    324             WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
    325             WithArg<2>(ReturnCallbackDone())));
    326     // clang-format on
    327     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    328                                 false, StrEq("pulling file.zip")))
    329         .WillOnce(Return(true));
    330 
    331     const char* args[] = {"bugreport", "file.zip"};
    332     ASSERT_EQ(0, br_.DoIt(2, args));
    333 }
    334 
    335 // Tests 'adb bugreport dir' when it succeeds and destination is a directory.
    336 TEST_F(BugreportTest, OkDirectory) {
    337     ExpectBugreportzVersion("1.1");
    338     TemporaryDir td;
    339     std::string dest_file =
    340         android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
    341 
    342     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    343         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
    344                         WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
    345                         WithArg<2>(ReturnCallbackDone())));
    346     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    347                                 false, StrEq("pulling da_bugreport.zip")))
    348         .WillOnce(Return(true));
    349 
    350     const char* args[] = {"bugreport", td.path};
    351     ASSERT_EQ(0, br_.DoIt(2, args));
    352 }
    353 
    354 // Tests 'adb bugreport file' when it succeeds
    355 TEST_F(BugreportTest, OkNoExtension) {
    356     ExpectBugreportzVersion("1.1");
    357     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    358         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip\n")),
    359                         WithArg<2>(ReturnCallbackDone())));
    360     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    361                                 false, StrEq("pulling file.zip")))
    362         .WillOnce(Return(true));
    363 
    364     const char* args[] = {"bugreport", "file"};
    365     ASSERT_EQ(0, br_.DoIt(2, args));
    366 }
    367 
    368 // Tests 'adb bugreport dir' when it succeeds and destination is a directory and device runs N.
    369 TEST_F(BugreportTest, OkNDeviceDirectory) {
    370     ExpectBugreportzVersion("1.0");
    371     TemporaryDir td;
    372     std::string dest_file =
    373         android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
    374 
    375     EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
    376         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
    377                         WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
    378                         WithArg<2>(ReturnCallbackDone())));
    379     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    380                                 false, StrEq("pulling da_bugreport.zip")))
    381         .WillOnce(Return(true));
    382 
    383     const char* args[] = {"bugreport", td.path};
    384     ASSERT_EQ(0, br_.DoIt(2, args));
    385 }
    386 
    387 // Tests 'adb bugreport file.zip' when the bugreport itself failed
    388 TEST_F(BugreportTest, BugreportzReturnedFail) {
    389     ExpectBugreportzVersion("1.1");
    390     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    391         .WillOnce(
    392             DoAll(WithArg<2>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<2>(ReturnCallbackDone())));
    393 
    394     CaptureStderr();
    395     const char* args[] = {"bugreport", "file.zip"};
    396     ASSERT_EQ(-1, br_.DoIt(2, args));
    397     ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
    398 }
    399 
    400 // Tests 'adb bugreport file.zip' when the bugreport itself failed but response
    401 // was sent in
    402 // multiple buffer writes
    403 TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) {
    404     ExpectBugreportzVersion("1.1");
    405     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    406         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("FAIL")), WithArg<2>(WriteOnStdout(":D'OH!\n")),
    407                         WithArg<2>(ReturnCallbackDone())));
    408 
    409     CaptureStderr();
    410     const char* args[] = {"bugreport", "file.zip"};
    411     ASSERT_EQ(-1, br_.DoIt(2, args));
    412     ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
    413 }
    414 
    415 // Tests 'adb bugreport file.zip' when the bugreportz returned an unsupported
    416 // response.
    417 TEST_F(BugreportTest, BugreportzReturnedUnsupported) {
    418     ExpectBugreportzVersion("1.1");
    419     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    420         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("bugreportz? What am I, a zombie?")),
    421                         WithArg<2>(ReturnCallbackDone())));
    422 
    423     CaptureStderr();
    424     const char* args[] = {"bugreport", "file.zip"};
    425     ASSERT_EQ(-1, br_.DoIt(2, args));
    426     ASSERT_THAT(GetCapturedStderr(), HasSubstr("bugreportz? What am I, a zombie?"));
    427 }
    428 
    429 // Tests 'adb bugreport file.zip' when the bugreportz -v command failed
    430 TEST_F(BugreportTest, BugreportzVersionFailed) {
    431     EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _)).WillOnce(Return(666));
    432 
    433     const char* args[] = {"bugreport", "file.zip"};
    434     ASSERT_EQ(666, br_.DoIt(2, args));
    435 }
    436 
    437 // Tests 'adb bugreport file.zip' when the bugreportz -v returns status 0 but with no output.
    438 TEST_F(BugreportTest, BugreportzVersionEmpty) {
    439     ExpectBugreportzVersion("");
    440 
    441     const char* args[] = {"bugreport", "file.zip"};
    442     ASSERT_EQ(-1, br_.DoIt(2, args));
    443 }
    444 
    445 // Tests 'adb bugreport file.zip' when the main bugreportz command failed
    446 TEST_F(BugreportTest, BugreportzFailed) {
    447     ExpectBugreportzVersion("1.1");
    448     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)).WillOnce(Return(666));
    449 
    450     const char* args[] = {"bugreport", "file.zip"};
    451     ASSERT_EQ(666, br_.DoIt(2, args));
    452 }
    453 
    454 // Tests 'adb bugreport file.zip' when the bugreport could not be pulled
    455 TEST_F(BugreportTest, PullFails) {
    456     ExpectBugreportzVersion("1.1");
    457     EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
    458         .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
    459                         WithArg<2>(ReturnCallbackDone())));
    460     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    461                                 false, HasSubstr("file.zip")))
    462         .WillOnce(Return(false));
    463 
    464     const char* args[] = {"bugreport", "file.zip"};
    465     ASSERT_EQ(1, br_.DoIt(2, args));
    466 }
    467