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 #define LOG_TAG "dumpstate"
18 #include <cutils/log.h>
19 
20 #include "DumpstateInternal.h"
21 #include "DumpstateService.h"
22 #include "android/os/BnDumpstate.h"
23 #include "dumpstate.h"
24 
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27 
28 #include <fcntl.h>
29 #include <libgen.h>
30 #include <signal.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <thread>
34 
35 #include <android-base/file.h>
36 #include <android-base/properties.h>
37 #include <android-base/stringprintf.h>
38 #include <android-base/strings.h>
39 #include <cutils/properties.h>
40 
41 namespace android {
42 namespace os {
43 namespace dumpstate {
44 
45 using ::testing::EndsWith;
46 using ::testing::HasSubstr;
47 using ::testing::IsNull;
48 using ::testing::IsEmpty;
49 using ::testing::NotNull;
50 using ::testing::StrEq;
51 using ::testing::StartsWith;
52 using ::testing::Test;
53 using ::testing::internal::CaptureStderr;
54 using ::testing::internal::CaptureStdout;
55 using ::testing::internal::GetCapturedStderr;
56 using ::testing::internal::GetCapturedStdout;
57 
58 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
59 
60 class DumpstateListenerMock : public IDumpstateListener {
61   public:
62     MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
63     MOCK_METHOD1(onError, binder::Status(int32_t error_code));
64     MOCK_METHOD0(onFinished, binder::Status());
65 
66   protected:
67     MOCK_METHOD0(onAsBinder, IBinder*());
68 };
69 
70 static int calls_;
71 
72 // Base class for all tests in this file
73 class DumpstateBaseTest : public Test {
74   public:
SetUp()75     virtual void SetUp() override {
76         calls_++;
77         SetDryRun(false);
78     }
79 
SetDryRun(bool dry_run) const80     void SetDryRun(bool dry_run) const {
81         PropertiesHelper::dry_run_ = dry_run;
82     }
83 
SetBuildType(const std::string & build_type) const84     void SetBuildType(const std::string& build_type) const {
85         PropertiesHelper::build_type_ = build_type;
86     }
87 
SetUnroot(bool unroot) const88     void SetUnroot(bool unroot) const {
89         PropertiesHelper::unroot_ = unroot;
90     }
91 
IsStandalone() const92     bool IsStandalone() const {
93         return calls_ == 1;
94     }
95 
DropRoot() const96     void DropRoot() const {
97         DropRootUser();
98         uid_t uid = getuid();
99         ASSERT_EQ(2000, (int)uid);
100     }
101 
102   protected:
103     const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str());
104     const std::string kTestDataPath = kTestPath + "/tests/testdata/";
105     const std::string kSimpleCommand = kTestPath + "/dumpstate_test_fixture";
106     const std::string kEchoCommand = "/system/bin/echo";
107 
108     /*
109      * Copies a text file fixture to a temporary file, returning it's path.
110      *
111      * Useful in cases where the test case changes the content of the tile.
112      */
CopyTextFileFixture(const std::string & relative_name)113     std::string CopyTextFileFixture(const std::string& relative_name) {
114         std::string from = kTestDataPath + relative_name;
115         // Not using TemporaryFile because it's deleted at the end, and it's useful to keep it
116         // around for poking when the test fails.
117         std::string to = kTestDataPath + relative_name + ".tmp";
118         ALOGD("CopyTextFileFixture: from %s to %s\n", from.c_str(), to.c_str());
119         android::base::RemoveFileIfExists(to);
120         CopyTextFile(from, to);
121         return to.c_str();
122     }
123 
124     // Need functions that returns void to use assertions -
125     // https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#assertion-placement
ReadFileToString(const std::string & path,std::string * content)126     void ReadFileToString(const std::string& path, std::string* content) {
127         ASSERT_TRUE(android::base::ReadFileToString(path, content))
128             << "could not read contents from " << path;
129     }
WriteStringToFile(const std::string & content,const std::string & path)130     void WriteStringToFile(const std::string& content, const std::string& path) {
131         ASSERT_TRUE(android::base::WriteStringToFile(content, path))
132             << "could not write contents to " << path;
133     }
134 
135   private:
CopyTextFile(const std::string & from,const std::string & to)136     void CopyTextFile(const std::string& from, const std::string& to) {
137         std::string content;
138         ReadFileToString(from, &content);
139         WriteStringToFile(content, to);
140     }
141 };
142 
143 class DumpOptionsTest : public Test {
144   public:
~DumpOptionsTest()145     virtual ~DumpOptionsTest() {
146     }
SetUp()147     virtual void SetUp() {
148         options_ = Dumpstate::DumpOptions();
149     }
TearDown()150     void TearDown() {
151         // Reset the property
152         property_set("dumpstate.options", "");
153     }
154     Dumpstate::DumpOptions options_;
155 };
156 
TEST_F(DumpOptionsTest,InitializeNone)157 TEST_F(DumpOptionsTest, InitializeNone) {
158     // clang-format off
159     char* argv[] = {
160         const_cast<char*>("dumpstate")
161     };
162     // clang-format on
163 
164     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
165 
166     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
167 
168     EXPECT_FALSE(options_.do_add_date);
169     EXPECT_FALSE(options_.do_zip_file);
170     EXPECT_FALSE(options_.use_socket);
171     EXPECT_FALSE(options_.use_control_socket);
172     EXPECT_FALSE(options_.show_header_only);
173     EXPECT_TRUE(options_.do_vibrate);
174     EXPECT_FALSE(options_.do_fb);
175     EXPECT_FALSE(options_.do_progress_updates);
176     EXPECT_FALSE(options_.is_remote_mode);
177     EXPECT_FALSE(options_.do_broadcast);
178 }
179 
TEST_F(DumpOptionsTest,InitializeAdbBugreport)180 TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
181     // clang-format off
182     char* argv[] = {
183         const_cast<char*>("dumpstatez"),
184         const_cast<char*>("-S"),
185         const_cast<char*>("-d"),
186         const_cast<char*>("-z"),
187     };
188     // clang-format on
189 
190     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
191 
192     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
193     EXPECT_TRUE(options_.do_add_date);
194     EXPECT_TRUE(options_.do_zip_file);
195     EXPECT_TRUE(options_.use_control_socket);
196 
197     // Other options retain default values
198     EXPECT_TRUE(options_.do_vibrate);
199     EXPECT_FALSE(options_.show_header_only);
200     EXPECT_FALSE(options_.do_fb);
201     EXPECT_FALSE(options_.do_progress_updates);
202     EXPECT_FALSE(options_.is_remote_mode);
203     EXPECT_FALSE(options_.do_broadcast);
204     EXPECT_FALSE(options_.use_socket);
205 }
206 
TEST_F(DumpOptionsTest,InitializeAdbShellBugreport)207 TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) {
208     // clang-format off
209     char* argv[] = {
210         const_cast<char*>("dumpstate"),
211         const_cast<char*>("-s"),
212     };
213     // clang-format on
214 
215     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
216 
217     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
218     EXPECT_TRUE(options_.use_socket);
219 
220     // Other options retain default values
221     EXPECT_TRUE(options_.do_vibrate);
222     EXPECT_FALSE(options_.do_add_date);
223     EXPECT_FALSE(options_.do_zip_file);
224     EXPECT_FALSE(options_.use_control_socket);
225     EXPECT_FALSE(options_.show_header_only);
226     EXPECT_FALSE(options_.do_fb);
227     EXPECT_FALSE(options_.do_progress_updates);
228     EXPECT_FALSE(options_.is_remote_mode);
229     EXPECT_FALSE(options_.do_broadcast);
230 }
231 
TEST_F(DumpOptionsTest,InitializeFullBugReport)232 TEST_F(DumpOptionsTest, InitializeFullBugReport) {
233     // clang-format off
234     char* argv[] = {
235         const_cast<char*>("bugreport"),
236         const_cast<char*>("-d"),
237         const_cast<char*>("-p"),
238         const_cast<char*>("-B"),
239         const_cast<char*>("-z"),
240     };
241     // clang-format on
242     property_set("dumpstate.options", "bugreportfull");
243 
244     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
245 
246     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
247     EXPECT_TRUE(options_.do_add_date);
248     EXPECT_TRUE(options_.do_fb);
249     EXPECT_TRUE(options_.do_zip_file);
250     EXPECT_TRUE(options_.do_broadcast);
251 
252     // Other options retain default values
253     EXPECT_TRUE(options_.do_vibrate);
254     EXPECT_FALSE(options_.use_control_socket);
255     EXPECT_FALSE(options_.show_header_only);
256     EXPECT_FALSE(options_.do_progress_updates);
257     EXPECT_FALSE(options_.is_remote_mode);
258     EXPECT_FALSE(options_.use_socket);
259     EXPECT_FALSE(options_.do_start_service);
260 }
261 
TEST_F(DumpOptionsTest,InitializeInteractiveBugReport)262 TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
263     // clang-format off
264     char* argv[] = {
265         const_cast<char*>("bugreport"),
266         const_cast<char*>("-d"),
267         const_cast<char*>("-p"),
268         const_cast<char*>("-B"),
269         const_cast<char*>("-z"),
270     };
271     // clang-format on
272 
273     property_set("dumpstate.options", "bugreportplus");
274 
275     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
276 
277     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
278     EXPECT_TRUE(options_.do_add_date);
279     EXPECT_TRUE(options_.do_broadcast);
280     EXPECT_TRUE(options_.do_zip_file);
281     EXPECT_TRUE(options_.do_progress_updates);
282     EXPECT_TRUE(options_.do_start_service);
283     EXPECT_FALSE(options_.do_fb);
284 
285     // Other options retain default values
286     EXPECT_TRUE(options_.do_vibrate);
287     EXPECT_FALSE(options_.use_control_socket);
288     EXPECT_FALSE(options_.show_header_only);
289     EXPECT_FALSE(options_.is_remote_mode);
290     EXPECT_FALSE(options_.use_socket);
291 }
292 
TEST_F(DumpOptionsTest,InitializeRemoteBugReport)293 TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
294     // clang-format off
295     char* argv[] = {
296         const_cast<char*>("bugreport"),
297         const_cast<char*>("-d"),
298         const_cast<char*>("-p"),
299         const_cast<char*>("-B"),
300         const_cast<char*>("-z"),
301     };
302     // clang-format on
303 
304     property_set("dumpstate.options", "bugreportremote");
305 
306     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
307 
308     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
309     EXPECT_TRUE(options_.do_add_date);
310     EXPECT_TRUE(options_.do_broadcast);
311     EXPECT_TRUE(options_.do_zip_file);
312     EXPECT_TRUE(options_.is_remote_mode);
313     EXPECT_FALSE(options_.do_vibrate);
314     EXPECT_FALSE(options_.do_fb);
315 
316     // Other options retain default values
317     EXPECT_FALSE(options_.use_control_socket);
318     EXPECT_FALSE(options_.show_header_only);
319     EXPECT_FALSE(options_.do_progress_updates);
320     EXPECT_FALSE(options_.use_socket);
321 }
322 
TEST_F(DumpOptionsTest,InitializeWearBugReport)323 TEST_F(DumpOptionsTest, InitializeWearBugReport) {
324     // clang-format off
325     char* argv[] = {
326         const_cast<char*>("bugreport"),
327         const_cast<char*>("-d"),
328         const_cast<char*>("-p"),
329         const_cast<char*>("-B"),
330         const_cast<char*>("-z"),
331     };
332     // clang-format on
333 
334     property_set("dumpstate.options", "bugreportwear");
335 
336     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
337 
338     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
339     EXPECT_TRUE(options_.do_add_date);
340     EXPECT_TRUE(options_.do_fb);
341     EXPECT_TRUE(options_.do_broadcast);
342     EXPECT_TRUE(options_.do_zip_file);
343     EXPECT_TRUE(options_.do_progress_updates);
344     EXPECT_TRUE(options_.do_start_service);
345 
346     // Other options retain default values
347     EXPECT_TRUE(options_.do_vibrate);
348     EXPECT_FALSE(options_.use_control_socket);
349     EXPECT_FALSE(options_.show_header_only);
350     EXPECT_FALSE(options_.is_remote_mode);
351     EXPECT_FALSE(options_.use_socket);
352 }
353 
TEST_F(DumpOptionsTest,InitializeTelephonyBugReport)354 TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
355     // clang-format off
356     char* argv[] = {
357         const_cast<char*>("bugreport"),
358         const_cast<char*>("-d"),
359         const_cast<char*>("-p"),
360         const_cast<char*>("-B"),
361         const_cast<char*>("-z"),
362     };
363     // clang-format on
364 
365     property_set("dumpstate.options", "bugreporttelephony");
366 
367     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
368 
369     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
370     EXPECT_TRUE(options_.do_add_date);
371     EXPECT_FALSE(options_.do_fb);
372     EXPECT_TRUE(options_.do_broadcast);
373     EXPECT_TRUE(options_.do_zip_file);
374     EXPECT_TRUE(options_.telephony_only);
375     EXPECT_TRUE(options_.do_progress_updates);
376 
377     // Other options retain default values
378     EXPECT_TRUE(options_.do_vibrate);
379     EXPECT_FALSE(options_.use_control_socket);
380     EXPECT_FALSE(options_.show_header_only);
381     EXPECT_FALSE(options_.is_remote_mode);
382     EXPECT_FALSE(options_.use_socket);
383 }
384 
TEST_F(DumpOptionsTest,InitializeWifiBugReport)385 TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
386     // clang-format off
387     char* argv[] = {
388         const_cast<char*>("bugreport"),
389         const_cast<char*>("-d"),
390         const_cast<char*>("-p"),
391         const_cast<char*>("-B"),
392         const_cast<char*>("-z"),
393     };
394     // clang-format on
395 
396     property_set("dumpstate.options", "bugreportwifi");
397 
398     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
399 
400     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
401     EXPECT_TRUE(options_.do_add_date);
402     EXPECT_FALSE(options_.do_fb);
403     EXPECT_TRUE(options_.do_broadcast);
404     EXPECT_TRUE(options_.do_zip_file);
405     EXPECT_TRUE(options_.wifi_only);
406 
407     // Other options retain default values
408     EXPECT_TRUE(options_.do_vibrate);
409     EXPECT_FALSE(options_.use_control_socket);
410     EXPECT_FALSE(options_.show_header_only);
411     EXPECT_FALSE(options_.do_progress_updates);
412     EXPECT_FALSE(options_.is_remote_mode);
413     EXPECT_FALSE(options_.use_socket);
414 }
415 
TEST_F(DumpOptionsTest,InitializeDefaultBugReport)416 TEST_F(DumpOptionsTest, InitializeDefaultBugReport) {
417     // default: commandline options are not overridden
418     // clang-format off
419     char* argv[] = {
420         const_cast<char*>("bugreport"),
421         const_cast<char*>("-d"),
422         const_cast<char*>("-p"),
423         const_cast<char*>("-B"),
424         const_cast<char*>("-z"),
425     };
426     // clang-format on
427 
428     property_set("dumpstate.options", "");
429 
430     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
431 
432     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
433     EXPECT_TRUE(options_.do_add_date);
434     EXPECT_TRUE(options_.do_fb);
435     EXPECT_TRUE(options_.do_zip_file);
436     EXPECT_TRUE(options_.do_broadcast);
437 
438     // Other options retain default values
439     EXPECT_TRUE(options_.do_vibrate);
440     EXPECT_FALSE(options_.use_control_socket);
441     EXPECT_FALSE(options_.show_header_only);
442     EXPECT_FALSE(options_.do_progress_updates);
443     EXPECT_FALSE(options_.is_remote_mode);
444     EXPECT_FALSE(options_.use_socket);
445     EXPECT_FALSE(options_.wifi_only);
446 }
447 
TEST_F(DumpOptionsTest,InitializePartial1)448 TEST_F(DumpOptionsTest, InitializePartial1) {
449     // clang-format off
450     char* argv[] = {
451         const_cast<char*>("dumpstate"),
452         const_cast<char*>("-d"),
453         const_cast<char*>("-z"),
454         const_cast<char*>("-s"),
455         const_cast<char*>("-S"),
456 
457     };
458     // clang-format on
459 
460     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
461 
462     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
463     EXPECT_TRUE(options_.do_add_date);
464     EXPECT_TRUE(options_.do_zip_file);
465     // TODO: Maybe we should trim the filename
466     EXPECT_TRUE(options_.use_socket);
467     EXPECT_TRUE(options_.use_control_socket);
468 
469     // Other options retain default values
470     EXPECT_FALSE(options_.show_header_only);
471     EXPECT_TRUE(options_.do_vibrate);
472     EXPECT_FALSE(options_.do_fb);
473     EXPECT_FALSE(options_.do_progress_updates);
474     EXPECT_FALSE(options_.is_remote_mode);
475     EXPECT_FALSE(options_.do_broadcast);
476 }
477 
TEST_F(DumpOptionsTest,InitializePartial2)478 TEST_F(DumpOptionsTest, InitializePartial2) {
479     // clang-format off
480     char* argv[] = {
481         const_cast<char*>("dumpstate"),
482         const_cast<char*>("-v"),
483         const_cast<char*>("-q"),
484         const_cast<char*>("-p"),
485         const_cast<char*>("-P"),
486         const_cast<char*>("-R"),
487         const_cast<char*>("-B"),
488     };
489     // clang-format on
490 
491     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
492 
493     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
494     EXPECT_TRUE(options_.show_header_only);
495     EXPECT_FALSE(options_.do_vibrate);
496     EXPECT_TRUE(options_.do_fb);
497     EXPECT_TRUE(options_.do_progress_updates);
498     EXPECT_TRUE(options_.is_remote_mode);
499     EXPECT_TRUE(options_.do_broadcast);
500 
501     // Other options retain default values
502     EXPECT_FALSE(options_.do_add_date);
503     EXPECT_FALSE(options_.do_zip_file);
504     EXPECT_FALSE(options_.use_socket);
505     EXPECT_FALSE(options_.use_control_socket);
506 }
507 
TEST_F(DumpOptionsTest,InitializeHelp)508 TEST_F(DumpOptionsTest, InitializeHelp) {
509     // clang-format off
510     char* argv[] = {
511         const_cast<char*>("dumpstate"),
512         const_cast<char*>("-h")
513     };
514     // clang-format on
515 
516     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
517 
518     // -h is for help.
519     EXPECT_EQ(status, Dumpstate::RunStatus::HELP);
520 }
521 
TEST_F(DumpOptionsTest,InitializeUnknown)522 TEST_F(DumpOptionsTest, InitializeUnknown) {
523     // clang-format off
524     char* argv[] = {
525         const_cast<char*>("dumpstate"),
526         const_cast<char*>("-u")  // unknown flag
527     };
528     // clang-format on
529 
530     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
531 
532     // -u is unknown.
533     EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT);
534 }
535 
TEST_F(DumpOptionsTest,ValidateOptionsNeedOutfile1)536 TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
537     options_.do_zip_file = true;
538     // Writing to socket = !writing to file.
539     options_.use_socket = true;
540     EXPECT_FALSE(options_.ValidateOptions());
541 
542     options_.use_socket = false;
543     EXPECT_TRUE(options_.ValidateOptions());
544 }
545 
TEST_F(DumpOptionsTest,ValidateOptionsNeedOutfile2)546 TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
547     options_.do_broadcast = true;
548     // Writing to socket = !writing to file.
549     options_.use_socket = true;
550     EXPECT_FALSE(options_.ValidateOptions());
551 
552     options_.use_socket = false;
553     EXPECT_TRUE(options_.ValidateOptions());
554 }
555 
TEST_F(DumpOptionsTest,ValidateOptionsNeedZipfile)556 TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) {
557     options_.use_control_socket = true;
558     EXPECT_FALSE(options_.ValidateOptions());
559 
560     options_.do_zip_file = true;
561     EXPECT_TRUE(options_.ValidateOptions());
562 }
563 
TEST_F(DumpOptionsTest,ValidateOptionsUpdateProgressNeedsBroadcast)564 TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
565     options_.do_progress_updates = true;
566     EXPECT_FALSE(options_.ValidateOptions());
567 
568     options_.do_broadcast = true;
569     EXPECT_TRUE(options_.ValidateOptions());
570 }
571 
TEST_F(DumpOptionsTest,ValidateOptionsRemoteMode)572 TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
573     options_.is_remote_mode = true;
574     EXPECT_FALSE(options_.ValidateOptions());
575 
576     options_.do_broadcast = true;
577     options_.do_zip_file = true;
578     options_.do_add_date = true;
579     EXPECT_TRUE(options_.ValidateOptions());
580 }
581 
582 class DumpstateTest : public DumpstateBaseTest {
583   public:
SetUp()584     void SetUp() {
585         DumpstateBaseTest::SetUp();
586         SetDryRun(false);
587         SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
588         ds.progress_.reset(new Progress());
589         ds.options_.reset(new Dumpstate::DumpOptions());
590     }
591 
592     // Runs a command and capture `stdout` and `stderr`.
RunCommand(const std::string & title,const std::vector<std::string> & full_command,const CommandOptions & options=CommandOptions::DEFAULT)593     int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
594                    const CommandOptions& options = CommandOptions::DEFAULT) {
595         CaptureStdout();
596         CaptureStderr();
597         int status = ds.RunCommand(title, full_command, options);
598         out = GetCapturedStdout();
599         err = GetCapturedStderr();
600         return status;
601     }
602 
603     // Dumps a file and capture `stdout` and `stderr`.
DumpFile(const std::string & title,const std::string & path)604     int DumpFile(const std::string& title, const std::string& path) {
605         CaptureStdout();
606         CaptureStderr();
607         int status = ds.DumpFile(title, path);
608         out = GetCapturedStdout();
609         err = GetCapturedStderr();
610         return status;
611     }
612 
SetProgress(long progress,long initial_max)613     void SetProgress(long progress, long initial_max) {
614         ds.last_reported_percent_progress_ = 0;
615         ds.options_->do_progress_updates = true;
616         ds.progress_.reset(new Progress(initial_max, progress, 1.2));
617     }
618 
GetProgressMessage(const std::string & listener_name,int progress,int max,int old_max=0,bool update_progress=true)619     std::string GetProgressMessage(const std::string& listener_name, int progress, int max,
620                                    int old_max = 0, bool update_progress = true) {
621         EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress";
622         EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max";
623 
624         bool max_increased = old_max > 0;
625 
626         std::string message = "";
627         if (max_increased) {
628             message =
629                 android::base::StringPrintf("Adjusting max progress from %d to %d\n", old_max, max);
630         }
631 
632         if (update_progress) {
633             message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n",
634                                                    listener_name.c_str(), progress, max,
635                                                    (100 * progress / max));
636         }
637 
638         return message;
639     }
640 
641     // `stdout` and `stderr` from the last command ran.
642     std::string out, err;
643 
644     Dumpstate& ds = Dumpstate::GetInstance();
645 };
646 
TEST_F(DumpstateTest,RunCommandNoArgs)647 TEST_F(DumpstateTest, RunCommandNoArgs) {
648     EXPECT_EQ(-1, RunCommand("", {}));
649 }
650 
TEST_F(DumpstateTest,RunCommandNoTitle)651 TEST_F(DumpstateTest, RunCommandNoTitle) {
652     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
653     EXPECT_THAT(out, StrEq("stdout\n"));
654     EXPECT_THAT(err, StrEq("stderr\n"));
655 }
656 
TEST_F(DumpstateTest,RunCommandWithTitle)657 TEST_F(DumpstateTest, RunCommandWithTitle) {
658     EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
659     EXPECT_THAT(err, StrEq("stderr\n"));
660     // The duration may not get output, depending on how long it takes,
661     // so we just check the prefix.
662     EXPECT_THAT(out,
663                 StartsWith("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n"));
664 }
665 
TEST_F(DumpstateTest,RunCommandWithLoggingMessage)666 TEST_F(DumpstateTest, RunCommandWithLoggingMessage) {
667     EXPECT_EQ(
668         0, RunCommand("", {kSimpleCommand},
669                       CommandOptions::WithTimeout(10).Log("COMMAND, Y U NO LOG FIRST?").Build()));
670     EXPECT_THAT(out, StrEq("stdout\n"));
671     EXPECT_THAT(err, StrEq("COMMAND, Y U NO LOG FIRST?stderr\n"));
672 }
673 
TEST_F(DumpstateTest,RunCommandRedirectStderr)674 TEST_F(DumpstateTest, RunCommandRedirectStderr) {
675     EXPECT_EQ(0, RunCommand("", {kSimpleCommand},
676                             CommandOptions::WithTimeout(10).RedirectStderr().Build()));
677     EXPECT_THAT(out, IsEmpty());
678     EXPECT_THAT(err, StrEq("stdout\nstderr\n"));
679 }
680 
TEST_F(DumpstateTest,RunCommandWithOneArg)681 TEST_F(DumpstateTest, RunCommandWithOneArg) {
682     EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one"}));
683     EXPECT_THAT(err, IsEmpty());
684     EXPECT_THAT(out, StrEq("one\n"));
685 }
686 
TEST_F(DumpstateTest,RunCommandWithMultipleArgs)687 TEST_F(DumpstateTest, RunCommandWithMultipleArgs) {
688     EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one", "is", "the", "loniest", "number"}));
689     EXPECT_THAT(err, IsEmpty());
690     EXPECT_THAT(out, StrEq("one is the loniest number\n"));
691 }
692 
TEST_F(DumpstateTest,RunCommandDryRun)693 TEST_F(DumpstateTest, RunCommandDryRun) {
694     SetDryRun(true);
695     EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
696     // The duration may not get output, depending on how long it takes,
697     // so we just check the prefix.
698     EXPECT_THAT(out, StartsWith("------ I AM GROOT (" + kSimpleCommand +
699                                 ") ------\n\t(skipped on dry run)\n"));
700     EXPECT_THAT(err, IsEmpty());
701 }
702 
TEST_F(DumpstateTest,RunCommandDryRunNoTitle)703 TEST_F(DumpstateTest, RunCommandDryRunNoTitle) {
704     SetDryRun(true);
705     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
706     EXPECT_THAT(out, IsEmpty());
707     EXPECT_THAT(err, IsEmpty());
708 }
709 
TEST_F(DumpstateTest,RunCommandDryRunAlways)710 TEST_F(DumpstateTest, RunCommandDryRunAlways) {
711     SetDryRun(true);
712     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Always().Build()));
713     EXPECT_THAT(out, StrEq("stdout\n"));
714     EXPECT_THAT(err, StrEq("stderr\n"));
715 }
716 
TEST_F(DumpstateTest,RunCommandNotFound)717 TEST_F(DumpstateTest, RunCommandNotFound) {
718     EXPECT_NE(0, RunCommand("", {"/there/cannot/be/such/command"}));
719     EXPECT_THAT(out, StartsWith("*** command '/there/cannot/be/such/command' failed: exit code"));
720     EXPECT_THAT(err, StartsWith("execvp on command '/there/cannot/be/such/command' failed"));
721 }
722 
TEST_F(DumpstateTest,RunCommandFails)723 TEST_F(DumpstateTest, RunCommandFails) {
724     EXPECT_EQ(42, RunCommand("", {kSimpleCommand, "--exit", "42"}));
725     EXPECT_THAT(out, StrEq("stdout\n*** command '" + kSimpleCommand +
726                            " --exit 42' failed: exit code 42\n"));
727     EXPECT_THAT(err, StrEq("stderr\n*** command '" + kSimpleCommand +
728                            " --exit 42' failed: exit code 42\n"));
729 }
730 
TEST_F(DumpstateTest,RunCommandCrashes)731 TEST_F(DumpstateTest, RunCommandCrashes) {
732     EXPECT_NE(0, RunCommand("", {kSimpleCommand, "--crash"}));
733     // We don't know the exit code, so check just the prefix.
734     EXPECT_THAT(
735         out, StartsWith("stdout\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
736     EXPECT_THAT(
737         err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
738 }
739 
TEST_F(DumpstateTest,RunCommandTimesout)740 TEST_F(DumpstateTest, RunCommandTimesout) {
741     EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
742                              CommandOptions::WithTimeout(1).Build()));
743     EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
744                                 " --sleep 2' timed out after 1"));
745     EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
746                                 " --sleep 2' timed out after 1"));
747 }
748 
TEST_F(DumpstateTest,RunCommandIsKilled)749 TEST_F(DumpstateTest, RunCommandIsKilled) {
750     CaptureStdout();
751     CaptureStderr();
752 
753     std::thread t([=]() {
754         EXPECT_EQ(SIGTERM, ds.RunCommand("", {kSimpleCommand, "--pid", "--sleep", "20"},
755                                          CommandOptions::WithTimeout(100).Always().Build()));
756     });
757 
758     // Capture pid and pre-sleep output.
759     sleep(1);  // Wait a little bit to make sure pid and 1st line were printed.
760     std::string err = GetCapturedStderr();
761     EXPECT_THAT(err, StrEq("sleeping for 20s\n"));
762 
763     std::string out = GetCapturedStdout();
764     std::vector<std::string> lines = android::base::Split(out, "\n");
765     ASSERT_EQ(3, (int)lines.size()) << "Invalid lines before sleep: " << out;
766 
767     int pid = atoi(lines[0].c_str());
768     EXPECT_THAT(lines[1], StrEq("stdout line1"));
769     EXPECT_THAT(lines[2], IsEmpty());  // \n
770 
771     // Then kill the process.
772     CaptureStdout();
773     CaptureStderr();
774     ASSERT_EQ(0, kill(pid, SIGTERM)) << "failed to kill pid " << pid;
775     t.join();
776 
777     // Finally, check output after murder.
778     out = GetCapturedStdout();
779     err = GetCapturedStderr();
780 
781     EXPECT_THAT(out, StrEq("*** command '" + kSimpleCommand +
782                            " --pid --sleep 20' failed: killed by signal 15\n"));
783     EXPECT_THAT(err, StrEq("*** command '" + kSimpleCommand +
784                            " --pid --sleep 20' failed: killed by signal 15\n"));
785 }
786 
TEST_F(DumpstateTest,RunCommandProgress)787 TEST_F(DumpstateTest, RunCommandProgress) {
788     sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
789     ds.listener_ = listener;
790     ds.listener_name_ = "FoxMulder";
791     SetProgress(0, 30);
792 
793     EXPECT_CALL(*listener, onProgress(66));  // 20/30 %
794     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
795     std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
796     EXPECT_THAT(out, StrEq("stdout\n"));
797     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
798 
799     EXPECT_CALL(*listener, onProgress(80));  // 24/30 %
800     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
801     progress_message = GetProgressMessage(ds.listener_name_, 24, 30);
802     EXPECT_THAT(out, StrEq("stdout\n"));
803     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
804 
805     // Make sure command ran while in dry_run is counted.
806     SetDryRun(true);
807     EXPECT_CALL(*listener, onProgress(90));  // 27/30 %
808     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
809     progress_message = GetProgressMessage(ds.listener_name_, 27, 30);
810     EXPECT_THAT(out, IsEmpty());
811     EXPECT_THAT(err, StrEq(progress_message));
812 
813     SetDryRun(false);
814     EXPECT_CALL(*listener, onProgress(96));  // 29/30 %
815     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build()));
816     progress_message = GetProgressMessage(ds.listener_name_, 29, 30);
817     EXPECT_THAT(out, StrEq("stdout\n"));
818     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
819 
820     EXPECT_CALL(*listener, onProgress(100));  // 30/30 %
821     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
822     progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
823     EXPECT_THAT(out, StrEq("stdout\n"));
824     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
825 
826     ds.listener_.clear();
827 }
828 
TEST_F(DumpstateTest,RunCommandDropRoot)829 TEST_F(DumpstateTest, RunCommandDropRoot) {
830     if (!IsStandalone()) {
831         // TODO: temporarily disabled because it might cause other tests to fail after dropping
832         // to Shell - need to refactor tests to avoid this problem)
833         MYLOGE("Skipping DumpstateTest.RunCommandDropRoot() on test suite\n")
834         return;
835     }
836     // First check root case - only available when running with 'adb root'.
837     uid_t uid = getuid();
838     if (uid == 0) {
839         EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}));
840         EXPECT_THAT(out, StrEq("0\nstdout\n"));
841         EXPECT_THAT(err, StrEq("stderr\n"));
842         return;
843     }
844     // Then run dropping root.
845     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
846                             CommandOptions::WithTimeout(1).DropRoot().Build()));
847     EXPECT_THAT(out, StrEq("2000\nstdout\n"));
848     EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
849 }
850 
TEST_F(DumpstateTest,RunCommandAsRootUserBuild)851 TEST_F(DumpstateTest, RunCommandAsRootUserBuild) {
852     if (!IsStandalone()) {
853         // TODO: temporarily disabled because it might cause other tests to fail after dropping
854         // to Shell - need to refactor tests to avoid this problem)
855         MYLOGE("Skipping DumpstateTest.RunCommandAsRootUserBuild() on test suite\n")
856         return;
857     }
858     if (!PropertiesHelper::IsUserBuild()) {
859         // Emulates user build if necessarily.
860         SetBuildType("user");
861     }
862 
863     DropRoot();
864 
865     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).AsRoot().Build()));
866 
867     // We don't know the exact path of su, so we just check for the 'root ...' commands
868     EXPECT_THAT(out, StartsWith("Skipping"));
869     EXPECT_THAT(out, EndsWith("root " + kSimpleCommand + "' on user build.\n"));
870     EXPECT_THAT(err, IsEmpty());
871 }
872 
TEST_F(DumpstateTest,RunCommandAsRootNonUserBuild)873 TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild) {
874     if (!IsStandalone()) {
875         // TODO: temporarily disabled because it might cause other tests to fail after dropping
876         // to Shell - need to refactor tests to avoid this problem)
877         MYLOGE("Skipping DumpstateTest.RunCommandAsRootNonUserBuild() on test suite\n")
878         return;
879     }
880     if (PropertiesHelper::IsUserBuild()) {
881         ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
882         return;
883     }
884 
885     DropRoot();
886 
887     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
888                             CommandOptions::WithTimeout(1).AsRoot().Build()));
889 
890     EXPECT_THAT(out, StrEq("0\nstdout\n"));
891     EXPECT_THAT(err, StrEq("stderr\n"));
892 }
893 
TEST_F(DumpstateTest,RunCommandAsRootNonUserBuild_withUnroot)894 TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild_withUnroot) {
895     if (!IsStandalone()) {
896         // TODO: temporarily disabled because it might cause other tests to fail after dropping
897         // to Shell - need to refactor tests to avoid this problem)
898         MYLOGE(
899             "Skipping DumpstateTest.RunCommandAsRootNonUserBuild_withUnroot() "
900             "on test suite\n")
901         return;
902     }
903     if (PropertiesHelper::IsUserBuild()) {
904         ALOGI("Skipping RunCommandAsRootNonUserBuild_withUnroot on user builds\n");
905         return;
906     }
907 
908     // Same test as above, but with unroot property set, which will override su availability.
909     SetUnroot(true);
910     DropRoot();
911 
912     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
913                             CommandOptions::WithTimeout(1).AsRoot().Build()));
914 
915     // AsRoot is ineffective.
916     EXPECT_THAT(out, StrEq("2000\nstdout\n"));
917     EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
918 }
919 
TEST_F(DumpstateTest,RunCommandAsRootIfAvailableOnUserBuild)920 TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) {
921     if (!IsStandalone()) {
922         // TODO: temporarily disabled because it might cause other tests to fail after dropping
923         // to Shell - need to refactor tests to avoid this problem)
924         MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
925         return;
926     }
927     if (!PropertiesHelper::IsUserBuild()) {
928         // Emulates user build if necessarily.
929         SetBuildType("user");
930     }
931 
932     DropRoot();
933 
934     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
935                             CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
936 
937     EXPECT_THAT(out, StrEq("2000\nstdout\n"));
938     EXPECT_THAT(err, StrEq("stderr\n"));
939 }
940 
TEST_F(DumpstateTest,RunCommandAsRootIfAvailableOnDebugBuild)941 TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild) {
942     if (!IsStandalone()) {
943         // TODO: temporarily disabled because it might cause other tests to fail after dropping
944         // to Shell - need to refactor tests to avoid this problem)
945         MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
946         return;
947     }
948     if (PropertiesHelper::IsUserBuild()) {
949         ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
950         return;
951     }
952 
953     DropRoot();
954 
955     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
956                             CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
957 
958     EXPECT_THAT(out, StrEq("0\nstdout\n"));
959     EXPECT_THAT(err, StrEq("stderr\n"));
960 }
961 
TEST_F(DumpstateTest,RunCommandAsRootIfAvailableOnDebugBuild_withUnroot)962 TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild_withUnroot) {
963     if (!IsStandalone()) {
964         // TODO: temporarily disabled because it might cause other tests to fail after dropping
965         // to Shell - need to refactor tests to avoid this problem)
966         MYLOGE(
967             "Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild_withUnroot() "
968             "on test suite\n")
969         return;
970     }
971     if (PropertiesHelper::IsUserBuild()) {
972         ALOGI("Skipping RunCommandAsRootIfAvailableOnDebugBuild_withUnroot on user builds\n");
973         return;
974     }
975     // Same test as above, but with unroot property set, which will override su availability.
976     SetUnroot(true);
977 
978     DropRoot();
979 
980     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
981                             CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
982 
983     // It's a userdebug build, so "su root" should be available, but unroot=true overrides it.
984     EXPECT_THAT(out, StrEq("2000\nstdout\n"));
985     EXPECT_THAT(err, StrEq("stderr\n"));
986 }
987 
TEST_F(DumpstateTest,DumpFileNotFoundNoTitle)988 TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
989     EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
990     EXPECT_THAT(out,
991                 StrEq("*** Error dumping /I/cant/believe/I/exist: No such file or directory\n"));
992     EXPECT_THAT(err, IsEmpty());
993 }
994 
TEST_F(DumpstateTest,DumpFileNotFoundWithTitle)995 TEST_F(DumpstateTest, DumpFileNotFoundWithTitle) {
996     EXPECT_EQ(-1, DumpFile("Y U NO EXIST?", "/I/cant/believe/I/exist"));
997     EXPECT_THAT(err, IsEmpty());
998     // The duration may not get output, depending on how long it takes,
999     // so we just check the prefix.
1000     EXPECT_THAT(out, StartsWith("*** Error dumping /I/cant/believe/I/exist (Y U NO EXIST?): No "
1001                                 "such file or directory\n"));
1002 }
1003 
TEST_F(DumpstateTest,DumpFileSingleLine)1004 TEST_F(DumpstateTest, DumpFileSingleLine) {
1005     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
1006     EXPECT_THAT(err, IsEmpty());
1007     EXPECT_THAT(out, StrEq("I AM LINE1\n"));  // dumpstate adds missing newline
1008 }
1009 
TEST_F(DumpstateTest,DumpFileSingleLineWithNewLine)1010 TEST_F(DumpstateTest, DumpFileSingleLineWithNewLine) {
1011     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line-with-newline.txt"));
1012     EXPECT_THAT(err, IsEmpty());
1013     EXPECT_THAT(out, StrEq("I AM LINE1\n"));
1014 }
1015 
TEST_F(DumpstateTest,DumpFileMultipleLines)1016 TEST_F(DumpstateTest, DumpFileMultipleLines) {
1017     EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines.txt"));
1018     EXPECT_THAT(err, IsEmpty());
1019     EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
1020 }
1021 
TEST_F(DumpstateTest,DumpFileMultipleLinesWithNewLine)1022 TEST_F(DumpstateTest, DumpFileMultipleLinesWithNewLine) {
1023     EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines-with-newline.txt"));
1024     EXPECT_THAT(err, IsEmpty());
1025     EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
1026 }
1027 
TEST_F(DumpstateTest,DumpFileOnDryRunNoTitle)1028 TEST_F(DumpstateTest, DumpFileOnDryRunNoTitle) {
1029     SetDryRun(true);
1030     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
1031     EXPECT_THAT(err, IsEmpty());
1032     EXPECT_THAT(out, IsEmpty());
1033 }
1034 
TEST_F(DumpstateTest,DumpFileOnDryRun)1035 TEST_F(DumpstateTest, DumpFileOnDryRun) {
1036     SetDryRun(true);
1037     EXPECT_EQ(0, DumpFile("Might as well dump. Dump!", kTestDataPath + "single-line.txt"));
1038     EXPECT_THAT(err, IsEmpty());
1039     EXPECT_THAT(
1040         out, StartsWith("------ Might as well dump. Dump! (" + kTestDataPath + "single-line.txt:"));
1041     EXPECT_THAT(out, HasSubstr("\n\t(skipped on dry run)\n"));
1042 }
1043 
TEST_F(DumpstateTest,DumpFileUpdateProgress)1044 TEST_F(DumpstateTest, DumpFileUpdateProgress) {
1045     sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
1046     ds.listener_ = listener;
1047     ds.listener_name_ = "FoxMulder";
1048     SetProgress(0, 30);
1049 
1050     EXPECT_CALL(*listener, onProgress(16));  // 5/30 %
1051     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
1052 
1053     std::string progress_message =
1054         GetProgressMessage(ds.listener_name_, 5, 30);  // TODO: unhardcode WEIGHT_FILE (5)?
1055     EXPECT_THAT(err, StrEq(progress_message));
1056     EXPECT_THAT(out, StrEq("I AM LINE1\n"));  // dumpstate adds missing newline
1057 
1058     ds.listener_.clear();
1059 }
1060 
1061 class DumpstateServiceTest : public DumpstateBaseTest {
1062   public:
1063     DumpstateService dss;
1064 };
1065 
TEST_F(DumpstateServiceTest,SetListenerNoName)1066 TEST_F(DumpstateServiceTest, SetListenerNoName) {
1067     sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
1068     sp<IDumpstateToken> token;
1069     EXPECT_TRUE(dss.setListener("", listener, /* getSectionDetails = */ false, &token).isOk());
1070     ASSERT_THAT(token, IsNull());
1071 }
1072 
TEST_F(DumpstateServiceTest,SetListenerNoPointer)1073 TEST_F(DumpstateServiceTest, SetListenerNoPointer) {
1074     sp<IDumpstateToken> token;
1075     EXPECT_TRUE(
1076         dss.setListener("whatever", nullptr, /* getSectionDetails = */ false, &token).isOk());
1077     ASSERT_THAT(token, IsNull());
1078 }
1079 
TEST_F(DumpstateServiceTest,SetListenerTwice)1080 TEST_F(DumpstateServiceTest, SetListenerTwice) {
1081     sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
1082     sp<IDumpstateToken> token;
1083     EXPECT_TRUE(
1084         dss.setListener("whatever", listener, /* getSectionDetails = */ false, &token).isOk());
1085     ASSERT_THAT(token, NotNull());
1086     EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
1087     EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
1088 
1089     token.clear();
1090     EXPECT_TRUE(
1091         dss.setListener("whatsoever", listener, /* getSectionDetails = */ false, &token).isOk());
1092     ASSERT_THAT(token, IsNull());
1093     EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
1094     EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
1095 }
1096 
TEST_F(DumpstateServiceTest,SetListenerWithSectionDetails)1097 TEST_F(DumpstateServiceTest, SetListenerWithSectionDetails) {
1098     sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
1099     sp<IDumpstateToken> token;
1100     Dumpstate::GetInstance().listener_ = nullptr;
1101     EXPECT_TRUE(
1102         dss.setListener("whatever", listener, /* getSectionDetails = */ true, &token).isOk());
1103     ASSERT_THAT(token, NotNull());
1104     EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
1105     EXPECT_TRUE(Dumpstate::GetInstance().report_section_);
1106 }
1107 
1108 class ProgressTest : public DumpstateBaseTest {
1109   public:
GetInstance(int32_t max,double growth_factor,const std::string & path="")1110     Progress GetInstance(int32_t max, double growth_factor, const std::string& path = "") {
1111         return Progress(max, growth_factor, path);
1112     }
1113 
AssertStats(const std::string & path,int32_t expected_runs,int32_t expected_average)1114     void AssertStats(const std::string& path, int32_t expected_runs, int32_t expected_average) {
1115         std::string expected_content =
1116             android::base::StringPrintf("%d %d\n", expected_runs, expected_average);
1117         std::string actual_content;
1118         ReadFileToString(path, &actual_content);
1119         ASSERT_THAT(actual_content, StrEq(expected_content)) << "invalid stats on " << path;
1120     }
1121 };
1122 
TEST_F(ProgressTest,SimpleTest)1123 TEST_F(ProgressTest, SimpleTest) {
1124     Progress progress;
1125     EXPECT_EQ(0, progress.Get());
1126     EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
1127     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1128 
1129     bool max_increased = progress.Inc(1);
1130     EXPECT_EQ(1, progress.Get());
1131     EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
1132     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1133     EXPECT_FALSE(max_increased);
1134 
1135     // Ignore negative increase.
1136     max_increased = progress.Inc(-1);
1137     EXPECT_EQ(1, progress.Get());
1138     EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
1139     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1140     EXPECT_FALSE(max_increased);
1141 }
1142 
TEST_F(ProgressTest,MaxGrowsInsideNewRange)1143 TEST_F(ProgressTest, MaxGrowsInsideNewRange) {
1144     Progress progress = GetInstance(10, 1.2);  // 20% growth factor
1145     EXPECT_EQ(0, progress.Get());
1146     EXPECT_EQ(10, progress.GetInitialMax());
1147     EXPECT_EQ(10, progress.GetMax());
1148 
1149     // No increase
1150     bool max_increased = progress.Inc(10);
1151     EXPECT_EQ(10, progress.Get());
1152     EXPECT_EQ(10, progress.GetMax());
1153     EXPECT_FALSE(max_increased);
1154 
1155     // Increase, with new value < max*20%
1156     max_increased = progress.Inc(1);
1157     EXPECT_EQ(11, progress.Get());
1158     EXPECT_EQ(13, progress.GetMax());  // 11 average * 20% growth = 13.2 = 13
1159     EXPECT_TRUE(max_increased);
1160 }
1161 
TEST_F(ProgressTest,MaxGrowsOutsideNewRange)1162 TEST_F(ProgressTest, MaxGrowsOutsideNewRange) {
1163     Progress progress = GetInstance(10, 1.2);  // 20% growth factor
1164     EXPECT_EQ(0, progress.Get());
1165     EXPECT_EQ(10, progress.GetInitialMax());
1166     EXPECT_EQ(10, progress.GetMax());
1167 
1168     // No increase
1169     bool max_increased = progress.Inc(10);
1170     EXPECT_EQ(10, progress.Get());
1171     EXPECT_EQ(10, progress.GetMax());
1172     EXPECT_FALSE(max_increased);
1173 
1174     // Increase, with new value > max*20%
1175     max_increased = progress.Inc(5);
1176     EXPECT_EQ(15, progress.Get());
1177     EXPECT_EQ(18, progress.GetMax());  // 15 average * 20% growth = 18
1178     EXPECT_TRUE(max_increased);
1179 }
1180 
TEST_F(ProgressTest,InvalidPath)1181 TEST_F(ProgressTest, InvalidPath) {
1182     Progress progress("/devil/null");
1183     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1184 }
1185 
TEST_F(ProgressTest,EmptyFile)1186 TEST_F(ProgressTest, EmptyFile) {
1187     Progress progress(CopyTextFileFixture("empty-file.txt"));
1188     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1189 }
1190 
TEST_F(ProgressTest,InvalidLine1stEntryNAN)1191 TEST_F(ProgressTest, InvalidLine1stEntryNAN) {
1192     Progress progress(CopyTextFileFixture("stats-invalid-1st-NAN.txt"));
1193     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1194 }
1195 
TEST_F(ProgressTest,InvalidLine2ndEntryNAN)1196 TEST_F(ProgressTest, InvalidLine2ndEntryNAN) {
1197     Progress progress(CopyTextFileFixture("stats-invalid-2nd-NAN.txt"));
1198     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1199 }
1200 
TEST_F(ProgressTest,InvalidLineBothNAN)1201 TEST_F(ProgressTest, InvalidLineBothNAN) {
1202     Progress progress(CopyTextFileFixture("stats-invalid-both-NAN.txt"));
1203     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1204 }
1205 
TEST_F(ProgressTest,InvalidLine1stEntryNegative)1206 TEST_F(ProgressTest, InvalidLine1stEntryNegative) {
1207     Progress progress(CopyTextFileFixture("stats-invalid-1st-negative.txt"));
1208     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1209 }
1210 
TEST_F(ProgressTest,InvalidLine2ndEntryNegative)1211 TEST_F(ProgressTest, InvalidLine2ndEntryNegative) {
1212     Progress progress(CopyTextFileFixture("stats-invalid-2nd-negative.txt"));
1213     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1214 }
1215 
TEST_F(ProgressTest,InvalidLine1stEntryTooBig)1216 TEST_F(ProgressTest, InvalidLine1stEntryTooBig) {
1217     Progress progress(CopyTextFileFixture("stats-invalid-1st-too-big.txt"));
1218     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1219 }
1220 
TEST_F(ProgressTest,InvalidLine2ndEntryTooBig)1221 TEST_F(ProgressTest, InvalidLine2ndEntryTooBig) {
1222     Progress progress(CopyTextFileFixture("stats-invalid-2nd-too-big.txt"));
1223     EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1224 }
1225 
1226 // Tests stats are properly saved when the file does not exists.
TEST_F(ProgressTest,FirstTime)1227 TEST_F(ProgressTest, FirstTime) {
1228     if (!IsStandalone()) {
1229         // TODO: temporarily disabled because it's failing when running as suite
1230         MYLOGE("Skipping ProgressTest.FirstTime() on test suite\n")
1231         return;
1232     }
1233 
1234     std::string path = kTestDataPath + "FirstTime.txt";
1235     android::base::RemoveFileIfExists(path);
1236 
1237     Progress run1(path);
1238     EXPECT_EQ(0, run1.Get());
1239     EXPECT_EQ(Progress::kDefaultMax, run1.GetInitialMax());
1240     EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
1241 
1242     bool max_increased = run1.Inc(20);
1243     EXPECT_EQ(20, run1.Get());
1244     EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
1245     EXPECT_FALSE(max_increased);
1246 
1247     run1.Save();
1248     AssertStats(path, 1, 20);
1249 }
1250 
1251 // Tests what happens when the persistent settings contains the average duration of 1 run.
1252 // Data on file is 1 run and 109 average.
TEST_F(ProgressTest,SecondTime)1253 TEST_F(ProgressTest, SecondTime) {
1254     std::string path = CopyTextFileFixture("stats-one-run-no-newline.txt");
1255 
1256     Progress run1 = GetInstance(-42, 1.2, path);
1257     EXPECT_EQ(0, run1.Get());
1258     EXPECT_EQ(10, run1.GetInitialMax());
1259     EXPECT_EQ(10, run1.GetMax());
1260 
1261     bool max_increased = run1.Inc(20);
1262     EXPECT_EQ(20, run1.Get());
1263     EXPECT_EQ(24, run1.GetMax());
1264     EXPECT_TRUE(max_increased);
1265 
1266     // Average now is 2 runs and (10 + 20)/ 2 = 15
1267     run1.Save();
1268     AssertStats(path, 2, 15);
1269 
1270     Progress run2 = GetInstance(-42, 1.2, path);
1271     EXPECT_EQ(0, run2.Get());
1272     EXPECT_EQ(15, run2.GetInitialMax());
1273     EXPECT_EQ(15, run2.GetMax());
1274 
1275     max_increased = run2.Inc(25);
1276     EXPECT_EQ(25, run2.Get());
1277     EXPECT_EQ(30, run2.GetMax());
1278     EXPECT_TRUE(max_increased);
1279 
1280     // Average now is 3 runs and (15 * 2 + 25)/ 3 = 18.33 = 18
1281     run2.Save();
1282     AssertStats(path, 3, 18);
1283 
1284     Progress run3 = GetInstance(-42, 1.2, path);
1285     EXPECT_EQ(0, run3.Get());
1286     EXPECT_EQ(18, run3.GetInitialMax());
1287     EXPECT_EQ(18, run3.GetMax());
1288 
1289     // Make sure average decreases as well
1290     max_increased = run3.Inc(5);
1291     EXPECT_EQ(5, run3.Get());
1292     EXPECT_EQ(18, run3.GetMax());
1293     EXPECT_FALSE(max_increased);
1294 
1295     // Average now is 4 runs and (18 * 3 + 5)/ 4 = 14.75 = 14
1296     run3.Save();
1297     AssertStats(path, 4, 14);
1298 }
1299 
1300 // Tests what happens when the persistent settings contains the average duration of 2 runs.
1301 // Data on file is 2 runs and 15 average.
TEST_F(ProgressTest,ThirdTime)1302 TEST_F(ProgressTest, ThirdTime) {
1303     std::string path = CopyTextFileFixture("stats-two-runs.txt");
1304     AssertStats(path, 2, 15);  // Sanity check
1305 
1306     Progress run1 = GetInstance(-42, 1.2, path);
1307     EXPECT_EQ(0, run1.Get());
1308     EXPECT_EQ(15, run1.GetInitialMax());
1309     EXPECT_EQ(15, run1.GetMax());
1310 
1311     bool max_increased = run1.Inc(20);
1312     EXPECT_EQ(20, run1.Get());
1313     EXPECT_EQ(24, run1.GetMax());
1314     EXPECT_TRUE(max_increased);
1315 
1316     // Average now is 3 runs and (15 * 2 + 20)/ 3 = 16.66 = 16
1317     run1.Save();
1318     AssertStats(path, 3, 16);
1319 }
1320 
1321 class DumpstateUtilTest : public DumpstateBaseTest {
1322   public:
SetUp()1323     void SetUp() {
1324         DumpstateBaseTest::SetUp();
1325         SetDryRun(false);
1326     }
1327 
CaptureFdOut()1328     void CaptureFdOut() {
1329         ReadFileToString(path_, &out);
1330     }
1331 
CreateFd(const std::string & name)1332     void CreateFd(const std::string& name) {
1333         path_ = kTestDataPath + name;
1334         MYLOGD("Creating fd for file %s\n", path_.c_str());
1335 
1336         fd = TEMP_FAILURE_RETRY(open(path_.c_str(),
1337                                      O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1338                                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
1339         ASSERT_GE(fd, 0) << "could not create FD for path " << path_;
1340     }
1341 
1342     // Runs a command into the `fd` and capture `stderr`.
RunCommand(const std::string & title,const std::vector<std::string> & full_command,const CommandOptions & options=CommandOptions::DEFAULT)1343     int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
1344                    const CommandOptions& options = CommandOptions::DEFAULT) {
1345         CaptureStderr();
1346         int status = RunCommandToFd(fd, title, full_command, options);
1347         close(fd);
1348 
1349         CaptureFdOut();
1350         err = GetCapturedStderr();
1351         return status;
1352     }
1353 
1354     // Dumps a file and into the `fd` and `stderr`.
DumpFile(const std::string & title,const std::string & path)1355     int DumpFile(const std::string& title, const std::string& path) {
1356         CaptureStderr();
1357         int status = DumpFileToFd(fd, title, path);
1358         close(fd);
1359 
1360         CaptureFdOut();
1361         err = GetCapturedStderr();
1362         return status;
1363     }
1364 
1365     int fd;
1366 
1367     // 'fd` output and `stderr` from the last command ran.
1368     std::string out, err;
1369 
1370   private:
1371     std::string path_;
1372 };
1373 
TEST_F(DumpstateUtilTest,RunCommandNoArgs)1374 TEST_F(DumpstateUtilTest, RunCommandNoArgs) {
1375     CreateFd("RunCommandNoArgs.txt");
1376     EXPECT_EQ(-1, RunCommand("", {}));
1377 }
1378 
TEST_F(DumpstateUtilTest,RunCommandNoTitle)1379 TEST_F(DumpstateUtilTest, RunCommandNoTitle) {
1380     CreateFd("RunCommandWithNoArgs.txt");
1381     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
1382     EXPECT_THAT(out, StrEq("stdout\n"));
1383     EXPECT_THAT(err, StrEq("stderr\n"));
1384 }
1385 
TEST_F(DumpstateUtilTest,RunCommandWithTitle)1386 TEST_F(DumpstateUtilTest, RunCommandWithTitle) {
1387     CreateFd("RunCommandWithNoArgs.txt");
1388     EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
1389     EXPECT_THAT(out, StrEq("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n"));
1390     EXPECT_THAT(err, StrEq("stderr\n"));
1391 }
1392 
TEST_F(DumpstateUtilTest,RunCommandWithOneArg)1393 TEST_F(DumpstateUtilTest, RunCommandWithOneArg) {
1394     CreateFd("RunCommandWithOneArg.txt");
1395     EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one"}));
1396     EXPECT_THAT(err, IsEmpty());
1397     EXPECT_THAT(out, StrEq("one\n"));
1398 }
1399 
TEST_F(DumpstateUtilTest,RunCommandWithMultipleArgs)1400 TEST_F(DumpstateUtilTest, RunCommandWithMultipleArgs) {
1401     CreateFd("RunCommandWithMultipleArgs.txt");
1402     EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one", "is", "the", "loniest", "number"}));
1403     EXPECT_THAT(err, IsEmpty());
1404     EXPECT_THAT(out, StrEq("one is the loniest number\n"));
1405 }
1406 
TEST_F(DumpstateUtilTest,RunCommandWithLoggingMessage)1407 TEST_F(DumpstateUtilTest, RunCommandWithLoggingMessage) {
1408     CreateFd("RunCommandWithLoggingMessage.txt");
1409     EXPECT_EQ(
1410         0, RunCommand("", {kSimpleCommand},
1411                       CommandOptions::WithTimeout(10).Log("COMMAND, Y U NO LOG FIRST?").Build()));
1412     EXPECT_THAT(out, StrEq("stdout\n"));
1413     EXPECT_THAT(err, StrEq("COMMAND, Y U NO LOG FIRST?stderr\n"));
1414 }
1415 
TEST_F(DumpstateUtilTest,RunCommandRedirectStderr)1416 TEST_F(DumpstateUtilTest, RunCommandRedirectStderr) {
1417     CreateFd("RunCommandRedirectStderr.txt");
1418     EXPECT_EQ(0, RunCommand("", {kSimpleCommand},
1419                             CommandOptions::WithTimeout(10).RedirectStderr().Build()));
1420     EXPECT_THAT(out, IsEmpty());
1421     EXPECT_THAT(err, StrEq("stdout\nstderr\n"));
1422 }
1423 
TEST_F(DumpstateUtilTest,RunCommandDryRun)1424 TEST_F(DumpstateUtilTest, RunCommandDryRun) {
1425     CreateFd("RunCommandDryRun.txt");
1426     SetDryRun(true);
1427     EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
1428     EXPECT_THAT(out, StrEq(android::base::StringPrintf(
1429                          "------ I AM GROOT (%s) ------\n\t(skipped on dry run)\n",
1430                          kSimpleCommand.c_str())));
1431     EXPECT_THAT(err, IsEmpty());
1432 }
1433 
TEST_F(DumpstateUtilTest,RunCommandDryRunNoTitle)1434 TEST_F(DumpstateUtilTest, RunCommandDryRunNoTitle) {
1435     CreateFd("RunCommandDryRun.txt");
1436     SetDryRun(true);
1437     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
1438     EXPECT_THAT(
1439         out, StrEq(android::base::StringPrintf("%s: skipped on dry run\n", kSimpleCommand.c_str())));
1440     EXPECT_THAT(err, IsEmpty());
1441 }
1442 
TEST_F(DumpstateUtilTest,RunCommandDryRunAlways)1443 TEST_F(DumpstateUtilTest, RunCommandDryRunAlways) {
1444     CreateFd("RunCommandDryRunAlways.txt");
1445     SetDryRun(true);
1446     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Always().Build()));
1447     EXPECT_THAT(out, StrEq("stdout\n"));
1448     EXPECT_THAT(err, StrEq("stderr\n"));
1449 }
1450 
TEST_F(DumpstateUtilTest,RunCommandNotFound)1451 TEST_F(DumpstateUtilTest, RunCommandNotFound) {
1452     CreateFd("RunCommandNotFound.txt");
1453     EXPECT_NE(0, RunCommand("", {"/there/cannot/be/such/command"}));
1454     EXPECT_THAT(out, StartsWith("*** command '/there/cannot/be/such/command' failed: exit code"));
1455     EXPECT_THAT(err, StartsWith("execvp on command '/there/cannot/be/such/command' failed"));
1456 }
1457 
TEST_F(DumpstateUtilTest,RunCommandFails)1458 TEST_F(DumpstateUtilTest, RunCommandFails) {
1459     CreateFd("RunCommandFails.txt");
1460     EXPECT_EQ(42, RunCommand("", {kSimpleCommand, "--exit", "42"}));
1461     EXPECT_THAT(out, StrEq("stdout\n*** command '" + kSimpleCommand +
1462                            " --exit 42' failed: exit code 42\n"));
1463     EXPECT_THAT(err, StrEq("stderr\n*** command '" + kSimpleCommand +
1464                            " --exit 42' failed: exit code 42\n"));
1465 }
1466 
TEST_F(DumpstateUtilTest,RunCommandCrashes)1467 TEST_F(DumpstateUtilTest, RunCommandCrashes) {
1468     CreateFd("RunCommandCrashes.txt");
1469     EXPECT_NE(0, RunCommand("", {kSimpleCommand, "--crash"}));
1470     // We don't know the exit code, so check just the prefix.
1471     EXPECT_THAT(
1472         out, StartsWith("stdout\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
1473     EXPECT_THAT(
1474         err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
1475 }
1476 
TEST_F(DumpstateUtilTest,RunCommandTimesoutWithSec)1477 TEST_F(DumpstateUtilTest, RunCommandTimesoutWithSec) {
1478     CreateFd("RunCommandTimesout.txt");
1479     EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
1480                              CommandOptions::WithTimeout(1).Build()));
1481     EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
1482                                 " --sleep 2' timed out after 1"));
1483     EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
1484                                 " --sleep 2' timed out after 1"));
1485 }
1486 
TEST_F(DumpstateUtilTest,RunCommandTimesoutWithMsec)1487 TEST_F(DumpstateUtilTest, RunCommandTimesoutWithMsec) {
1488     CreateFd("RunCommandTimesout.txt");
1489     EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
1490                              CommandOptions::WithTimeoutInMs(1000).Build()));
1491     EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
1492                                 " --sleep 2' timed out after 1"));
1493     EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
1494                                 " --sleep 2' timed out after 1"));
1495 }
1496 
1497 
TEST_F(DumpstateUtilTest,RunCommandIsKilled)1498 TEST_F(DumpstateUtilTest, RunCommandIsKilled) {
1499     CreateFd("RunCommandIsKilled.txt");
1500     CaptureStderr();
1501 
1502     std::thread t([=]() {
1503         EXPECT_EQ(SIGTERM, RunCommandToFd(fd, "", {kSimpleCommand, "--pid", "--sleep", "20"},
1504                                           CommandOptions::WithTimeout(100).Always().Build()));
1505     });
1506 
1507     // Capture pid and pre-sleep output.
1508     sleep(1);  // Wait a little bit to make sure pid and 1st line were printed.
1509     std::string err = GetCapturedStderr();
1510     EXPECT_THAT(err, StrEq("sleeping for 20s\n"));
1511 
1512     CaptureFdOut();
1513     std::vector<std::string> lines = android::base::Split(out, "\n");
1514     ASSERT_EQ(3, (int)lines.size()) << "Invalid lines before sleep: " << out;
1515 
1516     int pid = atoi(lines[0].c_str());
1517     EXPECT_THAT(lines[1], StrEq("stdout line1"));
1518     EXPECT_THAT(lines[2], IsEmpty());  // \n
1519 
1520     // Then kill the process.
1521     CaptureFdOut();
1522     CaptureStderr();
1523     ASSERT_EQ(0, kill(pid, SIGTERM)) << "failed to kill pid " << pid;
1524     t.join();
1525 
1526     // Finally, check output after murder.
1527     CaptureFdOut();
1528     err = GetCapturedStderr();
1529 
1530     // out starts with the pid, which is an unknown
1531     EXPECT_THAT(out, EndsWith("stdout line1\n*** command '" + kSimpleCommand +
1532                               " --pid --sleep 20' failed: killed by signal 15\n"));
1533     EXPECT_THAT(err, StrEq("*** command '" + kSimpleCommand +
1534                            " --pid --sleep 20' failed: killed by signal 15\n"));
1535 }
1536 
TEST_F(DumpstateUtilTest,RunCommandAsRootUserBuild)1537 TEST_F(DumpstateUtilTest, RunCommandAsRootUserBuild) {
1538     if (!IsStandalone()) {
1539         // TODO: temporarily disabled because it might cause other tests to fail after dropping
1540         // to Shell - need to refactor tests to avoid this problem)
1541         MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootUserBuild() on test suite\n")
1542         return;
1543     }
1544     CreateFd("RunCommandAsRootUserBuild.txt");
1545     if (!PropertiesHelper::IsUserBuild()) {
1546         // Emulates user build if necessarily.
1547         SetBuildType("user");
1548     }
1549 
1550     DropRoot();
1551 
1552     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).AsRoot().Build()));
1553 
1554     // We don't know the exact path of su, so we just check for the 'root ...' commands
1555     EXPECT_THAT(out, StartsWith("Skipping"));
1556     EXPECT_THAT(out, EndsWith("root " + kSimpleCommand + "' on user build.\n"));
1557     EXPECT_THAT(err, IsEmpty());
1558 }
1559 
TEST_F(DumpstateUtilTest,RunCommandAsRootNonUserBuild)1560 TEST_F(DumpstateUtilTest, RunCommandAsRootNonUserBuild) {
1561     if (!IsStandalone()) {
1562         // TODO: temporarily disabled because it might cause other tests to fail after dropping
1563         // to Shell - need to refactor tests to avoid this problem)
1564         MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootNonUserBuild() on test suite\n")
1565         return;
1566     }
1567     CreateFd("RunCommandAsRootNonUserBuild.txt");
1568     if (PropertiesHelper::IsUserBuild()) {
1569         ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
1570         return;
1571     }
1572 
1573     DropRoot();
1574 
1575     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
1576                             CommandOptions::WithTimeout(1).AsRoot().Build()));
1577 
1578     EXPECT_THAT(out, StrEq("0\nstdout\n"));
1579     EXPECT_THAT(err, StrEq("stderr\n"));
1580 }
1581 
1582 
TEST_F(DumpstateUtilTest,RunCommandAsRootIfAvailableOnUserBuild)1583 TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnUserBuild) {
1584     if (!IsStandalone()) {
1585         // TODO: temporarily disabled because it might cause other tests to fail after dropping
1586         // to Shell - need to refactor tests to avoid this problem)
1587         MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
1588         return;
1589     }
1590     CreateFd("RunCommandAsRootIfAvailableOnUserBuild.txt");
1591     if (!PropertiesHelper::IsUserBuild()) {
1592         // Emulates user build if necessarily.
1593         SetBuildType("user");
1594     }
1595 
1596     DropRoot();
1597 
1598     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
1599                             CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
1600 
1601     EXPECT_THAT(out, StrEq("2000\nstdout\n"));
1602     EXPECT_THAT(err, StrEq("stderr\n"));
1603 }
1604 
TEST_F(DumpstateUtilTest,RunCommandAsRootIfAvailableOnDebugBuild)1605 TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnDebugBuild) {
1606     if (!IsStandalone()) {
1607         // TODO: temporarily disabled because it might cause other tests to fail after dropping
1608         // to Shell - need to refactor tests to avoid this problem)
1609         MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
1610         return;
1611     }
1612     CreateFd("RunCommandAsRootIfAvailableOnDebugBuild.txt");
1613     if (PropertiesHelper::IsUserBuild()) {
1614         ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
1615         return;
1616     }
1617 
1618     DropRoot();
1619 
1620     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
1621                             CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
1622 
1623     EXPECT_THAT(out, StrEq("0\nstdout\n"));
1624     EXPECT_THAT(err, StrEq("stderr\n"));
1625 }
1626 
TEST_F(DumpstateUtilTest,RunCommandDropRoot)1627 TEST_F(DumpstateUtilTest, RunCommandDropRoot) {
1628     if (!IsStandalone()) {
1629         // TODO: temporarily disabled because it might cause other tests to fail after dropping
1630         // to Shell - need to refactor tests to avoid this problem)
1631         MYLOGE("Skipping DumpstateUtilTest.RunCommandDropRoot() on test suite\n")
1632         return;
1633     }
1634     CreateFd("RunCommandDropRoot.txt");
1635     // First check root case - only available when running with 'adb root'.
1636     uid_t uid = getuid();
1637     if (uid == 0) {
1638         EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}));
1639         EXPECT_THAT(out, StrEq("0\nstdout\n"));
1640         EXPECT_THAT(err, StrEq("stderr\n"));
1641         return;
1642     }
1643     // Then run dropping root.
1644     EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
1645                             CommandOptions::WithTimeout(1).DropRoot().Build()));
1646     EXPECT_THAT(out, StrEq("2000\nstdout\n"));
1647     EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
1648 }
1649 
TEST_F(DumpstateUtilTest,DumpFileNotFoundNoTitle)1650 TEST_F(DumpstateUtilTest, DumpFileNotFoundNoTitle) {
1651     CreateFd("DumpFileNotFound.txt");
1652     EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
1653     EXPECT_THAT(out,
1654                 StrEq("*** Error dumping /I/cant/believe/I/exist: No such file or directory\n"));
1655     EXPECT_THAT(err, IsEmpty());
1656 }
1657 
TEST_F(DumpstateUtilTest,DumpFileNotFoundWithTitle)1658 TEST_F(DumpstateUtilTest, DumpFileNotFoundWithTitle) {
1659     CreateFd("DumpFileNotFound.txt");
1660     EXPECT_EQ(-1, DumpFile("Y U NO EXIST?", "/I/cant/believe/I/exist"));
1661     EXPECT_THAT(out, StrEq("*** Error dumping /I/cant/believe/I/exist (Y U NO EXIST?): No such "
1662                            "file or directory\n"));
1663     EXPECT_THAT(err, IsEmpty());
1664 }
1665 
TEST_F(DumpstateUtilTest,DumpFileSingleLine)1666 TEST_F(DumpstateUtilTest, DumpFileSingleLine) {
1667     CreateFd("DumpFileSingleLine.txt");
1668     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
1669     EXPECT_THAT(err, IsEmpty());
1670     EXPECT_THAT(out, StrEq("I AM LINE1\n"));  // dumpstate adds missing newline
1671 }
1672 
TEST_F(DumpstateUtilTest,DumpFileSingleLineWithNewLine)1673 TEST_F(DumpstateUtilTest, DumpFileSingleLineWithNewLine) {
1674     CreateFd("DumpFileSingleLineWithNewLine.txt");
1675     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line-with-newline.txt"));
1676     EXPECT_THAT(err, IsEmpty());
1677     EXPECT_THAT(out, StrEq("I AM LINE1\n"));
1678 }
1679 
TEST_F(DumpstateUtilTest,DumpFileMultipleLines)1680 TEST_F(DumpstateUtilTest, DumpFileMultipleLines) {
1681     CreateFd("DumpFileMultipleLines.txt");
1682     EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines.txt"));
1683     EXPECT_THAT(err, IsEmpty());
1684     EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
1685 }
1686 
TEST_F(DumpstateUtilTest,DumpFileMultipleLinesWithNewLine)1687 TEST_F(DumpstateUtilTest, DumpFileMultipleLinesWithNewLine) {
1688     CreateFd("DumpFileMultipleLinesWithNewLine.txt");
1689     EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines-with-newline.txt"));
1690     EXPECT_THAT(err, IsEmpty());
1691     EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
1692 }
1693 
TEST_F(DumpstateUtilTest,DumpFileOnDryRunNoTitle)1694 TEST_F(DumpstateUtilTest, DumpFileOnDryRunNoTitle) {
1695     CreateFd("DumpFileOnDryRun.txt");
1696     SetDryRun(true);
1697     std::string path = kTestDataPath + "single-line.txt";
1698     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
1699     EXPECT_THAT(err, IsEmpty());
1700     EXPECT_THAT(out, StrEq(path + ": skipped on dry run\n"));
1701 }
1702 
TEST_F(DumpstateUtilTest,DumpFileOnDryRun)1703 TEST_F(DumpstateUtilTest, DumpFileOnDryRun) {
1704     CreateFd("DumpFileOnDryRun.txt");
1705     SetDryRun(true);
1706     std::string path = kTestDataPath + "single-line.txt";
1707     EXPECT_EQ(0, DumpFile("Might as well dump. Dump!", kTestDataPath + "single-line.txt"));
1708     EXPECT_THAT(err, IsEmpty());
1709     EXPECT_THAT(
1710         out, StartsWith("------ Might as well dump. Dump! (" + kTestDataPath + "single-line.txt:"));
1711     EXPECT_THAT(out, EndsWith("skipped on dry run\n"));
1712 }
1713 
1714 }  // namespace dumpstate
1715 }  // namespace os
1716 }  // namespace android
1717