blob: 2ce3cc4fd6db760b2aa0aa35f5c874ccd1516d55 [file] [log] [blame]
Darin Petkov0406e402010-10-06 21:33:11 -07001// Copyright (c) 2010 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;
148 install_plan.is_full_update = false;
Darin Petkov3aefa862010-12-07 14:45:00 -0800149 if (verify_hash) {
150 if (use_kernel_partition) {
151 install_plan.kernel_install_path = a_dev;
152 install_plan.kernel_size =
153 kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
154 EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
155 a_loop_data,
156 &install_plan.kernel_hash));
157 } else {
158 install_plan.install_path = a_dev;
159 install_plan.rootfs_size =
160 kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
161 EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
162 a_loop_data,
163 &install_plan.rootfs_hash));
164 }
165 } else {
166 if (use_kernel_partition) {
167 install_plan.kernel_install_path = b_dev;
168 } else {
169 install_plan.install_path = b_dev;
170 }
171 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000172
173 ActionProcessor processor;
174 FilesystemCopierActionTestDelegate delegate;
175 delegate.set_loop(loop);
176 processor.set_delegate(&delegate);
177
178 ObjectFeederAction<InstallPlan> feeder_action;
Darin Petkov3aefa862010-12-07 14:45:00 -0800179 FilesystemCopierAction copier_action(use_kernel_partition,
180 verify_hash != 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000181 ObjectCollectorAction<InstallPlan> collector_action;
182
183 BondActions(&feeder_action, &copier_action);
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700184 BondActions(&copier_action, &collector_action);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000185
186 processor.EnqueueAction(&feeder_action);
187 processor.EnqueueAction(&copier_action);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000188 processor.EnqueueAction(&collector_action);
189
Darin Petkov3aefa862010-12-07 14:45:00 -0800190 if (!verify_hash) {
191 copier_action.set_copy_source(a_dev);
192 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000193 feeder_action.set_obj(install_plan);
194
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700195 StartProcessorCallbackArgs start_callback_args;
196 start_callback_args.processor = &processor;
197 start_callback_args.filesystem_copier_action = &copier_action;
198 start_callback_args.terminate_early = terminate_early;
199
200 g_timeout_add(0, &StartProcessorInRunLoop, &start_callback_args);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000201 g_main_loop_run(loop);
202 g_main_loop_unref(loop);
203
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700204 if (!terminate_early)
205 EXPECT_TRUE(delegate.ran());
206 if (run_out_of_space || terminate_early) {
Darin Petkovc1a8b422010-07-19 11:34:49 -0700207 EXPECT_EQ(kActionCodeError, delegate.code());
adlr@google.com3defe6a2009-12-04 20:57:17 +0000208 return;
209 }
Darin Petkov3aefa862010-12-07 14:45:00 -0800210 if (verify_hash == 2) {
211 EXPECT_EQ(use_kernel_partition ?
212 kActionCodeNewKernelVerificationError :
213 kActionCodeNewRootfsVerificationError,
214 delegate.code());
215 return;
216 }
Darin Petkovc1a8b422010-07-19 11:34:49 -0700217 EXPECT_EQ(kActionCodeSuccess, delegate.code());
adlr@google.com3defe6a2009-12-04 20:57:17 +0000218
adlr@google.com3defe6a2009-12-04 20:57:17 +0000219 // Make sure everything in the out_image is there
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700220 vector<char> a_out;
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700221 EXPECT_TRUE(utils::ReadFile(a_dev, &a_out));
Darin Petkov3aefa862010-12-07 14:45:00 -0800222 if (!verify_hash) {
223 vector<char> b_out;
224 EXPECT_TRUE(utils::ReadFile(b_dev, &b_out));
225 EXPECT_TRUE(ExpectVectorsEq(a_out, b_out));
226 }
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700227 EXPECT_TRUE(ExpectVectorsEq(a_loop_data, a_out));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000228
adlr@google.com3defe6a2009-12-04 20:57:17 +0000229 EXPECT_TRUE(collector_action.object() == install_plan);
230}
231
232class FilesystemCopierActionTest2Delegate : public ActionProcessorDelegate {
233 public:
234 void ActionCompleted(ActionProcessor* processor,
235 AbstractAction* action,
Darin Petkovc1a8b422010-07-19 11:34:49 -0700236 ActionExitCode code) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000237 if (action->Type() == FilesystemCopierAction::StaticType()) {
238 ran_ = true;
Darin Petkovc1a8b422010-07-19 11:34:49 -0700239 code_ = code;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000240 }
241 }
242 GMainLoop *loop_;
243 bool ran_;
Darin Petkovc1a8b422010-07-19 11:34:49 -0700244 ActionExitCode code_;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000245};
246
247TEST_F(FilesystemCopierActionTest, MissingInputObjectTest) {
248 ActionProcessor processor;
249 FilesystemCopierActionTest2Delegate delegate;
250
251 processor.set_delegate(&delegate);
252
Darin Petkov3aefa862010-12-07 14:45:00 -0800253 FilesystemCopierAction copier_action(false, false);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000254 ObjectCollectorAction<InstallPlan> collector_action;
255
256 BondActions(&copier_action, &collector_action);
257
258 processor.EnqueueAction(&copier_action);
259 processor.EnqueueAction(&collector_action);
260 processor.StartProcessing();
261 EXPECT_FALSE(processor.IsRunning());
262 EXPECT_TRUE(delegate.ran_);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700263 EXPECT_EQ(kActionCodeError, delegate.code_);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000264}
265
266TEST_F(FilesystemCopierActionTest, FullUpdateTest) {
267 ActionProcessor processor;
268 FilesystemCopierActionTest2Delegate delegate;
269
270 processor.set_delegate(&delegate);
271
272 ObjectFeederAction<InstallPlan> feeder_action;
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700273 const char* kUrl = "http://some/url";
Darin Petkov0406e402010-10-06 21:33:11 -0700274 InstallPlan install_plan(true, false, kUrl, 0, "", "", "");
adlr@google.com3defe6a2009-12-04 20:57:17 +0000275 feeder_action.set_obj(install_plan);
Darin Petkov3aefa862010-12-07 14:45:00 -0800276 FilesystemCopierAction copier_action(false, false);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000277 ObjectCollectorAction<InstallPlan> collector_action;
278
279 BondActions(&feeder_action, &copier_action);
280 BondActions(&copier_action, &collector_action);
281
282 processor.EnqueueAction(&feeder_action);
283 processor.EnqueueAction(&copier_action);
284 processor.EnqueueAction(&collector_action);
285 processor.StartProcessing();
286 EXPECT_FALSE(processor.IsRunning());
287 EXPECT_TRUE(delegate.ran_);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700288 EXPECT_EQ(kActionCodeSuccess, delegate.code_);
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700289 EXPECT_EQ(kUrl, collector_action.object().download_url);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000290}
291
Darin Petkov9b230572010-10-08 10:20:09 -0700292TEST_F(FilesystemCopierActionTest, ResumeTest) {
293 ActionProcessor processor;
294 FilesystemCopierActionTest2Delegate delegate;
295
296 processor.set_delegate(&delegate);
297
298 ObjectFeederAction<InstallPlan> feeder_action;
299 const char* kUrl = "http://some/url";
300 InstallPlan install_plan(false, true, kUrl, 0, "", "", "");
301 feeder_action.set_obj(install_plan);
Darin Petkov3aefa862010-12-07 14:45:00 -0800302 FilesystemCopierAction copier_action(false, false);
Darin Petkov9b230572010-10-08 10:20:09 -0700303 ObjectCollectorAction<InstallPlan> collector_action;
304
305 BondActions(&feeder_action, &copier_action);
306 BondActions(&copier_action, &collector_action);
307
308 processor.EnqueueAction(&feeder_action);
309 processor.EnqueueAction(&copier_action);
310 processor.EnqueueAction(&collector_action);
311 processor.StartProcessing();
312 EXPECT_FALSE(processor.IsRunning());
313 EXPECT_TRUE(delegate.ran_);
314 EXPECT_EQ(kActionCodeSuccess, delegate.code_);
315 EXPECT_EQ(kUrl, collector_action.object().download_url);
316}
317
adlr@google.com3defe6a2009-12-04 20:57:17 +0000318TEST_F(FilesystemCopierActionTest, NonExistentDriveTest) {
319 ActionProcessor processor;
320 FilesystemCopierActionTest2Delegate delegate;
321
322 processor.set_delegate(&delegate);
323
324 ObjectFeederAction<InstallPlan> feeder_action;
Darin Petkov0406e402010-10-06 21:33:11 -0700325 InstallPlan install_plan(false,
326 false,
327 "",
328 0,
329 "",
330 "/no/such/file",
331 "/no/such/file");
adlr@google.com3defe6a2009-12-04 20:57:17 +0000332 feeder_action.set_obj(install_plan);
Darin Petkov3aefa862010-12-07 14:45:00 -0800333 FilesystemCopierAction copier_action(false, false);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000334 ObjectCollectorAction<InstallPlan> collector_action;
335
336 BondActions(&copier_action, &collector_action);
337
338 processor.EnqueueAction(&feeder_action);
339 processor.EnqueueAction(&copier_action);
340 processor.EnqueueAction(&collector_action);
341 processor.StartProcessing();
342 EXPECT_FALSE(processor.IsRunning());
343 EXPECT_TRUE(delegate.ran_);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700344 EXPECT_EQ(kActionCodeError, delegate.code_);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000345}
346
Darin Petkov3aefa862010-12-07 14:45:00 -0800347TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashTest) {
348 ASSERT_EQ(0, getuid());
349 DoTest(false, false, false, 1);
350 DoTest(false, false, true, 1);
351}
352
353TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashFailTest) {
354 ASSERT_EQ(0, getuid());
355 DoTest(false, false, false, 2);
356 DoTest(false, false, true, 2);
357}
358
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700359TEST_F(FilesystemCopierActionTest, RunAsRootNoSpaceTest) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000360 ASSERT_EQ(0, getuid());
Darin Petkov3aefa862010-12-07 14:45:00 -0800361 DoTest(true, false, false, 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000362}
363
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700364TEST_F(FilesystemCopierActionTest, RunAsRootTerminateEarlyTest) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000365 ASSERT_EQ(0, getuid());
Darin Petkov3aefa862010-12-07 14:45:00 -0800366 DoTest(false, true, false, 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000367}
368
Darin Petkov698d0412010-10-13 10:59:44 -0700369TEST_F(FilesystemCopierActionTest, RunAsRootDetermineFilesystemSizeTest) {
370 string img;
371 EXPECT_TRUE(utils::MakeTempFile("/tmp/img.XXXXXX", &img, NULL));
372 ScopedPathUnlinker img_unlinker(img);
373 CreateExtImageAtPath(img, NULL);
374 // Extend the "partition" holding the file system from 10MiB to 20MiB.
375 EXPECT_EQ(0, System(StringPrintf(
376 "dd if=/dev/zero of=%s seek=20971519 bs=1 count=1",
377 img.c_str())));
378 EXPECT_EQ(20 * 1024 * 1024, utils::FileSize(img));
379
380 for (int i = 0; i < 2; ++i) {
381 bool is_kernel = i == 1;
Darin Petkov3aefa862010-12-07 14:45:00 -0800382 FilesystemCopierAction action(is_kernel, false);
Darin Petkov698d0412010-10-13 10:59:44 -0700383 EXPECT_EQ(kint64max, action.filesystem_size_);
384 {
385 int fd = HANDLE_EINTR(open(img.c_str(), O_RDONLY));
386 EXPECT_TRUE(fd > 0);
387 ScopedFdCloser fd_closer(&fd);
388 action.DetermineFilesystemSize(fd);
389 }
390 EXPECT_EQ(is_kernel ? kint64max : 10 * 1024 * 1024,
391 action.filesystem_size_);
392 }
393}
394
395
adlr@google.com3defe6a2009-12-04 20:57:17 +0000396} // namespace chromeos_update_engine