| Index: src/platform/update_engine/integration_unittest.cc
|
| diff --git a/src/platform/update_engine/integration_unittest.cc b/src/platform/update_engine/integration_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..671240f98126c29bdd636bab2003e7d5cc98e1c0
|
| --- /dev/null
|
| +++ b/src/platform/update_engine/integration_unittest.cc
|
| @@ -0,0 +1,189 @@
|
| +// Copyright (c) 2009 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_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/update_check_action.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) {
|
| + processing_done_called_ = true;
|
| + g_main_loop_quit(loop_);
|
| + }
|
| +
|
| + virtual void ActionCompleted(ActionProcessor* processor,
|
| + AbstractAction* action,
|
| + bool success) {
|
| + // make sure actions always succeed
|
| + EXPECT_TRUE(success);
|
| +
|
| + // 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 = GetUnusedLoopDevice();
|
| + string cmd = string("losetup ") + dev + " " + kTestDir + "/dev2";
|
| + EXPECT_EQ(0, system(cmd.c_str()));
|
| + 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);
|
| + UpdateCheckAction update_check_action(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_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::ReadFileToString(
|
| + "/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
|
|
|