Home | History | Annotate | Download | only in common
      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 
     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 
     63 TEST(UtilsTest, ReadFileFailure) {
     64   brillo::Blob empty;
     65   EXPECT_FALSE(utils::ReadFile("/this/doesn't/exist", &empty));
     66 }
     67 
     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 
     89 TEST(UtilsTest, ErrnoNumberAsStringTest) {
     90   EXPECT_EQ("No such file or directory", utils::ErrnoNumberAsString(ENOENT));
     91 }
     92 
     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 
    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 
    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 
    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 
    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 
    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 
    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 {
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    550 TEST(UtilsTest, UnmountFilesystemFailureTest) {
    551   EXPECT_FALSE(utils::UnmountFilesystem("/path/to/non-existing-dir"));
    552 }
    553 
    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