Split payload application code into a subdirectory.
This patch splits from the main libupdate_engine code the part that
is strictly used to download and apply a payload into a new static
library, moving the code to subdirectories. The new library is divided
in two subdirectories: common/ and payload_consumer/, and should not
depend on other update_engine files outside those two subdirectories.
The main difference between those two is that the common/ tools are more
generic and not tied to the payload consumer process, but otherwise they
are both compiled together.
There are still dependencies from the new libpayload_consumer library
into the main directory files and DBus generated files. Those will be
addressed in follow up CLs.
Bug: 25197634
Test: FEATURES=test emerge-link update_engine; `mm` on Brillo.
Change-Id: Id8d0204ea573627e6e26ca9ea17b9592ca95bc23
diff --git a/common/test_utils.h b/common/test_utils.h
new file mode 100644
index 0000000..616bdd3
--- /dev/null
+++ b/common/test_utils.h
@@ -0,0 +1,271 @@
+//
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_COMMON_TEST_UTILS_H_
+#define UPDATE_ENGINE_COMMON_TEST_UTILS_H_
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// Streams used for gtest's PrintTo() functions.
+#include <iostream> // NOLINT(readability/streams)
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <base/callback.h>
+#include <base/files/file_path.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/common/action.h"
+#include "update_engine/common/subprocess.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/update_metadata.pb.h"
+
+// These are some handy functions for unittests.
+
+namespace chromeos_update_engine {
+
+// PrintTo() functions are used by gtest to log these objects. These PrintTo()
+// functions must be defined in the same namespace as the first argument.
+void PrintTo(const Extent& extent, ::std::ostream* os);
+
+namespace test_utils {
+
+// 300 byte pseudo-random string. Not null terminated.
+// This does not gzip compress well.
+extern const uint8_t kRandomString[300];
+
+// Writes the data passed to path. The file at path will be overwritten if it
+// exists. Returns true on success, false otherwise.
+bool WriteFileVector(const std::string& path, const brillo::Blob& data);
+bool WriteFileString(const std::string& path, const std::string& data);
+
+bool BindToUnusedLoopDevice(const std::string &filename,
+ std::string* lo_dev_name_ptr);
+
+// Returns true iff a == b
+bool ExpectVectorsEq(const brillo::Blob& a, const brillo::Blob& b);
+
+inline int System(const std::string& cmd) {
+ return system(cmd.c_str());
+}
+
+inline int Symlink(const std::string& oldpath, const std::string& newpath) {
+ return symlink(oldpath.c_str(), newpath.c_str());
+}
+
+inline int Chmod(const std::string& path, mode_t mode) {
+ return chmod(path.c_str(), mode);
+}
+
+inline int Mkdir(const std::string& path, mode_t mode) {
+ return mkdir(path.c_str(), mode);
+}
+
+inline int Chdir(const std::string& path) {
+ return chdir(path.c_str());
+}
+
+// Checks if xattr is supported in the directory specified by
+// |dir_path| which must be writable. Returns true if the feature is
+// supported, false if not or if an error occurred.
+bool IsXAttrSupported(const base::FilePath& dir_path);
+
+void FillWithData(brillo::Blob* buffer);
+
+// Creates an empty ext image.
+void CreateEmptyExtImageAtPath(const std::string& path,
+ size_t size,
+ int block_size);
+
+// Creates an ext image with some files in it. The paths creates are
+// returned in out_paths.
+void CreateExtImageAtPath(const std::string& path,
+ std::vector<std::string>* out_paths);
+
+// Class to unmount FS when object goes out of scope
+class ScopedFilesystemUnmounter {
+ public:
+ explicit ScopedFilesystemUnmounter(const std::string& mountpoint)
+ : mountpoint_(mountpoint),
+ should_unmount_(true) {}
+ ~ScopedFilesystemUnmounter() {
+ if (should_unmount_) {
+ utils::UnmountFilesystem(mountpoint_);
+ }
+ }
+ void set_should_unmount(bool unmount) { should_unmount_ = unmount; }
+ private:
+ const std::string mountpoint_;
+ bool should_unmount_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedFilesystemUnmounter);
+};
+
+class ScopedLoopbackDeviceBinder {
+ public:
+ ScopedLoopbackDeviceBinder(const std::string& file, std::string* dev) {
+ is_bound_ = BindToUnusedLoopDevice(file, &dev_);
+ EXPECT_TRUE(is_bound_);
+
+ if (is_bound_ && dev)
+ *dev = dev_;
+ }
+
+ ~ScopedLoopbackDeviceBinder() {
+ if (!is_bound_)
+ return;
+
+ for (int retry = 0; retry < 5; retry++) {
+ std::vector<std::string> args;
+ args.push_back("/sbin/losetup");
+ args.push_back("-d");
+ args.push_back(dev_);
+ int return_code = 0;
+ EXPECT_TRUE(Subprocess::SynchronousExec(args, &return_code, nullptr));
+ if (return_code == 0) {
+ return;
+ }
+ sleep(1);
+ }
+ ADD_FAILURE();
+ }
+
+ const std::string &dev() {
+ EXPECT_TRUE(is_bound_);
+ return dev_;
+ }
+
+ bool is_bound() const { return is_bound_; }
+
+ private:
+ std::string dev_;
+ bool is_bound_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedLoopbackDeviceBinder);
+};
+
+class ScopedTempFile {
+ public:
+ ScopedTempFile() {
+ EXPECT_TRUE(utils::MakeTempFile("update_engine_test_temp_file.XXXXXX",
+ &path_,
+ nullptr));
+ unlinker_.reset(new ScopedPathUnlinker(path_));
+ }
+ const std::string& GetPath() { return path_; }
+ private:
+ std::string path_;
+ std::unique_ptr<ScopedPathUnlinker> unlinker_;
+};
+
+class ScopedLoopMounter {
+ public:
+ explicit ScopedLoopMounter(const std::string& file_path,
+ std::string* mnt_path,
+ unsigned long flags); // NOLINT(runtime/int)
+
+ private:
+ // These objects must be destructed in the following order:
+ // ScopedFilesystemUnmounter (the file system must be unmounted first)
+ // ScopedLoopbackDeviceBinder (then the loop device can be deleted)
+ // ScopedDirRemover (then the mount point can be deleted)
+ std::unique_ptr<ScopedDirRemover> dir_remover_;
+ std::unique_ptr<ScopedLoopbackDeviceBinder> loop_binder_;
+ std::unique_ptr<ScopedFilesystemUnmounter> unmounter_;
+};
+
+// Returns the path where the build artifacts are stored. This is the directory
+// where the unittest executable is being run from.
+base::FilePath GetBuildArtifactsPath();
+
+} // namespace test_utils
+
+// Useful actions for test. These need to be defined in the
+// chromeos_update_engine namespace.
+
+class NoneType;
+
+template<typename T>
+class ObjectFeederAction;
+
+template<typename T>
+class ActionTraits<ObjectFeederAction<T>> {
+ public:
+ typedef T OutputObjectType;
+ typedef NoneType InputObjectType;
+};
+
+// This is a simple Action class for testing. It feeds an object into
+// another action.
+template<typename T>
+class ObjectFeederAction : public Action<ObjectFeederAction<T>> {
+ public:
+ typedef NoneType InputObjectType;
+ typedef T OutputObjectType;
+ void PerformAction() {
+ LOG(INFO) << "feeder running!";
+ CHECK(this->processor_);
+ if (this->HasOutputPipe()) {
+ this->SetOutputObject(out_obj_);
+ }
+ this->processor_->ActionComplete(this, ErrorCode::kSuccess);
+ }
+ static std::string StaticType() { return "ObjectFeederAction"; }
+ std::string Type() const { return StaticType(); }
+ void set_obj(const T& out_obj) {
+ out_obj_ = out_obj;
+ }
+ private:
+ T out_obj_;
+};
+
+template<typename T>
+class ObjectCollectorAction;
+
+template<typename T>
+class ActionTraits<ObjectCollectorAction<T>> {
+ public:
+ typedef NoneType OutputObjectType;
+ typedef T InputObjectType;
+};
+
+// This is a simple Action class for testing. It receives an object from
+// another action.
+template<typename T>
+class ObjectCollectorAction : public Action<ObjectCollectorAction<T>> {
+ public:
+ typedef T InputObjectType;
+ typedef NoneType OutputObjectType;
+ void PerformAction() {
+ LOG(INFO) << "collector running!";
+ ASSERT_TRUE(this->processor_);
+ if (this->HasInputObject()) {
+ object_ = this->GetInputObject();
+ }
+ this->processor_->ActionComplete(this, ErrorCode::kSuccess);
+ }
+ static std::string StaticType() { return "ObjectCollectorAction"; }
+ std::string Type() const { return StaticType(); }
+ const T& object() const { return object_; }
+ private:
+ T object_;
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_COMMON_TEST_UTILS_H_