• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(TransportType transport_type,const char * serial,const std::string & command,bool disable_shell_protocol,StandardStreamsCallbackInterface * callback)54 int 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 
60 enum StreamType {
61     kStreamStdout,
62     kStreamStderr,
63 };
64 
65 // gmock black magic to provide a WithArg<4>(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_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 
129 class BugreportTest : public ::testing::Test {
130   public:
SetUp()131     void SetUp() {
132         if (!getcwd(&cwd_)) {
133             ADD_FAILURE() << "getcwd failed: " << strerror(errno);
134             return;
135         }
136     }
137 
ExpectBugreportzVersion(const std::string & version)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 
ExpectProgress(int progress_percentage,const std::string & file="file.zip")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
TEST_F(BugreportTest,InvalidNumberArgs)154 TEST_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)
TEST_F(BugreportTest,NoArgumentsPreNDevice)161 TEST_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.
TEST_F(BugreportTest,NoArgumentsNDevice)181 TEST_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.
TEST_F(BugreportTest,NoArgumentsPostNDevice)199 TEST_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.
TEST_F(BugreportTest,OkNDevice)218 TEST_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.
TEST_F(BugreportTest,OkNDeviceSplitBuffer)233 TEST_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.
TEST_F(BugreportTest,OkProgress)248 TEST_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.
TEST_F(BugreportTest,OkProgressAlwaysForward)284 TEST_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%
TEST_F(BugreportTest,OkProgressZeroPercentIsNotIgnored)315 TEST_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.
TEST_F(BugreportTest,OkDirectory)338 TEST_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
TEST_F(BugreportTest,OkNoExtension)357 TEST_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.
TEST_F(BugreportTest,OkNDeviceDirectory)371 TEST_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
TEST_F(BugreportTest,BugreportzReturnedFail)390 TEST_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
TEST_F(BugreportTest,BugreportzReturnedFailSplitBuffer)405 TEST_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.
TEST_F(BugreportTest,BugreportzReturnedUnsupported)419 TEST_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
TEST_F(BugreportTest,BugreportzVersionFailed)432 TEST_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.
TEST_F(BugreportTest,BugreportzVersionEmpty)441 TEST_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
TEST_F(BugreportTest,BugreportzFailed)449 TEST_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
TEST_F(BugreportTest,PullFails)459 TEST_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