blob: ccad03a316fc810ba14bcec05329476a55cc9dc8 [file] [log] [blame]
Mike Frysinger8155d082012-04-06 15:23:18 -04001// Copyright (c) 2012 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>
Mike Frysinger8155d082012-04-06 15:23:18 -040013#include <base/stringprintf.h>
Darin Petkov698d0412010-10-13 10:59:44 -070014#include <glib.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000015#include <gtest/gtest.h>
Darin Petkov698d0412010-10-13 10:59:44 -070016
adlr@google.com3defe6a2009-12-04 20:57:17 +000017#include "update_engine/filesystem_copier_action.h"
18#include "update_engine/filesystem_iterator.h"
19#include "update_engine/omaha_hash_calculator.h"
20#include "update_engine/test_utils.h"
21#include "update_engine/utils.h"
22
23using std::set;
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -080024using std::string;
adlr@google.com3defe6a2009-12-04 20:57:17 +000025using std::vector;
26
27namespace chromeos_update_engine {
28
29class FilesystemCopierActionTest : public ::testing::Test {
30 protected:
Darin Petkov3aefa862010-12-07 14:45:00 -080031 // |verify_hash|: 0 - no hash verification, 1 -- successful hash verification,
32 // 2 -- hash verification failure.
Andrew de los Reyesf9185172010-05-03 11:07:05 -070033 void DoTest(bool run_out_of_space,
34 bool terminate_early,
Darin Petkov3aefa862010-12-07 14:45:00 -080035 bool use_kernel_partition,
36 int verify_hash);
adlr@google.com3defe6a2009-12-04 20:57:17 +000037 void SetUp() {
adlr@google.com3defe6a2009-12-04 20:57:17 +000038 }
39 void TearDown() {
adlr@google.com3defe6a2009-12-04 20:57:17 +000040 }
41};
42
43class FilesystemCopierActionTestDelegate : public ActionProcessorDelegate {
44 public:
Darin Petkovc1a8b422010-07-19 11:34:49 -070045 FilesystemCopierActionTestDelegate() : ran_(false), code_(kActionCodeError) {}
Andrew de los Reyesc7020782010-04-28 10:46:04 -070046 void ExitMainLoop() {
47 while (g_main_context_pending(NULL)) {
48 g_main_context_iteration(NULL, false);
49 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000050 g_main_loop_quit(loop_);
51 }
Darin Petkovc1a8b422010-07-19 11:34:49 -070052 void ProcessingDone(const ActionProcessor* processor, ActionExitCode code) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070053 ExitMainLoop();
54 }
55 void ProcessingStopped(const ActionProcessor* processor) {
56 ExitMainLoop();
57 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000058 void ActionCompleted(ActionProcessor* processor,
59 AbstractAction* action,
Darin Petkovc1a8b422010-07-19 11:34:49 -070060 ActionExitCode code) {
adlr@google.com3defe6a2009-12-04 20:57:17 +000061 if (action->Type() == FilesystemCopierAction::StaticType()) {
62 ran_ = true;
Darin Petkovc1a8b422010-07-19 11:34:49 -070063 code_ = code;
adlr@google.com3defe6a2009-12-04 20:57:17 +000064 }
65 }
66 void set_loop(GMainLoop* loop) {
67 loop_ = loop;
68 }
69 bool ran() { return ran_; }
Darin Petkovc1a8b422010-07-19 11:34:49 -070070 ActionExitCode code() { return code_; }
adlr@google.com3defe6a2009-12-04 20:57:17 +000071 private:
72 GMainLoop* loop_;
73 bool ran_;
Darin Petkovc1a8b422010-07-19 11:34:49 -070074 ActionExitCode code_;
adlr@google.com3defe6a2009-12-04 20:57:17 +000075};
76
Andrew de los Reyesc7020782010-04-28 10:46:04 -070077struct StartProcessorCallbackArgs {
78 ActionProcessor* processor;
79 FilesystemCopierAction* filesystem_copier_action;
80 bool terminate_early;
81};
82
adlr@google.com3defe6a2009-12-04 20:57:17 +000083gboolean StartProcessorInRunLoop(gpointer data) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070084 StartProcessorCallbackArgs* args =
85 reinterpret_cast<StartProcessorCallbackArgs*>(data);
86 ActionProcessor* processor = args->processor;
adlr@google.com3defe6a2009-12-04 20:57:17 +000087 processor->StartProcessing();
Andrew de los Reyesc7020782010-04-28 10:46:04 -070088 if (args->terminate_early) {
89 EXPECT_TRUE(args->filesystem_copier_action);
90 args->processor->StopProcessing();
91 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000092 return FALSE;
93}
94
95TEST_F(FilesystemCopierActionTest, RunAsRootSimpleTest) {
96 ASSERT_EQ(0, getuid());
Darin Petkov3aefa862010-12-07 14:45:00 -080097 DoTest(false, false, false, 0);
98 DoTest(false, false, true, 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +000099}
Darin Petkov3aefa862010-12-07 14:45:00 -0800100
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700101void FilesystemCopierActionTest::DoTest(bool run_out_of_space,
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700102 bool terminate_early,
Darin Petkov3aefa862010-12-07 14:45:00 -0800103 bool use_kernel_partition,
104 int verify_hash) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000105 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
106
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700107 string a_loop_file;
108 string b_loop_file;
Darin Petkovc1a8b422010-07-19 11:34:49 -0700109
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700110 EXPECT_TRUE(utils::MakeTempFile("/tmp/a_loop_file.XXXXXX",
111 &a_loop_file,
112 NULL));
113 ScopedPathUnlinker a_loop_file_unlinker(a_loop_file);
114 EXPECT_TRUE(utils::MakeTempFile("/tmp/b_loop_file.XXXXXX",
115 &b_loop_file,
116 NULL));
117 ScopedPathUnlinker b_loop_file_unlinker(b_loop_file);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700118
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700119 // Make random data for a, zero filled data for b.
120 const size_t kLoopFileSize = 10 * 1024 * 1024 + 512;
121 vector<char> a_loop_data(kLoopFileSize);
122 FillWithData(&a_loop_data);
123 vector<char> b_loop_data(run_out_of_space ?
124 (kLoopFileSize - 1) :
125 kLoopFileSize,
126 '\0'); // Fill with 0s
adlr@google.com3defe6a2009-12-04 20:57:17 +0000127
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700128 // Write data to disk
129 EXPECT_TRUE(WriteFileVector(a_loop_file, a_loop_data));
130 EXPECT_TRUE(WriteFileVector(b_loop_file, b_loop_data));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000131
Don Garrett58e8b1f2012-01-31 16:38:16 -0800132 // Attach loop devices to the files
133 string a_dev;
134 string b_dev;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000135
Don Garrett58e8b1f2012-01-31 16:38:16 -0800136 ScopedLoopbackDeviceBinder a_dev_releaser(a_loop_file, &a_dev);
137 ScopedLoopbackDeviceBinder b_dev_releaser(b_loop_file, &b_dev);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000138
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700139 // Set up the action objects
adlr@google.com3defe6a2009-12-04 20:57:17 +0000140 InstallPlan install_plan;
Darin Petkov3aefa862010-12-07 14:45:00 -0800141 if (verify_hash) {
142 if (use_kernel_partition) {
143 install_plan.kernel_install_path = a_dev;
144 install_plan.kernel_size =
145 kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
146 EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
147 a_loop_data,
148 &install_plan.kernel_hash));
149 } else {
150 install_plan.install_path = a_dev;
151 install_plan.rootfs_size =
152 kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
153 EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
154 a_loop_data,
155 &install_plan.rootfs_hash));
156 }
157 } else {
158 if (use_kernel_partition) {
159 install_plan.kernel_install_path = b_dev;
160 } else {
161 install_plan.install_path = b_dev;
162 }
163 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000164
165 ActionProcessor processor;
166 FilesystemCopierActionTestDelegate delegate;
167 delegate.set_loop(loop);
168 processor.set_delegate(&delegate);
169
170 ObjectFeederAction<InstallPlan> feeder_action;
Darin Petkov3aefa862010-12-07 14:45:00 -0800171 FilesystemCopierAction copier_action(use_kernel_partition,
172 verify_hash != 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000173 ObjectCollectorAction<InstallPlan> collector_action;
174
175 BondActions(&feeder_action, &copier_action);
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700176 BondActions(&copier_action, &collector_action);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000177
178 processor.EnqueueAction(&feeder_action);
179 processor.EnqueueAction(&copier_action);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000180 processor.EnqueueAction(&collector_action);
181
Darin Petkov3aefa862010-12-07 14:45:00 -0800182 if (!verify_hash) {
183 copier_action.set_copy_source(a_dev);
184 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000185 feeder_action.set_obj(install_plan);
186
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700187 StartProcessorCallbackArgs start_callback_args;
188 start_callback_args.processor = &processor;
189 start_callback_args.filesystem_copier_action = &copier_action;
190 start_callback_args.terminate_early = terminate_early;
191
192 g_timeout_add(0, &StartProcessorInRunLoop, &start_callback_args);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000193 g_main_loop_run(loop);
194 g_main_loop_unref(loop);
195
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700196 if (!terminate_early)
197 EXPECT_TRUE(delegate.ran());
198 if (run_out_of_space || terminate_early) {
Darin Petkovc1a8b422010-07-19 11:34:49 -0700199 EXPECT_EQ(kActionCodeError, delegate.code());
adlr@google.com3defe6a2009-12-04 20:57:17 +0000200 return;
201 }
Darin Petkov3aefa862010-12-07 14:45:00 -0800202 if (verify_hash == 2) {
203 EXPECT_EQ(use_kernel_partition ?
204 kActionCodeNewKernelVerificationError :
205 kActionCodeNewRootfsVerificationError,
206 delegate.code());
207 return;
208 }
Darin Petkovc1a8b422010-07-19 11:34:49 -0700209 EXPECT_EQ(kActionCodeSuccess, delegate.code());
adlr@google.com3defe6a2009-12-04 20:57:17 +0000210
adlr@google.com3defe6a2009-12-04 20:57:17 +0000211 // Make sure everything in the out_image is there
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700212 vector<char> a_out;
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700213 EXPECT_TRUE(utils::ReadFile(a_dev, &a_out));
Darin Petkov3aefa862010-12-07 14:45:00 -0800214 if (!verify_hash) {
215 vector<char> b_out;
216 EXPECT_TRUE(utils::ReadFile(b_dev, &b_out));
217 EXPECT_TRUE(ExpectVectorsEq(a_out, b_out));
218 }
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700219 EXPECT_TRUE(ExpectVectorsEq(a_loop_data, a_out));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000220
adlr@google.com3defe6a2009-12-04 20:57:17 +0000221 EXPECT_TRUE(collector_action.object() == install_plan);
222}
223
224class FilesystemCopierActionTest2Delegate : public ActionProcessorDelegate {
225 public:
226 void ActionCompleted(ActionProcessor* processor,
227 AbstractAction* action,
Darin Petkovc1a8b422010-07-19 11:34:49 -0700228 ActionExitCode code) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000229 if (action->Type() == FilesystemCopierAction::StaticType()) {
230 ran_ = true;
Darin Petkovc1a8b422010-07-19 11:34:49 -0700231 code_ = code;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000232 }
233 }
234 GMainLoop *loop_;
235 bool ran_;
Darin Petkovc1a8b422010-07-19 11:34:49 -0700236 ActionExitCode code_;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000237};
238
239TEST_F(FilesystemCopierActionTest, MissingInputObjectTest) {
240 ActionProcessor processor;
241 FilesystemCopierActionTest2Delegate delegate;
242
243 processor.set_delegate(&delegate);
244
Darin Petkov3aefa862010-12-07 14:45:00 -0800245 FilesystemCopierAction copier_action(false, false);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000246 ObjectCollectorAction<InstallPlan> collector_action;
247
248 BondActions(&copier_action, &collector_action);
249
250 processor.EnqueueAction(&copier_action);
251 processor.EnqueueAction(&collector_action);
252 processor.StartProcessing();
253 EXPECT_FALSE(processor.IsRunning());
254 EXPECT_TRUE(delegate.ran_);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700255 EXPECT_EQ(kActionCodeError, delegate.code_);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000256}
257
Darin Petkov9b230572010-10-08 10:20:09 -0700258TEST_F(FilesystemCopierActionTest, ResumeTest) {
259 ActionProcessor processor;
260 FilesystemCopierActionTest2Delegate delegate;
261
262 processor.set_delegate(&delegate);
263
264 ObjectFeederAction<InstallPlan> feeder_action;
265 const char* kUrl = "http://some/url";
Darin Petkov7ed561b2011-10-04 02:59:03 -0700266 InstallPlan install_plan(true, kUrl, 0, "", "", "");
Darin Petkov9b230572010-10-08 10:20:09 -0700267 feeder_action.set_obj(install_plan);
Darin Petkov3aefa862010-12-07 14:45:00 -0800268 FilesystemCopierAction copier_action(false, false);
Darin Petkov9b230572010-10-08 10:20:09 -0700269 ObjectCollectorAction<InstallPlan> collector_action;
270
271 BondActions(&feeder_action, &copier_action);
272 BondActions(&copier_action, &collector_action);
273
274 processor.EnqueueAction(&feeder_action);
275 processor.EnqueueAction(&copier_action);
276 processor.EnqueueAction(&collector_action);
277 processor.StartProcessing();
278 EXPECT_FALSE(processor.IsRunning());
279 EXPECT_TRUE(delegate.ran_);
280 EXPECT_EQ(kActionCodeSuccess, delegate.code_);
281 EXPECT_EQ(kUrl, collector_action.object().download_url);
282}
283
adlr@google.com3defe6a2009-12-04 20:57:17 +0000284TEST_F(FilesystemCopierActionTest, NonExistentDriveTest) {
285 ActionProcessor processor;
286 FilesystemCopierActionTest2Delegate delegate;
287
288 processor.set_delegate(&delegate);
289
290 ObjectFeederAction<InstallPlan> feeder_action;
Darin Petkov0406e402010-10-06 21:33:11 -0700291 InstallPlan install_plan(false,
Darin Petkov0406e402010-10-06 21:33:11 -0700292 "",
293 0,
294 "",
295 "/no/such/file",
296 "/no/such/file");
adlr@google.com3defe6a2009-12-04 20:57:17 +0000297 feeder_action.set_obj(install_plan);
Darin Petkov3aefa862010-12-07 14:45:00 -0800298 FilesystemCopierAction copier_action(false, false);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000299 ObjectCollectorAction<InstallPlan> collector_action;
300
301 BondActions(&copier_action, &collector_action);
302
303 processor.EnqueueAction(&feeder_action);
304 processor.EnqueueAction(&copier_action);
305 processor.EnqueueAction(&collector_action);
306 processor.StartProcessing();
307 EXPECT_FALSE(processor.IsRunning());
308 EXPECT_TRUE(delegate.ran_);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700309 EXPECT_EQ(kActionCodeError, delegate.code_);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000310}
311
Darin Petkov3aefa862010-12-07 14:45:00 -0800312TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashTest) {
313 ASSERT_EQ(0, getuid());
314 DoTest(false, false, false, 1);
315 DoTest(false, false, true, 1);
316}
317
318TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashFailTest) {
319 ASSERT_EQ(0, getuid());
320 DoTest(false, false, false, 2);
321 DoTest(false, false, true, 2);
322}
323
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700324TEST_F(FilesystemCopierActionTest, RunAsRootNoSpaceTest) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000325 ASSERT_EQ(0, getuid());
Darin Petkov3aefa862010-12-07 14:45:00 -0800326 DoTest(true, false, false, 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000327}
328
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700329TEST_F(FilesystemCopierActionTest, RunAsRootTerminateEarlyTest) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000330 ASSERT_EQ(0, getuid());
Darin Petkov3aefa862010-12-07 14:45:00 -0800331 DoTest(false, true, false, 0);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000332}
333
Darin Petkov698d0412010-10-13 10:59:44 -0700334TEST_F(FilesystemCopierActionTest, RunAsRootDetermineFilesystemSizeTest) {
335 string img;
336 EXPECT_TRUE(utils::MakeTempFile("/tmp/img.XXXXXX", &img, NULL));
337 ScopedPathUnlinker img_unlinker(img);
338 CreateExtImageAtPath(img, NULL);
339 // Extend the "partition" holding the file system from 10MiB to 20MiB.
340 EXPECT_EQ(0, System(StringPrintf(
341 "dd if=/dev/zero of=%s seek=20971519 bs=1 count=1",
342 img.c_str())));
343 EXPECT_EQ(20 * 1024 * 1024, utils::FileSize(img));
344
345 for (int i = 0; i < 2; ++i) {
346 bool is_kernel = i == 1;
Darin Petkov3aefa862010-12-07 14:45:00 -0800347 FilesystemCopierAction action(is_kernel, false);
Darin Petkov698d0412010-10-13 10:59:44 -0700348 EXPECT_EQ(kint64max, action.filesystem_size_);
349 {
350 int fd = HANDLE_EINTR(open(img.c_str(), O_RDONLY));
351 EXPECT_TRUE(fd > 0);
352 ScopedFdCloser fd_closer(&fd);
353 action.DetermineFilesystemSize(fd);
354 }
355 EXPECT_EQ(is_kernel ? kint64max : 10 * 1024 * 1024,
356 action.filesystem_size_);
357 }
358}
359
360
adlr@google.com3defe6a2009-12-04 20:57:17 +0000361} // namespace chromeos_update_engine