blob: 37d552f6f63de472e888c8b6194b3d9fea8a9d55 [file] [log] [blame]
Gilad Arnoldc33faeb2012-07-24 15:11:11 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
rspangler@google.com49fdf182009-10-10 00:57:34 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Gilad Arnoldcf175a02014-07-10 16:48:47 -07005#ifndef UPDATE_ENGINE_TEST_UTILS_H_
6#define UPDATE_ENGINE_TEST_UTILS_H_
rspangler@google.com49fdf182009-10-10 00:57:34 +00007
Gilad Arnold2c2b8842013-07-16 06:44:37 -07008#include <sys/stat.h>
9#include <sys/types.h>
10#include <unistd.h>
11
adlr@google.comc98a7ed2009-12-04 18:54:03 +000012#include <set>
rspangler@google.com49fdf182009-10-10 00:57:34 +000013#include <string>
adlr@google.comc98a7ed2009-12-04 18:54:03 +000014#include <vector>
Thieu Le5c7d9752010-12-15 16:09:28 -080015
Alex Deymo53556ec2014-03-17 10:05:57 -070016#include <base/callback.h>
Chris Masoned903c3b2011-05-12 15:35:46 -070017#include <base/memory/scoped_ptr.h>
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070018#include <glib-object.h>
adlr@google.comc98a7ed2009-12-04 18:54:03 +000019#include <gtest/gtest.h>
Thieu Le5c7d9752010-12-15 16:09:28 -080020
adlr@google.comc98a7ed2009-12-04 18:54:03 +000021#include "update_engine/action.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070022#include "update_engine/subprocess.h"
Andrew de los Reyesf9185172010-05-03 11:07:05 -070023#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000024
25// These are some handy functions for unittests.
26
27namespace chromeos_update_engine {
28
rspangler@google.com49fdf182009-10-10 00:57:34 +000029// Writes the data passed to path. The file at path will be overwritten if it
30// exists. Returns true on success, false otherwise.
adlr@google.comc98a7ed2009-12-04 18:54:03 +000031bool WriteFileVector(const std::string& path, const std::vector<char>& data);
32bool WriteFileString(const std::string& path, const std::string& data);
rspangler@google.com49fdf182009-10-10 00:57:34 +000033
adlr@google.comc98a7ed2009-12-04 18:54:03 +000034// Reads a symlink from disk. Returns empty string on failure.
35std::string Readlink(const std::string& path);
36
rspangler@google.com49fdf182009-10-10 00:57:34 +000037// Gzip compresses the data passed using the gzip command line program.
38// Returns compressed data back.
39std::vector<char> GzipCompressData(const std::vector<char>& data);
40
adlr@google.comc98a7ed2009-12-04 18:54:03 +000041// Gives back a 512-bytes length array that contains an MBR with
42// the first partition is marked bootable.
43std::vector<char> GenerateSampleMbr();
44
Gilad Arnold19a45f02012-07-19 12:36:10 -070045bool BindToUnusedLoopDevice(const std::string &filename,
46 std::string* lo_dev_name_ptr);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000047
48// Returns true iff a == b
49bool ExpectVectorsEq(const std::vector<char>& a, const std::vector<char>& b);
50
51inline int System(const std::string& cmd) {
52 return system(cmd.c_str());
53}
54
Gilad Arnold2c2b8842013-07-16 06:44:37 -070055inline int Symlink(const std::string& oldpath, const std::string& newpath) {
56 return symlink(oldpath.c_str(), newpath.c_str());
57}
58
59inline int Chmod(const std::string& path, mode_t mode) {
60 return chmod(path.c_str(), mode);
61}
62
63inline int Mkdir(const std::string& path, mode_t mode) {
64 return mkdir(path.c_str(), mode);
65}
66
Gilad Arnold30dedd82013-07-03 06:19:09 -070067inline int Chdir(const std::string& path) {
68 return chdir(path.c_str());
69}
70
Andrew de los Reyes80061062010-02-04 14:25:00 -080071void FillWithData(std::vector<char>* buffer);
72
Alex Vakulenkod2779df2014-06-16 13:19:00 -070073namespace { // NOLINT(build/namespaces) - anon. NS in header file.
adlr@google.comc98a7ed2009-12-04 18:54:03 +000074// 300 byte pseudo-random string. Not null terminated.
75// This does not gzip compress well.
76const unsigned char kRandomString[] = {
77 0xf2, 0xb7, 0x55, 0x92, 0xea, 0xa6, 0xc9, 0x57,
78 0xe0, 0xf8, 0xeb, 0x34, 0x93, 0xd9, 0xc4, 0x8f,
79 0xcb, 0x20, 0xfa, 0x37, 0x4b, 0x40, 0xcf, 0xdc,
80 0xa5, 0x08, 0x70, 0x89, 0x79, 0x35, 0xe2, 0x3d,
81 0x56, 0xa4, 0x75, 0x73, 0xa3, 0x6d, 0xd1, 0xd5,
82 0x26, 0xbb, 0x9c, 0x60, 0xbd, 0x2f, 0x5a, 0xfa,
83 0xb7, 0xd4, 0x3a, 0x50, 0xa7, 0x6b, 0x3e, 0xfd,
84 0x61, 0x2b, 0x3a, 0x31, 0x30, 0x13, 0x33, 0x53,
85 0xdb, 0xd0, 0x32, 0x71, 0x5c, 0x39, 0xed, 0xda,
86 0xb4, 0x84, 0xca, 0xbc, 0xbd, 0x78, 0x1c, 0x0c,
87 0xd8, 0x0b, 0x41, 0xe8, 0xe1, 0xe0, 0x41, 0xad,
88 0x03, 0x12, 0xd3, 0x3d, 0xb8, 0x75, 0x9b, 0xe6,
89 0xd9, 0x01, 0xd0, 0x87, 0xf4, 0x36, 0xfa, 0xa7,
90 0x0a, 0xfa, 0xc5, 0x87, 0x65, 0xab, 0x9a, 0x7b,
91 0xeb, 0x58, 0x23, 0xf0, 0xa8, 0x0a, 0xf2, 0x33,
92 0x3a, 0xe2, 0xe3, 0x35, 0x74, 0x95, 0xdd, 0x3c,
93 0x59, 0x5a, 0xd9, 0x52, 0x3a, 0x3c, 0xac, 0xe5,
94 0x15, 0x87, 0x6d, 0x82, 0xbc, 0xf8, 0x7d, 0xbe,
95 0xca, 0xd3, 0x2c, 0xd6, 0xec, 0x38, 0xeb, 0xe4,
96 0x53, 0xb0, 0x4c, 0x3f, 0x39, 0x29, 0xf7, 0xa4,
97 0x73, 0xa8, 0xcb, 0x32, 0x50, 0x05, 0x8c, 0x1c,
98 0x1c, 0xca, 0xc9, 0x76, 0x0b, 0x8f, 0x6b, 0x57,
99 0x1f, 0x24, 0x2b, 0xba, 0x82, 0xba, 0xed, 0x58,
100 0xd8, 0xbf, 0xec, 0x06, 0x64, 0x52, 0x6a, 0x3f,
101 0xe4, 0xad, 0xce, 0x84, 0xb4, 0x27, 0x55, 0x14,
102 0xe3, 0x75, 0x59, 0x73, 0x71, 0x51, 0xea, 0xe8,
103 0xcc, 0xda, 0x4f, 0x09, 0xaf, 0xa4, 0xbc, 0x0e,
104 0xa6, 0x1f, 0xe2, 0x3a, 0xf8, 0x96, 0x7d, 0x30,
105 0x23, 0xc5, 0x12, 0xb5, 0xd8, 0x73, 0x6b, 0x71,
106 0xab, 0xf1, 0xd7, 0x43, 0x58, 0xa7, 0xc9, 0xf0,
107 0xe4, 0x85, 0x1c, 0xd6, 0x92, 0x50, 0x2c, 0x98,
108 0x36, 0xfe, 0x87, 0xaf, 0x43, 0x8f, 0x8f, 0xf5,
109 0x88, 0x48, 0x18, 0x42, 0xcf, 0x42, 0xc1, 0xa8,
110 0xe8, 0x05, 0x08, 0xa1, 0x45, 0x70, 0x5b, 0x8c,
111 0x39, 0x28, 0xab, 0xe9, 0x6b, 0x51, 0xd2, 0xcb,
112 0x30, 0x04, 0xea, 0x7d, 0x2f, 0x6e, 0x6c, 0x3b,
113 0x5f, 0x82, 0xd9, 0x5b, 0x89, 0x37, 0x65, 0x65,
114 0xbe, 0x9f, 0xa3, 0x5d
115};
116
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700117} // namespace
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000118
Thieu Le5c7d9752010-12-15 16:09:28 -0800119// Creates an empty ext image.
120void CreateEmptyExtImageAtPath(const std::string& path,
121 size_t size,
122 int block_size);
123
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000124// Creates an ext image with some files in it. The paths creates are
125// returned in out_paths.
126void CreateExtImageAtPath(const std::string& path,
127 std::vector<std::string>* out_paths);
128
129// Verifies that for each path in paths, it exists in the filesystem under
130// parent. Also, verifies that no additional paths are present under parent.
131// Also tests properties of various files created by CreateExtImageAtPath().
132// Intentionally copies expected_paths.
133void VerifyAllPaths(const std::string& parent,
134 std::set<std::string> expected_paths);
135
Don Garrett58e8b1f2012-01-31 16:38:16 -0800136class ScopedLoopbackDeviceBinder {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700137 public:
Don Garrett58e8b1f2012-01-31 16:38:16 -0800138 ScopedLoopbackDeviceBinder(const std::string& file, std::string* dev) {
Gilad Arnold19a45f02012-07-19 12:36:10 -0700139 is_bound_ = BindToUnusedLoopDevice(file, &dev_);
140 EXPECT_TRUE(is_bound_);
Don Garrett58e8b1f2012-01-31 16:38:16 -0800141
Gilad Arnold19a45f02012-07-19 12:36:10 -0700142 if (is_bound_ && dev)
Don Garrett58e8b1f2012-01-31 16:38:16 -0800143 *dev = dev_;
144 }
145
146 ~ScopedLoopbackDeviceBinder() {
Gilad Arnold19a45f02012-07-19 12:36:10 -0700147 if (!is_bound_)
148 return;
149
Darin Petkovcf562482010-12-03 10:31:00 -0800150 for (int retry = 0; retry < 5; retry++) {
151 std::vector<std::string> args;
152 args.push_back("/sbin/losetup");
153 args.push_back("-d");
154 args.push_back(dev_);
155 int return_code = 0;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700156 EXPECT_TRUE(Subprocess::SynchronousExec(args, &return_code, nullptr));
Darin Petkovcf562482010-12-03 10:31:00 -0800157 if (return_code == 0) {
158 return;
159 }
160 sleep(1);
161 }
162 ADD_FAILURE();
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700163 }
Don Garrett58e8b1f2012-01-31 16:38:16 -0800164
Gilad Arnold19a45f02012-07-19 12:36:10 -0700165 const std::string &dev() {
166 EXPECT_TRUE(is_bound_);
167 return dev_;
168 }
Don Garrett58e8b1f2012-01-31 16:38:16 -0800169
Gilad Arnoldc33faeb2012-07-24 15:11:11 -0700170 bool is_bound() const { return is_bound_; }
171
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700172 private:
Don Garrett58e8b1f2012-01-31 16:38:16 -0800173 std::string dev_;
Gilad Arnold19a45f02012-07-19 12:36:10 -0700174 bool is_bound_;
Don Garrett58e8b1f2012-01-31 16:38:16 -0800175 DISALLOW_COPY_AND_ASSIGN(ScopedLoopbackDeviceBinder);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700176};
177
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700178class ScopedTempFile {
179 public:
180 ScopedTempFile() {
181 EXPECT_TRUE(utils::MakeTempFile("/tmp/update_engine_test_temp_file.XXXXXX",
182 &path_,
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700183 nullptr));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700184 unlinker_.reset(new ScopedPathUnlinker(path_));
185 }
186 const std::string& GetPath() { return path_; }
187 private:
188 std::string path_;
189 scoped_ptr<ScopedPathUnlinker> unlinker_;
190};
191
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000192// Useful actions for test
193
194class NoneType;
195
196template<typename T>
197class ObjectFeederAction;
198
199template<typename T>
Ben Chanf9cb98c2014-09-21 18:31:30 -0700200class ActionTraits<ObjectFeederAction<T>> {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000201 public:
202 typedef T OutputObjectType;
203 typedef NoneType InputObjectType;
204};
205
206// This is a simple Action class for testing. It feeds an object into
207// another action.
208template<typename T>
Ben Chanf9cb98c2014-09-21 18:31:30 -0700209class ObjectFeederAction : public Action<ObjectFeederAction<T>> {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000210 public:
211 typedef NoneType InputObjectType;
212 typedef T OutputObjectType;
213 void PerformAction() {
214 LOG(INFO) << "feeder running!";
215 CHECK(this->processor_);
216 if (this->HasOutputPipe()) {
217 this->SetOutputObject(out_obj_);
218 }
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700219 this->processor_->ActionComplete(this, ErrorCode::kSuccess);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000220 }
221 static std::string StaticType() { return "ObjectFeederAction"; }
222 std::string Type() const { return StaticType(); }
223 void set_obj(const T& out_obj) {
224 out_obj_ = out_obj;
225 }
226 private:
227 T out_obj_;
228};
229
230template<typename T>
231class ObjectCollectorAction;
232
233template<typename T>
Ben Chanf9cb98c2014-09-21 18:31:30 -0700234class ActionTraits<ObjectCollectorAction<T>> {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000235 public:
236 typedef NoneType OutputObjectType;
237 typedef T InputObjectType;
238};
239
240// This is a simple Action class for testing. It receives an object from
241// another action.
242template<typename T>
Ben Chanf9cb98c2014-09-21 18:31:30 -0700243class ObjectCollectorAction : public Action<ObjectCollectorAction<T>> {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000244 public:
245 typedef T InputObjectType;
246 typedef NoneType OutputObjectType;
247 void PerformAction() {
248 LOG(INFO) << "collector running!";
249 ASSERT_TRUE(this->processor_);
250 if (this->HasInputObject()) {
251 object_ = this->GetInputObject();
252 }
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700253 this->processor_->ActionComplete(this, ErrorCode::kSuccess);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000254 }
255 static std::string StaticType() { return "ObjectCollectorAction"; }
256 std::string Type() const { return StaticType(); }
257 const T& object() const { return object_; }
258 private:
259 T object_;
260};
261
Thieu Le5c7d9752010-12-15 16:09:28 -0800262class ScopedLoopMounter {
263 public:
264 explicit ScopedLoopMounter(const std::string& file_path,
265 std::string* mnt_path,
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700266 unsigned long flags); // NOLINT(runtime/int)
Thieu Le5c7d9752010-12-15 16:09:28 -0800267
268 private:
269 // These objects must be destructed in the following order:
270 // ScopedFilesystemUnmounter (the file system must be unmounted first)
Don Garrett58e8b1f2012-01-31 16:38:16 -0800271 // ScopedLoopbackDeviceBinder (then the loop device can be deleted)
Thieu Le5c7d9752010-12-15 16:09:28 -0800272 // ScopedDirRemover (then the mount point can be deleted)
273 scoped_ptr<ScopedDirRemover> dir_remover_;
Don Garrett58e8b1f2012-01-31 16:38:16 -0800274 scoped_ptr<ScopedLoopbackDeviceBinder> loop_binder_;
Thieu Le5c7d9752010-12-15 16:09:28 -0800275 scoped_ptr<ScopedFilesystemUnmounter> unmounter_;
276};
277
Alex Deymo53556ec2014-03-17 10:05:57 -0700278// Runs the default GLib main loop for at most |timeout_msec| or until the
279// function |terminate| returns true, whichever happens first. The function
280// |terminate| is called before every GLib main loop iteration and its value is
281// checked.
282void RunGMainLoopUntil(int timeout_msec, base::Callback<bool()> terminate);
283
Alex Deymo7b948f02014-03-10 17:01:10 -0700284// Runs the default GLib main loop at most |iterations| times. This
285// dispatches all the events that are already waiting in the main loop and
286// those that get scheduled as a result of these events being attended.
287// Returns the number of iterations the main loop was ran. If there are more
288// than |iterations| events to attend, then this function returns |iterations|
289// and the remaining events are not dispatched.
290int RunGMainLoopMaxIterations(int iterations);
291
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700292// Allocates, initializes and returns a string GValue object.
293GValue* GValueNewString(const char* str);
294
295// Frees a GValue object and its allocated resources.
296void GValueFree(gpointer arg);
297
rspangler@google.com49fdf182009-10-10 00:57:34 +0000298} // namespace chromeos_update_engine
299
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700300#endif // UPDATE_ENGINE_TEST_UTILS_H_