forked from coreos/update_engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathintegration_unittest.cc
192 lines (165 loc) · 7.01 KB
/
integration_unittest.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <vector>
#include <glib.h>
#include <pthread.h>
#include <gtest/gtest.h>
#include "update_engine/download_action.h"
#include "update_engine/install_action.h"
#include "update_engine/libcurl_http_fetcher.h"
#include "update_engine/mock_http_fetcher.h"
#include "update_engine/omaha_request_action.h"
#include "update_engine/omaha_request_prep_action.h"
#include "update_engine/omaha_response_handler_action.h"
#include "update_engine/postinstall_runner_action.h"
#include "update_engine/set_bootable_flag_action.h"
#include "update_engine/test_utils.h"
#include "update_engine/utils.h"
// The tests here integrate many Action objects together. This test that
// the objects work well together, whereas most other tests focus on a single
// action at a time.
namespace chromeos_update_engine {
using std::string;
using std::vector;
class IntegrationTest : public ::testing::Test { };
namespace {
const char* kTestDir = "/tmp/update_engine-integration-test";
class IntegrationTestProcessorDelegate : public ActionProcessorDelegate {
public:
IntegrationTestProcessorDelegate()
: loop_(NULL), processing_done_called_(false) {}
virtual ~IntegrationTestProcessorDelegate() {
EXPECT_TRUE(processing_done_called_);
}
virtual void ProcessingDone(const ActionProcessor* processor,
ActionExitCode code) {
processing_done_called_ = true;
g_main_loop_quit(loop_);
}
virtual void ActionCompleted(ActionProcessor* processor,
AbstractAction* action,
ActionExitCode code) {
// make sure actions always succeed
EXPECT_EQ(kActionCodeSuccess, code);
// Swap in the device path for PostinstallRunnerAction with a loop device
if (action->Type() == InstallAction::StaticType()) {
InstallAction* install_action = static_cast<InstallAction*>(action);
old_dev_ = install_action->GetOutputObject();
string dev;
BindToUnusedDevice(kTestDir + "/dev2", &dev);
install_action->SetOutputObject(dev);
} else if (action->Type() == PostinstallRunnerAction::StaticType()) {
PostinstallRunnerAction* postinstall_runner_action =
static_cast<PostinstallRunnerAction*>(action);
string dev = postinstall_runner_action->GetOutputObject();
EXPECT_EQ(0, system((string("losetup -d ") + dev).c_str()));
postinstall_runner_action->SetOutputObject(old_dev_);
old_dev_ = "";
}
}
void set_loop(GMainLoop* loop) {
loop_ = loop;
}
private:
GMainLoop *loop_;
bool processing_done_called_;
// We have to change the dev for the PostinstallRunnerAction action.
// Before that runs, we store the device here, and after it runs, we
// restore it.
// This is because we use a file, rather than a device, to install into,
// but the PostinstallRunnerAction requires a real device. We set up a
// loop device pointing to the file when necessary.
string old_dev_;
};
gboolean TestStarter(gpointer data) {
ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
processor->StartProcessing();
return FALSE;
}
} // namespace {}
TEST(IntegrationTest, DISABLED_RunAsRootFullInstallTest) {
ASSERT_EQ(0, getuid());
GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
ActionProcessor processor;
IntegrationTestProcessorDelegate delegate;
delegate.set_loop(loop);
processor.set_delegate(&delegate);
// Actions:
OmahaRequestPrepAction request_prep_action(false);
OmahaRequestAction update_check_action(NULL, new LibcurlHttpFetcher);
OmahaResponseHandlerAction response_handler_action;
DownloadAction download_action(new LibcurlHttpFetcher);
InstallAction install_action;
PostinstallRunnerAction postinstall_runner_action;
SetBootableFlagAction set_bootable_flag_action;
// Enqueue the actions
processor.EnqueueAction(&request_prep_action);
processor.EnqueueAction(&update_check_action);
processor.EnqueueAction(&response_handler_action);
processor.EnqueueAction(&download_action);
processor.EnqueueAction(&install_action);
processor.EnqueueAction(&postinstall_runner_action);
processor.EnqueueAction(&set_bootable_flag_action);
// Bond them together
BondActions(&request_prep_action, &update_check_action);
BondActions(&update_check_action, &response_handler_action);
BondActions(&response_handler_action, &download_action);
BondActions(&download_action, &install_action);
BondActions(&install_action, &postinstall_runner_action);
BondActions(&postinstall_runner_action, &set_bootable_flag_action);
// Set up filesystem to trick some of the actions
ASSERT_EQ(0, System(string("rm -rf ") + kTestDir));
ASSERT_EQ(0, system("rm -f /tmp/update_engine_test_postinst_out.txt"));
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
ASSERT_EQ(0, system((string("mkdir -p ") + kTestDir +
utils::kStatefulPartition +
"/etc").c_str()));
ASSERT_TRUE(WriteFileString(string(kTestDir) + "/etc/lsb-release",
"GOOGLE_RELEASE=0.2.0.0\n"
"GOOGLE_TRACK=unittest-track"));
ASSERT_EQ(0, System(string("touch ") + kTestDir + "/dev1"));
ASSERT_EQ(0, System(string("touch ") + kTestDir + "/dev2"));
ASSERT_TRUE(WriteFileVector(string(kTestDir) + "/dev", GenerateSampleMbr()));
request_prep_action.set_root(kTestDir);
response_handler_action.set_boot_device(string(kTestDir) + "/dev1");
// Run the actions
g_timeout_add(0, &TestStarter, &processor);
g_main_loop_run(loop);
g_main_loop_unref(loop);
// Verify the results
struct stat stbuf;
ASSERT_EQ(0, lstat((string(kTestDir) + "/dev1").c_str(), &stbuf));
EXPECT_EQ(0, stbuf.st_size);
EXPECT_TRUE(S_ISREG(stbuf.st_mode));
ASSERT_EQ(0, lstat((string(kTestDir) + "/dev2").c_str(), &stbuf));
EXPECT_EQ(996147200, stbuf.st_size);
EXPECT_TRUE(S_ISREG(stbuf.st_mode));
ASSERT_EQ(0, lstat((string(kTestDir) + "/dev").c_str(), &stbuf));
ASSERT_EQ(512, stbuf.st_size);
EXPECT_TRUE(S_ISREG(stbuf.st_mode));
vector<char> new_mbr;
EXPECT_TRUE(utils::ReadFile((string(kTestDir) + "/dev").c_str(), &new_mbr));
// Check bootable flag in MBR
for (int i = 0; i < 4; i++) {
char expected_flag = '\0';
if (i == 1)
expected_flag = 0x80;
EXPECT_EQ(expected_flag, new_mbr[446 + 16 * i]);
}
// Check MBR signature
EXPECT_EQ(static_cast<char>(0x55), new_mbr[510]);
EXPECT_EQ(static_cast<char>(0xaa), new_mbr[511]);
ASSERT_EQ(0, lstat("/tmp/update_engine_test_postinst_out.txt", &stbuf));
EXPECT_TRUE(S_ISREG(stbuf.st_mode));
string file_data;
EXPECT_TRUE(utils::ReadFile(
"/tmp/update_engine_test_postinst_out.txt",
&file_data));
EXPECT_EQ("POSTINST_DONE\n", file_data);
// cleanup
ASSERT_EQ(0, System(string("rm -rf ") + kTestDir));
ASSERT_EQ(0, system("rm -f /tmp/update_engine_test_postinst_out.txt"));
}
} // namespace chromeos_update_engine