blob: da095fab5f54eddf5c0ee48be756003fa959fc77 [file] [log] [blame]
Mike Frysinger1dad0972019-02-23 18:36:37 -05001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "dev-install/dev_install.h"
6
Mike Frysinger60260f62019-02-24 02:28:23 -05007#include <unistd.h>
8
9#include <istream>
10#include <sstream>
11#include <string>
12
Mike Frysingerb9c9f6c2019-02-24 02:32:32 -050013#include <base/files/file_path.h>
14#include <base/files/file_util.h>
15#include <base/files/scoped_temp_dir.h>
Mike Frysinger1dad0972019-02-23 18:36:37 -050016#include <gmock/gmock.h>
17#include <gtest/gtest.h>
18
19using ::testing::_;
20using ::testing::Return;
21
22namespace dev_install {
23
24namespace {
25
26class DevInstallMock : public DevInstall {
27 public:
Ben Chan1ea2ba12019-09-19 11:58:03 -070028 MOCK_METHOD(int, Exec, (const std::vector<const char*>&), (override));
29 MOCK_METHOD(bool, IsDevMode, (), (const, override));
30 MOCK_METHOD(bool,
31 PromptUser,
32 (std::istream&, const std::string&),
33 (override));
Mike Frysinger69c167f2019-02-24 05:14:57 -050034 MOCK_METHOD(bool, ClearStateDir, (const base::FilePath&), (override));
Mike Frysinger1dad0972019-02-23 18:36:37 -050035};
36
37class DevInstallTest : public ::testing::Test {
Mike Frysingeree5af6e2019-02-23 23:47:03 -050038 public:
39 void SetUp() override {
40 // Set the default to dev mode enabled. Most tests want that.
41 ON_CALL(dev_install_, IsDevMode()).WillByDefault(Return(true));
Mike Frysinger69c167f2019-02-24 05:14:57 -050042
43 // Most tests should run with a path that doesn't exist.
44 dev_install_.SetStateDirForTest(base::FilePath("/.path-does-not-exist"));
Mike Frysingeree5af6e2019-02-23 23:47:03 -050045 }
46
Mike Frysinger1dad0972019-02-23 18:36:37 -050047 protected:
48 DevInstallMock dev_install_;
49};
50
51} // namespace
52
53// Check default run through.
54TEST_F(DevInstallTest, Run) {
55 EXPECT_CALL(dev_install_, Exec(_)).WillOnce(Return(1234));
56 EXPECT_EQ(1234, dev_install_.Run());
57}
58
Mike Frysingeree5af6e2019-02-23 23:47:03 -050059// Systems not in dev mode should abort.
60TEST_F(DevInstallTest, NonDevMode) {
61 EXPECT_CALL(dev_install_, IsDevMode()).WillOnce(Return(false));
Mike Frysinger69c167f2019-02-24 05:14:57 -050062 EXPECT_CALL(dev_install_, ClearStateDir(_)).Times(0);
Mike Frysingeree5af6e2019-02-23 23:47:03 -050063 EXPECT_CALL(dev_install_, Exec(_)).Times(0);
64 EXPECT_EQ(2, dev_install_.Run());
65}
66
Mike Frysinger69c167f2019-02-24 05:14:57 -050067// Check system has been initialized.
68TEST_F(DevInstallTest, AlreadyInitialized) {
69 dev_install_.SetStateDirForTest(base::FilePath("/"));
70 EXPECT_CALL(dev_install_, Exec(_)).Times(0);
71 ASSERT_EQ(4, dev_install_.Run());
72}
73
74// Check --reinstall passed.
75TEST_F(DevInstallTest, RunReinstallWorked) {
76 dev_install_.SetReinstallForTest(true);
77 EXPECT_CALL(dev_install_, ClearStateDir(_)).WillOnce(Return(true));
78 EXPECT_CALL(dev_install_, Exec(_)).WillOnce(Return(1234));
79 ASSERT_EQ(1234, dev_install_.Run());
80}
81
82// Check when --reinstall is requested but clearing fails.
83TEST_F(DevInstallTest, RunReinstallFails) {
84 dev_install_.SetReinstallForTest(true);
85 EXPECT_CALL(dev_install_, ClearStateDir(_)).WillOnce(Return(false));
86 EXPECT_CALL(dev_install_, Exec(_)).Times(0);
87 ASSERT_EQ(1, dev_install_.Run());
88}
89
90// Check --uninstall passed.
91TEST_F(DevInstallTest, RunUninstall) {
92 dev_install_.SetUninstallForTest(true);
93 EXPECT_CALL(dev_install_, ClearStateDir(_)).WillOnce(Return(true));
94 EXPECT_CALL(dev_install_, Exec(_)).Times(0);
95 ASSERT_EQ(0, dev_install_.Run());
96}
97
Mike Frysinger60260f62019-02-24 02:28:23 -050098namespace {
99
100class PromptUserTest : public ::testing::Test {
101 protected:
102 DevInstall dev_install_;
103};
104
105} // namespace
106
107// The --yes flag should pass w/out prompting the user.
108TEST_F(PromptUserTest, Forced) {
109 dev_install_.SetYesForTest(true);
110 std::stringstream stream("");
111 EXPECT_TRUE(dev_install_.PromptUser(stream, ""));
112}
113
114// EOF input should fail.
115TEST_F(PromptUserTest, Eof) {
116 std::stringstream stream("");
117 EXPECT_FALSE(dev_install_.PromptUser(stream, ""));
118}
119
120// Default input (hitting enter) should fail.
121TEST_F(PromptUserTest, Default) {
122 std::stringstream stream("\n");
123 EXPECT_FALSE(dev_install_.PromptUser(stream, ""));
124}
125
126// Entering "n" should fail.
127TEST_F(PromptUserTest, No) {
128 std::stringstream stream("n\n");
129 EXPECT_FALSE(dev_install_.PromptUser(stream, ""));
130}
131
132// Entering "y" should pass.
133TEST_F(PromptUserTest, Yes) {
134 std::stringstream stream("y\n");
135 EXPECT_TRUE(dev_install_.PromptUser(stream, ""));
136}
137
Mike Frysingerb9c9f6c2019-02-24 02:32:32 -0500138namespace {
139
140class DeletePathTest : public ::testing::Test {
141 public:
142 void SetUp() override {
143 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
144 test_dir_ = scoped_temp_dir_.GetPath();
145 dev_install_.SetStateDirForTest(test_dir_);
146 }
147
148 protected:
149 DevInstall dev_install_;
150 base::FilePath test_dir_;
151 base::ScopedTempDir scoped_temp_dir_;
152};
153
154} // namespace
155
156// Check missing dir.
157TEST_F(DeletePathTest, Missing) {
158 struct stat st = {};
159 EXPECT_TRUE(dev_install_.DeletePath(st, test_dir_.Append("foo")));
160}
161
162// Check deleting dir contents leaves the dir alone.
163TEST_F(DeletePathTest, Empty) {
164 struct stat st = {};
165 EXPECT_TRUE(dev_install_.DeletePath(st, test_dir_));
166 EXPECT_TRUE(base::PathExists(test_dir_));
167}
168
169// Check mounted deletion.
170TEST_F(DeletePathTest, Mounted) {
171 struct stat st = {};
172 const base::FilePath subdir = test_dir_.Append("subdir");
173 EXPECT_TRUE(base::CreateDirectory(subdir));
174 EXPECT_FALSE(dev_install_.DeletePath(st, test_dir_));
175 EXPECT_TRUE(base::PathExists(subdir));
176}
177
178// Check recursive deletion.
179TEST_F(DeletePathTest, Works) {
180 struct stat st;
181 EXPECT_EQ(0, stat(test_dir_.value().c_str(), &st));
182
183 EXPECT_EQ(3, base::WriteFile(test_dir_.Append("file"), "123", 3));
184 EXPECT_EQ(0, symlink("x", test_dir_.Append("broken-sym").value().c_str()));
185 EXPECT_EQ(0, symlink("file", test_dir_.Append("file-sym").value().c_str()));
186 EXPECT_EQ(0, symlink(".", test_dir_.Append("dir-sym").value().c_str()));
187 EXPECT_EQ(0, symlink("subdir", test_dir_.Append("dir-sym2").value().c_str()));
188 const base::FilePath subdir = test_dir_.Append("subdir");
189 EXPECT_TRUE(base::CreateDirectory(subdir));
190 EXPECT_EQ(3, base::WriteFile(subdir.Append("file"), "123", 3));
191 const base::FilePath subsubdir = test_dir_.Append("subdir");
192 EXPECT_TRUE(base::CreateDirectory(subsubdir));
193 EXPECT_EQ(3, base::WriteFile(subsubdir.Append("file"), "123", 3));
194
195 EXPECT_TRUE(dev_install_.DeletePath(st, test_dir_));
196 EXPECT_TRUE(base::PathExists(test_dir_));
197 EXPECT_EQ(0, rmdir(test_dir_.value().c_str()));
198}
199
Mike Frysinger69c167f2019-02-24 05:14:57 -0500200namespace {
201
202// We could mock out DeletePath, but it's easy to lightly validate it.
203class ClearStateDirMock : public DevInstall {
204 public:
205 MOCK_METHOD(bool,
206 PromptUser,
207 (std::istream&, const std::string&),
208 (override));
209};
210
211class ClearStateDirTest : public ::testing::Test {
212 public:
213 void SetUp() {
214 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
215 test_dir_ = scoped_temp_dir_.GetPath();
216 }
217
218 protected:
219 ClearStateDirMock dev_install_;
220 base::FilePath test_dir_;
221 base::ScopedTempDir scoped_temp_dir_;
222};
223
224} // namespace
225
226// Check user rejecting things.
227TEST_F(ClearStateDirTest, Cancel) {
228 EXPECT_CALL(dev_install_, PromptUser(_, _)).WillOnce(Return(false));
229 const base::FilePath subdir = test_dir_.Append("subdir");
230 ASSERT_TRUE(base::CreateDirectory(subdir));
231 ASSERT_FALSE(dev_install_.ClearStateDir(test_dir_));
232 ASSERT_TRUE(base::PathExists(subdir));
233}
234
235// Check missing dir is handled.
236TEST_F(ClearStateDirTest, Missing) {
237 EXPECT_CALL(dev_install_, PromptUser(_, _)).WillOnce(Return(true));
238 ASSERT_TRUE(dev_install_.ClearStateDir(test_dir_.Append("subdir")));
239 ASSERT_TRUE(base::PathExists(test_dir_));
240}
241
242// Check empty dir is handled.
243TEST_F(ClearStateDirTest, Empty) {
244 EXPECT_CALL(dev_install_, PromptUser(_, _)).WillOnce(Return(true));
245 ASSERT_TRUE(dev_install_.ClearStateDir(test_dir_));
246 ASSERT_TRUE(base::PathExists(test_dir_));
247}
248
249// Check dir with contents is cleared.
250TEST_F(ClearStateDirTest, Works) {
251 EXPECT_CALL(dev_install_, PromptUser(_, _)).WillOnce(Return(true));
252 const base::FilePath subdir = test_dir_.Append("subdir");
253 ASSERT_TRUE(base::CreateDirectory(subdir));
254 ASSERT_TRUE(dev_install_.ClearStateDir(test_dir_));
255 ASSERT_FALSE(base::PathExists(subdir));
256}
257
Mike Frysinger1dad0972019-02-23 18:36:37 -0500258} // namespace dev_install