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...
do_sync_pull(const std::vector<const char * > & srcs,const char * dst,bool copy_attrs,const char * name)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
send_shell_command(const std::string & command,bool disable_shell_protocol,StandardStreamsCallbackInterface * callback)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:
OnStandardStreamsCallbackAction(StreamType type,const std::string & output)70 explicit OnStandardStreamsCallbackAction(StreamType type, const std::string& output)
71 : type_(type), output_(output) {
72 }
Perform(const ArgumentTuple & args)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)
WriteOnStdout(const std::string & output)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)
WriteOnStderr(const std::string & output)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:
CallbackDoneAction(int status)103 explicit CallbackDoneAction(int status) : status_(status) {
104 }
Perform(const ArgumentTuple & args)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)
ReturnCallbackDone(int status=-1337)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:
SetUp()130 void SetUp() {
131 if (!getcwd(&cwd_)) {
132 ADD_FAILURE() << "getcwd failed: " << strerror(errno);
133 return;
134 }
135 }
136
ExpectBugreportzVersion(const std::string & version)137 void ExpectBugreportzVersion(const std::string& version) {
138 EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
139 .WillOnce(DoAll(WithArg<2>(WriteOnStderr(version)),
140 WithArg<2>(ReturnCallbackDone(0))));
141 }
142
ExpectProgress(int progress_percentage,const std::string & file="file.zip")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
TEST_F(BugreportTest,InvalidNumberArgs)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)
TEST_F(BugreportTest,NoArgumentsPreNDevice)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.
TEST_F(BugreportTest,NoArgumentsNDevice)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.
TEST_F(BugreportTest,NoArgumentsPostNDevice)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.
TEST_F(BugreportTest,OkNDevice)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.
TEST_F(BugreportTest,OkNDeviceSplitBuffer)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.
TEST_F(BugreportTest,OkProgress)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.
TEST_F(BugreportTest,OkProgressAlwaysForward)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%
TEST_F(BugreportTest,OkProgressZeroPercentIsNotIgnored)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.
TEST_F(BugreportTest,OkDirectory)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
TEST_F(BugreportTest,OkNoExtension)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.
TEST_F(BugreportTest,OkNDeviceDirectory)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
TEST_F(BugreportTest,BugreportzReturnedFail)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
TEST_F(BugreportTest,BugreportzReturnedFailSplitBuffer)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.
TEST_F(BugreportTest,BugreportzReturnedUnsupported)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
TEST_F(BugreportTest,BugreportzVersionFailed)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.
TEST_F(BugreportTest,BugreportzVersionEmpty)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
TEST_F(BugreportTest,BugreportzFailed)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
TEST_F(BugreportTest,PullFails)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