blob: 7926e22a82ef364381cc22b7cf5ef0e8e3a4429d [file] [log] [blame]
Darin Petkov7ed561b2011-10-04 02:59:03 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
adlr@google.com3defe6a2009-12-04 20:57:17 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Darin Petkov698d0412010-10-13 10:59:44 -07005#include <fcntl.h>
6
adlr@google.com3defe6a2009-12-04 20:57:17 +00007#include <set>
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -08008#include <string>
adlr@google.com3defe6a2009-12-04 20:57:17 +00009#include <vector>
Darin Petkov698d0412010-10-13 10:59:44 -070010
11#include <base/eintr_wrapper.h>
12#include <base/string_util.h>
13#include <glib.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000014#include <gtest/gtest.h>
Darin Petkov698d0412010-10-13 10:59:44 -070015
adlr@google.com3defe6a2009-12-04 20:57:17 +000016#include "update_engine/filesystem_copier_action.h"
17#include "update_engine/filesystem_iterator.h"
18#include "update_engine/omaha_hash_calculator.h"
19#include "update_engine/test_utils.h"
20#include "update_engine/utils.h"
21
22using std::set;
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -080023using std::string;
adlr@google.com3defe6a2009-12-04 20:57:17 +000024using std::vector;
25
26namespace chromeos_update_engine {
27
28class FilesystemCopierActionTest : public ::testing::Test {
29 protected:
Darin Petkov3aefa862010-12-07 14:45:00 -080030 // |verify_hash|: 0 - no hash verification, 1 -- successful hash verification,
31 // 2 -- hash verification failure.
Andrew de los Reyesf9185172010-05-03 11:07:05 -070032 void DoTest(bool run_out_of_space,
33 bool terminate_early,
Darin Petkov3aefa862010-12-07 14:45:00 -080034 bool use_kernel_partition,
35 int verify_hash);
adlr@google.com3defe6a2009-12-04 20:57:17 +000036 void SetUp() {
adlr@google.com3defe6a2009-12-04 20:57:17 +000037 }
38 void TearDown() {
adlr@google.com3defe6a2009-12-04 20:57:17 +000039 }
40};
41
42class FilesystemCopierActionTestDelegate : public ActionProcessorDelegate {
43 public:
Darin Petkovc1a8b422010-07-19 11:34:49 -070044 FilesystemCopierActionTestDelegate() : ran_(false), code_(kActionCodeError) {}
Andrew de los Reyesc7020782010-04-28 10:46:04 -070045 void ExitMainLoop() {
46 while (g_main_context_pending(NULL)) {
47 g_main_context_iteration(NULL, false);
48 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000049 g_main_loop_quit(loop_);
50 }
Darin Petkovc1a8b422010-07-19 11:34:49 -070051 void ProcessingDone(const ActionProcessor* processor, ActionExitCode code) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070052 ExitMainLoop();
53 }
54 void ProcessingStopped(const ActionProcessor* processor) {
55 ExitMainLoop();
56 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000057 void ActionCompleted(ActionProcessor* processor,
58 AbstractAction* action,
Darin Petkovc1a8b422010-07-19 11:34:49 -070059 ActionExitCode code) {
adlr@google.com3defe6a2009-12-04 20:57:17 +000060 if (action->Type() == FilesystemCopierAction::StaticType()) {
61 ran_ = true;
Darin Petkovc1a8b422010-07-19 11:34:49 -070062 code_ = code;
adlr@google.com3defe6a2009-12-04 20:57:17 +000063 }
64 }
65 void set_loop(GMainLoop* loop) {
66 loop_ = loop;
67 }
68 bool ran() { return ran_; }
Darin Petkovc1a8b422010-07-19 11:34:49 -070069 ActionExitCode code() { return code_; }
adlr@google.com3defe6a2009-12-04 20:57:17 +000070 private:
71 GMainLoop* loop_;
72 bool ran_;
Darin Petkovc1a8b422010-07-19 11:34:49 -070073 ActionExitCode code_;
adlr@google.com3defe6a2009-12-04 20:57:17 +000074};
75
Andrew de los Reyesc7020782010-04-28 10:46:04 -070076struct StartProcessorCallbackArgs {
77 ActionProcessor* processor;
78 FilesystemCopierAction* filesystem_copier_action;
79 bool terminate_early;
80};
81
adlr@google.com3defe6a2009-12-04 20:57:17 +000082gboolean StartProcessorInRunLoop(gpointer data) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070083 StartProcessorCallbackArgs* args =
84 reinterpret_cast<StartProcessorCallbackArgs*>(data);
85 ActionProcessor* processor = args->processor;
adlr@google.com3defe6a2009-12-04 20:57:17 +000086 processor->StartProcessing();
Andrew de los Reyesc7020782010-04-28 10:46:04 -070087 if (args->terminate_early) {
88 EXPECT_TRUE(args->filesystem_copier_action);
89 args->processor->StopProcessing();
90 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000091 return FALSE;
92}
93
94TEST_F(FilesystemCopierActionTest, RunAsRootSimpleTest) {
95 ASSERT_EQ(0, getuid());
Darin Petkov3aefa862010-12-07 14:45:00 -080096 DoTest(false, false, false, 0);
97 DoTest(false, false, true, 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +000098}
Darin Petkov3aefa862010-12-07 14:45:00 -080099
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700100void FilesystemCopierActionTest::DoTest(bool run_out_of_space,
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700101 bool terminate_early,
Darin Petkov3aefa862010-12-07 14:45:00 -0800102 bool use_kernel_partition,
103 int verify_hash) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000104 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
105
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700106 string a_loop_file;
107 string b_loop_file;
Darin Petkovc1a8b422010-07-19 11:34:49 -0700108
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700109 EXPECT_TRUE(utils::MakeTempFile("/tmp/a_loop_file.XXXXXX",
110 &a_loop_file,
111 NULL));
112 ScopedPathUnlinker a_loop_file_unlinker(a_loop_file);
113 EXPECT_TRUE(utils::MakeTempFile("/tmp/b_loop_file.XXXXXX",
114 &b_loop_file,
115 NULL));
116 ScopedPathUnlinker b_loop_file_unlinker(b_loop_file);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700117
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700118 // Make random data for a, zero filled data for b.
119 const size_t kLoopFileSize = 10 * 1024 * 1024 + 512;
120 vector<char> a_loop_data(kLoopFileSize);
121 FillWithData(&a_loop_data);
122 vector<char> b_loop_data(run_out_of_space ?
123 (kLoopFileSize - 1) :
124 kLoopFileSize,
125 '\0'); // Fill with 0s
adlr@google.com3defe6a2009-12-04 20:57:17 +0000126
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700127 // Write data to disk
128 EXPECT_TRUE(WriteFileVector(a_loop_file, a_loop_data));
129 EXPECT_TRUE(WriteFileVector(b_loop_file, b_loop_data));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000130
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700131 // Make loop devices for the files
132 string a_dev = GetUnusedLoopDevice();
133 EXPECT_FALSE(a_dev.empty());
134 EXPECT_EQ(0, System(StringPrintf("losetup %s %s",
135 a_dev.c_str(),
136 a_loop_file.c_str())));
137 ScopedLoopbackDeviceReleaser a_dev_releaser(a_dev);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000138
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700139 string b_dev = GetUnusedLoopDevice();
140 EXPECT_FALSE(b_dev.empty());
141 EXPECT_EQ(0, System(StringPrintf("losetup %s %s",
142 b_dev.c_str(),
143 b_loop_file.c_str())));
144 ScopedLoopbackDeviceReleaser b_dev_releaser(b_dev);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000145
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700146 // Set up the action objects
adlr@google.com3defe6a2009-12-04 20:57:17 +0000147 InstallPlan install_plan;
Darin Petkov3aefa862010-12-07 14:45:00 -0800148 if (verify_hash) {
149 if (use_kernel_partition) {
150 install_plan.kernel_install_path = a_dev;
151 install_plan.kernel_size =
152 kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
153 EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
154 a_loop_data,
155 &install_plan.kernel_hash));
156 } else {
157 install_plan.install_path = a_dev;
158 install_plan.rootfs_size =
159 kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
160 EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
161 a_loop_data,
162 &install_plan.rootfs_hash));
163 }
164 } else {
165 if (use_kernel_partition) {
166 install_plan.kernel_install_path = b_dev;
167 } else {
168 install_plan.install_path = b_dev;
169 }
170 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000171
172 ActionProcessor processor;
173 FilesystemCopierActionTestDelegate delegate;
174 delegate.set_loop(loop);
175 processor.set_delegate(&delegate);
176
177 ObjectFeederAction<InstallPlan> feeder_action;
Darin Petkov3aefa862010-12-07 14:45:00 -0800178 FilesystemCopierAction copier_action(use_kernel_partition,
179 verify_hash != 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000180 ObjectCollectorAction<InstallPlan> collector_action;
181
182 BondActions(&feeder_action, &copier_action);
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700183 BondActions(&copier_action, &collector_action);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000184
185 processor.EnqueueAction(&feeder_action);
186 processor.EnqueueAction(&copier_action);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000187 processor.EnqueueAction(&collector_action);
188
Darin Petkov3aefa862010-12-07 14:45:00 -0800189 if (!verify_hash) {
190 copier_action.set_copy_source(a_dev);
191 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000192 feeder_action.set_obj(install_plan);
193
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700194 StartProcessorCallbackArgs start_callback_args;
195 start_callback_args.processor = &processor;
196 start_callback_args.filesystem_copier_action = &copier_action;
197 start_callback_args.terminate_early = terminate_early;
198
199 g_timeout_add(0, &StartProcessorInRunLoop, &start_callback_args);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000200 g_main_loop_run(loop);
201 g_main_loop_unref(loop);
202
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700203 if (!terminate_early)
204 EXPECT_TRUE(delegate.ran());
205 if (run_out_of_space || terminate_early) {
Darin Petkovc1a8b422010-07-19 11:34:49 -0700206 EXPECT_EQ(kActionCodeError, delegate.code());
adlr@google.com3defe6a2009-12-04 20:57:17 +0000207 return;
208 }
Darin Petkov3aefa862010-12-07 14:45:00 -0800209 if (verify_hash == 2) {
210 EXPECT_EQ(use_kernel_partition ?
211 kActionCodeNewKernelVerificationError :
212 kActionCodeNewRootfsVerificationError,
213 delegate.code());
214 return;
215 }
Darin Petkovc1a8b422010-07-19 11:34:49 -0700216 EXPECT_EQ(kActionCodeSuccess, delegate.code());
adlr@google.com3defe6a2009-12-04 20:57:17 +0000217
adlr@google.com3defe6a2009-12-04 20:57:17 +0000218 // Make sure everything in the out_image is there
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700219 vector<char> a_out;
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700220 EXPECT_TRUE(utils::ReadFile(a_dev, &a_out));
Darin Petkov3aefa862010-12-07 14:45:00 -0800221 if (!verify_hash) {
222 vector<char> b_out;
223 EXPECT_TRUE(utils::ReadFile(b_dev, &b_out));
224 EXPECT_TRUE(ExpectVectorsEq(a_out, b_out));
225 }
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700226 EXPECT_TRUE(ExpectVectorsEq(a_loop_data, a_out));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000227
adlr@google.com3defe6a2009-12-04 20:57:17 +0000228 EXPECT_TRUE(collector_action.object() == install_plan);
229}
230
231class FilesystemCopierActionTest2Delegate : public ActionProcessorDelegate {
232 public:
233 void ActionCompleted(ActionProcessor* processor,
234 AbstractAction* action,
Darin Petkovc1a8b422010-07-19 11:34:49 -0700235 ActionExitCode code) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000236 if (action->Type() == FilesystemCopierAction::StaticType()) {
237 ran_ = true;
Darin Petkovc1a8b422010-07-19 11:34:49 -0700238 code_ = code;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000239 }
240 }
241 GMainLoop *loop_;
242 bool ran_;
Darin Petkovc1a8b422010-07-19 11:34:49 -0700243 ActionExitCode code_;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000244};
245
246TEST_F(FilesystemCopierActionTest, MissingInputObjectTest) {
247 ActionProcessor processor;
248 FilesystemCopierActionTest2Delegate delegate;
249
250 processor.set_delegate(&delegate);
251
Darin Petkov3aefa862010-12-07 14:45:00 -0800252 FilesystemCopierAction copier_action(false, false);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000253 ObjectCollectorAction<InstallPlan> collector_action;
254
255 BondActions(&copier_action, &collector_action);
256
257 processor.EnqueueAction(&copier_action);
258 processor.EnqueueAction(&collector_action);
259 processor.StartProcessing();
260 EXPECT_FALSE(processor.IsRunning());
261 EXPECT_TRUE(delegate.ran_);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700262 EXPECT_EQ(kActionCodeError, delegate.code_);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000263}
264
Darin Petkov9b230572010-10-08 10:20:09 -0700265TEST_F(FilesystemCopierActionTest, ResumeTest) {
266 ActionProcessor processor;
267 FilesystemCopierActionTest2Delegate delegate;
268
269 processor.set_delegate(&delegate);
270
271 ObjectFeederAction<InstallPlan> feeder_action;
272 const char* kUrl = "http://some/url";
Darin Petkov7ed561b2011-10-04 02:59:03 -0700273 InstallPlan install_plan(true, kUrl, 0, "", "", "");
Darin Petkov9b230572010-10-08 10:20:09 -0700274 feeder_action.set_obj(install_plan);
Darin Petkov3aefa862010-12-07 14:45:00 -0800275 FilesystemCopierAction copier_action(false, false);
Darin Petkov9b230572010-10-08 10:20:09 -0700276 ObjectCollectorAction<InstallPlan> collector_action;
277
278 BondActions(&feeder_action, &copier_action);
279 BondActions(&copier_action, &collector_action);
280
281 processor.EnqueueAction(&feeder_action);
282 processor.EnqueueAction(&copier_action);
283 processor.EnqueueAction(&collector_action);
284 processor.StartProcessing();
285 EXPECT_FALSE(processor.IsRunning());
286 EXPECT_TRUE(delegate.ran_);
287 EXPECT_EQ(kActionCodeSuccess, delegate.code_);
288 EXPECT_EQ(kUrl, collector_action.object().download_url);
289}
290
adlr@google.com3defe6a2009-12-04 20:57:17 +0000291TEST_F(FilesystemCopierActionTest, NonExistentDriveTest) {
292 ActionProcessor processor;
293 FilesystemCopierActionTest2Delegate delegate;
294
295 processor.set_delegate(&delegate);
296
297 ObjectFeederAction<InstallPlan> feeder_action;
Darin Petkov0406e402010-10-06 21:33:11 -0700298 InstallPlan install_plan(false,
Darin Petkov0406e402010-10-06 21:33:11 -0700299 "",
300 0,
301 "",
302 "/no/such/file",
303 "/no/such/file");
adlr@google.com3defe6a2009-12-04 20:57:17 +0000304 feeder_action.set_obj(install_plan);
Darin Petkov3aefa862010-12-07 14:45:00 -0800305 FilesystemCopierAction copier_action(false, false);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000306 ObjectCollectorAction<InstallPlan> collector_action;
307
308 BondActions(&copier_action, &collector_action);
309
310 processor.EnqueueAction(&feeder_action);
311 processor.EnqueueAction(&copier_action);
312 processor.EnqueueAction(&collector_action);
313 processor.StartProcessing();
314 EXPECT_FALSE(processor.IsRunning());
315 EXPECT_TRUE(delegate.ran_);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700316 EXPECT_EQ(kActionCodeError, delegate.code_);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000317}
318
Darin Petkov3aefa862010-12-07 14:45:00 -0800319TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashTest) {
320 ASSERT_EQ(0, getuid());
321 DoTest(false, false, false, 1);
322 DoTest(false, false, true, 1);
323}
324
325TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashFailTest) {
326 ASSERT_EQ(0, getuid());
327 DoTest(false, false, false, 2);
328 DoTest(false, false, true, 2);
329}
330
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700331TEST_F(FilesystemCopierActionTest, RunAsRootNoSpaceTest) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000332 ASSERT_EQ(0, getuid());
Darin Petkov3aefa862010-12-07 14:45:00 -0800333 DoTest(true, false, false, 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000334}
335
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700336TEST_F(FilesystemCopierActionTest, RunAsRootTerminateEarlyTest) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000337 ASSERT_EQ(0, getuid());
Darin Petkov3aefa862010-12-07 14:45:00 -0800338 DoTest(false, true, false, 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000339}
340
Darin Petkov698d0412010-10-13 10:59:44 -0700341TEST_F(FilesystemCopierActionTest, RunAsRootDetermineFilesystemSizeTest) {
342 string img;
343 EXPECT_TRUE(utils::MakeTempFile("/tmp/img.XXXXXX", &img, NULL));
344 ScopedPathUnlinker img_unlinker(img);
345 CreateExtImageAtPath(img, NULL);
346 // Extend the "partition" holding the file system from 10MiB to 20MiB.
347 EXPECT_EQ(0, System(StringPrintf(
348 "dd if=/dev/zero of=%s seek=20971519 bs=1 count=1",
349 img.c_str())));
350 EXPECT_EQ(20 * 1024 * 1024, utils::FileSize(img));
351
352 for (int i = 0; i < 2; ++i) {
353 bool is_kernel = i == 1;
Darin Petkov3aefa862010-12-07 14:45:00 -0800354 FilesystemCopierAction action(is_kernel, false);
Darin Petkov698d0412010-10-13 10:59:44 -0700355 EXPECT_EQ(kint64max, action.filesystem_size_);
356 {
357 int fd = HANDLE_EINTR(open(img.c_str(), O_RDONLY));
358 EXPECT_TRUE(fd > 0);
359 ScopedFdCloser fd_closer(&fd);
360 action.DetermineFilesystemSize(fd);
361 }
362 EXPECT_EQ(is_kernel ? kint64max : 10 * 1024 * 1024,
363 action.filesystem_size_);
364 }
365}
366
367
adlr@google.com3defe6a2009-12-04 20:57:17 +0000368} // namespace chromeos_update_engine