blob: 0d6890127296e43d32a689097c6b972a109452b3 [file] [log] [blame]
Felipe Leme4c2d6632016-09-28 14:32:00 -07001/*
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
Felipe Leme75876a22016-10-27 16:31:27 -070017#define LOG_TAG "dumpstate"
18#include <cutils/log.h>
19
20#include "DumpstateService.h"
21#include "android/os/BnDumpstate.h"
Felipe Leme4c2d6632016-09-28 14:32:00 -070022#include "dumpstate.h"
23
24#include <gmock/gmock.h>
25#include <gtest/gtest.h>
26
27#include <libgen.h>
Felipe Lemefd8affa2016-09-30 17:38:57 -070028#include <signal.h>
29#include <sys/types.h>
Felipe Leme4c2d6632016-09-28 14:32:00 -070030#include <unistd.h>
Felipe Lemefd8affa2016-09-30 17:38:57 -070031#include <thread>
Felipe Leme4c2d6632016-09-28 14:32:00 -070032
33#include <android-base/file.h>
Felipe Lemed80e6b62016-10-03 13:08:14 -070034#include <android-base/properties.h>
35#include <android-base/stringprintf.h>
Felipe Lemefd8affa2016-09-30 17:38:57 -070036#include <android-base/strings.h>
Felipe Leme4c2d6632016-09-28 14:32:00 -070037
Felipe Leme75876a22016-10-27 16:31:27 -070038using namespace android;
Felipe Lemed80e6b62016-10-03 13:08:14 -070039
Felipe Leme4c2d6632016-09-28 14:32:00 -070040using ::testing::EndsWith;
Felipe Leme009ecbb2016-11-07 10:18:44 -080041using ::testing::IsNull;
Felipe Leme4c2d6632016-09-28 14:32:00 -070042using ::testing::IsEmpty;
Felipe Leme009ecbb2016-11-07 10:18:44 -080043using ::testing::NotNull;
Felipe Leme4c2d6632016-09-28 14:32:00 -070044using ::testing::StrEq;
45using ::testing::StartsWith;
46using ::testing::Test;
47using ::testing::internal::CaptureStderr;
48using ::testing::internal::CaptureStdout;
49using ::testing::internal::GetCapturedStderr;
50using ::testing::internal::GetCapturedStdout;
51
Felipe Leme75876a22016-10-27 16:31:27 -070052using os::DumpstateService;
53using os::IDumpstateListener;
Felipe Leme009ecbb2016-11-07 10:18:44 -080054using os::IDumpstateToken;
Felipe Leme75876a22016-10-27 16:31:27 -070055
Felipe Leme4c2d6632016-09-28 14:32:00 -070056// Not used on test cases yet...
57void dumpstate_board(void) {
58}
59
Felipe Leme75876a22016-10-27 16:31:27 -070060class DumpstateListenerMock : public IDumpstateListener {
61 public:
62 MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
63 MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
64
65 protected:
66 MOCK_METHOD0(onAsBinder, IBinder*());
67};
68
Felipe Leme7447d7c2016-11-03 18:12:22 -070069// Base class for all tests in this file
70class DumpstateBaseTest : public Test {
71 protected:
72 const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str());
73 const std::string kFixturesPath = kTestPath + "/../dumpstate_test_fixture/";
74 const std::string kTestDataPath = kFixturesPath + "/testdata/";
75 const std::string kSimpleCommand = kFixturesPath + "dumpstate_test_fixture";
76 const std::string kEchoCommand = "/system/bin/echo";
77
78 /*
79 * Copies a text file fixture to a temporary file, returning it's path.
80 *
81 * Useful in cases where the test case changes the content of the tile.
82 */
83 std::string CopyTextFileFixture(const std::string& relative_name) {
84 std::string from = kTestDataPath + relative_name;
85 // Not using TemporaryFile because it's deleted at the end, and it's useful to keep it
86 // around for poking when the test fails.
87 std::string to = kTestDataPath + relative_name + ".tmp";
88 ALOGD("CopyTextFileFixture: from %s to %s\n", from.c_str(), to.c_str());
89 android::base::RemoveFileIfExists(to);
90 CopyTextFile(from, to);
91 return to.c_str();
92 }
93
94 private:
95 // Need a function that returns void to use assertions -
96 // https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#assertion-placement
97 void CopyTextFile(const std::string& from, const std::string& to) {
98 std::string content;
99 ASSERT_TRUE(android::base::ReadFileToString(from, &content)) << "could not read from "
100 << from;
101 ASSERT_TRUE(android::base::WriteStringToFile(content, to)) << "could not write to " << to;
102 }
103};
104
105class DumpstateTest : public DumpstateBaseTest {
Felipe Leme4c2d6632016-09-28 14:32:00 -0700106 public:
107 void SetUp() {
108 SetDryRun(false);
Felipe Lemed80e6b62016-10-03 13:08:14 -0700109 SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700110 ds.progress_.reset(new Progress());
Felipe Leme9a523ae2016-10-20 15:10:33 -0700111 ds.update_progress_ = false;
Felipe Leme009ecbb2016-11-07 10:18:44 -0800112 ds.update_progress_threshold_ = 0;
Felipe Leme4c2d6632016-09-28 14:32:00 -0700113 }
114
115 // Runs a command and capture `stdout` and `stderr`.
Felipe Leme9a523ae2016-10-20 15:10:33 -0700116 int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
Felipe Leme4c2d6632016-09-28 14:32:00 -0700117 const CommandOptions& options = CommandOptions::DEFAULT) {
118 CaptureStdout();
119 CaptureStderr();
Felipe Leme9a523ae2016-10-20 15:10:33 -0700120 int status = ds.RunCommand(title, full_command, options);
Felipe Leme4c2d6632016-09-28 14:32:00 -0700121 out = GetCapturedStdout();
122 err = GetCapturedStderr();
123 return status;
124 }
125
Felipe Lemecef02982016-10-03 17:22:22 -0700126 // Dumps a file and capture `stdout` and `stderr`.
127 int DumpFile(const std::string& title, const std::string& path) {
128 CaptureStdout();
129 CaptureStderr();
130 int status = ds.DumpFile(title, path);
131 out = GetCapturedStdout();
132 err = GetCapturedStderr();
133 return status;
134 }
135
Felipe Leme9a523ae2016-10-20 15:10:33 -0700136 void SetDryRun(bool dry_run) {
137 ALOGD("Setting dry_run_ to %s\n", dry_run ? "true" : "false");
138 ds.dry_run_ = dry_run;
Felipe Lemed80e6b62016-10-03 13:08:14 -0700139 }
140
Felipe Leme9a523ae2016-10-20 15:10:33 -0700141 void SetBuildType(const std::string& build_type) {
142 ALOGD("Setting build_type_ to '%s'\n", build_type.c_str());
143 ds.build_type_ = build_type;
Felipe Lemed80e6b62016-10-03 13:08:14 -0700144 }
145
146 bool IsUserBuild() {
147 return "user" == android::base::GetProperty("ro.build.type", "(unknown)");
148 }
149
150 void DropRoot() {
151 drop_root_user();
152 uid_t uid = getuid();
153 ASSERT_EQ(2000, (int)uid);
154 }
155
Felipe Leme009ecbb2016-11-07 10:18:44 -0800156 void SetProgress(long progress, long initial_max, long threshold = 0) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700157 ds.update_progress_ = true;
Felipe Leme009ecbb2016-11-07 10:18:44 -0800158 ds.update_progress_threshold_ = threshold;
159 ds.last_updated_progress_ = 0;
Felipe Leme7447d7c2016-11-03 18:12:22 -0700160 ds.progress_.reset(new Progress(initial_max, progress, 1.2));
161 }
162
Felipe Leme7447d7c2016-11-03 18:12:22 -0700163 std::string GetProgressMessage(const std::string& listener_name, int progress, int max,
Felipe Leme009ecbb2016-11-07 10:18:44 -0800164 int old_max = 0, bool update_progress = true) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700165 EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress";
166 EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max";
Felipe Leme75876a22016-10-27 16:31:27 -0700167
Felipe Leme7447d7c2016-11-03 18:12:22 -0700168 bool max_increased = old_max > 0;
Felipe Leme75876a22016-10-27 16:31:27 -0700169
Felipe Leme009ecbb2016-11-07 10:18:44 -0800170 std::string message = "";
Felipe Leme75876a22016-10-27 16:31:27 -0700171 if (max_increased) {
Felipe Leme009ecbb2016-11-07 10:18:44 -0800172 message =
Felipe Leme7447d7c2016-11-03 18:12:22 -0700173 android::base::StringPrintf("Adjusting max progress from %d to %d\n", old_max, max);
Felipe Leme75876a22016-10-27 16:31:27 -0700174 }
175
Felipe Leme009ecbb2016-11-07 10:18:44 -0800176 if (update_progress) {
177 message += android::base::StringPrintf("Setting progress (%s): %d/%d\n",
178 listener_name.c_str(), progress, max);
179 }
180
181 return message;
Felipe Lemed80e6b62016-10-03 13:08:14 -0700182 }
183
Felipe Leme4c2d6632016-09-28 14:32:00 -0700184 // `stdout` and `stderr` from the last command ran.
185 std::string out, err;
186
Felipe Lemefd8affa2016-09-30 17:38:57 -0700187 Dumpstate& ds = Dumpstate::GetInstance();
Felipe Leme4c2d6632016-09-28 14:32:00 -0700188};
189
190TEST_F(DumpstateTest, RunCommandNoArgs) {
191 EXPECT_EQ(-1, RunCommand("", {}));
192}
193
194TEST_F(DumpstateTest, RunCommandNoTitle) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700195 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700196 EXPECT_THAT(out, StrEq("stdout\n"));
197 EXPECT_THAT(err, StrEq("stderr\n"));
198}
199
200TEST_F(DumpstateTest, RunCommandWithTitle) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700201 EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700202 EXPECT_THAT(err, StrEq("stderr\n"));
203 // We don't know the exact duration, so we check the prefix and suffix
Felipe Lemefd8affa2016-09-30 17:38:57 -0700204 EXPECT_THAT(out,
Felipe Leme7447d7c2016-11-03 18:12:22 -0700205 StartsWith("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n------"));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700206 EXPECT_THAT(out, EndsWith("s was the duration of 'I AM GROOT' ------\n"));
207}
208
Felipe Lemefd8affa2016-09-30 17:38:57 -0700209TEST_F(DumpstateTest, RunCommandWithLoggingMessage) {
Felipe Leme4c2d6632016-09-28 14:32:00 -0700210 EXPECT_EQ(
Felipe Leme7447d7c2016-11-03 18:12:22 -0700211 0, RunCommand("", {kSimpleCommand},
Felipe Lemefd8affa2016-09-30 17:38:57 -0700212 CommandOptions::WithTimeout(10).Log("COMMAND, Y U NO LOG FIRST?").Build()));
213 EXPECT_THAT(out, StrEq("stdout\n"));
214 EXPECT_THAT(err, StrEq("COMMAND, Y U NO LOG FIRST?stderr\n"));
215}
216
217TEST_F(DumpstateTest, RunCommandRedirectStderr) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700218 EXPECT_EQ(0, RunCommand("", {kSimpleCommand},
Felipe Lemefd8affa2016-09-30 17:38:57 -0700219 CommandOptions::WithTimeout(10).RedirectStderr().Build()));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700220 EXPECT_THAT(out, IsEmpty());
Felipe Lemefd8affa2016-09-30 17:38:57 -0700221 EXPECT_THAT(err, StrEq("stdout\nstderr\n"));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700222}
223
224TEST_F(DumpstateTest, RunCommandWithOneArg) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700225 EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one"}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700226 EXPECT_THAT(err, IsEmpty());
227 EXPECT_THAT(out, StrEq("one\n"));
228}
229
Felipe Lemefd8affa2016-09-30 17:38:57 -0700230TEST_F(DumpstateTest, RunCommandWithMultipleArgs) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700231 EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one", "is", "the", "loniest", "number"}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700232 EXPECT_THAT(err, IsEmpty());
233 EXPECT_THAT(out, StrEq("one is the loniest number\n"));
234}
235
236TEST_F(DumpstateTest, RunCommandDryRun) {
237 SetDryRun(true);
Felipe Leme7447d7c2016-11-03 18:12:22 -0700238 EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700239 // We don't know the exact duration, so we check the prefix and suffix
Felipe Leme7447d7c2016-11-03 18:12:22 -0700240 EXPECT_THAT(out, StartsWith("------ I AM GROOT (" + kSimpleCommand +
Felipe Leme4c2d6632016-09-28 14:32:00 -0700241 ") ------\n\t(skipped on dry run)\n------"));
242 EXPECT_THAT(out, EndsWith("s was the duration of 'I AM GROOT' ------\n"));
243 EXPECT_THAT(err, IsEmpty());
244}
245
246TEST_F(DumpstateTest, RunCommandDryRunNoTitle) {
247 SetDryRun(true);
Felipe Leme7447d7c2016-11-03 18:12:22 -0700248 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700249 EXPECT_THAT(out, IsEmpty());
250 EXPECT_THAT(err, IsEmpty());
251}
252
253TEST_F(DumpstateTest, RunCommandDryRunAlways) {
254 SetDryRun(true);
Felipe Leme7447d7c2016-11-03 18:12:22 -0700255 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Always().Build()));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700256 EXPECT_THAT(out, StrEq("stdout\n"));
257 EXPECT_THAT(err, StrEq("stderr\n"));
258}
259
Felipe Lemefd8affa2016-09-30 17:38:57 -0700260TEST_F(DumpstateTest, RunCommandNotFound) {
261 EXPECT_NE(0, RunCommand("", {"/there/cannot/be/such/command"}));
262 EXPECT_THAT(out, StartsWith("*** command '/there/cannot/be/such/command' failed: exit code"));
263 EXPECT_THAT(err, StartsWith("execvp on command '/there/cannot/be/such/command' failed"));
264}
265
266TEST_F(DumpstateTest, RunCommandFails) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700267 EXPECT_EQ(42, RunCommand("", {kSimpleCommand, "--exit", "42"}));
268 EXPECT_THAT(out, StrEq("stdout\n*** command '" + kSimpleCommand +
Felipe Leme9a523ae2016-10-20 15:10:33 -0700269 " --exit 42' failed: exit code 42\n"));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700270 EXPECT_THAT(err, StrEq("stderr\n*** command '" + kSimpleCommand +
Felipe Leme9a523ae2016-10-20 15:10:33 -0700271 " --exit 42' failed: exit code 42\n"));
Felipe Lemefd8affa2016-09-30 17:38:57 -0700272}
273
274TEST_F(DumpstateTest, RunCommandCrashes) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700275 EXPECT_NE(0, RunCommand("", {kSimpleCommand, "--crash"}));
Felipe Lemefd8affa2016-09-30 17:38:57 -0700276 // We don't know the exit code, so check just the prefix.
277 EXPECT_THAT(
Felipe Leme7447d7c2016-11-03 18:12:22 -0700278 out, StartsWith("stdout\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
Felipe Lemefd8affa2016-09-30 17:38:57 -0700279 EXPECT_THAT(
Felipe Leme7447d7c2016-11-03 18:12:22 -0700280 err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
Felipe Lemefd8affa2016-09-30 17:38:57 -0700281}
282
283TEST_F(DumpstateTest, RunCommandTimesout) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700284 EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
Felipe Lemefd8affa2016-09-30 17:38:57 -0700285 CommandOptions::WithTimeout(1).Build()));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700286 EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
Felipe Lemefd8affa2016-09-30 17:38:57 -0700287 " --sleep 2' timed out after 1"));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700288 EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
Felipe Lemefd8affa2016-09-30 17:38:57 -0700289 " --sleep 2' timed out after 1"));
290}
291
292TEST_F(DumpstateTest, RunCommandIsKilled) {
293 CaptureStdout();
294 CaptureStderr();
295
296 std::thread t([=]() {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700297 EXPECT_EQ(SIGTERM, ds.RunCommand("", {kSimpleCommand, "--pid", "--sleep", "20"},
Felipe Lemefd8affa2016-09-30 17:38:57 -0700298 CommandOptions::WithTimeout(100).Always().Build()));
299 });
300
301 // Capture pid and pre-sleep output.
302 sleep(1); // Wait a little bit to make sure pid and 1st line were printed.
303 std::string err = GetCapturedStderr();
304 EXPECT_THAT(err, StrEq("sleeping for 20s\n"));
305
306 std::string out = GetCapturedStdout();
307 std::vector<std::string> lines = android::base::Split(out, "\n");
308 ASSERT_EQ(3, (int)lines.size()) << "Invalid lines before sleep: " << out;
309
310 int pid = atoi(lines[0].c_str());
311 EXPECT_THAT(lines[1], StrEq("stdout line1"));
312 EXPECT_THAT(lines[2], IsEmpty()); // \n
313
314 // Then kill the process.
315 CaptureStdout();
316 CaptureStderr();
317 ASSERT_EQ(0, kill(pid, SIGTERM)) << "failed to kill pid " << pid;
318 t.join();
319
320 // Finally, check output after murder.
321 out = GetCapturedStdout();
322 err = GetCapturedStderr();
323
Felipe Leme7447d7c2016-11-03 18:12:22 -0700324 EXPECT_THAT(out, StrEq("*** command '" + kSimpleCommand +
Felipe Lemefd8affa2016-09-30 17:38:57 -0700325 " --pid --sleep 20' failed: killed by signal 15\n"));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700326 EXPECT_THAT(err, StrEq("*** command '" + kSimpleCommand +
Felipe Lemefd8affa2016-09-30 17:38:57 -0700327 " --pid --sleep 20' failed: killed by signal 15\n"));
328}
329
Felipe Leme75876a22016-10-27 16:31:27 -0700330TEST_F(DumpstateTest, RunCommandProgress) {
331 sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
332 ds.listener_ = listener;
333 ds.listener_name_ = "FoxMulder";
Felipe Leme7447d7c2016-11-03 18:12:22 -0700334 SetProgress(0, 30);
Felipe Leme75876a22016-10-27 16:31:27 -0700335
336 EXPECT_CALL(*listener, onProgressUpdated(20));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700337 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
Felipe Leme75876a22016-10-27 16:31:27 -0700338 std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
339 EXPECT_THAT(out, StrEq("stdout\n"));
340 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
341
342 EXPECT_CALL(*listener, onProgressUpdated(30));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700343 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
Felipe Leme75876a22016-10-27 16:31:27 -0700344 progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
345 EXPECT_THAT(out, StrEq("stdout\n"));
346 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
347
348 // Run a command that will increase maximum timeout.
349 EXPECT_CALL(*listener, onProgressUpdated(31));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700350 EXPECT_CALL(*listener, onMaxProgressUpdated(37));
351 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
352 progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase
Felipe Leme75876a22016-10-27 16:31:27 -0700353 EXPECT_THAT(out, StrEq("stdout\n"));
354 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
355
356 // Make sure command ran while in dry_run is counted.
357 SetDryRun(true);
358 EXPECT_CALL(*listener, onProgressUpdated(35));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700359 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
360 progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
Felipe Leme75876a22016-10-27 16:31:27 -0700361 EXPECT_THAT(out, IsEmpty());
362 EXPECT_THAT(err, StrEq(progress_message));
363
364 ds.listener_.clear();
365}
366
Felipe Leme009ecbb2016-11-07 10:18:44 -0800367TEST_F(DumpstateTest, RunCommandProgressIgnoreThreshold) {
368 sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
369 ds.listener_ = listener;
370 ds.listener_name_ = "FoxMulder";
371 SetProgress(0, 8, 5); // 8 max, 5 threshold
372
373 // First update should always be sent.
374 EXPECT_CALL(*listener, onProgressUpdated(1));
375 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
376 std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
377 EXPECT_THAT(out, StrEq("stdout\n"));
378 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
379
380 // Fourth update should be ignored because it's between the threshold (5 -1 = 4 < 5).
381 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
382 EXPECT_THAT(out, StrEq("stdout\n"));
383 EXPECT_THAT(err, StrEq("stderr\n"));
384
385 // Third update should be sent because it reaches threshold (6 - 1 = 5).
386 EXPECT_CALL(*listener, onProgressUpdated(6));
387 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
388 progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
389 EXPECT_THAT(out, StrEq("stdout\n"));
390 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
391
392 // Fourth update should be ignored because it's between the threshold (9 - 6 = 3 < 5).
393 // But max update should be sent.
394 EXPECT_CALL(*listener, onMaxProgressUpdated(10)); // 9 * 120% = 10.8 = 10
395 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
396 progress_message = GetProgressMessage(ds.listener_name_, 9, 10, 8, false);
397 EXPECT_THAT(out, StrEq("stdout\n"));
398 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
399
400 ds.listener_.clear();
401}
402
Felipe Lemed80e6b62016-10-03 13:08:14 -0700403TEST_F(DumpstateTest, RunCommandDropRoot) {
404 // First check root case - only available when running with 'adb root'.
405 uid_t uid = getuid();
406 if (uid == 0) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700407 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}));
Felipe Lemed80e6b62016-10-03 13:08:14 -0700408 EXPECT_THAT(out, StrEq("0\nstdout\n"));
409 EXPECT_THAT(err, StrEq("stderr\n"));
410 return;
411 }
Felipe Leme7447d7c2016-11-03 18:12:22 -0700412 // Then run dropping root.
413 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
Felipe Lemed80e6b62016-10-03 13:08:14 -0700414 CommandOptions::WithTimeout(1).DropRoot().Build()));
415 EXPECT_THAT(out, StrEq("2000\nstdout\n"));
Felipe Leme26c41572016-10-06 14:34:43 -0700416 EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
Felipe Lemed80e6b62016-10-03 13:08:14 -0700417}
418
419TEST_F(DumpstateTest, RunCommandAsRootUserBuild) {
420 if (!IsUserBuild()) {
421 // Emulates user build if necessarily.
422 SetBuildType("user");
423 }
424
425 DropRoot();
426
Felipe Leme7447d7c2016-11-03 18:12:22 -0700427 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).AsRoot().Build()));
Felipe Lemed80e6b62016-10-03 13:08:14 -0700428
429 // We don't know the exact path of su, so we just check for the 'root ...' commands
430 EXPECT_THAT(out, StartsWith("Skipping"));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700431 EXPECT_THAT(out, EndsWith("root " + kSimpleCommand + "' on user build.\n"));
Felipe Lemed80e6b62016-10-03 13:08:14 -0700432 EXPECT_THAT(err, IsEmpty());
433}
434
Felipe Lemecef02982016-10-03 17:22:22 -0700435TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
436 EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
437 EXPECT_THAT(out,
438 StrEq("*** Error dumping /I/cant/believe/I/exist: No such file or directory\n"));
439 EXPECT_THAT(err, IsEmpty());
440}
441
442TEST_F(DumpstateTest, DumpFileNotFoundWithTitle) {
443 EXPECT_EQ(-1, DumpFile("Y U NO EXIST?", "/I/cant/believe/I/exist"));
444 EXPECT_THAT(err, IsEmpty());
445 // We don't know the exact duration, so we check the prefix and suffix
446 EXPECT_THAT(out, StartsWith("*** Error dumping /I/cant/believe/I/exist (Y U NO EXIST?): No "
447 "such file or directory\n"));
448 EXPECT_THAT(out, EndsWith("s was the duration of 'Y U NO EXIST?' ------\n"));
449}
450
451TEST_F(DumpstateTest, DumpFileSingleLine) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700452 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
Felipe Lemecef02982016-10-03 17:22:22 -0700453 EXPECT_THAT(err, IsEmpty());
454 EXPECT_THAT(out, StrEq("I AM LINE1\n")); // dumpstate adds missing newline
455}
456
457TEST_F(DumpstateTest, DumpFileSingleLineWithNewLine) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700458 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line-with-newline.txt"));
Felipe Lemecef02982016-10-03 17:22:22 -0700459 EXPECT_THAT(err, IsEmpty());
460 EXPECT_THAT(out, StrEq("I AM LINE1\n"));
461}
462
463TEST_F(DumpstateTest, DumpFileMultipleLines) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700464 EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines.txt"));
Felipe Lemecef02982016-10-03 17:22:22 -0700465 EXPECT_THAT(err, IsEmpty());
466 EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
467}
468
469TEST_F(DumpstateTest, DumpFileMultipleLinesWithNewLine) {
Felipe Leme7447d7c2016-11-03 18:12:22 -0700470 EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines-with-newline.txt"));
Felipe Lemecef02982016-10-03 17:22:22 -0700471 EXPECT_THAT(err, IsEmpty());
472 EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
473}
474
475TEST_F(DumpstateTest, DumpFileOnDryRunNoTitle) {
476 SetDryRun(true);
Felipe Leme7447d7c2016-11-03 18:12:22 -0700477 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
Felipe Lemecef02982016-10-03 17:22:22 -0700478 EXPECT_THAT(err, IsEmpty());
479 EXPECT_THAT(out, IsEmpty());
480}
481
482TEST_F(DumpstateTest, DumpFileOnDryRun) {
483 SetDryRun(true);
Felipe Leme7447d7c2016-11-03 18:12:22 -0700484 EXPECT_EQ(0, DumpFile("Might as well dump. Dump!", kTestDataPath + "single-line.txt"));
Felipe Lemecef02982016-10-03 17:22:22 -0700485 EXPECT_THAT(err, IsEmpty());
Felipe Leme7447d7c2016-11-03 18:12:22 -0700486 EXPECT_THAT(out, StartsWith("------ Might as well dump. Dump! (" + kTestDataPath +
Felipe Lemecef02982016-10-03 17:22:22 -0700487 "single-line.txt) ------\n\t(skipped on dry run)\n------"));
488 EXPECT_THAT(out, EndsWith("s was the duration of 'Might as well dump. Dump!' ------\n"));
489 EXPECT_THAT(err, IsEmpty());
490}
491
Felipe Leme75876a22016-10-27 16:31:27 -0700492TEST_F(DumpstateTest, DumpFileUpdateProgress) {
493 sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
494 ds.listener_ = listener;
495 ds.listener_name_ = "FoxMulder";
Felipe Leme7447d7c2016-11-03 18:12:22 -0700496 SetProgress(0, 30);
Felipe Leme75876a22016-10-27 16:31:27 -0700497
498 EXPECT_CALL(*listener, onProgressUpdated(5));
Felipe Leme7447d7c2016-11-03 18:12:22 -0700499 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
Felipe Leme75876a22016-10-27 16:31:27 -0700500
501 std::string progress_message =
502 GetProgressMessage(ds.listener_name_, 5, 30); // TODO: unhardcode WEIGHT_FILE (5)?
503 EXPECT_THAT(err, StrEq(progress_message));
504 EXPECT_THAT(out, StrEq("I AM LINE1\n")); // dumpstate adds missing newline
505
506 ds.listener_.clear();
507}
508
Felipe Leme7447d7c2016-11-03 18:12:22 -0700509class DumpstateServiceTest : public DumpstateBaseTest {
Felipe Leme75876a22016-10-27 16:31:27 -0700510 public:
511 DumpstateService dss;
512};
513
514TEST_F(DumpstateServiceTest, SetListenerNoName) {
515 sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
Felipe Leme009ecbb2016-11-07 10:18:44 -0800516 sp<IDumpstateToken> token;
517 EXPECT_TRUE(dss.setListener("", listener, &token).isOk());
518 ASSERT_THAT(token, IsNull());
Felipe Leme75876a22016-10-27 16:31:27 -0700519}
520
521TEST_F(DumpstateServiceTest, SetListenerNoPointer) {
Felipe Leme009ecbb2016-11-07 10:18:44 -0800522 sp<IDumpstateToken> token;
523 EXPECT_TRUE(dss.setListener("whatever", nullptr, &token).isOk());
524 ASSERT_THAT(token, IsNull());
Felipe Leme75876a22016-10-27 16:31:27 -0700525}
526
527TEST_F(DumpstateServiceTest, SetListenerTwice) {
528 sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
Felipe Leme009ecbb2016-11-07 10:18:44 -0800529 sp<IDumpstateToken> token;
530 EXPECT_TRUE(dss.setListener("whatever", listener, &token).isOk());
531 ASSERT_THAT(token, NotNull());
Felipe Leme75876a22016-10-27 16:31:27 -0700532 EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
533
Felipe Leme009ecbb2016-11-07 10:18:44 -0800534 token.clear();
535 EXPECT_TRUE(dss.setListener("whatsoever", listener, &token).isOk());
536 ASSERT_THAT(token, IsNull());
537 EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
Felipe Leme75876a22016-10-27 16:31:27 -0700538}
Felipe Leme7447d7c2016-11-03 18:12:22 -0700539
540class ProgressTest : public DumpstateBaseTest {
541 public:
542 Progress GetInstance(int32_t max, double growth_factor, const std::string& path = "") {
543 return Progress(max, growth_factor, path);
544 }
545
546 void AssertStats(const std::string& path, int32_t expected_runs, int32_t expected_average) {
547 std::string expected_content =
548 android::base::StringPrintf("%d %d\n", expected_runs, expected_average);
549 std::string actual_content;
550 ASSERT_TRUE(android::base::ReadFileToString(path, &actual_content))
551 << "could not read statsfrom" << path;
552 ASSERT_THAT(actual_content, StrEq(expected_content)) << "invalid stats on " << path;
553 }
554};
555
556TEST_F(ProgressTest, SimpleTest) {
557 Progress progress;
558 EXPECT_EQ(0, progress.Get());
559 EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
560 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
561
562 bool max_increased = progress.Inc(1);
563 EXPECT_EQ(1, progress.Get());
564 EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
565 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
566 EXPECT_FALSE(max_increased);
567
568 // Ignore negative increase.
569 max_increased = progress.Inc(-1);
570 EXPECT_EQ(1, progress.Get());
571 EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
572 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
573 EXPECT_FALSE(max_increased);
574}
575
576TEST_F(ProgressTest, MaxGrowsInsideNewRange) {
577 Progress progress = GetInstance(10, 1.2); // 20% growth factor
578 EXPECT_EQ(0, progress.Get());
579 EXPECT_EQ(10, progress.GetInitialMax());
580 EXPECT_EQ(10, progress.GetMax());
581
582 // No increase
583 bool max_increased = progress.Inc(10);
584 EXPECT_EQ(10, progress.Get());
585 EXPECT_EQ(10, progress.GetMax());
586 EXPECT_FALSE(max_increased);
587
588 // Increase, with new value < max*20%
589 max_increased = progress.Inc(1);
590 EXPECT_EQ(11, progress.Get());
591 EXPECT_EQ(13, progress.GetMax()); // 11 average * 20% growth = 13.2 = 13
592 EXPECT_TRUE(max_increased);
593}
594
595TEST_F(ProgressTest, MaxGrowsOutsideNewRange) {
596 Progress progress = GetInstance(10, 1.2); // 20% growth factor
597 EXPECT_EQ(0, progress.Get());
598 EXPECT_EQ(10, progress.GetInitialMax());
599 EXPECT_EQ(10, progress.GetMax());
600
601 // No increase
602 bool max_increased = progress.Inc(10);
603 EXPECT_EQ(10, progress.Get());
604 EXPECT_EQ(10, progress.GetMax());
605 EXPECT_FALSE(max_increased);
606
607 // Increase, with new value > max*20%
608 max_increased = progress.Inc(5);
609 EXPECT_EQ(15, progress.Get());
610 EXPECT_EQ(18, progress.GetMax()); // 15 average * 20% growth = 18
611 EXPECT_TRUE(max_increased);
612}
613
614TEST_F(ProgressTest, InvalidPath) {
615 Progress progress("/devil/null");
616 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
617}
618
619TEST_F(ProgressTest, EmptyFile) {
620 Progress progress(CopyTextFileFixture("empty-file.txt"));
621 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
622}
623
624TEST_F(ProgressTest, InvalidLine1stEntryNAN) {
625 Progress progress(CopyTextFileFixture("stats-invalid-1st-NAN.txt"));
626 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
627}
628
629TEST_F(ProgressTest, InvalidLine2ndEntryNAN) {
630 Progress progress(CopyTextFileFixture("stats-invalid-2nd-NAN.txt"));
631 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
632}
633
634TEST_F(ProgressTest, InvalidLineBothNAN) {
635 Progress progress(CopyTextFileFixture("stats-invalid-both-NAN.txt"));
636 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
637}
638
639TEST_F(ProgressTest, InvalidLine1stEntryNegative) {
640 Progress progress(CopyTextFileFixture("stats-invalid-1st-negative.txt"));
641 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
642}
643
644TEST_F(ProgressTest, InvalidLine2ndEntryNegative) {
645 Progress progress(CopyTextFileFixture("stats-invalid-2nd-negative.txt"));
646 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
647}
648
649TEST_F(ProgressTest, InvalidLine1stEntryTooBig) {
650 Progress progress(CopyTextFileFixture("stats-invalid-1st-too-big.txt"));
651 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
652}
653
654TEST_F(ProgressTest, InvalidLine2ndEntryTooBig) {
655 Progress progress(CopyTextFileFixture("stats-invalid-2nd-too-big.txt"));
656 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
657}
658
659// Tests stats are properly saved when the file does not exists.
660TEST_F(ProgressTest, FirstTime) {
661 std::string path = kTestDataPath + "FirstTime.txt";
662 android::base::RemoveFileIfExists(path);
663
664 Progress run1(path);
665 EXPECT_EQ(0, run1.Get());
666 EXPECT_EQ(Progress::kDefaultMax, run1.GetInitialMax());
667 EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
668
669 bool max_increased = run1.Inc(20);
670 EXPECT_EQ(20, run1.Get());
671 EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
672 EXPECT_FALSE(max_increased);
673
674 run1.Save();
675 AssertStats(path, 1, 20);
676}
677
678// Tests what happens when the persistent settings contains the average duration of 1 run.
679// Data on file is 1 run and 109 average.
680TEST_F(ProgressTest, SecondTime) {
681 std::string path = CopyTextFileFixture("stats-one-run-no-newline.txt");
682
683 Progress run1 = GetInstance(-42, 1.2, path);
684 EXPECT_EQ(0, run1.Get());
685 EXPECT_EQ(10, run1.GetInitialMax());
686 EXPECT_EQ(10, run1.GetMax());
687
688 bool max_increased = run1.Inc(20);
689 EXPECT_EQ(20, run1.Get());
690 EXPECT_EQ(24, run1.GetMax());
691 EXPECT_TRUE(max_increased);
692
693 // Average now is 2 runs and (10 + 20)/ 2 = 15
694 run1.Save();
695 AssertStats(path, 2, 15);
696
697 Progress run2 = GetInstance(-42, 1.2, path);
698 EXPECT_EQ(0, run2.Get());
699 EXPECT_EQ(15, run2.GetInitialMax());
700 EXPECT_EQ(15, run2.GetMax());
701
702 max_increased = run2.Inc(25);
703 EXPECT_EQ(25, run2.Get());
704 EXPECT_EQ(30, run2.GetMax());
705 EXPECT_TRUE(max_increased);
706
707 // Average now is 3 runs and (15 * 2 + 25)/ 3 = 18.33 = 18
708 run2.Save();
709 AssertStats(path, 3, 18);
710
711 Progress run3 = GetInstance(-42, 1.2, path);
712 EXPECT_EQ(0, run3.Get());
713 EXPECT_EQ(18, run3.GetInitialMax());
714 EXPECT_EQ(18, run3.GetMax());
715
716 // Make sure average decreases as well
717 max_increased = run3.Inc(5);
718 EXPECT_EQ(5, run3.Get());
719 EXPECT_EQ(18, run3.GetMax());
720 EXPECT_FALSE(max_increased);
721
722 // Average now is 4 runs and (18 * 3 + 5)/ 4 = 14.75 = 14
723 run3.Save();
724 AssertStats(path, 4, 14);
725}
726
727// Tests what happens when the persistent settings contains the average duration of 2 runs.
728// Data on file is 2 runs and 15 average.
729TEST_F(ProgressTest, ThirdTime) {
730 std::string path = CopyTextFileFixture("stats-two-runs.txt");
731 AssertStats(path, 2, 15); // Sanity check
732
733 Progress run1 = GetInstance(-42, 1.2, path);
734 EXPECT_EQ(0, run1.Get());
735 EXPECT_EQ(15, run1.GetInitialMax());
736 EXPECT_EQ(15, run1.GetMax());
737
738 bool max_increased = run1.Inc(20);
739 EXPECT_EQ(20, run1.Get());
740 EXPECT_EQ(24, run1.GetMax());
741 EXPECT_TRUE(max_increased);
742
743 // Average now is 3 runs and (15 * 2 + 20)/ 3 = 16.66 = 16
744 run1.Save();
745 AssertStats(path, 3, 16);
746}
747
748// TODO: RunCommandAsRootNonUserBuild must be the last test because it drops root, which could cause
749// other tests to fail if they're relyin on the process running as root.
750// For now this is fine, but eventually it might need to be moved to its own test case / process.
751TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild) {
752 if (IsUserBuild()) {
753 ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
754 return;
755 }
756
757 DropRoot();
758
759 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
760 CommandOptions::WithTimeout(1).AsRoot().Build()));
761
762 EXPECT_THAT(out, StrEq("0\nstdout\n"));
763 EXPECT_THAT(err, StrEq("stderr\n"));
764}