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