Split payload application code into a subdirectory.

This patch splits from the main libupdate_engine code the part that
is strictly used to download and apply a payload into a new static
library, moving the code to subdirectories. The new library is divided
in two subdirectories: common/ and payload_consumer/, and should not
depend on other update_engine files outside those two subdirectories.
The main difference between those two is that the common/ tools are more
generic and not tied to the payload consumer process, but otherwise they
are both compiled together.

There are still dependencies from the new libpayload_consumer library
into the main directory files and DBus generated files. Those will be
addressed in follow up CLs.

Bug: 25197634
Test: FEATURES=test emerge-link update_engine; `mm` on Brillo.

Change-Id: Id8d0204ea573627e6e26ca9ea17b9592ca95bc23
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
new file mode 100644
index 0000000..2fd58e9
--- /dev/null
+++ b/common/utils_unittest.cc
@@ -0,0 +1,752 @@
+//
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/common/utils.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/message_loops/fake_message_loop.h>
+#include <brillo/message_loops/message_loop_utils.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/common/fake_clock.h"
+#include "update_engine/common/fake_prefs.h"
+#include "update_engine/common/prefs.h"
+#include "update_engine/common/test_utils.h"
+#include "update_engine/fake_system_state.h"
+
+using brillo::FakeMessageLoop;
+using std::map;
+using std::string;
+using std::vector;
+
+namespace chromeos_update_engine {
+
+class UtilsTest : public ::testing::Test { };
+
+TEST(UtilsTest, CanParseECVersion) {
+  // Should be able to parse and valid key value line.
+  EXPECT_EQ("12345", utils::ParseECVersion("fw_version=12345"));
+  EXPECT_EQ("123456", utils::ParseECVersion(
+      "b=1231a fw_version=123456 a=fasd2"));
+  EXPECT_EQ("12345", utils::ParseECVersion("fw_version=12345"));
+  EXPECT_EQ("00VFA616", utils::ParseECVersion(
+      "vendor=\"sam\" fw_version=\"00VFA616\""));
+
+  // For invalid entries, should return the empty string.
+  EXPECT_EQ("", utils::ParseECVersion("b=1231a fw_version a=fasd2"));
+}
+
+TEST(UtilsTest, ReadFileFailure) {
+  brillo::Blob empty;
+  EXPECT_FALSE(utils::ReadFile("/this/doesn't/exist", &empty));
+}
+
+TEST(UtilsTest, ReadFileChunk) {
+  base::FilePath file;
+  EXPECT_TRUE(base::CreateTemporaryFile(&file));
+  ScopedPathUnlinker unlinker(file.value());
+  brillo::Blob data;
+  const size_t kSize = 1024 * 1024;
+  for (size_t i = 0; i < kSize; i++) {
+    data.push_back(i % 255);
+  }
+  EXPECT_TRUE(utils::WriteFile(file.value().c_str(), data.data(), data.size()));
+  brillo::Blob in_data;
+  EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), kSize, 10, &in_data));
+  EXPECT_TRUE(in_data.empty());
+  EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), 0, -1, &in_data));
+  EXPECT_TRUE(data == in_data);
+  in_data.clear();
+  EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), 10, 20, &in_data));
+  EXPECT_TRUE(brillo::Blob(data.begin() + 10, data.begin() + 10 + 20) ==
+              in_data);
+}
+
+TEST(UtilsTest, ErrnoNumberAsStringTest) {
+  EXPECT_EQ("No such file or directory", utils::ErrnoNumberAsString(ENOENT));
+}
+
+TEST(UtilsTest, IsSymlinkTest) {
+  string temp_dir;
+  EXPECT_TRUE(utils::MakeTempDirectory("symlink-test.XXXXXX", &temp_dir));
+  string temp_file = temp_dir + "/temp-file";
+  EXPECT_TRUE(utils::WriteFile(temp_file.c_str(), "", 0));
+  string temp_symlink = temp_dir + "/temp-symlink";
+  EXPECT_EQ(0, symlink(temp_file.c_str(), temp_symlink.c_str()));
+  EXPECT_FALSE(utils::IsSymlink(temp_dir.c_str()));
+  EXPECT_FALSE(utils::IsSymlink(temp_file.c_str()));
+  EXPECT_TRUE(utils::IsSymlink(temp_symlink.c_str()));
+  EXPECT_FALSE(utils::IsSymlink("/non/existent/path"));
+  EXPECT_TRUE(base::DeleteFile(base::FilePath(temp_dir), true));
+}
+
+TEST(UtilsTest, SplitPartitionNameTest) {
+  string disk;
+  int part_num;
+
+  EXPECT_TRUE(utils::SplitPartitionName("/dev/sda3", &disk, &part_num));
+  EXPECT_EQ("/dev/sda", disk);
+  EXPECT_EQ(3, part_num);
+
+  EXPECT_TRUE(utils::SplitPartitionName("/dev/sdp1234", &disk, &part_num));
+  EXPECT_EQ("/dev/sdp", disk);
+  EXPECT_EQ(1234, part_num);
+
+  EXPECT_TRUE(utils::SplitPartitionName("/dev/mmcblk0p3", &disk, &part_num));
+  EXPECT_EQ("/dev/mmcblk0", disk);
+  EXPECT_EQ(3, part_num);
+
+  EXPECT_TRUE(utils::SplitPartitionName("/dev/ubiblock3_2", &disk, &part_num));
+  EXPECT_EQ("/dev/ubiblock", disk);
+  EXPECT_EQ(3, part_num);
+
+  EXPECT_TRUE(utils::SplitPartitionName("/dev/loop10", &disk, &part_num));
+  EXPECT_EQ("/dev/loop", disk);
+  EXPECT_EQ(10, part_num);
+
+  EXPECT_TRUE(utils::SplitPartitionName("/dev/loop28p11", &disk, &part_num));
+  EXPECT_EQ("/dev/loop28", disk);
+  EXPECT_EQ(11, part_num);
+
+  EXPECT_TRUE(utils::SplitPartitionName("/dev/loop10_0", &disk, &part_num));
+  EXPECT_EQ("/dev/loop", disk);
+  EXPECT_EQ(10, part_num);
+
+  EXPECT_TRUE(utils::SplitPartitionName("/dev/loop28p11_0", &disk, &part_num));
+  EXPECT_EQ("/dev/loop28", disk);
+  EXPECT_EQ(11, part_num);
+
+  EXPECT_FALSE(utils::SplitPartitionName("/dev/mmcblk0p", &disk, &part_num));
+  EXPECT_FALSE(utils::SplitPartitionName("/dev/sda", &disk, &part_num));
+  EXPECT_FALSE(utils::SplitPartitionName("/dev/foo/bar", &disk, &part_num));
+  EXPECT_FALSE(utils::SplitPartitionName("/", &disk, &part_num));
+  EXPECT_FALSE(utils::SplitPartitionName("", &disk, &part_num));
+}
+
+TEST(UtilsTest, MakePartitionNameTest) {
+  EXPECT_EQ("/dev/sda4", utils::MakePartitionName("/dev/sda", 4));
+  EXPECT_EQ("/dev/sda123", utils::MakePartitionName("/dev/sda", 123));
+  EXPECT_EQ("/dev/mmcblk2", utils::MakePartitionName("/dev/mmcblk", 2));
+  EXPECT_EQ("/dev/mmcblk0p2", utils::MakePartitionName("/dev/mmcblk0", 2));
+  EXPECT_EQ("/dev/loop8", utils::MakePartitionName("/dev/loop", 8));
+  EXPECT_EQ("/dev/loop12p2", utils::MakePartitionName("/dev/loop12", 2));
+  EXPECT_EQ("/dev/ubi5_0", utils::MakePartitionName("/dev/ubiblock", 5));
+  EXPECT_EQ("/dev/mtd4", utils::MakePartitionName("/dev/ubiblock", 4));
+  EXPECT_EQ("/dev/ubi3_0", utils::MakePartitionName("/dev/ubiblock", 3));
+  EXPECT_EQ("/dev/mtd2", utils::MakePartitionName("/dev/ubiblock", 2));
+  EXPECT_EQ("/dev/ubi1_0", utils::MakePartitionName("/dev/ubiblock", 1));
+}
+
+TEST(UtilsTest, MakePartitionNameForMountTest) {
+  EXPECT_EQ("/dev/sda4", utils::MakePartitionNameForMount("/dev/sda4"));
+  EXPECT_EQ("/dev/sda123", utils::MakePartitionNameForMount("/dev/sda123"));
+  EXPECT_EQ("/dev/mmcblk2", utils::MakePartitionNameForMount("/dev/mmcblk2"));
+  EXPECT_EQ("/dev/mmcblk0p2",
+            utils::MakePartitionNameForMount("/dev/mmcblk0p2"));
+  EXPECT_EQ("/dev/loop0", utils::MakePartitionNameForMount("/dev/loop0"));
+  EXPECT_EQ("/dev/loop8", utils::MakePartitionNameForMount("/dev/loop8"));
+  EXPECT_EQ("/dev/loop12p2",
+            utils::MakePartitionNameForMount("/dev/loop12p2"));
+  EXPECT_EQ("/dev/ubiblock5_0",
+            utils::MakePartitionNameForMount("/dev/ubiblock5_0"));
+  EXPECT_EQ("/dev/mtd4",
+            utils::MakePartitionNameForMount("/dev/ubi4_0"));
+  EXPECT_EQ("/dev/ubiblock3_0",
+            utils::MakePartitionNameForMount("/dev/ubiblock3"));
+  EXPECT_EQ("/dev/mtd2", utils::MakePartitionNameForMount("/dev/ubi2"));
+  EXPECT_EQ("/dev/ubi1_0",
+            utils::MakePartitionNameForMount("/dev/ubiblock1"));
+}
+
+namespace {
+// Compares cpu shares and returns an integer that is less
+// than, equal to or greater than 0 if |shares_lhs| is,
+// respectively, lower than, same as or higher than |shares_rhs|.
+int CompareCpuShares(utils::CpuShares shares_lhs,
+                     utils::CpuShares shares_rhs) {
+  return static_cast<int>(shares_lhs) - static_cast<int>(shares_rhs);
+}
+}  // namespace
+
+// Tests the CPU shares enum is in the order we expect it.
+TEST(UtilsTest, CompareCpuSharesTest) {
+  EXPECT_LT(CompareCpuShares(utils::kCpuSharesLow,
+                             utils::kCpuSharesNormal), 0);
+  EXPECT_GT(CompareCpuShares(utils::kCpuSharesNormal,
+                             utils::kCpuSharesLow), 0);
+  EXPECT_EQ(CompareCpuShares(utils::kCpuSharesNormal,
+                             utils::kCpuSharesNormal), 0);
+  EXPECT_GT(CompareCpuShares(utils::kCpuSharesHigh,
+                             utils::kCpuSharesNormal), 0);
+}
+
+TEST(UtilsTest, FuzzIntTest) {
+  static const unsigned int kRanges[] = { 0, 1, 2, 20 };
+  for (unsigned int range : kRanges) {
+    const int kValue = 50;
+    for (int tries = 0; tries < 100; ++tries) {
+      int value = utils::FuzzInt(kValue, range);
+      EXPECT_GE(value, kValue - range / 2);
+      EXPECT_LE(value, kValue + range - range / 2);
+    }
+  }
+}
+
+TEST(UtilsTest, RunAsRootGetFilesystemSizeTest) {
+  string img;
+  EXPECT_TRUE(utils::MakeTempFile("img.XXXXXX", &img, nullptr));
+  ScopedPathUnlinker img_unlinker(img);
+  test_utils::CreateExtImageAtPath(img, nullptr);
+  // Extend the "partition" holding the file system from 10MiB to 20MiB.
+  EXPECT_EQ(0, test_utils::System(base::StringPrintf(
+      "dd if=/dev/zero of=%s seek=20971519 bs=1 count=1 status=none",
+      img.c_str())));
+  EXPECT_EQ(20 * 1024 * 1024, utils::FileSize(img));
+  int block_count = 0;
+  int block_size = 0;
+  EXPECT_TRUE(utils::GetFilesystemSize(img, &block_count, &block_size));
+  EXPECT_EQ(4096, block_size);
+  EXPECT_EQ(10 * 1024 * 1024 / 4096, block_count);
+}
+
+// Squashfs example filesystem, generated with:
+//   echo hola>hola
+//   mksquashfs hola hola.sqfs -noappend -nopad
+//   hexdump hola.sqfs -e '16/1 "%02x, " "\n"'
+const uint8_t kSquashfsFile[] = {
+  0x68, 0x73, 0x71, 0x73, 0x02, 0x00, 0x00, 0x00,  // magic, inodes
+  0x3e, 0x49, 0x61, 0x54, 0x00, 0x00, 0x02, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00,
+  0xc0, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00,  // flags, noids, major, minor
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // root_inode
+  0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // bytes_used
+  0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x68, 0x6f, 0x6c, 0x61, 0x0a, 0x2c, 0x00, 0x78,
+  0xda, 0x63, 0x62, 0x58, 0xc2, 0xc8, 0xc0, 0xc0,
+  0xc8, 0xd0, 0x6b, 0x91, 0x18, 0x02, 0x64, 0xa0,
+  0x00, 0x56, 0x06, 0x90, 0xcc, 0x7f, 0xb0, 0xbc,
+  0x9d, 0x67, 0x62, 0x08, 0x13, 0x54, 0x1c, 0x44,
+  0x4b, 0x03, 0x31, 0x33, 0x10, 0x03, 0x00, 0xb5,
+  0x87, 0x04, 0x89, 0x16, 0x00, 0x78, 0xda, 0x63,
+  0x60, 0x80, 0x00, 0x46, 0x28, 0xcd, 0xc4, 0xc0,
+  0xcc, 0x90, 0x91, 0x9f, 0x93, 0x08, 0x00, 0x04,
+  0x70, 0x01, 0xab, 0x10, 0x80, 0x60, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x78,
+  0xda, 0x63, 0x60, 0x80, 0x00, 0x05, 0x28, 0x0d,
+  0x00, 0x01, 0x10, 0x00, 0x21, 0xc5, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x99,
+  0xcd, 0x02, 0x00, 0x88, 0x13, 0x00, 0x00, 0xdd,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+TEST(UtilsTest, GetSquashfs4Size) {
+  uint8_t buffer[sizeof(kSquashfsFile)];
+  memcpy(buffer, kSquashfsFile, sizeof(kSquashfsFile));
+
+  int block_count = -1;
+  int block_size = -1;
+  // Not enough bytes passed.
+  EXPECT_FALSE(utils::GetSquashfs4Size(buffer, 10, nullptr, nullptr));
+
+  // The whole file system is passed, which is enough for parsing.
+  EXPECT_TRUE(utils::GetSquashfs4Size(buffer, sizeof(kSquashfsFile),
+                                      &block_count, &block_size));
+  EXPECT_EQ(4096, block_size);
+  EXPECT_EQ(1, block_count);
+
+  // Modify the major version to 5.
+  uint16_t* s_major = reinterpret_cast<uint16_t*>(buffer + 0x1c);
+  *s_major = 5;
+  EXPECT_FALSE(utils::GetSquashfs4Size(buffer, 10, nullptr, nullptr));
+  memcpy(buffer, kSquashfsFile, sizeof(kSquashfsFile));
+
+  // Modify the bytes_used to have 6 blocks.
+  int64_t* bytes_used = reinterpret_cast<int64_t*>(buffer + 0x28);
+  *bytes_used = 4096 * 5 + 1;  // 6 "blocks".
+  EXPECT_TRUE(utils::GetSquashfs4Size(buffer, sizeof(kSquashfsFile),
+                                      &block_count, &block_size));
+  EXPECT_EQ(4096, block_size);
+  EXPECT_EQ(6, block_count);
+}
+
+namespace {
+void GetFileFormatTester(const string& expected,
+                         const vector<uint8_t>& contents) {
+  test_utils::ScopedTempFile file;
+  ASSERT_TRUE(utils::WriteFile(file.GetPath().c_str(),
+                               reinterpret_cast<const char*>(contents.data()),
+                               contents.size()));
+  EXPECT_EQ(expected, utils::GetFileFormat(file.GetPath()));
+}
+}  // namespace
+
+TEST(UtilsTest, GetFileFormatTest) {
+  EXPECT_EQ("File not found.", utils::GetFileFormat("/path/to/nowhere"));
+  GetFileFormatTester("data", vector<uint8_t>{1, 2, 3, 4, 5, 6, 7, 8});
+  GetFileFormatTester("ELF", vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46});
+
+  // Real tests from cros_installer on different boards.
+  // ELF 32-bit LSB executable, Intel 80386
+  GetFileFormatTester(
+      "ELF 32-bit little-endian x86",
+      vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                      0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
+                      0x90, 0x83, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00});
+
+  // ELF 32-bit LSB executable, MIPS
+  GetFileFormatTester(
+      "ELF 32-bit little-endian mips",
+      vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                      0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
+                      0xc0, 0x12, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00});
+
+  // ELF 32-bit LSB executable, ARM
+  GetFileFormatTester(
+      "ELF 32-bit little-endian arm",
+      vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                      0x02, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00,
+                      0x85, 0x8b, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00});
+
+  // ELF 64-bit LSB executable, x86-64
+  GetFileFormatTester(
+      "ELF 64-bit little-endian x86-64",
+      vector<uint8_t>{0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                      0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
+                      0xb0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00});
+}
+
+TEST(UtilsTest, ScheduleCrashReporterUploadTest) {
+  // Not much to test. At least this tests for memory leaks, crashes,
+  // log errors.
+  FakeMessageLoop loop(nullptr);
+  loop.SetAsCurrent();
+  utils::ScheduleCrashReporterUpload();
+  // Test that we scheduled one callback from the crash reporter.
+  EXPECT_EQ(1, brillo::MessageLoopRunMaxIterations(&loop, 100));
+  EXPECT_FALSE(loop.PendingTasks());
+}
+
+TEST(UtilsTest, FormatTimeDeltaTest) {
+  // utils::FormatTimeDelta() is not locale-aware (it's only used for logging
+  // which is not localized) so we only need to test the C locale
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromMilliseconds(100)),
+            "0.1s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(0)),
+            "0s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(1)),
+            "1s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(59)),
+            "59s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(60)),
+            "1m0s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(61)),
+            "1m1s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(90)),
+            "1m30s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(1205)),
+            "20m5s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(3600)),
+            "1h0m0s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(3601)),
+            "1h0m1s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(3661)),
+            "1h1m1s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(7261)),
+            "2h1m1s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(86400)),
+            "1d0h0m0s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(86401)),
+            "1d0h0m1s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(200000)),
+            "2d7h33m20s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(200000) +
+                                   base::TimeDelta::FromMilliseconds(1)),
+            "2d7h33m20.001s");
+  EXPECT_EQ(utils::FormatTimeDelta(base::TimeDelta::FromSeconds(-1)),
+            "-1s");
+}
+
+TEST(UtilsTest, TimeFromStructTimespecTest) {
+  struct timespec ts;
+
+  // Unix epoch (Thursday 00:00:00 UTC on Jan 1, 1970)
+  ts = (struct timespec) {.tv_sec = 0, .tv_nsec = 0};
+  EXPECT_EQ(base::Time::UnixEpoch(), utils::TimeFromStructTimespec(&ts));
+
+  // 42 ms after the Unix billennium (Sunday 01:46:40 UTC on September 9, 2001)
+  ts = (struct timespec) {.tv_sec = 1000 * 1000 * 1000,
+                          .tv_nsec = 42 * 1000 * 1000};
+  base::Time::Exploded exploded = (base::Time::Exploded) {
+    .year = 2001, .month = 9, .day_of_week = 0, .day_of_month = 9,
+    .hour = 1, .minute = 46, .second = 40, .millisecond = 42};
+  EXPECT_EQ(base::Time::FromUTCExploded(exploded),
+            utils::TimeFromStructTimespec(&ts));
+}
+
+TEST(UtilsTest, DecodeAndStoreBase64String) {
+  base::FilePath path;
+
+  // Ensure we return false on empty strings or invalid base64.
+  EXPECT_FALSE(utils::DecodeAndStoreBase64String("", &path));
+  EXPECT_FALSE(utils::DecodeAndStoreBase64String("not valid base64", &path));
+
+  // Pass known base64 and check that it matches. This string was generated
+  // the following way:
+  //
+  //   $ echo "Update Engine" | base64
+  //   VXBkYXRlIEVuZ2luZQo=
+  EXPECT_TRUE(utils::DecodeAndStoreBase64String("VXBkYXRlIEVuZ2luZQo=",
+                                                &path));
+  ScopedPathUnlinker unlinker(path.value());
+  string expected_contents = "Update Engine\n";
+  string contents;
+  EXPECT_TRUE(utils::ReadFile(path.value(), &contents));
+  EXPECT_EQ(contents, expected_contents);
+  EXPECT_EQ(utils::FileSize(path.value()), expected_contents.size());
+}
+
+TEST(UtilsTest, ConvertToOmahaInstallDate) {
+  // The Omaha Epoch starts at Jan 1, 2007 0:00 PST which is a
+  // Monday. In Unix time, this point in time is easily obtained via
+  // the date(1) command like this:
+  //
+  //  $ date +"%s" --date="Jan 1, 2007 0:00 PST"
+  const time_t omaha_epoch = 1167638400;
+  int value;
+
+  // Points in time *on and after* the Omaha epoch should not fail.
+  EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(omaha_epoch), &value));
+  EXPECT_GE(value, 0);
+
+  // Anything before the Omaha epoch should fail. We test it for two points.
+  EXPECT_FALSE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(omaha_epoch - 1), &value));
+  EXPECT_FALSE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(omaha_epoch - 100*24*3600), &value));
+
+  // Check that we jump from 0 to 7 exactly on the one-week mark, e.g.
+  // on Jan 8, 2007 0:00 PST.
+  EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(omaha_epoch + 7*24*3600 - 1), &value));
+  EXPECT_EQ(value, 0);
+  EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(omaha_epoch + 7*24*3600), &value));
+  EXPECT_EQ(value, 7);
+
+  // Check a couple of more values.
+  EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(omaha_epoch + 10*24*3600), &value));
+  EXPECT_EQ(value, 7);
+  EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(omaha_epoch + 20*24*3600), &value));
+  EXPECT_EQ(value, 14);
+  EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(omaha_epoch + 26*24*3600), &value));
+  EXPECT_EQ(value, 21);
+  EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(omaha_epoch + 29*24*3600), &value));
+  EXPECT_EQ(value, 28);
+
+  // The date Jun 4, 2007 0:00 PDT is a Monday and is hence a point
+  // where the Omaha InstallDate jumps 7 days. Its unix time is
+  // 1180940400. Notably, this is a point in time where Daylight
+  // Savings Time (DST) was is in effect (e.g. it's PDT, not PST).
+  //
+  // Note that as utils::ConvertToOmahaInstallDate() _deliberately_
+  // ignores DST (as it's hard to implement in a thread-safe way using
+  // glibc, see comments in utils.h) we have to fudge by the DST
+  // offset which is one hour. Conveniently, if the function were
+  // someday modified to be DST aware, this test would have to be
+  // modified as well.
+  const time_t dst_time = 1180940400;  // Jun 4, 2007 0:00 PDT.
+  const time_t fudge = 3600;
+  int value1, value2;
+  EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(dst_time + fudge - 1), &value1));
+  EXPECT_TRUE(utils::ConvertToOmahaInstallDate(
+      base::Time::FromTimeT(dst_time + fudge), &value2));
+  EXPECT_EQ(value1, value2 - 7);
+}
+
+TEST(UtilsTest, WallclockDurationHelper) {
+  FakeSystemState fake_system_state;
+  FakeClock fake_clock;
+  base::TimeDelta duration;
+  string state_variable_key = "test-prefs";
+  FakePrefs fake_prefs;
+
+  fake_system_state.set_clock(&fake_clock);
+  fake_system_state.set_prefs(&fake_prefs);
+
+  // Initialize wallclock to 1 sec.
+  fake_clock.SetWallclockTime(base::Time::FromInternalValue(1000000));
+
+  // First time called so no previous measurement available.
+  EXPECT_FALSE(utils::WallclockDurationHelper(&fake_system_state,
+                                              state_variable_key,
+                                              &duration));
+
+  // Next time, we should get zero since the clock didn't advance.
+  EXPECT_TRUE(utils::WallclockDurationHelper(&fake_system_state,
+                                             state_variable_key,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+
+  // We can also call it as many times as we want with it being
+  // considered a failure.
+  EXPECT_TRUE(utils::WallclockDurationHelper(&fake_system_state,
+                                             state_variable_key,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+  EXPECT_TRUE(utils::WallclockDurationHelper(&fake_system_state,
+                                             state_variable_key,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+
+  // Advance the clock one second, then we should get 1 sec on the
+  // next call and 0 sec on the subsequent call.
+  fake_clock.SetWallclockTime(base::Time::FromInternalValue(2000000));
+  EXPECT_TRUE(utils::WallclockDurationHelper(&fake_system_state,
+                                             state_variable_key,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 1);
+  EXPECT_TRUE(utils::WallclockDurationHelper(&fake_system_state,
+                                             state_variable_key,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+
+  // Advance clock two seconds and we should get 2 sec and then 0 sec.
+  fake_clock.SetWallclockTime(base::Time::FromInternalValue(4000000));
+  EXPECT_TRUE(utils::WallclockDurationHelper(&fake_system_state,
+                                             state_variable_key,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 2);
+  EXPECT_TRUE(utils::WallclockDurationHelper(&fake_system_state,
+                                             state_variable_key,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+
+  // There's a possibility that the wallclock can go backwards (NTP
+  // adjustments, for example) so check that we properly handle this
+  // case.
+  fake_clock.SetWallclockTime(base::Time::FromInternalValue(3000000));
+  EXPECT_FALSE(utils::WallclockDurationHelper(&fake_system_state,
+                                              state_variable_key,
+                                              &duration));
+  fake_clock.SetWallclockTime(base::Time::FromInternalValue(4000000));
+  EXPECT_TRUE(utils::WallclockDurationHelper(&fake_system_state,
+                                             state_variable_key,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 1);
+}
+
+TEST(UtilsTest, MonotonicDurationHelper) {
+  int64_t storage = 0;
+  FakeSystemState fake_system_state;
+  FakeClock fake_clock;
+  base::TimeDelta duration;
+
+  fake_system_state.set_clock(&fake_clock);
+
+  // Initialize monotonic clock to 1 sec.
+  fake_clock.SetMonotonicTime(base::Time::FromInternalValue(1000000));
+
+  // First time called so no previous measurement available.
+  EXPECT_FALSE(utils::MonotonicDurationHelper(&fake_system_state,
+                                              &storage,
+                                              &duration));
+
+  // Next time, we should get zero since the clock didn't advance.
+  EXPECT_TRUE(utils::MonotonicDurationHelper(&fake_system_state,
+                                             &storage,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+
+  // We can also call it as many times as we want with it being
+  // considered a failure.
+  EXPECT_TRUE(utils::MonotonicDurationHelper(&fake_system_state,
+                                             &storage,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+  EXPECT_TRUE(utils::MonotonicDurationHelper(&fake_system_state,
+                                             &storage,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+
+  // Advance the clock one second, then we should get 1 sec on the
+  // next call and 0 sec on the subsequent call.
+  fake_clock.SetMonotonicTime(base::Time::FromInternalValue(2000000));
+  EXPECT_TRUE(utils::MonotonicDurationHelper(&fake_system_state,
+                                             &storage,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 1);
+  EXPECT_TRUE(utils::MonotonicDurationHelper(&fake_system_state,
+                                             &storage,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+
+  // Advance clock two seconds and we should get 2 sec and then 0 sec.
+  fake_clock.SetMonotonicTime(base::Time::FromInternalValue(4000000));
+  EXPECT_TRUE(utils::MonotonicDurationHelper(&fake_system_state,
+                                             &storage,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 2);
+  EXPECT_TRUE(utils::MonotonicDurationHelper(&fake_system_state,
+                                             &storage,
+                                             &duration));
+  EXPECT_EQ(duration.InSeconds(), 0);
+}
+
+TEST(UtilsTest, GetConnectionType) {
+  // Check that expected combinations map to the right value.
+  EXPECT_EQ(metrics::ConnectionType::kUnknown,
+            utils::GetConnectionType(NetworkConnectionType::kUnknown,
+                                     NetworkTethering::kUnknown));
+  EXPECT_EQ(metrics::ConnectionType::kEthernet,
+            utils::GetConnectionType(NetworkConnectionType::kEthernet,
+                                     NetworkTethering::kUnknown));
+  EXPECT_EQ(metrics::ConnectionType::kWifi,
+            utils::GetConnectionType(NetworkConnectionType::kWifi,
+                                     NetworkTethering::kUnknown));
+  EXPECT_EQ(metrics::ConnectionType::kWimax,
+            utils::GetConnectionType(NetworkConnectionType::kWimax,
+                                     NetworkTethering::kUnknown));
+  EXPECT_EQ(metrics::ConnectionType::kBluetooth,
+            utils::GetConnectionType(NetworkConnectionType::kBluetooth,
+                                     NetworkTethering::kUnknown));
+  EXPECT_EQ(metrics::ConnectionType::kCellular,
+            utils::GetConnectionType(NetworkConnectionType::kCellular,
+                                     NetworkTethering::kUnknown));
+  EXPECT_EQ(metrics::ConnectionType::kTetheredEthernet,
+            utils::GetConnectionType(NetworkConnectionType::kEthernet,
+                                     NetworkTethering::kConfirmed));
+  EXPECT_EQ(metrics::ConnectionType::kTetheredWifi,
+            utils::GetConnectionType(NetworkConnectionType::kWifi,
+                                     NetworkTethering::kConfirmed));
+
+  // Ensure that we don't report tethered ethernet unless it's confirmed.
+  EXPECT_EQ(metrics::ConnectionType::kEthernet,
+            utils::GetConnectionType(NetworkConnectionType::kEthernet,
+                                     NetworkTethering::kNotDetected));
+  EXPECT_EQ(metrics::ConnectionType::kEthernet,
+            utils::GetConnectionType(NetworkConnectionType::kEthernet,
+                                     NetworkTethering::kSuspected));
+  EXPECT_EQ(metrics::ConnectionType::kEthernet,
+            utils::GetConnectionType(NetworkConnectionType::kEthernet,
+                                     NetworkTethering::kUnknown));
+
+  // Ditto for tethered wifi.
+  EXPECT_EQ(metrics::ConnectionType::kWifi,
+            utils::GetConnectionType(NetworkConnectionType::kWifi,
+                                     NetworkTethering::kNotDetected));
+  EXPECT_EQ(metrics::ConnectionType::kWifi,
+            utils::GetConnectionType(NetworkConnectionType::kWifi,
+                                     NetworkTethering::kSuspected));
+  EXPECT_EQ(metrics::ConnectionType::kWifi,
+            utils::GetConnectionType(NetworkConnectionType::kWifi,
+                                     NetworkTethering::kUnknown));
+}
+
+TEST(UtilsTest, GetMinorVersion) {
+  // Test GetMinorVersion by verifying that it parses the conf file and returns
+  // the correct value.
+  uint32_t minor_version;
+
+  brillo::KeyValueStore store;
+  EXPECT_FALSE(utils::GetMinorVersion(store, &minor_version));
+
+  EXPECT_TRUE(store.LoadFromString("PAYLOAD_MINOR_VERSION=one-two-three\n"));
+  EXPECT_FALSE(utils::GetMinorVersion(store, &minor_version));
+
+  EXPECT_TRUE(store.LoadFromString("PAYLOAD_MINOR_VERSION=123\n"));
+  EXPECT_TRUE(utils::GetMinorVersion(store, &minor_version));
+  EXPECT_EQ(minor_version, 123);
+}
+
+static bool BoolMacroTestHelper() {
+  int i = 1;
+  unsigned int ui = 1;
+  bool b = 1;
+  std::unique_ptr<char> cptr(new char);
+
+  TEST_AND_RETURN_FALSE(i);
+  TEST_AND_RETURN_FALSE(ui);
+  TEST_AND_RETURN_FALSE(b);
+  TEST_AND_RETURN_FALSE(cptr);
+
+  TEST_AND_RETURN_FALSE_ERRNO(i);
+  TEST_AND_RETURN_FALSE_ERRNO(ui);
+  TEST_AND_RETURN_FALSE_ERRNO(b);
+  TEST_AND_RETURN_FALSE_ERRNO(cptr);
+
+  return true;
+}
+
+static void VoidMacroTestHelper(bool* ret) {
+  int i = 1;
+  unsigned int ui = 1;
+  bool b = 1;
+  std::unique_ptr<char> cptr(new char);
+
+  *ret = false;
+
+  TEST_AND_RETURN(i);
+  TEST_AND_RETURN(ui);
+  TEST_AND_RETURN(b);
+  TEST_AND_RETURN(cptr);
+
+  TEST_AND_RETURN_ERRNO(i);
+  TEST_AND_RETURN_ERRNO(ui);
+  TEST_AND_RETURN_ERRNO(b);
+  TEST_AND_RETURN_ERRNO(cptr);
+
+  *ret = true;
+}
+
+TEST(UtilsTest, TestMacros) {
+  bool void_test = false;
+  VoidMacroTestHelper(&void_test);
+  EXPECT_TRUE(void_test);
+
+  EXPECT_TRUE(BoolMacroTestHelper());
+}
+
+}  // namespace chromeos_update_engine