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 <fcntl.h>
     20 #include <stdint.h>
     21 #include <sys/mount.h>
     22 #include <sys/stat.h>
     23 #include <sys/types.h>
     24 
     25 #include <string>
     26 #include <vector>
     27 
     28 #include <base/files/file_path.h>
     29 #include <base/files/file_util.h>
     30 #include <base/files/scoped_temp_dir.h>
     31 #include <gtest/gtest.h>
     32 
     33 #include "update_engine/common/test_utils.h"
     34 
     35 using std::string;
     36 using std::vector;
     37 
     38 namespace chromeos_update_engine {
     39 
     40 class UtilsTest : public ::testing::Test { };
     41 
     42 TEST(UtilsTest, CanParseECVersion) {
     43   // Should be able to parse and valid key value line.
     44   EXPECT_EQ("12345", utils::ParseECVersion("fw_version=12345"));
     45   EXPECT_EQ("123456", utils::ParseECVersion(
     46       "b=1231a fw_version=123456 a=fasd2"));
     47   EXPECT_EQ("12345", utils::ParseECVersion("fw_version=12345"));
     48   EXPECT_EQ("00VFA616", utils::ParseECVersion(
     49       "vendor=\"sam\" fw_version=\"00VFA616\""));
     50 
     51   // For invalid entries, should return the empty string.
     52   EXPECT_EQ("", utils::ParseECVersion("b=1231a fw_version a=fasd2"));
     53 }
     54 
     55 TEST(UtilsTest, WriteFileOpenFailure) {
     56   EXPECT_FALSE(utils::WriteFile("/this/doesn't/exist", "hello", 5));
     57 }
     58 
     59 TEST(UtilsTest, WriteFileReadFile) {
     60   base::FilePath file;
     61   EXPECT_TRUE(base::CreateTemporaryFile(&file));
     62   ScopedPathUnlinker unlinker(file.value());
     63   EXPECT_TRUE(utils::WriteFile(file.value().c_str(), "hello", 5));
     64 
     65   brillo::Blob readback;
     66   EXPECT_TRUE(utils::ReadFile(file.value().c_str(), &readback));
     67   EXPECT_EQ("hello", string(readback.begin(), readback.end()));
     68 }
     69 
     70 TEST(UtilsTest, ReadFileFailure) {
     71   brillo::Blob empty;
     72   EXPECT_FALSE(utils::ReadFile("/this/doesn't/exist", &empty));
     73 }
     74 
     75 TEST(UtilsTest, ReadFileChunk) {
     76   base::FilePath file;
     77   EXPECT_TRUE(base::CreateTemporaryFile(&file));
     78   ScopedPathUnlinker unlinker(file.value());
     79   brillo::Blob data;
     80   const size_t kSize = 1024 * 1024;
     81   for (size_t i = 0; i < kSize; i++) {
     82     data.push_back(i % 255);
     83   }
     84   EXPECT_TRUE(utils::WriteFile(file.value().c_str(), data.data(), data.size()));
     85   brillo::Blob in_data;
     86   EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), kSize, 10, &in_data));
     87   EXPECT_TRUE(in_data.empty());
     88   EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), 0, -1, &in_data));
     89   EXPECT_TRUE(data == in_data);
     90   in_data.clear();
     91   EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), 10, 20, &in_data));
     92   EXPECT_TRUE(brillo::Blob(data.begin() + 10, data.begin() + 10 + 20) ==
     93               in_data);
     94 }
     95 
     96 TEST(UtilsTest, ErrnoNumberAsStringTest) {
     97   EXPECT_EQ("No such file or directory", utils::ErrnoNumberAsString(ENOENT));
     98 }
     99 
    100 TEST(UtilsTest, IsSymlinkTest) {
    101   base::ScopedTempDir temp_dir;
    102   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    103   string temp_file = temp_dir.GetPath().Append("temp-file").value();
    104   EXPECT_TRUE(utils::WriteFile(temp_file.c_str(), "", 0));
    105   string temp_symlink = temp_dir.GetPath().Append("temp-symlink").value();
    106   EXPECT_EQ(0, symlink(temp_file.c_str(), temp_symlink.c_str()));
    107   EXPECT_FALSE(utils::IsSymlink(temp_dir.GetPath().value().c_str()));
    108   EXPECT_FALSE(utils::IsSymlink(temp_file.c_str()));
    109   EXPECT_TRUE(utils::IsSymlink(temp_symlink.c_str()));
    110   EXPECT_FALSE(utils::IsSymlink("/non/existent/path"));
    111 }
    112 
    113 TEST(UtilsTest, SplitPartitionNameTest) {
    114   string disk;
    115   int part_num;
    116 
    117   EXPECT_TRUE(utils::SplitPartitionName("/dev/sda3", &disk, &part_num));
    118   EXPECT_EQ("/dev/sda", disk);
    119   EXPECT_EQ(3, part_num);
    120 
    121   EXPECT_TRUE(utils::SplitPartitionName("/dev/sdp1234", &disk, &part_num));
    122   EXPECT_EQ("/dev/sdp", disk);
    123   EXPECT_EQ(1234, part_num);
    124 
    125   EXPECT_TRUE(utils::SplitPartitionName("/dev/mmcblk0p3", &disk, &part_num));
    126   EXPECT_EQ("/dev/mmcblk0", disk);
    127   EXPECT_EQ(3, part_num);
    128 
    129   EXPECT_TRUE(utils::SplitPartitionName("/dev/ubiblock3_2", &disk, &part_num));
    130   EXPECT_EQ("/dev/ubiblock", disk);
    131   EXPECT_EQ(3, part_num);
    132 
    133   EXPECT_TRUE(utils::SplitPartitionName("/dev/loop10", &disk, &part_num));
    134   EXPECT_EQ("/dev/loop", disk);
    135   EXPECT_EQ(10, part_num);
    136 
    137   EXPECT_TRUE(utils::SplitPartitionName("/dev/loop28p11", &disk, &part_num));
    138   EXPECT_EQ("/dev/loop28", disk);
    139   EXPECT_EQ(11, part_num);
    140 
    141   EXPECT_TRUE(utils::SplitPartitionName("/dev/loop10_0", &disk, &part_num));
    142   EXPECT_EQ("/dev/loop", disk);
    143   EXPECT_EQ(10, part_num);
    144 
    145   EXPECT_TRUE(utils::SplitPartitionName("/dev/loop28p11_0", &disk, &part_num));
    146   EXPECT_EQ("/dev/loop28", disk);
    147   EXPECT_EQ(11, part_num);
    148 
    149   EXPECT_FALSE(utils::SplitPartitionName("/dev/mmcblk0p", &disk, &part_num));
    150   EXPECT_FALSE(utils::SplitPartitionName("/dev/sda", &disk, &part_num));
    151   EXPECT_FALSE(utils::SplitPartitionName("/dev/foo/bar", &disk, &part_num));
    152   EXPECT_FALSE(utils::SplitPartitionName("/", &disk, &part_num));
    153   EXPECT_FALSE(utils::SplitPartitionName("", &disk, &part_num));
    154 }
    155 
    156 TEST(UtilsTest, MakePartitionNameTest) {
    157   EXPECT_EQ("/dev/sda4", utils::MakePartitionName("/dev/sda", 4));
    158   EXPECT_EQ("/dev/sda123", utils::MakePartitionName("/dev/sda", 123));
    159   EXPECT_EQ("/dev/mmcblk2", utils::MakePartitionName("/dev/mmcblk", 2));
    160   EXPECT_EQ("/dev/mmcblk0p2", utils::MakePartitionName("/dev/mmcblk0", 2));
    161   EXPECT_EQ("/dev/loop8", utils::MakePartitionName("/dev/loop", 8));
    162   EXPECT_EQ("/dev/loop12p2", utils::MakePartitionName("/dev/loop12", 2));
    163   EXPECT_EQ("/dev/ubi5_0", utils::MakePartitionName("/dev/ubiblock", 5));
    164   EXPECT_EQ("/dev/mtd4", utils::MakePartitionName("/dev/ubiblock", 4));
    165   EXPECT_EQ("/dev/ubi3_0", utils::MakePartitionName("/dev/ubiblock", 3));
    166   EXPECT_EQ("/dev/mtd2", utils::MakePartitionName("/dev/ubiblock", 2));
    167   EXPECT_EQ("/dev/ubi1_0", utils::MakePartitionName("/dev/ubiblock", 1));
    168 }
    169 
    170 TEST(UtilsTest, MakePartitionNameForMountTest) {
    171   EXPECT_EQ("/dev/sda4", utils::MakePartitionNameForMount("/dev/sda4"));
    172   EXPECT_EQ("/dev/sda123", utils::MakePartitionNameForMount("/dev/sda123"));
    173   EXPECT_EQ("/dev/mmcblk2", utils::MakePartitionNameForMount("/dev/mmcblk2"));
    174   EXPECT_EQ("/dev/mmcblk0p2",
    175             utils::MakePartitionNameForMount("/dev/mmcblk0p2"));
    176   EXPECT_EQ("/dev/loop0", utils::MakePartitionNameForMount("/dev/loop0"));
    177   EXPECT_EQ("/dev/loop8", utils::MakePartitionNameForMount("/dev/loop8"));
    178   EXPECT_EQ("/dev/loop12p2",
    179             utils::MakePartitionNameForMount("/dev/loop12p2"));
    180   EXPECT_EQ("/dev/ubiblock5_0",
    181             utils::MakePartitionNameForMount("/dev/ubiblock5_0"));
    182   EXPECT_EQ("/dev/mtd4",
    183             utils::MakePartitionNameForMount("/dev/ubi4_0"));
    184   EXPECT_EQ("/dev/ubiblock3_0",
    185             utils::MakePartitionNameForMount("/dev/ubiblock3"));
    186   EXPECT_EQ("/dev/mtd2", utils::MakePartitionNameForMount("/dev/ubi2"));
    187   EXPECT_EQ("/dev/ubi1_0",
    188             utils::MakePartitionNameForMount("/dev/ubiblock1"));
    189 }
    190 
    191 TEST(UtilsTest, FuzzIntTest) {
    192   static const uint32_t kRanges[] = { 0, 1, 2, 20 };
    193   for (uint32_t range : kRanges) {
    194     const int kValue = 50;
    195     for (int tries = 0; tries < 100; ++tries) {
    196       uint32_t value = utils::FuzzInt(kValue, range);
    197       EXPECT_GE(value, kValue - range / 2);
    198       EXPECT_LE(value, kValue + range - range / 2);
    199     }
    200   }
    201 }
    202 
    203 namespace {
    204 void GetFileFormatTester(const string& expected,
    205                          const vector<uint8_t>& contents) {
    206   test_utils::ScopedTempFile file;
    207   ASSERT_TRUE(utils::WriteFile(file.path().c_str(),
    208                                reinterpret_cast<const char*>(contents.data()),
    209                                contents.size()));
    210   EXPECT_EQ(expected, utils::GetFileFormat(file.path()));
    211 }
    212 }  // namespace
    213 
    214 TEST(UtilsTest, GetFileFormatTest) {
    215   EXPECT_EQ("File not found.", utils::GetFileFormat("/path/to/nowhere"));
    216   GetFileFormatTester("data", vector<uint8_t>{1, 2, 3, 4, 5, 6, 7, 8});
    217   GetFileFormatTester("ELF", vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46});
    218 
    219   // Real tests from cros_installer on different boards.
    220   // ELF 32-bit LSB executable, Intel 80386
    221   GetFileFormatTester(
    222       "ELF 32-bit little-endian x86",
    223       vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00,
    224                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    225                       0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
    226                       0x90, 0x83, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00});
    227 
    228   // ELF 32-bit LSB executable, MIPS
    229   GetFileFormatTester(
    230       "ELF 32-bit little-endian mips",
    231       vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00,
    232                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    233                       0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
    234                       0xc0, 0x12, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00});
    235 
    236   // ELF 32-bit LSB executable, ARM
    237   GetFileFormatTester(
    238       "ELF 32-bit little-endian arm",
    239       vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00,
    240                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    241                       0x02, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00,
    242                       0x85, 0x8b, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00});
    243 
    244   // ELF 64-bit LSB executable, x86-64
    245   GetFileFormatTester(
    246       "ELF 64-bit little-endian x86-64",
    247       vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
    248                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    249                       0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
    250                       0xb0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00});
    251 }
    252 
    253 TEST(UtilsTest, FormatTimeDeltaTest) {
    254   // utils::FormatTimeDelta() is not locale-aware (it's only used for logging
    255   // which is not localized) so we only need to test the C locale
    256   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromMilliseconds(100)),
    257             "0.1s");
    258   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(0)),
    259             "0s");
    260   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(1)),
    261             "1s");
    262   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(59)),
    263             "59s");
    264   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(60)),
    265             "1m0s");
    266   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(61)),
    267             "1m1s");
    268   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(90)),
    269             "1m30s");
    270   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(1205)),
    271             "20m5s");
    272   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(3600)),
    273             "1h0m0s");
    274   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(3601)),
    275             "1h0m1s");
    276   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(3661)),
    277             "1h1m1s");
    278   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(7261)),
    279             "2h1m1s");
    280   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(86400)),
    281             "1d0h0m0s");
    282   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(86401)),
    283             "1d0h0m1s");
    284   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(200000)),
    285             "2d7h33m20s");
    286   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(200000) +
    287                                    base::TimeDelta::FromMilliseconds(1)),
    288             "2d7h33m20.001s");
    289   EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(-1)),
    290             "-1s");
    291 }
    292 
    293 TEST(UtilsTest, TimeFromStructTimespecTest) {
    294   struct timespec ts;
    295 
    296   // Unix epoch (Thursday 00:00:00 UTC on Jan 1, 1970)
    297   ts = (struct timespec) {.tv_sec = 0, .tv_nsec = 0};
    298   EXPECT_EQ(base::Time::UnixEpoch(), utils::TimeFromStructTimespec(&ts));
    299 
    300   // 42 ms after the Unix billennium (Sunday 01:46:40 UTC on September 9, 2001)
    301   ts = (struct timespec) {.tv_sec = 1000 * 1000 * 1000,
    302                           .tv_nsec = 42 * 1000 * 1000};
    303   base::Time::Exploded exploded = (base::Time::Exploded) {
    304     .year = 2001, .month = 9, .day_of_week = 0, .day_of_month = 9,
    305     .hour = 1, .minute = 46, .second = 40, .millisecond = 42};
    306   base::Time time;
    307   EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time));
    308   EXPECT_EQ(time, utils::TimeFromStructTimespec(&ts));
    309 }
    310 
    311 TEST(UtilsTest, DecodeAndStoreBase64String) {
    312   base::FilePath path;
    313 
    314   // Ensure we return false on empty strings or invalid base64.
    315   EXPECT_FALSE(utils::DecodeAndStoreBase64String("", &path));
    316   EXPECT_FALSE(utils::DecodeAndStoreBase64String("not valid base64", &path));
    317 
    318   // Pass known base64 and check that it matches. This string was generated
    319   // the following way:
    320   //
    321   //   $ echo "Update Engine" | base64
    322   //   VXBkYXRlIEVuZ2luZQo=
    323   EXPECT_TRUE(utils::DecodeAndStoreBase64String("VXBkYXRlIEVuZ2luZQo=",
    324                                                 &path));
    325   ScopedPathUnlinker unlinker(path.value());
    326   string expected_contents = "Update Engine\n";
    327   string contents;
    328   EXPECT_TRUE(utils::ReadFile(path.value(), &contents));
    329   EXPECT_EQ(contents, expected_contents);
    330   EXPECT_EQ(static_cast<off_t>(expected_contents.size()),
    331             utils::FileSize(path.value()));
    332 }
    333 
    334 TEST(UtilsTest, ConvertToOmahaInstallDate) {
    335   // The Omaha Epoch starts at Jan 1, 2007 0:00 PST which is a
    336   // Monday. In Unix time, this point in time is easily obtained via
    337   // the date(1) command like this:
    338   //
    339   //  $ date +"%s" --date="Jan 1, 2007 0:00 PST"
    340   const time_t omaha_epoch = 1167638400;
    341   int value;
    342 
    343   // Points in time *on and after* the Omaha epoch should not fail.
    344   EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
    345       base::Time::FromTimeT(omaha_epoch), &value));
    346   EXPECT_GE(value, 0);
    347 
    348   // Anything before the Omaha epoch should fail. We test it for two points.
    349   EXPECT_FALSE(utils::ConvertToOmahaInstallDate(
    350       base::Time::FromTimeT(omaha_epoch - 1), &value));
    351   EXPECT_FALSE(utils::ConvertToOmahaInstallDate(
    352       base::Time::FromTimeT(omaha_epoch - 100*24*3600), &value));
    353 
    354   // Check that we jump from 0 to 7 exactly on the one-week mark, e.g.
    355   // on Jan 8, 2007 0:00 PST.
    356   EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
    357       base::Time::FromTimeT(omaha_epoch + 7*24*3600 - 1), &value));
    358   EXPECT_EQ(value, 0);
    359   EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
    360       base::Time::FromTimeT(omaha_epoch + 7*24*3600), &value));
    361   EXPECT_EQ(value, 7);
    362 
    363   // Check a couple of more values.
    364   EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
    365       base::Time::FromTimeT(omaha_epoch + 10*24*3600), &value));
    366   EXPECT_EQ(value, 7);
    367   EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
    368       base::Time::FromTimeT(omaha_epoch + 20*24*3600), &value));
    369   EXPECT_EQ(value, 14);
    370   EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
    371       base::Time::FromTimeT(omaha_epoch + 26*24*3600), &value));
    372   EXPECT_EQ(value, 21);
    373   EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
    374       base::Time::FromTimeT(omaha_epoch + 29*24*3600), &value));
    375   EXPECT_EQ(value, 28);
    376 
    377   // The date Jun 4, 2007 0:00 PDT is a Monday and is hence a point
    378   // where the Omaha InstallDate jumps 7 days. Its unix time is
    379   // 1180940400. Notably, this is a point in time where Daylight
    380   // Savings Time (DST) was is in effect (e.g. it's PDT, not PST).
    381   //
    382   // Note that as utils::ConvertToOmahaInstallDate() _deliberately_
    383   // ignores DST (as it's hard to implement in a thread-safe way using
    384   // glibc, see comments in utils.h) we have to fudge by the DST
    385   // offset which is one hour. Conveniently, if the function were
    386   // someday modified to be DST aware, this test would have to be
    387   // modified as well.
    388   const time_t dst_time = 1180940400;  // Jun 4, 2007 0:00 PDT.
    389   const time_t fudge = 3600;
    390   int value1, value2;
    391   EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
    392       base::Time::FromTimeT(dst_time + fudge - 1), &value1));
    393   EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
    394       base::Time::FromTimeT(dst_time + fudge), &value2));
    395   EXPECT_EQ(value1, value2 - 7);
    396 }
    397 
    398 TEST(UtilsTest, GetMinorVersion) {
    399   // Test GetMinorVersion by verifying that it parses the conf file and returns
    400   // the correct value.
    401   uint32_t minor_version;
    402 
    403   brillo::KeyValueStore store;
    404   EXPECT_FALSE(utils::GetMinorVersion(store, &minor_version));
    405 
    406   EXPECT_TRUE(store.LoadFromString("PAYLOAD_MINOR_VERSION=one-two-three\n"));
    407   EXPECT_FALSE(utils::GetMinorVersion(store, &minor_version));
    408 
    409   EXPECT_TRUE(store.LoadFromString("PAYLOAD_MINOR_VERSION=123\n"));
    410   EXPECT_TRUE(utils::GetMinorVersion(store, &minor_version));
    411   EXPECT_EQ(123U, minor_version);
    412 }
    413 
    414 static bool BoolMacroTestHelper() {
    415   int i = 1;
    416   unsigned int ui = 1;
    417   bool b = 1;
    418   std::unique_ptr<char> cptr(new char);
    419 
    420   TEST_AND_RETURN_FALSE(i);
    421   TEST_AND_RETURN_FALSE(ui);
    422   TEST_AND_RETURN_FALSE(b);
    423   TEST_AND_RETURN_FALSE(cptr);
    424 
    425   TEST_AND_RETURN_FALSE_ERRNO(i);
    426   TEST_AND_RETURN_FALSE_ERRNO(ui);
    427   TEST_AND_RETURN_FALSE_ERRNO(b);
    428   TEST_AND_RETURN_FALSE_ERRNO(cptr);
    429 
    430   return true;
    431 }
    432 
    433 static void VoidMacroTestHelper(bool* ret) {
    434   int i = 1;
    435   unsigned int ui = 1;
    436   bool b = 1;
    437   std::unique_ptr<char> cptr(new char);
    438 
    439   *ret = false;
    440 
    441   TEST_AND_RETURN(i);
    442   TEST_AND_RETURN(ui);
    443   TEST_AND_RETURN(b);
    444   TEST_AND_RETURN(cptr);
    445 
    446   TEST_AND_RETURN_ERRNO(i);
    447   TEST_AND_RETURN_ERRNO(ui);
    448   TEST_AND_RETURN_ERRNO(b);
    449   TEST_AND_RETURN_ERRNO(cptr);
    450 
    451   *ret = true;
    452 }
    453 
    454 TEST(UtilsTest, TestMacros) {
    455   bool void_test = false;
    456   VoidMacroTestHelper(&void_test);
    457   EXPECT_TRUE(void_test);
    458 
    459   EXPECT_TRUE(BoolMacroTestHelper());
    460 }
    461 
    462 TEST(UtilsTest, RunAsRootUnmountFilesystemFailureTest) {
    463   EXPECT_FALSE(utils::UnmountFilesystem("/path/to/non-existing-dir"));
    464 }
    465 
    466 TEST(UtilsTest, RunAsRootUnmountFilesystemBusyFailureTest) {
    467   string tmp_image;
    468   EXPECT_TRUE(utils::MakeTempFile("img.XXXXXX", &tmp_image, nullptr));
    469   ScopedPathUnlinker tmp_image_unlinker(tmp_image);
    470 
    471   EXPECT_TRUE(base::CopyFile(
    472       test_utils::GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
    473       base::FilePath(tmp_image)));
    474 
    475   base::ScopedTempDir mnt_dir;
    476   EXPECT_TRUE(mnt_dir.CreateUniqueTempDir());
    477 
    478   string loop_dev;
    479   test_utils::ScopedLoopbackDeviceBinder loop_binder(
    480       tmp_image, true, &loop_dev);
    481 
    482   EXPECT_FALSE(utils::IsMountpoint(mnt_dir.GetPath().value()));
    483   // This is the actual test part. While we hold a file descriptor open for the
    484   // mounted filesystem, umount should still succeed.
    485   EXPECT_TRUE(utils::MountFilesystem(
    486       loop_dev, mnt_dir.GetPath().value(), MS_RDONLY, "ext4", ""));
    487   // Verify the directory is a mount point now.
    488   EXPECT_TRUE(utils::IsMountpoint(mnt_dir.GetPath().value()));
    489 
    490   string target_file = mnt_dir.GetPath().Append("empty-file").value();
    491   int fd = HANDLE_EINTR(open(target_file.c_str(), O_RDONLY));
    492   EXPECT_GE(fd, 0);
    493   EXPECT_TRUE(utils::UnmountFilesystem(mnt_dir.GetPath().value()));
    494   // The filesystem should be already unmounted at this point.
    495   EXPECT_FALSE(utils::IsMountpoint(mnt_dir.GetPath().value()));
    496   IGNORE_EINTR(close(fd));
    497   // The filesystem was already unmounted so this call should fail.
    498   EXPECT_FALSE(utils::UnmountFilesystem(mnt_dir.GetPath().value()));
    499 }
    500 
    501 TEST(UtilsTest, IsMountpointTest) {
    502   EXPECT_TRUE(utils::IsMountpoint("/"));
    503   EXPECT_FALSE(utils::IsMountpoint("/path/to/nowhere"));
    504 
    505   base::ScopedTempDir mnt_dir;
    506   EXPECT_TRUE(mnt_dir.CreateUniqueTempDir());
    507   EXPECT_FALSE(utils::IsMountpoint(mnt_dir.GetPath().value()));
    508 
    509   base::FilePath file;
    510   EXPECT_TRUE(base::CreateTemporaryFile(&file));
    511   ScopedPathUnlinker unlinker(file.value());
    512   EXPECT_FALSE(utils::IsMountpoint(file.value()));
    513 }
    514 
    515 }  // namespace chromeos_update_engine
    516