blob: 66db9787f406d5a3ec11f7d4598b22a49c0389e8 [file] [log] [blame]
Mike Frysinger8155d082012-04-06 15:23:18 -04001// 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#include "update_engine/test_utils.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -07006
Alex Deymo10875d92014-11-10 21:52:57 -08007#include <attr/xattr.h>
adlr@google.comc98a7ed2009-12-04 18:54:03 +00008#include <errno.h>
rspangler@google.com49fdf182009-10-10 00:57:34 +00009#include <stdio.h>
10#include <stdlib.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070011#include <sys/stat.h>
12#include <sys/types.h>
rspangler@google.com49fdf182009-10-10 00:57:34 +000013#include <unistd.h>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070014
adlr@google.comc98a7ed2009-12-04 18:54:03 +000015#include <set>
rspangler@google.com49fdf182009-10-10 00:57:34 +000016#include <string>
17#include <vector>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070018
Alex Deymo2b19cfb2015-03-26 00:35:07 -070019#include <base/files/file_util.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070020#include <base/logging.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070021#include <base/strings/stringprintf.h>
Alex Deymo2b19cfb2015-03-26 00:35:07 -070022#include <base/strings/string_util.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070023
rspangler@google.com49fdf182009-10-10 00:57:34 +000024#include "update_engine/file_writer.h"
Alex Deymo161c4a12014-05-16 15:56:21 -070025#include "update_engine/payload_generator/filesystem_iterator.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000026#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000027
Alex Deymo161c4a12014-05-16 15:56:21 -070028using base::StringPrintf;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000029using std::set;
rspangler@google.com49fdf182009-10-10 00:57:34 +000030using std::string;
31using std::vector;
32
33namespace chromeos_update_engine {
34
Alex Deymo52490e72015-06-04 14:53:44 +020035void PrintTo(const Extent& extent, ::std::ostream* os) {
36 *os << "(" << extent.start_block() << ", " << extent.num_blocks() << ")";
37}
38
Alex Deymo10875d92014-11-10 21:52:57 -080039namespace test_utils {
40
Gilad Arnolda6742b32014-01-11 00:18:34 -080041const char* const kMountPathTemplate = "UpdateEngineTests_mnt-XXXXXX";
Gilad Arnold61d9d2c2013-07-22 17:54:52 -070042
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080043const uint8_t kRandomString[] = {
Alex Deymo10875d92014-11-10 21:52:57 -080044 0xf2, 0xb7, 0x55, 0x92, 0xea, 0xa6, 0xc9, 0x57,
45 0xe0, 0xf8, 0xeb, 0x34, 0x93, 0xd9, 0xc4, 0x8f,
46 0xcb, 0x20, 0xfa, 0x37, 0x4b, 0x40, 0xcf, 0xdc,
47 0xa5, 0x08, 0x70, 0x89, 0x79, 0x35, 0xe2, 0x3d,
48 0x56, 0xa4, 0x75, 0x73, 0xa3, 0x6d, 0xd1, 0xd5,
49 0x26, 0xbb, 0x9c, 0x60, 0xbd, 0x2f, 0x5a, 0xfa,
50 0xb7, 0xd4, 0x3a, 0x50, 0xa7, 0x6b, 0x3e, 0xfd,
51 0x61, 0x2b, 0x3a, 0x31, 0x30, 0x13, 0x33, 0x53,
52 0xdb, 0xd0, 0x32, 0x71, 0x5c, 0x39, 0xed, 0xda,
53 0xb4, 0x84, 0xca, 0xbc, 0xbd, 0x78, 0x1c, 0x0c,
54 0xd8, 0x0b, 0x41, 0xe8, 0xe1, 0xe0, 0x41, 0xad,
55 0x03, 0x12, 0xd3, 0x3d, 0xb8, 0x75, 0x9b, 0xe6,
56 0xd9, 0x01, 0xd0, 0x87, 0xf4, 0x36, 0xfa, 0xa7,
57 0x0a, 0xfa, 0xc5, 0x87, 0x65, 0xab, 0x9a, 0x7b,
58 0xeb, 0x58, 0x23, 0xf0, 0xa8, 0x0a, 0xf2, 0x33,
59 0x3a, 0xe2, 0xe3, 0x35, 0x74, 0x95, 0xdd, 0x3c,
60 0x59, 0x5a, 0xd9, 0x52, 0x3a, 0x3c, 0xac, 0xe5,
61 0x15, 0x87, 0x6d, 0x82, 0xbc, 0xf8, 0x7d, 0xbe,
62 0xca, 0xd3, 0x2c, 0xd6, 0xec, 0x38, 0xeb, 0xe4,
63 0x53, 0xb0, 0x4c, 0x3f, 0x39, 0x29, 0xf7, 0xa4,
64 0x73, 0xa8, 0xcb, 0x32, 0x50, 0x05, 0x8c, 0x1c,
65 0x1c, 0xca, 0xc9, 0x76, 0x0b, 0x8f, 0x6b, 0x57,
66 0x1f, 0x24, 0x2b, 0xba, 0x82, 0xba, 0xed, 0x58,
67 0xd8, 0xbf, 0xec, 0x06, 0x64, 0x52, 0x6a, 0x3f,
68 0xe4, 0xad, 0xce, 0x84, 0xb4, 0x27, 0x55, 0x14,
69 0xe3, 0x75, 0x59, 0x73, 0x71, 0x51, 0xea, 0xe8,
70 0xcc, 0xda, 0x4f, 0x09, 0xaf, 0xa4, 0xbc, 0x0e,
71 0xa6, 0x1f, 0xe2, 0x3a, 0xf8, 0x96, 0x7d, 0x30,
72 0x23, 0xc5, 0x12, 0xb5, 0xd8, 0x73, 0x6b, 0x71,
73 0xab, 0xf1, 0xd7, 0x43, 0x58, 0xa7, 0xc9, 0xf0,
74 0xe4, 0x85, 0x1c, 0xd6, 0x92, 0x50, 0x2c, 0x98,
75 0x36, 0xfe, 0x87, 0xaf, 0x43, 0x8f, 0x8f, 0xf5,
76 0x88, 0x48, 0x18, 0x42, 0xcf, 0x42, 0xc1, 0xa8,
77 0xe8, 0x05, 0x08, 0xa1, 0x45, 0x70, 0x5b, 0x8c,
78 0x39, 0x28, 0xab, 0xe9, 0x6b, 0x51, 0xd2, 0xcb,
79 0x30, 0x04, 0xea, 0x7d, 0x2f, 0x6e, 0x6c, 0x3b,
80 0x5f, 0x82, 0xd9, 0x5b, 0x89, 0x37, 0x65, 0x65,
81 0xbe, 0x9f, 0xa3, 0x5d,
82};
83
84bool IsXAttrSupported(const base::FilePath& dir_path) {
85 char *path = strdup(dir_path.Append("xattr_test_XXXXXX").value().c_str());
86
87 int fd = mkstemp(path);
88 if (fd == -1) {
89 PLOG(ERROR) << "Error creating temporary file in " << dir_path.value();
90 free(path);
91 return false;
92 }
93
94 if (unlink(path) != 0) {
95 PLOG(ERROR) << "Error unlinking temporary file " << path;
96 close(fd);
97 free(path);
98 return false;
99 }
100
101 int xattr_res = fsetxattr(fd, "user.xattr-test", "value", strlen("value"), 0);
102 if (xattr_res != 0) {
103 if (errno == ENOTSUP) {
104 // Leave it to call-sites to warn about non-support.
105 } else {
106 PLOG(ERROR) << "Error setting xattr on " << path;
107 }
108 }
109 close(fd);
110 free(path);
111 return xattr_res == 0;
112}
113
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800114bool WriteFileVector(const string& path, const chromeos::Blob& data) {
115 return utils::WriteFile(path.c_str(), data.data(), data.size());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000116}
117
Alex Deymof329b932014-10-30 01:37:48 -0700118bool WriteFileString(const string& path, const string& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -0800119 return utils::WriteFile(path.c_str(), data.data(), data.size());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000120}
121
Gilad Arnold19a45f02012-07-19 12:36:10 -0700122// Binds provided |filename| to an unused loopback device, whose name is written
123// to the string pointed to by |lo_dev_name_p|. Returns true on success, false
124// otherwise (along with corresponding test failures), in which case the content
125// of |lo_dev_name_p| is unknown.
126bool BindToUnusedLoopDevice(const string& filename, string* lo_dev_name_p) {
127 CHECK(lo_dev_name_p);
Don Garrett58e8b1f2012-01-31 16:38:16 -0800128
Gilad Arnold19a45f02012-07-19 12:36:10 -0700129 // Bind to an unused loopback device, sanity check the device name.
130 lo_dev_name_p->clear();
131 if (!(utils::ReadPipe("losetup --show -f " + filename, lo_dev_name_p) &&
132 StartsWithASCII(*lo_dev_name_p, "/dev/loop", true))) {
133 ADD_FAILURE();
134 return false;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000135 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000136
Gilad Arnold19a45f02012-07-19 12:36:10 -0700137 // Strip anything from the first newline char.
138 size_t newline_pos = lo_dev_name_p->find('\n');
139 if (newline_pos != string::npos)
140 lo_dev_name_p->erase(newline_pos);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000141
Gilad Arnold19a45f02012-07-19 12:36:10 -0700142 return true;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000143}
144
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800145bool ExpectVectorsEq(const chromeos::Blob& expected,
146 const chromeos::Blob& actual) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800147 EXPECT_EQ(expected.size(), actual.size());
148 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000149 return false;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700150 bool is_all_eq = true;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800151 for (unsigned int i = 0; i < expected.size(); i++) {
152 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700153 is_all_eq = is_all_eq && (expected[i] == actual[i]);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000154 }
Gilad Arnold617bbc22012-05-15 08:48:13 -0700155 return is_all_eq;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000156}
157
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800158void FillWithData(chromeos::Blob* buffer) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800159 size_t input_counter = 0;
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800160 for (uint8_t& b : *buffer) {
161 b = kRandomString[input_counter];
Andrew de los Reyes80061062010-02-04 14:25:00 -0800162 input_counter++;
163 input_counter %= sizeof(kRandomString);
164 }
165}
166
Thieu Le5c7d9752010-12-15 16:09:28 -0800167void CreateEmptyExtImageAtPath(const string& path,
168 size_t size,
169 int block_size) {
170 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
Alex Deymo1f93d032015-03-10 18:58:32 -0700171 " seek=%zu bs=1 count=1 status=none",
Thieu Le5c7d9752010-12-15 16:09:28 -0800172 path.c_str(), size)));
Alex Deymo6ded6542015-03-13 15:52:46 -0700173 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b %d -F %s",
Thieu Le5c7d9752010-12-15 16:09:28 -0800174 block_size, path.c_str())));
175}
176
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000177void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700178 // create 10MiB sparse file, mounted at a unique location.
179 string mount_path;
180 CHECK(utils::MakeTempDirectory(kMountPathTemplate, &mount_path));
Alex Deymoa58b62a2013-08-08 21:21:48 -0700181 ScopedDirRemover mount_path_unlinker(mount_path);
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700182
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000183 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
Alex Deymo1f93d032015-03-10 18:58:32 -0700184 " seek=10485759 bs=1 count=1 status=none",
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000185 path.c_str())));
Alex Deymo6ded6542015-03-13 15:52:46 -0700186 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b 4096 -F %s",
187 path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000188 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700189 mount_path.c_str())));
190 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", mount_path.c_str())));
191 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello",
192 mount_path.c_str())));
193 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", mount_path.c_str())));
194 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir",
195 mount_path.c_str())));
196 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt",
197 mount_path.c_str())));
198 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test",
199 mount_path.c_str())));
200 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo",
201 mount_path.c_str())));
202 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", mount_path.c_str())));
203 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym",
204 mount_path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000205 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700206 mount_path.c_str(), mount_path.c_str())));
207 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0",
208 mount_path.c_str())));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800209 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700210 mount_path.c_str(), mount_path.c_str())));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800211 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700212 mount_path.c_str())));
213 EXPECT_TRUE(utils::UnmountFilesystem(mount_path.c_str()));
Thieu Le5c7d9752010-12-15 16:09:28 -0800214
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000215 if (out_paths) {
216 out_paths->clear();
217 out_paths->push_back("");
218 out_paths->push_back("/hi");
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800219 out_paths->push_back("/boguslink");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000220 out_paths->push_back("/hello");
221 out_paths->push_back("/some_dir");
222 out_paths->push_back("/some_dir/empty_dir");
223 out_paths->push_back("/some_dir/mnt");
224 out_paths->push_back("/some_dir/test");
225 out_paths->push_back("/some_dir/fifo");
226 out_paths->push_back("/cdev");
227 out_paths->push_back("/testlink");
228 out_paths->push_back("/sym");
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800229 out_paths->push_back("/srchardlink0");
230 out_paths->push_back("/srchardlink1");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000231 out_paths->push_back("/lost+found");
232 }
233}
234
235void VerifyAllPaths(const string& parent, set<string> expected_paths) {
236 FilesystemIterator iter(parent, set<string>());
237 ino_t test_ino = 0;
238 ino_t testlink_ino = 0;
239 while (!iter.IsEnd()) {
240 string path = iter.GetFullPath();
241 EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()) << path;
242 EXPECT_EQ(1, expected_paths.erase(path));
Alex Deymo10875d92014-11-10 21:52:57 -0800243 if (EndsWith(path, "/hi", true) ||
244 EndsWith(path, "/hello", true) ||
245 EndsWith(path, "/test", true) ||
246 EndsWith(path, "/testlink", true)) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000247 EXPECT_TRUE(S_ISREG(iter.GetStat().st_mode));
Alex Deymo10875d92014-11-10 21:52:57 -0800248 if (EndsWith(path, "/test", true))
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000249 test_ino = iter.GetStat().st_ino;
Alex Deymo10875d92014-11-10 21:52:57 -0800250 else if (EndsWith(path, "/testlink", true))
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000251 testlink_ino = iter.GetStat().st_ino;
Alex Deymo10875d92014-11-10 21:52:57 -0800252 } else if (EndsWith(path, "/some_dir", true) ||
253 EndsWith(path, "/empty_dir", true) ||
254 EndsWith(path, "/mnt", true) ||
255 EndsWith(path, "/lost+found", true) ||
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000256 parent == path) {
257 EXPECT_TRUE(S_ISDIR(iter.GetStat().st_mode));
Alex Deymo10875d92014-11-10 21:52:57 -0800258 } else if (EndsWith(path, "/fifo", true)) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000259 EXPECT_TRUE(S_ISFIFO(iter.GetStat().st_mode));
Alex Deymo10875d92014-11-10 21:52:57 -0800260 } else if (EndsWith(path, "/cdev", true)) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000261 EXPECT_TRUE(S_ISCHR(iter.GetStat().st_mode));
Alex Deymo10875d92014-11-10 21:52:57 -0800262 } else if (EndsWith(path, "/sym", true)) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000263 EXPECT_TRUE(S_ISLNK(iter.GetStat().st_mode));
264 } else {
265 LOG(INFO) << "got non hardcoded path: " << path;
266 }
267 iter.Increment();
268 }
269 EXPECT_EQ(testlink_ino, test_ino);
270 EXPECT_NE(0, test_ino);
271 EXPECT_FALSE(iter.IsErr());
272 EXPECT_TRUE(expected_paths.empty());
273 if (!expected_paths.empty()) {
Alex Deymo020600d2014-11-05 21:05:55 -0800274 for (const string& path : expected_paths) {
275 LOG(INFO) << "extra path: " << path;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000276 }
277 }
278}
279
Don Garrett58e8b1f2012-01-31 16:38:16 -0800280ScopedLoopMounter::ScopedLoopMounter(const string& file_path,
281 string* mnt_path,
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700282 unsigned long flags) { // NOLINT - long
Gilad Arnolda6742b32014-01-11 00:18:34 -0800283 EXPECT_TRUE(utils::MakeTempDirectory("mnt.XXXXXX", mnt_path));
Thieu Le5c7d9752010-12-15 16:09:28 -0800284 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
285
Don Garrett58e8b1f2012-01-31 16:38:16 -0800286 string loop_dev;
287 loop_binder_.reset(new ScopedLoopbackDeviceBinder(file_path, &loop_dev));
Thieu Le5c7d9752010-12-15 16:09:28 -0800288
289 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
290 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
291}
292
Alex Deymo10875d92014-11-10 21:52:57 -0800293namespace {
294class ScopedDirCloser {
295 public:
296 explicit ScopedDirCloser(DIR** dir) : dir_(dir) {}
297 ~ScopedDirCloser() {
298 if (dir_ && *dir_) {
299 int r = closedir(*dir_);
300 TEST_AND_RETURN_ERRNO(r == 0);
301 *dir_ = nullptr;
302 dir_ = nullptr;
303 }
304 }
305 private:
306 DIR** dir_;
307};
308} // namespace
309
310bool RecursiveUnlinkDir(const string& path) {
311 struct stat stbuf;
312 int r = lstat(path.c_str(), &stbuf);
313 TEST_AND_RETURN_FALSE_ERRNO((r == 0) || (errno == ENOENT));
314 if ((r < 0) && (errno == ENOENT))
315 // path request is missing. that's fine.
316 return true;
317 if (!S_ISDIR(stbuf.st_mode)) {
318 TEST_AND_RETURN_FALSE_ERRNO((unlink(path.c_str()) == 0) ||
319 (errno == ENOENT));
320 // success or path disappeared before we could unlink.
321 return true;
322 }
323 {
324 // We have a dir, unlink all children, then delete dir
325 DIR *dir = opendir(path.c_str());
326 TEST_AND_RETURN_FALSE_ERRNO(dir);
327 ScopedDirCloser dir_closer(&dir);
328 struct dirent dir_entry;
329 struct dirent *dir_entry_p;
330 int err = 0;
331 while ((err = readdir_r(dir, &dir_entry, &dir_entry_p)) == 0) {
332 if (dir_entry_p == nullptr) {
333 // end of stream reached
334 break;
335 }
336 // Skip . and ..
337 if (!strcmp(dir_entry_p->d_name, ".") ||
338 !strcmp(dir_entry_p->d_name, ".."))
339 continue;
340 TEST_AND_RETURN_FALSE(RecursiveUnlinkDir(path + "/" +
341 dir_entry_p->d_name));
342 }
343 TEST_AND_RETURN_FALSE(err == 0);
344 }
345 // unlink dir
346 TEST_AND_RETURN_FALSE_ERRNO((rmdir(path.c_str()) == 0) || (errno == ENOENT));
347 return true;
348}
349
Alex Deymo53556ec2014-03-17 10:05:57 -0700350static gboolean RunGMainLoopOnTimeout(gpointer user_data) {
351 bool* timeout = static_cast<bool*>(user_data);
352 *timeout = true;
353 return FALSE; // Remove timeout source
354}
355
356void RunGMainLoopUntil(int timeout_msec, base::Callback<bool()> terminate) {
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700357 GMainLoop* loop = g_main_loop_new(nullptr, FALSE);
Alex Deymo53556ec2014-03-17 10:05:57 -0700358 GMainContext* context = g_main_context_default();
359
360 bool timeout = false;
361 guint source_id = g_timeout_add(
362 timeout_msec, RunGMainLoopOnTimeout, &timeout);
363
364 while (!timeout && (terminate.is_null() || !terminate.Run()))
365 g_main_context_iteration(context, TRUE);
366
367 g_source_remove(source_id);
368 g_main_loop_unref(loop);
369}
370
Alex Deymo7b948f02014-03-10 17:01:10 -0700371int RunGMainLoopMaxIterations(int iterations) {
372 int result;
373 GMainContext* context = g_main_context_default();
374 for (result = 0;
375 result < iterations && g_main_context_iteration(context, FALSE);
376 result++) {}
377 return result;
378}
379
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700380GValue* GValueNewString(const char* str) {
Alex Deymo5665d0c2014-05-28 17:45:43 -0700381 GValue* gval = g_new0(GValue, 1);
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700382 g_value_init(gval, G_TYPE_STRING);
383 g_value_set_string(gval, str);
384 return gval;
385}
386
387void GValueFree(gpointer arg) {
388 auto gval = reinterpret_cast<GValue*>(arg);
389 g_value_unset(gval);
Alex Deymo5665d0c2014-05-28 17:45:43 -0700390 g_free(gval);
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700391}
392
Alex Deymo2b19cfb2015-03-26 00:35:07 -0700393base::FilePath GetBuildArtifactsPath() {
394 base::FilePath exe_path;
395 base::ReadSymbolicLink(base::FilePath("/proc/self/exe"), &exe_path);
396 return exe_path.DirName();
397}
398
Alex Deymo10875d92014-11-10 21:52:57 -0800399} // namespace test_utils
rspangler@google.com49fdf182009-10-10 00:57:34 +0000400} // namespace chromeos_update_engine