blob: 10e663326000a265a92d29c029633c79d749e4f9 [file] [log] [blame]
Darin Petkovc1a8b422010-07-19 11:34:49 -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
5#include <string>
6#include <vector>
7#include <glib.h>
8#include <pthread.h>
9#include <gtest/gtest.h>
Chris Sosabe45bef2013-04-09 18:25:12 -070010#include "update_engine/constants.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000011#include "update_engine/download_action.h"
12#include "update_engine/install_action.h"
13#include "update_engine/libcurl_http_fetcher.h"
14#include "update_engine/mock_http_fetcher.h"
Darin Petkov6a5b3222010-07-13 14:55:28 -070015#include "update_engine/omaha_request_action.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000016#include "update_engine/omaha_request_prep_action.h"
17#include "update_engine/omaha_response_handler_action.h"
18#include "update_engine/postinstall_runner_action.h"
19#include "update_engine/set_bootable_flag_action.h"
20#include "update_engine/test_utils.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000021#include "update_engine/utils.h"
22
23// The tests here integrate many Action objects together. This test that
24// the objects work well together, whereas most other tests focus on a single
25// action at a time.
26
27namespace chromeos_update_engine {
28
29using std::string;
30using std::vector;
31
32class IntegrationTest : public ::testing::Test { };
33
34namespace {
adlr@google.com3defe6a2009-12-04 20:57:17 +000035
36class IntegrationTestProcessorDelegate : public ActionProcessorDelegate {
37 public:
Gilad Arnoldeff87cc2013-07-22 18:32:09 -070038 IntegrationTestProcessorDelegate(const string& test_dir)
39 : loop_(NULL), processing_done_called_(false), test_dir_(test_dir) {}
adlr@google.com3defe6a2009-12-04 20:57:17 +000040 virtual ~IntegrationTestProcessorDelegate() {
41 EXPECT_TRUE(processing_done_called_);
42 }
Darin Petkovc1a8b422010-07-19 11:34:49 -070043 virtual void ProcessingDone(const ActionProcessor* processor,
David Zeuthena99981f2013-04-29 13:42:47 -070044 ErrorCode code) {
adlr@google.com3defe6a2009-12-04 20:57:17 +000045 processing_done_called_ = true;
46 g_main_loop_quit(loop_);
47 }
48
49 virtual void ActionCompleted(ActionProcessor* processor,
50 AbstractAction* action,
David Zeuthena99981f2013-04-29 13:42:47 -070051 ErrorCode code) {
adlr@google.com3defe6a2009-12-04 20:57:17 +000052 // make sure actions always succeed
David Zeuthena99981f2013-04-29 13:42:47 -070053 EXPECT_EQ(kErrorCodeSuccess, code);
adlr@google.com3defe6a2009-12-04 20:57:17 +000054
55 // Swap in the device path for PostinstallRunnerAction with a loop device
56 if (action->Type() == InstallAction::StaticType()) {
57 InstallAction* install_action = static_cast<InstallAction*>(action);
58 old_dev_ = install_action->GetOutputObject();
Gilad Arnold19a45f02012-07-19 12:36:10 -070059 string dev;
Gilad Arnoldeff87cc2013-07-22 18:32:09 -070060 BindToUnusedDevice(test_dir_ + "/dev2", &dev);
adlr@google.com3defe6a2009-12-04 20:57:17 +000061 install_action->SetOutputObject(dev);
62 } else if (action->Type() == PostinstallRunnerAction::StaticType()) {
63 PostinstallRunnerAction* postinstall_runner_action =
64 static_cast<PostinstallRunnerAction*>(action);
65 string dev = postinstall_runner_action->GetOutputObject();
66 EXPECT_EQ(0, system((string("losetup -d ") + dev).c_str()));
67 postinstall_runner_action->SetOutputObject(old_dev_);
68 old_dev_ = "";
69 }
70 }
71
72 void set_loop(GMainLoop* loop) {
73 loop_ = loop;
74 }
75
76 private:
77 GMainLoop *loop_;
78 bool processing_done_called_;
79
80 // We have to change the dev for the PostinstallRunnerAction action.
81 // Before that runs, we store the device here, and after it runs, we
82 // restore it.
83 // This is because we use a file, rather than a device, to install into,
84 // but the PostinstallRunnerAction requires a real device. We set up a
85 // loop device pointing to the file when necessary.
86 string old_dev_;
Gilad Arnoldeff87cc2013-07-22 18:32:09 -070087
88 // A per-instance, customizable test directory. Used for avoiding race
89 // conditions while running multiple tests concurrently.
90 string test_dir_;
adlr@google.com3defe6a2009-12-04 20:57:17 +000091};
92
93gboolean TestStarter(gpointer data) {
94 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
95 processor->StartProcessing();
96 return FALSE;
97}
98
99} // namespace {}
100
101TEST(IntegrationTest, DISABLED_RunAsRootFullInstallTest) {
102 ASSERT_EQ(0, getuid());
103 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
104
Gilad Arnoldeff87cc2013-07-22 18:32:09 -0700105 // Create a uniquely named test directory.
106 string test_dir;
107 ASSERT_TRUE(utils::MakeTempDirectory(
108 "/tmp/update_engine-integration-test-XXXXXX", &test_dir));
109 ScopedPathUnlinker test_dir_unlinker(test_dir);
110
adlr@google.com3defe6a2009-12-04 20:57:17 +0000111 ActionProcessor processor;
Gilad Arnoldeff87cc2013-07-22 18:32:09 -0700112 IntegrationTestProcessorDelegate delegate(test_dir);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000113 delegate.set_loop(loop);
114 processor.set_delegate(&delegate);
115
116 // Actions:
117 OmahaRequestPrepAction request_prep_action(false);
Darin Petkov0dc8e9a2010-07-14 14:51:57 -0700118 OmahaRequestAction update_check_action(NULL, new LibcurlHttpFetcher);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000119 OmahaResponseHandlerAction response_handler_action;
120 DownloadAction download_action(new LibcurlHttpFetcher);
121 InstallAction install_action;
122 PostinstallRunnerAction postinstall_runner_action;
123 SetBootableFlagAction set_bootable_flag_action;
124
125 // Enqueue the actions
126 processor.EnqueueAction(&request_prep_action);
127 processor.EnqueueAction(&update_check_action);
128 processor.EnqueueAction(&response_handler_action);
129 processor.EnqueueAction(&download_action);
130 processor.EnqueueAction(&install_action);
131 processor.EnqueueAction(&postinstall_runner_action);
132 processor.EnqueueAction(&set_bootable_flag_action);
133
134 // Bond them together
135 BondActions(&request_prep_action, &update_check_action);
136 BondActions(&update_check_action, &response_handler_action);
137 BondActions(&response_handler_action, &download_action);
138 BondActions(&download_action, &install_action);
139 BondActions(&install_action, &postinstall_runner_action);
140 BondActions(&postinstall_runner_action, &set_bootable_flag_action);
141
142 // Set up filesystem to trick some of the actions
143 ASSERT_EQ(0, System(string("rm -rf ") + kTestDir));
144 ASSERT_EQ(0, system("rm -f /tmp/update_engine_test_postinst_out.txt"));
145 ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
Andrew de los Reyes970bb282009-12-09 16:34:04 -0800146 ASSERT_EQ(0, system((string("mkdir -p ") + kTestDir +
Chris Sosabe45bef2013-04-09 18:25:12 -0700147 kStatefulPartition +
Andrew de los Reyes970bb282009-12-09 16:34:04 -0800148 "/etc").c_str()));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000149 ASSERT_TRUE(WriteFileString(string(kTestDir) + "/etc/lsb-release",
150 "GOOGLE_RELEASE=0.2.0.0\n"
151 "GOOGLE_TRACK=unittest-track"));
152 ASSERT_EQ(0, System(string("touch ") + kTestDir + "/dev1"));
153 ASSERT_EQ(0, System(string("touch ") + kTestDir + "/dev2"));
154 ASSERT_TRUE(WriteFileVector(string(kTestDir) + "/dev", GenerateSampleMbr()));
155
156 request_prep_action.set_root(kTestDir);
157 response_handler_action.set_boot_device(string(kTestDir) + "/dev1");
158
159 // Run the actions
160 g_timeout_add(0, &TestStarter, &processor);
161 g_main_loop_run(loop);
162 g_main_loop_unref(loop);
163
164 // Verify the results
165 struct stat stbuf;
166 ASSERT_EQ(0, lstat((string(kTestDir) + "/dev1").c_str(), &stbuf));
167 EXPECT_EQ(0, stbuf.st_size);
168 EXPECT_TRUE(S_ISREG(stbuf.st_mode));
169 ASSERT_EQ(0, lstat((string(kTestDir) + "/dev2").c_str(), &stbuf));
170 EXPECT_EQ(996147200, stbuf.st_size);
171 EXPECT_TRUE(S_ISREG(stbuf.st_mode));
172 ASSERT_EQ(0, lstat((string(kTestDir) + "/dev").c_str(), &stbuf));
173 ASSERT_EQ(512, stbuf.st_size);
174 EXPECT_TRUE(S_ISREG(stbuf.st_mode));
175 vector<char> new_mbr;
176 EXPECT_TRUE(utils::ReadFile((string(kTestDir) + "/dev").c_str(), &new_mbr));
177
178 // Check bootable flag in MBR
179 for (int i = 0; i < 4; i++) {
180 char expected_flag = '\0';
181 if (i == 1)
182 expected_flag = 0x80;
183 EXPECT_EQ(expected_flag, new_mbr[446 + 16 * i]);
184 }
185 // Check MBR signature
186 EXPECT_EQ(static_cast<char>(0x55), new_mbr[510]);
187 EXPECT_EQ(static_cast<char>(0xaa), new_mbr[511]);
188
189 ASSERT_EQ(0, lstat("/tmp/update_engine_test_postinst_out.txt", &stbuf));
190 EXPECT_TRUE(S_ISREG(stbuf.st_mode));
191 string file_data;
Gilad Arnold19a45f02012-07-19 12:36:10 -0700192 EXPECT_TRUE(utils::ReadFile(
adlr@google.com3defe6a2009-12-04 20:57:17 +0000193 "/tmp/update_engine_test_postinst_out.txt",
194 &file_data));
195 EXPECT_EQ("POSTINST_DONE\n", file_data);
196
197 // cleanup
198 ASSERT_EQ(0, System(string("rm -rf ") + kTestDir));
199 ASSERT_EQ(0, system("rm -f /tmp/update_engine_test_postinst_out.txt"));
200}
201
202} // namespace chromeos_update_engine