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