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