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
41using brillo::FakeMessageLoop;
42using std::map;
43using std::string;
44using std::vector;
45
46namespace chromeos_update_engine {
47
48class UtilsTest : public ::testing::Test { };
49
50TEST(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
63TEST(UtilsTest, ReadFileFailure) {
64  brillo::Blob empty;
65  EXPECT_FALSE(utils::ReadFile("/this/doesn't/exist", &empty));
66}
67
68TEST(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
89TEST(UtilsTest, ErrnoNumberAsStringTest) {
90  EXPECT_EQ("No such file or directory", utils::ErrnoNumberAsString(ENOENT));
91}
92
93TEST(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
107TEST(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
150TEST(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
164TEST(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
185TEST(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
197TEST(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"'
218const 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
251TEST(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
281namespace {
282void 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
292TEST(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
331TEST(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
342TEST(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
382TEST(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
399TEST(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
422TEST(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
486TEST(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
502static 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
521static 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
542TEST(UtilsTest, TestMacros) {
543  bool void_test = false;
544  VoidMacroTestHelper(&void_test);
545  EXPECT_TRUE(void_test);
546
547  EXPECT_TRUE(BoolMacroTestHelper());
548}
549
550TEST(UtilsTest, UnmountFilesystemFailureTest) {
551  EXPECT_FALSE(utils::UnmountFilesystem("/path/to/non-existing-dir"));
552}
553
554TEST(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