blob: 4285c4d2f2f15fa24a78f333c5a83f6873d2de27 [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
adlr@google.comc98a7ed2009-12-04 18:54:03 +00005#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_TEST_UTILS_H__
6#define CHROMEOS_PLATFORM_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
Chris Masoned903c3b2011-05-12 15:35:46 -070016#include <base/memory/scoped_ptr.h>
adlr@google.comc98a7ed2009-12-04 18:54:03 +000017#include <gtest/gtest.h>
Thieu Le5c7d9752010-12-15 16:09:28 -080018
adlr@google.comc98a7ed2009-12-04 18:54:03 +000019#include "update_engine/action.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070020#include "update_engine/subprocess.h"
Andrew de los Reyesf9185172010-05-03 11:07:05 -070021#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000022
23// These are some handy functions for unittests.
24
25namespace chromeos_update_engine {
26
rspangler@google.com49fdf182009-10-10 00:57:34 +000027// Writes the data passed to path. The file at path will be overwritten if it
28// exists. Returns true on success, false otherwise.
adlr@google.comc98a7ed2009-12-04 18:54:03 +000029bool WriteFileVector(const std::string& path, const std::vector<char>& data);
30bool WriteFileString(const std::string& path, const std::string& data);
rspangler@google.com49fdf182009-10-10 00:57:34 +000031
adlr@google.comc98a7ed2009-12-04 18:54:03 +000032// Reads a symlink from disk. Returns empty string on failure.
33std::string Readlink(const std::string& path);
34
rspangler@google.com49fdf182009-10-10 00:57:34 +000035// Gzip compresses the data passed using the gzip command line program.
36// Returns compressed data back.
37std::vector<char> GzipCompressData(const std::vector<char>& data);
38
adlr@google.comc98a7ed2009-12-04 18:54:03 +000039// Gives back a 512-bytes length array that contains an MBR with
40// the first partition is marked bootable.
41std::vector<char> GenerateSampleMbr();
42
Gilad Arnold19a45f02012-07-19 12:36:10 -070043bool BindToUnusedLoopDevice(const std::string &filename,
44 std::string* lo_dev_name_ptr);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000045
46// Returns true iff a == b
47bool ExpectVectorsEq(const std::vector<char>& a, const std::vector<char>& b);
48
49inline int System(const std::string& cmd) {
50 return system(cmd.c_str());
51}
52
Gilad Arnold2c2b8842013-07-16 06:44:37 -070053inline int Symlink(const std::string& oldpath, const std::string& newpath) {
54 return symlink(oldpath.c_str(), newpath.c_str());
55}
56
57inline int Chmod(const std::string& path, mode_t mode) {
58 return chmod(path.c_str(), mode);
59}
60
61inline int Mkdir(const std::string& path, mode_t mode) {
62 return mkdir(path.c_str(), mode);
63}
64
Andrew de los Reyes80061062010-02-04 14:25:00 -080065void FillWithData(std::vector<char>* buffer);
66
adlr@google.comc98a7ed2009-12-04 18:54:03 +000067namespace {
68// 300 byte pseudo-random string. Not null terminated.
69// This does not gzip compress well.
70const unsigned char kRandomString[] = {
71 0xf2, 0xb7, 0x55, 0x92, 0xea, 0xa6, 0xc9, 0x57,
72 0xe0, 0xf8, 0xeb, 0x34, 0x93, 0xd9, 0xc4, 0x8f,
73 0xcb, 0x20, 0xfa, 0x37, 0x4b, 0x40, 0xcf, 0xdc,
74 0xa5, 0x08, 0x70, 0x89, 0x79, 0x35, 0xe2, 0x3d,
75 0x56, 0xa4, 0x75, 0x73, 0xa3, 0x6d, 0xd1, 0xd5,
76 0x26, 0xbb, 0x9c, 0x60, 0xbd, 0x2f, 0x5a, 0xfa,
77 0xb7, 0xd4, 0x3a, 0x50, 0xa7, 0x6b, 0x3e, 0xfd,
78 0x61, 0x2b, 0x3a, 0x31, 0x30, 0x13, 0x33, 0x53,
79 0xdb, 0xd0, 0x32, 0x71, 0x5c, 0x39, 0xed, 0xda,
80 0xb4, 0x84, 0xca, 0xbc, 0xbd, 0x78, 0x1c, 0x0c,
81 0xd8, 0x0b, 0x41, 0xe8, 0xe1, 0xe0, 0x41, 0xad,
82 0x03, 0x12, 0xd3, 0x3d, 0xb8, 0x75, 0x9b, 0xe6,
83 0xd9, 0x01, 0xd0, 0x87, 0xf4, 0x36, 0xfa, 0xa7,
84 0x0a, 0xfa, 0xc5, 0x87, 0x65, 0xab, 0x9a, 0x7b,
85 0xeb, 0x58, 0x23, 0xf0, 0xa8, 0x0a, 0xf2, 0x33,
86 0x3a, 0xe2, 0xe3, 0x35, 0x74, 0x95, 0xdd, 0x3c,
87 0x59, 0x5a, 0xd9, 0x52, 0x3a, 0x3c, 0xac, 0xe5,
88 0x15, 0x87, 0x6d, 0x82, 0xbc, 0xf8, 0x7d, 0xbe,
89 0xca, 0xd3, 0x2c, 0xd6, 0xec, 0x38, 0xeb, 0xe4,
90 0x53, 0xb0, 0x4c, 0x3f, 0x39, 0x29, 0xf7, 0xa4,
91 0x73, 0xa8, 0xcb, 0x32, 0x50, 0x05, 0x8c, 0x1c,
92 0x1c, 0xca, 0xc9, 0x76, 0x0b, 0x8f, 0x6b, 0x57,
93 0x1f, 0x24, 0x2b, 0xba, 0x82, 0xba, 0xed, 0x58,
94 0xd8, 0xbf, 0xec, 0x06, 0x64, 0x52, 0x6a, 0x3f,
95 0xe4, 0xad, 0xce, 0x84, 0xb4, 0x27, 0x55, 0x14,
96 0xe3, 0x75, 0x59, 0x73, 0x71, 0x51, 0xea, 0xe8,
97 0xcc, 0xda, 0x4f, 0x09, 0xaf, 0xa4, 0xbc, 0x0e,
98 0xa6, 0x1f, 0xe2, 0x3a, 0xf8, 0x96, 0x7d, 0x30,
99 0x23, 0xc5, 0x12, 0xb5, 0xd8, 0x73, 0x6b, 0x71,
100 0xab, 0xf1, 0xd7, 0x43, 0x58, 0xa7, 0xc9, 0xf0,
101 0xe4, 0x85, 0x1c, 0xd6, 0x92, 0x50, 0x2c, 0x98,
102 0x36, 0xfe, 0x87, 0xaf, 0x43, 0x8f, 0x8f, 0xf5,
103 0x88, 0x48, 0x18, 0x42, 0xcf, 0x42, 0xc1, 0xa8,
104 0xe8, 0x05, 0x08, 0xa1, 0x45, 0x70, 0x5b, 0x8c,
105 0x39, 0x28, 0xab, 0xe9, 0x6b, 0x51, 0xd2, 0xcb,
106 0x30, 0x04, 0xea, 0x7d, 0x2f, 0x6e, 0x6c, 0x3b,
107 0x5f, 0x82, 0xd9, 0x5b, 0x89, 0x37, 0x65, 0x65,
108 0xbe, 0x9f, 0xa3, 0x5d
109};
110
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800111const char* const kMountPath = "/tmp/UpdateEngineTests_mnt";
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000112} // namespace {}
113
Thieu Le5c7d9752010-12-15 16:09:28 -0800114// Creates an empty ext image.
115void CreateEmptyExtImageAtPath(const std::string& path,
116 size_t size,
117 int block_size);
118
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000119// Creates an ext image with some files in it. The paths creates are
120// returned in out_paths.
121void CreateExtImageAtPath(const std::string& path,
122 std::vector<std::string>* out_paths);
123
124// Verifies that for each path in paths, it exists in the filesystem under
125// parent. Also, verifies that no additional paths are present under parent.
126// Also tests properties of various files created by CreateExtImageAtPath().
127// Intentionally copies expected_paths.
128void VerifyAllPaths(const std::string& parent,
129 std::set<std::string> expected_paths);
130
Don Garrett58e8b1f2012-01-31 16:38:16 -0800131class ScopedLoopbackDeviceBinder {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700132 public:
Don Garrett58e8b1f2012-01-31 16:38:16 -0800133 ScopedLoopbackDeviceBinder(const std::string& file, std::string* dev) {
Gilad Arnold19a45f02012-07-19 12:36:10 -0700134 is_bound_ = BindToUnusedLoopDevice(file, &dev_);
135 EXPECT_TRUE(is_bound_);
Don Garrett58e8b1f2012-01-31 16:38:16 -0800136
Gilad Arnold19a45f02012-07-19 12:36:10 -0700137 if (is_bound_ && dev)
Don Garrett58e8b1f2012-01-31 16:38:16 -0800138 *dev = dev_;
139 }
140
141 ~ScopedLoopbackDeviceBinder() {
Gilad Arnold19a45f02012-07-19 12:36:10 -0700142 if (!is_bound_)
143 return;
144
Darin Petkovcf562482010-12-03 10:31:00 -0800145 for (int retry = 0; retry < 5; retry++) {
146 std::vector<std::string> args;
147 args.push_back("/sbin/losetup");
148 args.push_back("-d");
149 args.push_back(dev_);
150 int return_code = 0;
Darin Petkov85d02b72011-05-17 13:25:51 -0700151 EXPECT_TRUE(Subprocess::SynchronousExec(args, &return_code, NULL));
Darin Petkovcf562482010-12-03 10:31:00 -0800152 if (return_code == 0) {
153 return;
154 }
155 sleep(1);
156 }
157 ADD_FAILURE();
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700158 }
Don Garrett58e8b1f2012-01-31 16:38:16 -0800159
Gilad Arnold19a45f02012-07-19 12:36:10 -0700160 const std::string &dev() {
161 EXPECT_TRUE(is_bound_);
162 return dev_;
163 }
Don Garrett58e8b1f2012-01-31 16:38:16 -0800164
Gilad Arnoldc33faeb2012-07-24 15:11:11 -0700165 bool is_bound() const { return is_bound_; }
166
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700167 private:
Don Garrett58e8b1f2012-01-31 16:38:16 -0800168 std::string dev_;
Gilad Arnold19a45f02012-07-19 12:36:10 -0700169 bool is_bound_;
Don Garrett58e8b1f2012-01-31 16:38:16 -0800170 DISALLOW_COPY_AND_ASSIGN(ScopedLoopbackDeviceBinder);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700171};
172
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700173class ScopedTempFile {
174 public:
175 ScopedTempFile() {
176 EXPECT_TRUE(utils::MakeTempFile("/tmp/update_engine_test_temp_file.XXXXXX",
177 &path_,
178 NULL));
179 unlinker_.reset(new ScopedPathUnlinker(path_));
180 }
181 const std::string& GetPath() { return path_; }
182 private:
183 std::string path_;
184 scoped_ptr<ScopedPathUnlinker> unlinker_;
185};
186
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000187// Useful actions for test
188
189class NoneType;
190
191template<typename T>
192class ObjectFeederAction;
193
194template<typename T>
195class ActionTraits<ObjectFeederAction<T> > {
196 public:
197 typedef T OutputObjectType;
198 typedef NoneType InputObjectType;
199};
200
201// This is a simple Action class for testing. It feeds an object into
202// another action.
203template<typename T>
Yunlian Jianga178e5e2013-04-05 14:41:56 -0700204class ObjectFeederAction : public Action<ObjectFeederAction<T> > {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000205 public:
206 typedef NoneType InputObjectType;
207 typedef T OutputObjectType;
208 void PerformAction() {
209 LOG(INFO) << "feeder running!";
210 CHECK(this->processor_);
211 if (this->HasOutputPipe()) {
212 this->SetOutputObject(out_obj_);
213 }
David Zeuthena99981f2013-04-29 13:42:47 -0700214 this->processor_->ActionComplete(this, kErrorCodeSuccess);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000215 }
216 static std::string StaticType() { return "ObjectFeederAction"; }
217 std::string Type() const { return StaticType(); }
218 void set_obj(const T& out_obj) {
219 out_obj_ = out_obj;
220 }
221 private:
222 T out_obj_;
223};
224
225template<typename T>
226class ObjectCollectorAction;
227
228template<typename T>
229class ActionTraits<ObjectCollectorAction<T> > {
230 public:
231 typedef NoneType OutputObjectType;
232 typedef T InputObjectType;
233};
234
235// This is a simple Action class for testing. It receives an object from
236// another action.
237template<typename T>
Yunlian Jianga178e5e2013-04-05 14:41:56 -0700238class ObjectCollectorAction : public Action<ObjectCollectorAction<T> > {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000239 public:
240 typedef T InputObjectType;
241 typedef NoneType OutputObjectType;
242 void PerformAction() {
243 LOG(INFO) << "collector running!";
244 ASSERT_TRUE(this->processor_);
245 if (this->HasInputObject()) {
246 object_ = this->GetInputObject();
247 }
David Zeuthena99981f2013-04-29 13:42:47 -0700248 this->processor_->ActionComplete(this, kErrorCodeSuccess);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000249 }
250 static std::string StaticType() { return "ObjectCollectorAction"; }
251 std::string Type() const { return StaticType(); }
252 const T& object() const { return object_; }
253 private:
254 T object_;
255};
256
Thieu Le5c7d9752010-12-15 16:09:28 -0800257class ScopedLoopMounter {
258 public:
259 explicit ScopedLoopMounter(const std::string& file_path,
260 std::string* mnt_path,
261 unsigned long flags);
262
263 private:
264 // These objects must be destructed in the following order:
265 // ScopedFilesystemUnmounter (the file system must be unmounted first)
Don Garrett58e8b1f2012-01-31 16:38:16 -0800266 // ScopedLoopbackDeviceBinder (then the loop device can be deleted)
Thieu Le5c7d9752010-12-15 16:09:28 -0800267 // ScopedDirRemover (then the mount point can be deleted)
268 scoped_ptr<ScopedDirRemover> dir_remover_;
Don Garrett58e8b1f2012-01-31 16:38:16 -0800269 scoped_ptr<ScopedLoopbackDeviceBinder> loop_binder_;
Thieu Le5c7d9752010-12-15 16:09:28 -0800270 scoped_ptr<ScopedFilesystemUnmounter> unmounter_;
271};
272
rspangler@google.com49fdf182009-10-10 00:57:34 +0000273} // namespace chromeos_update_engine
274
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700275#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_TEST_UTILS_H__