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