1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "update_engine/common/utils.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdint.h>
22 #include <sys/mount.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25
26 #include <map>
27 #include <string>
28 #include <vector>
29
30 #include <base/files/file_path.h>
31 #include <base/files/file_util.h>
32 #include <base/files/scoped_temp_dir.h>
33 #include <base/strings/string_util.h>
34 #include <base/strings/stringprintf.h>
35 #include <brillo/message_loops/fake_message_loop.h>
36 #include <brillo/message_loops/message_loop_utils.h>
37 #include <gtest/gtest.h>
38
39 #include "update_engine/common/test_utils.h"
40
41 using brillo::FakeMessageLoop;
42 using std::map;
43 using std::string;
44 using std::vector;
45
46 namespace chromeos_update_engine {
47
48 class UtilsTest : public ::testing::Test { };
49
TEST(UtilsTest,CanParseECVersion)50 TEST(UtilsTest, CanParseECVersion) {
51 // Should be able to parse and valid key value line.
52 EXPECT_EQ("12345", utils::ParseECVersion("fw_version=12345"));
53 EXPECT_EQ("123456", utils::ParseECVersion(
54 "b=1231a fw_version=123456 a=fasd2"));
55 EXPECT_EQ("12345", utils::ParseECVersion("fw_version=12345"));
56 EXPECT_EQ("00VFA616", utils::ParseECVersion(
57 "vendor=\"sam\" fw_version=\"00VFA616\""));
58
59 // For invalid entries, should return the empty string.
60 EXPECT_EQ("", utils::ParseECVersion("b=1231a fw_version a=fasd2"));
61 }
62
TEST(UtilsTest,ReadFileFailure)63 TEST(UtilsTest, ReadFileFailure) {
64 brillo::Blob empty;
65 EXPECT_FALSE(utils::ReadFile("/this/doesn't/exist", &empty));
66 }
67
TEST(UtilsTest,ReadFileChunk)68 TEST(UtilsTest, ReadFileChunk) {
69 base::FilePath file;
70 EXPECT_TRUE(base::CreateTemporaryFile(&file));
71 ScopedPathUnlinker unlinker(file.value());
72 brillo::Blob data;
73 const size_t kSize = 1024 * 1024;
74 for (size_t i = 0; i < kSize; i++) {
75 data.push_back(i % 255);
76 }
77 EXPECT_TRUE(utils::WriteFile(file.value().c_str(), data.data(), data.size()));
78 brillo::Blob in_data;
79 EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), kSize, 10, &in_data));
80 EXPECT_TRUE(in_data.empty());
81 EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), 0, -1, &in_data));
82 EXPECT_TRUE(data == in_data);
83 in_data.clear();
84 EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), 10, 20, &in_data));
85 EXPECT_TRUE(brillo::Blob(data.begin() + 10, data.begin() + 10 + 20) ==
86 in_data);
87 }
88
TEST(UtilsTest,ErrnoNumberAsStringTest)89 TEST(UtilsTest, ErrnoNumberAsStringTest) {
90 EXPECT_EQ("No such file or directory", utils::ErrnoNumberAsString(ENOENT));
91 }
92
TEST(UtilsTest,IsSymlinkTest)93 TEST(UtilsTest, IsSymlinkTest) {
94 string temp_dir;
95 EXPECT_TRUE(utils::MakeTempDirectory("symlink-test.XXXXXX", &temp_dir));
96 string temp_file = temp_dir + "/temp-file";
97 EXPECT_TRUE(utils::WriteFile(temp_file.c_str(), "", 0));
98 string temp_symlink = temp_dir + "/temp-symlink";
99 EXPECT_EQ(0, symlink(temp_file.c_str(), temp_symlink.c_str()));
100 EXPECT_FALSE(utils::IsSymlink(temp_dir.c_str()));
101 EXPECT_FALSE(utils::IsSymlink(temp_file.c_str()));
102 EXPECT_TRUE(utils::IsSymlink(temp_symlink.c_str()));
103 EXPECT_FALSE(utils::IsSymlink("/non/existent/path"));
104 EXPECT_TRUE(base::DeleteFile(base::FilePath(temp_dir), true));
105 }
106
TEST(UtilsTest,SplitPartitionNameTest)107 TEST(UtilsTest, SplitPartitionNameTest) {
108 string disk;
109 int part_num;
110
111 EXPECT_TRUE(utils::SplitPartitionName("/dev/sda3", &disk, &part_num));
112 EXPECT_EQ("/dev/sda", disk);
113 EXPECT_EQ(3, part_num);
114
115 EXPECT_TRUE(utils::SplitPartitionName("/dev/sdp1234", &disk, &part_num));
116 EXPECT_EQ("/dev/sdp", disk);
117 EXPECT_EQ(1234, part_num);
118
119 EXPECT_TRUE(utils::SplitPartitionName("/dev/mmcblk0p3", &disk, &part_num));
120 EXPECT_EQ("/dev/mmcblk0", disk);
121 EXPECT_EQ(3, part_num);
122
123 EXPECT_TRUE(utils::SplitPartitionName("/dev/ubiblock3_2", &disk, &part_num));
124 EXPECT_EQ("/dev/ubiblock", disk);
125 EXPECT_EQ(3, part_num);
126
127 EXPECT_TRUE(utils::SplitPartitionName("/dev/loop10", &disk, &part_num));
128 EXPECT_EQ("/dev/loop", disk);
129 EXPECT_EQ(10, part_num);
130
131 EXPECT_TRUE(utils::SplitPartitionName("/dev/loop28p11", &disk, &part_num));
132 EXPECT_EQ("/dev/loop28", disk);
133 EXPECT_EQ(11, part_num);
134
135 EXPECT_TRUE(utils::SplitPartitionName("/dev/loop10_0", &disk, &part_num));
136 EXPECT_EQ("/dev/loop", disk);
137 EXPECT_EQ(10, part_num);
138
139 EXPECT_TRUE(utils::SplitPartitionName("/dev/loop28p11_0", &disk, &part_num));
140 EXPECT_EQ("/dev/loop28", disk);
141 EXPECT_EQ(11, part_num);
142
143 EXPECT_FALSE(utils::SplitPartitionName("/dev/mmcblk0p", &disk, &part_num));
144 EXPECT_FALSE(utils::SplitPartitionName("/dev/sda", &disk, &part_num));
145 EXPECT_FALSE(utils::SplitPartitionName("/dev/foo/bar", &disk, &part_num));
146 EXPECT_FALSE(utils::SplitPartitionName("/", &disk, &part_num));
147 EXPECT_FALSE(utils::SplitPartitionName("", &disk, &part_num));
148 }
149
TEST(UtilsTest,MakePartitionNameTest)150 TEST(UtilsTest, MakePartitionNameTest) {
151 EXPECT_EQ("/dev/sda4", utils::MakePartitionName("/dev/sda", 4));
152 EXPECT_EQ("/dev/sda123", utils::MakePartitionName("/dev/sda", 123));
153 EXPECT_EQ("/dev/mmcblk2", utils::MakePartitionName("/dev/mmcblk", 2));
154 EXPECT_EQ("/dev/mmcblk0p2", utils::MakePartitionName("/dev/mmcblk0", 2));
155 EXPECT_EQ("/dev/loop8", utils::MakePartitionName("/dev/loop", 8));
156 EXPECT_EQ("/dev/loop12p2", utils::MakePartitionName("/dev/loop12", 2));
157 EXPECT_EQ("/dev/ubi5_0", utils::MakePartitionName("/dev/ubiblock", 5));
158 EXPECT_EQ("/dev/mtd4", utils::MakePartitionName("/dev/ubiblock", 4));
159 EXPECT_EQ("/dev/ubi3_0", utils::MakePartitionName("/dev/ubiblock", 3));
160 EXPECT_EQ("/dev/mtd2", utils::MakePartitionName("/dev/ubiblock", 2));
161 EXPECT_EQ("/dev/ubi1_0", utils::MakePartitionName("/dev/ubiblock", 1));
162 }
163
TEST(UtilsTest,MakePartitionNameForMountTest)164 TEST(UtilsTest, MakePartitionNameForMountTest) {
165 EXPECT_EQ("/dev/sda4", utils::MakePartitionNameForMount("/dev/sda4"));
166 EXPECT_EQ("/dev/sda123", utils::MakePartitionNameForMount("/dev/sda123"));
167 EXPECT_EQ("/dev/mmcblk2", utils::MakePartitionNameForMount("/dev/mmcblk2"));
168 EXPECT_EQ("/dev/mmcblk0p2",
169 utils::MakePartitionNameForMount("/dev/mmcblk0p2"));
170 EXPECT_EQ("/dev/loop0", utils::MakePartitionNameForMount("/dev/loop0"));
171 EXPECT_EQ("/dev/loop8", utils::MakePartitionNameForMount("/dev/loop8"));
172 EXPECT_EQ("/dev/loop12p2",
173 utils::MakePartitionNameForMount("/dev/loop12p2"));
174 EXPECT_EQ("/dev/ubiblock5_0",
175 utils::MakePartitionNameForMount("/dev/ubiblock5_0"));
176 EXPECT_EQ("/dev/mtd4",
177 utils::MakePartitionNameForMount("/dev/ubi4_0"));
178 EXPECT_EQ("/dev/ubiblock3_0",
179 utils::MakePartitionNameForMount("/dev/ubiblock3"));
180 EXPECT_EQ("/dev/mtd2", utils::MakePartitionNameForMount("/dev/ubi2"));
181 EXPECT_EQ("/dev/ubi1_0",
182 utils::MakePartitionNameForMount("/dev/ubiblock1"));
183 }
184
TEST(UtilsTest,FuzzIntTest)185 TEST(UtilsTest, FuzzIntTest) {
186 static const uint32_t kRanges[] = { 0, 1, 2, 20 };
187 for (uint32_t range : kRanges) {
188 const int kValue = 50;
189 for (int tries = 0; tries < 100; ++tries) {
190 uint32_t value = utils::FuzzInt(kValue, range);
191 EXPECT_GE(value, kValue - range / 2);
192 EXPECT_LE(value, kValue + range - range / 2);
193 }
194 }
195 }
196
TEST(UtilsTest,RunAsRootGetFilesystemSizeTest)197 TEST(UtilsTest, RunAsRootGetFilesystemSizeTest) {
198 string img;
199 EXPECT_TRUE(utils::MakeTempFile("img.XXXXXX", &img, nullptr));
200 ScopedPathUnlinker img_unlinker(img);
201 test_utils::CreateExtImageAtPath(img, nullptr);
202 // Extend the "partition" holding the file system from 10MiB to 20MiB.
203 EXPECT_EQ(0, test_utils::System(base::StringPrintf(
204 "dd if=/dev/zero of=%s seek=20971519 bs=1 count=1 status=none",
205 img.c_str())));
206 EXPECT_EQ(20 * 1024 * 1024, utils::FileSize(img));
207 int block_count = 0;
208 int block_size = 0;
209 EXPECT_TRUE(utils::GetFilesystemSize(img, &block_count, &block_size));
210 EXPECT_EQ(4096, block_size);
211 EXPECT_EQ(10 * 1024 * 1024 / 4096, block_count);
212 }
213
214 // Squashfs example filesystem, generated with:
215 // echo hola>hola
216 // mksquashfs hola hola.sqfs -noappend -nopad
217 // hexdump hola.sqfs -e '16/1 "%02x, " "\n"'
218 const uint8_t kSquashfsFile[] = {
219 0x68, 0x73, 0x71, 0x73, 0x02, 0x00, 0x00, 0x00, // magic, inodes
220 0x3e, 0x49, 0x61, 0x54, 0x00, 0x00, 0x02, 0x00,
221 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00,
222 0xc0, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, // flags, noids, major, minor
223 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // root_inode
224 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bytes_used
225 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
227 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x68, 0x6f, 0x6c, 0x61, 0x0a, 0x2c, 0x00, 0x78,
232 0xda, 0x63, 0x62, 0x58, 0xc2, 0xc8, 0xc0, 0xc0,
233 0xc8, 0xd0, 0x6b, 0x91, 0x18, 0x02, 0x64, 0xa0,
234 0x00, 0x56, 0x06, 0x90, 0xcc, 0x7f, 0xb0, 0xbc,
235 0x9d, 0x67, 0x62, 0x08, 0x13, 0x54, 0x1c, 0x44,
236 0x4b, 0x03, 0x31, 0x33, 0x10, 0x03, 0x00, 0xb5,
237 0x87, 0x04, 0x89, 0x16, 0x00, 0x78, 0xda, 0x63,
238 0x60, 0x80, 0x00, 0x46, 0x28, 0xcd, 0xc4, 0xc0,
239 0xcc, 0x90, 0x91, 0x9f, 0x93, 0x08, 0x00, 0x04,
240 0x70, 0x01, 0xab, 0x10, 0x80, 0x60, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
242 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00,
243 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x78,
244 0xda, 0x63, 0x60, 0x80, 0x00, 0x05, 0x28, 0x0d,
245 0x00, 0x01, 0x10, 0x00, 0x21, 0xc5, 0x00, 0x00,
246 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x99,
247 0xcd, 0x02, 0x00, 0x88, 0x13, 0x00, 0x00, 0xdd,
248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
249 };
250
TEST(UtilsTest,GetSquashfs4Size)251 TEST(UtilsTest, GetSquashfs4Size) {
252 uint8_t buffer[sizeof(kSquashfsFile)];
253 memcpy(buffer, kSquashfsFile, sizeof(kSquashfsFile));
254
255 int block_count = -1;
256 int block_size = -1;
257 // Not enough bytes passed.
258 EXPECT_FALSE(utils::GetSquashfs4Size(buffer, 10, nullptr, nullptr));
259
260 // The whole file system is passed, which is enough for parsing.
261 EXPECT_TRUE(utils::GetSquashfs4Size(buffer, sizeof(kSquashfsFile),
262 &block_count, &block_size));
263 EXPECT_EQ(4096, block_size);
264 EXPECT_EQ(1, block_count);
265
266 // Modify the major version to 5.
267 uint16_t* s_major = reinterpret_cast<uint16_t*>(buffer + 0x1c);
268 *s_major = 5;
269 EXPECT_FALSE(utils::GetSquashfs4Size(buffer, 10, nullptr, nullptr));
270 memcpy(buffer, kSquashfsFile, sizeof(kSquashfsFile));
271
272 // Modify the bytes_used to have 6 blocks.
273 int64_t* bytes_used = reinterpret_cast<int64_t*>(buffer + 0x28);
274 *bytes_used = 4096 * 5 + 1; // 6 "blocks".
275 EXPECT_TRUE(utils::GetSquashfs4Size(buffer, sizeof(kSquashfsFile),
276 &block_count, &block_size));
277 EXPECT_EQ(4096, block_size);
278 EXPECT_EQ(6, block_count);
279 }
280
281 namespace {
GetFileFormatTester(const string & expected,const vector<uint8_t> & contents)282 void GetFileFormatTester(const string& expected,
283 const vector<uint8_t>& contents) {
284 test_utils::ScopedTempFile file;
285 ASSERT_TRUE(utils::WriteFile(file.path().c_str(),
286 reinterpret_cast<const char*>(contents.data()),
287 contents.size()));
288 EXPECT_EQ(expected, utils::GetFileFormat(file.path()));
289 }
290 } // namespace
291
TEST(UtilsTest,GetFileFormatTest)292 TEST(UtilsTest, GetFileFormatTest) {
293 EXPECT_EQ("File not found.", utils::GetFileFormat("/path/to/nowhere"));
294 GetFileFormatTester("data", vector<uint8_t>{1, 2, 3, 4, 5, 6, 7, 8});
295 GetFileFormatTester("ELF", vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46});
296
297 // Real tests from cros_installer on different boards.
298 // ELF 32-bit LSB executable, Intel 80386
299 GetFileFormatTester(
300 "ELF 32-bit little-endian x86",
301 vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
304 0x90, 0x83, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00});
305
306 // ELF 32-bit LSB executable, MIPS
307 GetFileFormatTester(
308 "ELF 32-bit little-endian mips",
309 vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
312 0xc0, 0x12, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00});
313
314 // ELF 32-bit LSB executable, ARM
315 GetFileFormatTester(
316 "ELF 32-bit little-endian arm",
317 vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00,
318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x02, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00,
320 0x85, 0x8b, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00});
321
322 // ELF 64-bit LSB executable, x86-64
323 GetFileFormatTester(
324 "ELF 64-bit little-endian x86-64",
325 vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
328 0xb0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00});
329 }
330
TEST(UtilsTest,ScheduleCrashReporterUploadTest)331 TEST(UtilsTest, ScheduleCrashReporterUploadTest) {
332 // Not much to test. At least this tests for memory leaks, crashes,
333 // log errors.
334 FakeMessageLoop loop(nullptr);
335 loop.SetAsCurrent();
336 utils::ScheduleCrashReporterUpload();
337 // Test that we scheduled one callback from the crash reporter.
338 EXPECT_EQ(1, brillo::MessageLoopRunMaxIterations(&loop, 100));
339 EXPECT_FALSE(loop.PendingTasks());
340 }
341
TEST(UtilsTest,FormatTimeDeltaTest)342 TEST(UtilsTest, FormatTimeDeltaTest) {
343 // utils::FormatTimeDelta() is not locale-aware (it's only used for logging
344 // which is not localized) so we only need to test the C locale
345 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromMilliseconds(100)),
346 "0.1s");
347 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(0)),
348 "0s");
349 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(1)),
350 "1s");
351 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(59)),
352 "59s");
353 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(60)),
354 "1m0s");
355 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(61)),
356 "1m1s");
357 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(90)),
358 "1m30s");
359 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(1205)),
360 "20m5s");
361 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(3600)),
362 "1h0m0s");
363 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(3601)),
364 "1h0m1s");
365 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(3661)),
366 "1h1m1s");
367 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(7261)),
368 "2h1m1s");
369 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(86400)),
370 "1d0h0m0s");
371 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(86401)),
372 "1d0h0m1s");
373 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(200000)),
374 "2d7h33m20s");
375 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(200000) +
376 base::TimeDelta::FromMilliseconds(1)),
377 "2d7h33m20.001s");
378 EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(-1)),
379 "-1s");
380 }
381
TEST(UtilsTest,TimeFromStructTimespecTest)382 TEST(UtilsTest, TimeFromStructTimespecTest) {
383 struct timespec ts;
384
385 // Unix epoch (Thursday 00:00:00 UTC on Jan 1, 1970)
386 ts = (struct timespec) {.tv_sec = 0, .tv_nsec = 0};
387 EXPECT_EQ(base::Time::UnixEpoch(), utils::TimeFromStructTimespec(&ts));
388
389 // 42 ms after the Unix billennium (Sunday 01:46:40 UTC on September 9, 2001)
390 ts = (struct timespec) {.tv_sec = 1000 * 1000 * 1000,
391 .tv_nsec = 42 * 1000 * 1000};
392 base::Time::Exploded exploded = (base::Time::Exploded) {
393 .year = 2001, .month = 9, .day_of_week = 0, .day_of_month = 9,
394 .hour = 1, .minute = 46, .second = 40, .millisecond = 42};
395 EXPECT_EQ(base::Time::FromUTCExploded(exploded),
396 utils::TimeFromStructTimespec(&ts));
397 }
398
TEST(UtilsTest,DecodeAndStoreBase64String)399 TEST(UtilsTest, DecodeAndStoreBase64String) {
400 base::FilePath path;
401
402 // Ensure we return false on empty strings or invalid base64.
403 EXPECT_FALSE(utils::DecodeAndStoreBase64String("", &path));
404 EXPECT_FALSE(utils::DecodeAndStoreBase64String("not valid base64", &path));
405
406 // Pass known base64 and check that it matches. This string was generated
407 // the following way:
408 //
409 // $ echo "Update Engine" | base64
410 // VXBkYXRlIEVuZ2luZQo=
411 EXPECT_TRUE(utils::DecodeAndStoreBase64String("VXBkYXRlIEVuZ2luZQo=",
412 &path));
413 ScopedPathUnlinker unlinker(path.value());
414 string expected_contents = "Update Engine\n";
415 string contents;
416 EXPECT_TRUE(utils::ReadFile(path.value(), &contents));
417 EXPECT_EQ(contents, expected_contents);
418 EXPECT_EQ(static_cast<off_t>(expected_contents.size()),
419 utils::FileSize(path.value()));
420 }
421
TEST(UtilsTest,ConvertToOmahaInstallDate)422 TEST(UtilsTest, ConvertToOmahaInstallDate) {
423 // The Omaha Epoch starts at Jan 1, 2007 0:00 PST which is a
424 // Monday. In Unix time, this point in time is easily obtained via
425 // the date(1) command like this:
426 //
427 // $ date +"%s" --date="Jan 1, 2007 0:00 PST"
428 const time_t omaha_epoch = 1167638400;
429 int value;
430
431 // Points in time *on and after* the Omaha epoch should not fail.
432 EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
433 base::Time::FromTimeT(omaha_epoch), &value));
434 EXPECT_GE(value, 0);
435
436 // Anything before the Omaha epoch should fail. We test it for two points.
437 EXPECT_FALSE(utils::ConvertToOmahaInstallDate(
438 base::Time::FromTimeT(omaha_epoch - 1), &value));
439 EXPECT_FALSE(utils::ConvertToOmahaInstallDate(
440 base::Time::FromTimeT(omaha_epoch - 100*24*3600), &value));
441
442 // Check that we jump from 0 to 7 exactly on the one-week mark, e.g.
443 // on Jan 8, 2007 0:00 PST.
444 EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
445 base::Time::FromTimeT(omaha_epoch + 7*24*3600 - 1), &value));
446 EXPECT_EQ(value, 0);
447 EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
448 base::Time::FromTimeT(omaha_epoch + 7*24*3600), &value));
449 EXPECT_EQ(value, 7);
450
451 // Check a couple of more values.
452 EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
453 base::Time::FromTimeT(omaha_epoch + 10*24*3600), &value));
454 EXPECT_EQ(value, 7);
455 EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
456 base::Time::FromTimeT(omaha_epoch + 20*24*3600), &value));
457 EXPECT_EQ(value, 14);
458 EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
459 base::Time::FromTimeT(omaha_epoch + 26*24*3600), &value));
460 EXPECT_EQ(value, 21);
461 EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
462 base::Time::FromTimeT(omaha_epoch + 29*24*3600), &value));
463 EXPECT_EQ(value, 28);
464
465 // The date Jun 4, 2007 0:00 PDT is a Monday and is hence a point
466 // where the Omaha InstallDate jumps 7 days. Its unix time is
467 // 1180940400. Notably, this is a point in time where Daylight
468 // Savings Time (DST) was is in effect (e.g. it's PDT, not PST).
469 //
470 // Note that as utils::ConvertToOmahaInstallDate() _deliberately_
471 // ignores DST (as it's hard to implement in a thread-safe way using
472 // glibc, see comments in utils.h) we have to fudge by the DST
473 // offset which is one hour. Conveniently, if the function were
474 // someday modified to be DST aware, this test would have to be
475 // modified as well.
476 const time_t dst_time = 1180940400; // Jun 4, 2007 0:00 PDT.
477 const time_t fudge = 3600;
478 int value1, value2;
479 EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
480 base::Time::FromTimeT(dst_time + fudge - 1), &value1));
481 EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
482 base::Time::FromTimeT(dst_time + fudge), &value2));
483 EXPECT_EQ(value1, value2 - 7);
484 }
485
TEST(UtilsTest,GetMinorVersion)486 TEST(UtilsTest, GetMinorVersion) {
487 // Test GetMinorVersion by verifying that it parses the conf file and returns
488 // the correct value.
489 uint32_t minor_version;
490
491 brillo::KeyValueStore store;
492 EXPECT_FALSE(utils::GetMinorVersion(store, &minor_version));
493
494 EXPECT_TRUE(store.LoadFromString("PAYLOAD_MINOR_VERSION=one-two-three\n"));
495 EXPECT_FALSE(utils::GetMinorVersion(store, &minor_version));
496
497 EXPECT_TRUE(store.LoadFromString("PAYLOAD_MINOR_VERSION=123\n"));
498 EXPECT_TRUE(utils::GetMinorVersion(store, &minor_version));
499 EXPECT_EQ(123U, minor_version);
500 }
501
BoolMacroTestHelper()502 static bool BoolMacroTestHelper() {
503 int i = 1;
504 unsigned int ui = 1;
505 bool b = 1;
506 std::unique_ptr<char> cptr(new char);
507
508 TEST_AND_RETURN_FALSE(i);
509 TEST_AND_RETURN_FALSE(ui);
510 TEST_AND_RETURN_FALSE(b);
511 TEST_AND_RETURN_FALSE(cptr);
512
513 TEST_AND_RETURN_FALSE_ERRNO(i);
514 TEST_AND_RETURN_FALSE_ERRNO(ui);
515 TEST_AND_RETURN_FALSE_ERRNO(b);
516 TEST_AND_RETURN_FALSE_ERRNO(cptr);
517
518 return true;
519 }
520
VoidMacroTestHelper(bool * ret)521 static void VoidMacroTestHelper(bool* ret) {
522 int i = 1;
523 unsigned int ui = 1;
524 bool b = 1;
525 std::unique_ptr<char> cptr(new char);
526
527 *ret = false;
528
529 TEST_AND_RETURN(i);
530 TEST_AND_RETURN(ui);
531 TEST_AND_RETURN(b);
532 TEST_AND_RETURN(cptr);
533
534 TEST_AND_RETURN_ERRNO(i);
535 TEST_AND_RETURN_ERRNO(ui);
536 TEST_AND_RETURN_ERRNO(b);
537 TEST_AND_RETURN_ERRNO(cptr);
538
539 *ret = true;
540 }
541
TEST(UtilsTest,TestMacros)542 TEST(UtilsTest, TestMacros) {
543 bool void_test = false;
544 VoidMacroTestHelper(&void_test);
545 EXPECT_TRUE(void_test);
546
547 EXPECT_TRUE(BoolMacroTestHelper());
548 }
549
TEST(UtilsTest,UnmountFilesystemFailureTest)550 TEST(UtilsTest, UnmountFilesystemFailureTest) {
551 EXPECT_FALSE(utils::UnmountFilesystem("/path/to/non-existing-dir"));
552 }
553
TEST(UtilsTest,UnmountFilesystemBusyFailureTest)554 TEST(UtilsTest, UnmountFilesystemBusyFailureTest) {
555 string tmp_image;
556 EXPECT_TRUE(utils::MakeTempFile("img.XXXXXX", &tmp_image, nullptr));
557 ScopedPathUnlinker tmp_image_unlinker(tmp_image);
558
559 EXPECT_TRUE(base::CopyFile(
560 test_utils::GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
561 base::FilePath(tmp_image)));
562
563 base::ScopedTempDir mnt_dir;
564 EXPECT_TRUE(mnt_dir.CreateUniqueTempDir());
565
566 string loop_dev;
567 test_utils::ScopedLoopbackDeviceBinder loop_binder(
568 tmp_image, true, &loop_dev);
569
570 // This is the actual test part. While we hold a file descriptor open for the
571 // mounted filesystem, umount should still succeed.
572 EXPECT_TRUE(utils::MountFilesystem(
573 loop_dev, mnt_dir.path().value(), MS_RDONLY, "ext4", ""));
574 string target_file = mnt_dir.path().Append("empty-file").value();
575 int fd = HANDLE_EINTR(open(target_file.c_str(), O_RDONLY));
576 EXPECT_GE(fd, 0);
577 EXPECT_TRUE(utils::UnmountFilesystem(mnt_dir.path().value()));
578 IGNORE_EINTR(close(fd));
579 // The filesystem was already unmounted so this call should fail.
580 EXPECT_FALSE(utils::UnmountFilesystem(mnt_dir.path().value()));
581 }
582
583 } // namespace chromeos_update_engine
584