diff options
Diffstat (limited to 'integration_unittest.cc')
-rw-r--r-- | integration_unittest.cc | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/integration_unittest.cc b/integration_unittest.cc new file mode 100644 index 00000000..671240f9 --- /dev/null +++ b/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 |