blob: 27826a17bb2423c9885c518e38d9b3a618270800 [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
17#include "dumpstate.h"
18
19#include <gmock/gmock.h>
20#include <gtest/gtest.h>
21
22#include <libgen.h>
Felipe Lemefd8affa2016-09-30 17:38:57 -070023#include <signal.h>
24#include <sys/types.h>
Felipe Leme4c2d6632016-09-28 14:32:00 -070025#include <unistd.h>
Felipe Lemefd8affa2016-09-30 17:38:57 -070026#include <thread>
Felipe Leme4c2d6632016-09-28 14:32:00 -070027
28#include <android-base/file.h>
Felipe Lemefd8affa2016-09-30 17:38:57 -070029#include <android-base/strings.h>
Felipe Leme4c2d6632016-09-28 14:32:00 -070030
31using ::testing::EndsWith;
32using ::testing::IsEmpty;
33using ::testing::StrEq;
34using ::testing::StartsWith;
35using ::testing::Test;
36using ::testing::internal::CaptureStderr;
37using ::testing::internal::CaptureStdout;
38using ::testing::internal::GetCapturedStderr;
39using ::testing::internal::GetCapturedStdout;
40
41// Not used on test cases yet...
42void dumpstate_board(void) {
43}
44
45class DumpstateTest : public Test {
46 public:
47 void SetUp() {
48 SetDryRun(false);
49 }
50
51 // Runs a command and capture `stdout` and `stderr`.
52 int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
53 const CommandOptions& options = CommandOptions::DEFAULT) {
54 CaptureStdout();
55 CaptureStderr();
Felipe Lemefd8affa2016-09-30 17:38:57 -070056 int status = ds.RunCommand(title, fullCommand, options);
Felipe Leme4c2d6632016-09-28 14:32:00 -070057 out = GetCapturedStdout();
58 err = GetCapturedStderr();
59 return status;
60 }
61
62 // `stdout` and `stderr` from the last command ran.
63 std::string out, err;
64
65 std::string testPath = dirname(android::base::GetExecutablePath().c_str());
Felipe Lemefd8affa2016-09-30 17:38:57 -070066 std::string simpleCommand = testPath + "/../dumpstate_test_fixture/dumpstate_test_fixture";
67 std::string echoCommand = "/system/bin/echo";
68
69 Dumpstate& ds = Dumpstate::GetInstance();
Felipe Leme4c2d6632016-09-28 14:32:00 -070070
71 void SetDryRun(bool dryRun) {
Felipe Lemefd8affa2016-09-30 17:38:57 -070072 ds.dryRun_ = dryRun;
Felipe Leme4c2d6632016-09-28 14:32:00 -070073 }
Felipe Leme4c2d6632016-09-28 14:32:00 -070074};
75
76TEST_F(DumpstateTest, RunCommandNoArgs) {
77 EXPECT_EQ(-1, RunCommand("", {}));
78}
79
80TEST_F(DumpstateTest, RunCommandNoTitle) {
Felipe Lemefd8affa2016-09-30 17:38:57 -070081 EXPECT_EQ(0, RunCommand("", {simpleCommand}));
Felipe Leme4c2d6632016-09-28 14:32:00 -070082 EXPECT_THAT(out, StrEq("stdout\n"));
83 EXPECT_THAT(err, StrEq("stderr\n"));
84}
85
86TEST_F(DumpstateTest, RunCommandWithTitle) {
Felipe Lemefd8affa2016-09-30 17:38:57 -070087 EXPECT_EQ(0, RunCommand("I AM GROOT", {simpleCommand}));
Felipe Leme4c2d6632016-09-28 14:32:00 -070088 EXPECT_THAT(err, StrEq("stderr\n"));
89 // We don't know the exact duration, so we check the prefix and suffix
Felipe Lemefd8affa2016-09-30 17:38:57 -070090 EXPECT_THAT(out,
91 StartsWith("------ I AM GROOT (" + simpleCommand + ") ------\nstdout\n------"));
Felipe Leme4c2d6632016-09-28 14:32:00 -070092 EXPECT_THAT(out, EndsWith("s was the duration of 'I AM GROOT' ------\n"));
93}
94
Felipe Lemefd8affa2016-09-30 17:38:57 -070095TEST_F(DumpstateTest, RunCommandWithLoggingMessage) {
Felipe Leme4c2d6632016-09-28 14:32:00 -070096 EXPECT_EQ(
Felipe Lemefd8affa2016-09-30 17:38:57 -070097 0, RunCommand("", {simpleCommand},
98 CommandOptions::WithTimeout(10).Log("COMMAND, Y U NO LOG FIRST?").Build()));
99 EXPECT_THAT(out, StrEq("stdout\n"));
100 EXPECT_THAT(err, StrEq("COMMAND, Y U NO LOG FIRST?stderr\n"));
101}
102
103TEST_F(DumpstateTest, RunCommandRedirectStderr) {
104 EXPECT_EQ(0, RunCommand("", {simpleCommand},
105 CommandOptions::WithTimeout(10).RedirectStderr().Build()));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700106 EXPECT_THAT(out, IsEmpty());
Felipe Lemefd8affa2016-09-30 17:38:57 -0700107 EXPECT_THAT(err, StrEq("stdout\nstderr\n"));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700108}
109
110TEST_F(DumpstateTest, RunCommandWithOneArg) {
Felipe Lemefd8affa2016-09-30 17:38:57 -0700111 EXPECT_EQ(0, RunCommand("", {echoCommand, "one"}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700112 EXPECT_THAT(err, IsEmpty());
113 EXPECT_THAT(out, StrEq("one\n"));
114}
115
Felipe Lemefd8affa2016-09-30 17:38:57 -0700116TEST_F(DumpstateTest, RunCommandWithMultipleArgs) {
117 EXPECT_EQ(0, RunCommand("", {echoCommand, "one", "is", "the", "loniest", "number"}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700118 EXPECT_THAT(err, IsEmpty());
119 EXPECT_THAT(out, StrEq("one is the loniest number\n"));
120}
121
122TEST_F(DumpstateTest, RunCommandDryRun) {
123 SetDryRun(true);
Felipe Lemefd8affa2016-09-30 17:38:57 -0700124 EXPECT_EQ(0, RunCommand("I AM GROOT", {simpleCommand}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700125 // We don't know the exact duration, so we check the prefix and suffix
Felipe Lemefd8affa2016-09-30 17:38:57 -0700126 EXPECT_THAT(out, StartsWith("------ I AM GROOT (" + simpleCommand +
Felipe Leme4c2d6632016-09-28 14:32:00 -0700127 ") ------\n\t(skipped on dry run)\n------"));
128 EXPECT_THAT(out, EndsWith("s was the duration of 'I AM GROOT' ------\n"));
129 EXPECT_THAT(err, IsEmpty());
130}
131
132TEST_F(DumpstateTest, RunCommandDryRunNoTitle) {
133 SetDryRun(true);
Felipe Lemefd8affa2016-09-30 17:38:57 -0700134 EXPECT_EQ(0, RunCommand("", {simpleCommand}));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700135 EXPECT_THAT(out, IsEmpty());
136 EXPECT_THAT(err, IsEmpty());
137}
138
139TEST_F(DumpstateTest, RunCommandDryRunAlways) {
140 SetDryRun(true);
Felipe Lemefd8affa2016-09-30 17:38:57 -0700141 EXPECT_EQ(0, RunCommand("", {simpleCommand}, CommandOptions::WithTimeout(10).Always().Build()));
Felipe Leme4c2d6632016-09-28 14:32:00 -0700142 EXPECT_THAT(out, StrEq("stdout\n"));
143 EXPECT_THAT(err, StrEq("stderr\n"));
144}
145
Felipe Lemefd8affa2016-09-30 17:38:57 -0700146TEST_F(DumpstateTest, RunCommandNotFound) {
147 EXPECT_NE(0, RunCommand("", {"/there/cannot/be/such/command"}));
148 EXPECT_THAT(out, StartsWith("*** command '/there/cannot/be/such/command' failed: exit code"));
149 EXPECT_THAT(err, StartsWith("execvp on command '/there/cannot/be/such/command' failed"));
150}
151
152TEST_F(DumpstateTest, RunCommandFails) {
153 EXPECT_EQ(42, RunCommand("", {simpleCommand, "--exit", "42"}));
154 EXPECT_THAT(
155 out, StrEq("stdout\n*** command '" + simpleCommand + " --exit 42' failed: exit code 42\n"));
156 EXPECT_THAT(
157 err, StrEq("stderr\n*** command '" + simpleCommand + " --exit 42' failed: exit code 42\n"));
158}
159
160TEST_F(DumpstateTest, RunCommandCrashes) {
161 EXPECT_NE(0, RunCommand("", {simpleCommand, "--crash"}));
162 // We don't know the exit code, so check just the prefix.
163 EXPECT_THAT(
164 out, StartsWith("stdout\n*** command '" + simpleCommand + " --crash' failed: exit code"));
165 EXPECT_THAT(
166 err, StartsWith("stderr\n*** command '" + simpleCommand + " --crash' failed: exit code"));
167}
168
169TEST_F(DumpstateTest, RunCommandTimesout) {
170 EXPECT_EQ(-1, RunCommand("", {simpleCommand, "--sleep", "2"},
171 CommandOptions::WithTimeout(1).Build()));
172 EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + simpleCommand +
173 " --sleep 2' timed out after 1"));
174 EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + simpleCommand +
175 " --sleep 2' timed out after 1"));
176}
177
178TEST_F(DumpstateTest, RunCommandIsKilled) {
179 CaptureStdout();
180 CaptureStderr();
181
182 std::thread t([=]() {
183 EXPECT_EQ(SIGTERM, ds.RunCommand("", {simpleCommand, "--pid", "--sleep", "20"},
184 CommandOptions::WithTimeout(100).Always().Build()));
185 });
186
187 // Capture pid and pre-sleep output.
188 sleep(1); // Wait a little bit to make sure pid and 1st line were printed.
189 std::string err = GetCapturedStderr();
190 EXPECT_THAT(err, StrEq("sleeping for 20s\n"));
191
192 std::string out = GetCapturedStdout();
193 std::vector<std::string> lines = android::base::Split(out, "\n");
194 ASSERT_EQ(3, (int)lines.size()) << "Invalid lines before sleep: " << out;
195
196 int pid = atoi(lines[0].c_str());
197 EXPECT_THAT(lines[1], StrEq("stdout line1"));
198 EXPECT_THAT(lines[2], IsEmpty()); // \n
199
200 // Then kill the process.
201 CaptureStdout();
202 CaptureStderr();
203 ASSERT_EQ(0, kill(pid, SIGTERM)) << "failed to kill pid " << pid;
204 t.join();
205
206 // Finally, check output after murder.
207 out = GetCapturedStdout();
208 err = GetCapturedStderr();
209
210 EXPECT_THAT(out, StrEq("*** command '" + simpleCommand +
211 " --pid --sleep 20' failed: killed by signal 15\n"));
212 EXPECT_THAT(err, StrEq("*** command '" + simpleCommand +
213 " --pid --sleep 20' failed: killed by signal 15\n"));
214}
215
Felipe Leme4c2d6632016-09-28 14:32:00 -0700216// TODO: add test for other scenarios:
217// - AsRoot()
218// - DropRoot
Felipe Leme4c2d6632016-09-28 14:32:00 -0700219// - test progress
220
221// TODO: test DumpFile()