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