blob: f3af9aceecde98e02c1a492a58fca93293b43c32 [file] [log] [blame]
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cros-disks/udev_device.h"
#include <utility>
#include <base/logging.h>
#include <brillo/udev/mock_udev_device.h>
#include <brillo/udev/udev.h>
#include <brillo/udev/udev_device.h>
#include <brillo/udev/udev_enumerate.h>
#include <brillo/udev/udev_monitor.h>
#include <gtest/gtest.h>
#include <linux/limits.h>
#include <rootdev/rootdev.h>
namespace cros_disks {
namespace {
using ::testing::Return;
using ::testing::StrictMock;
const char kLoopDevicePrefix[] = "/dev/loop";
const char kRamDeviceFile[] = "/dev/ram0";
const char kZRamDeviceFile[] = "/dev/zram0";
} // namespace
class UdevDeviceTest : public ::testing::Test {
protected:
void SetUp() override {
udev_ = brillo::Udev::Create();
if (!udev_)
return;
std::string boot_device_path = GetBootDevicePath();
auto enumerate = udev_->CreateEnumerate();
enumerate->AddMatchSubsystem("block");
ASSERT_TRUE(enumerate->ScanDevices());
for (auto entry = enumerate->GetListEntry(); entry;
entry = entry->GetNext()) {
const char* path = entry->GetName();
auto device = udev_->CreateDeviceFromSysPath(path);
if (!device)
continue;
const char* device_file = device->GetDeviceNode();
if (!device_file)
continue;
if (!boot_device_ && !boot_device_path.empty() &&
boot_device_path == device_file) {
boot_device_ = udev_->CreateDeviceFromSysPath(path);
// Check if the boot device is also mounted. If so, use it for tests
// that expect a mounted device since the boot device is unlikely to
// be unmounted during the tests.
std::vector<std::string> mount_paths =
UdevDevice::GetMountPaths(device_file);
if (!mounted_device_ && !mount_paths.empty()) {
mounted_device_ = udev_->CreateDeviceFromSysPath(path);
}
}
if (!loop_device_ && device_file != boot_device_path &&
strncmp(device_file, kLoopDevicePrefix, strlen(kLoopDevicePrefix)) ==
0) {
loop_device_ = udev_->CreateDeviceFromSysPath(path);
}
if (!ram_device_ && (strcmp(device_file, kRamDeviceFile) == 0 ||
strcmp(device_file, kZRamDeviceFile) == 0)) {
ram_device_ = udev_->CreateDeviceFromSysPath(path);
}
if (!partitioned_device_) {
const char* device_type = device->GetDeviceType();
if (device_type && strcmp(device_type, "partition") == 0) {
partitioned_device_ = device->GetParent();
}
}
}
}
static std::string GetBootDevicePath() {
char boot_device_path[PATH_MAX];
if (rootdev(boot_device_path, sizeof(boot_device_path), true, true) == 0)
return boot_device_path;
return std::string();
}
std::unique_ptr<brillo::Udev> udev_;
std::unique_ptr<brillo::UdevDevice> boot_device_;
std::unique_ptr<brillo::UdevDevice> loop_device_;
std::unique_ptr<brillo::UdevDevice> ram_device_;
std::unique_ptr<brillo::UdevDevice> mounted_device_;
std::unique_ptr<brillo::UdevDevice> partitioned_device_;
};
TEST_F(UdevDeviceTest, EnsureUTF8String) {
// Valid UTF8
EXPECT_EQ("ascii", UdevDevice::EnsureUTF8String("ascii"));
EXPECT_EQ("\xc2\x81", UdevDevice::EnsureUTF8String("\xc2\x81"));
// Invalid UTF8: overlong sequences
EXPECT_EQ("", UdevDevice::EnsureUTF8String("\xc0\x80")); // U+0000
}
TEST_F(UdevDeviceTest, IsValueBooleanTrue) {
EXPECT_FALSE(UdevDevice::IsValueBooleanTrue(nullptr));
EXPECT_FALSE(UdevDevice::IsValueBooleanTrue(""));
EXPECT_FALSE(UdevDevice::IsValueBooleanTrue("0"));
EXPECT_FALSE(UdevDevice::IsValueBooleanTrue("test"));
EXPECT_TRUE(UdevDevice::IsValueBooleanTrue("1"));
}
TEST_F(UdevDeviceTest, IsAttributeTrueForNonexistentAttribute) {
auto dev = std::make_unique<StrictMock<brillo::MockUdevDevice>>();
EXPECT_CALL(*dev, GetSysAttributeValue("nonexistent-attribute"))
.WillOnce(Return(nullptr));
UdevDevice device(std::move(dev));
EXPECT_FALSE(device.IsAttributeTrue("nonexistent-attribute"));
}
TEST_F(UdevDeviceTest, HasAttributeForExistentAttribute) {
if (mounted_device_) {
UdevDevice device(std::move(mounted_device_));
EXPECT_TRUE(device.HasAttribute("stat"));
EXPECT_TRUE(device.HasAttribute("size"));
}
}
TEST_F(UdevDeviceTest, GetAttributeForExistentAttribute) {
if (mounted_device_) {
UdevDevice device(std::move(mounted_device_));
EXPECT_NE("", device.GetAttribute("size"));
}
}
TEST_F(UdevDeviceTest, GetAttributeForNonexistentAttribute) {
auto dev = std::make_unique<StrictMock<brillo::MockUdevDevice>>();
EXPECT_CALL(*dev, GetSysAttributeValue("nonexistent-attribute"))
.WillOnce(Return(nullptr));
UdevDevice device(std::move(dev));
EXPECT_EQ("", device.GetAttribute("nonexistent-attribute"));
}
TEST_F(UdevDeviceTest, HasAttributeForNonexistentAttribute) {
auto dev = std::make_unique<StrictMock<brillo::MockUdevDevice>>();
EXPECT_CALL(*dev, GetSysAttributeValue("nonexistent-attribute"))
.WillOnce(Return(nullptr));
UdevDevice device(std::move(dev));
EXPECT_FALSE(device.HasAttribute("nonexistent-attribute"));
}
TEST_F(UdevDeviceTest, IsPropertyTrueForNonexistentProperty) {
auto dev = std::make_unique<StrictMock<brillo::MockUdevDevice>>();
EXPECT_CALL(*dev, GetPropertyValue("nonexistent-property"))
.WillOnce(Return(nullptr));
UdevDevice device(std::move(dev));
EXPECT_FALSE(device.IsPropertyTrue("nonexistent-property"));
}
TEST_F(UdevDeviceTest, GetPropertyForExistentProperty) {
if (mounted_device_) {
UdevDevice device(std::move(mounted_device_));
EXPECT_NE("", device.GetProperty("DEVTYPE"));
}
}
TEST_F(UdevDeviceTest, GetPropertyForNonexistentProperty) {
auto dev = std::make_unique<StrictMock<brillo::MockUdevDevice>>();
EXPECT_CALL(*dev, GetPropertyValue("nonexistent-property"))
.WillOnce(Return(nullptr));
UdevDevice device(std::move(dev));
EXPECT_EQ("", device.GetProperty("nonexistent-property"));
}
TEST_F(UdevDeviceTest, HasPropertyForExistentProperty) {
if (mounted_device_) {
UdevDevice device(std::move(mounted_device_));
EXPECT_TRUE(device.HasProperty("DEVTYPE"));
EXPECT_TRUE(device.HasProperty("DEVNAME"));
}
}
TEST_F(UdevDeviceTest, HasPropertyForNonexistentProperty) {
auto dev = std::make_unique<StrictMock<brillo::MockUdevDevice>>();
EXPECT_CALL(*dev, GetPropertyValue("nonexistent-property"))
.WillOnce(Return(nullptr));
UdevDevice device(std::move(dev));
EXPECT_FALSE(device.HasProperty("nonexistent-property"));
}
TEST_F(UdevDeviceTest, GetPropertyFromBlkIdForNonexistentProperty) {
if (mounted_device_) {
UdevDevice device(std::move(mounted_device_));
EXPECT_EQ("", device.GetPropertyFromBlkId("nonexistent-property"));
}
}
TEST_F(UdevDeviceTest, GetPartitionCount) {
if (partitioned_device_) {
UdevDevice device(std::move(partitioned_device_));
EXPECT_NE(0, device.GetPartitionCount());
}
}
TEST_F(UdevDeviceTest, IsAutoMountable) {
if (boot_device_) {
UdevDevice device(std::move(boot_device_));
EXPECT_FALSE(device.IsAutoMountable());
}
if (loop_device_) {
UdevDevice device(std::move(loop_device_));
EXPECT_FALSE(device.IsAutoMountable());
}
}
TEST_F(UdevDeviceTest, IsIgnored) {
if (boot_device_) {
UdevDevice device(std::move(boot_device_));
EXPECT_FALSE(device.IsIgnored());
}
if (loop_device_) {
UdevDevice device(std::move(loop_device_));
EXPECT_FALSE(device.IsIgnored());
}
if (ram_device_) {
UdevDevice device(std::move(ram_device_));
EXPECT_TRUE(device.IsIgnored());
}
}
TEST_F(UdevDeviceTest, IsOnBootDevice) {
if (boot_device_) {
UdevDevice device(std::move(boot_device_));
EXPECT_TRUE(device.IsOnBootDevice());
}
#if 0
// TODO(benchan): Re-enable this test case after figuring out why it fails on
// some buildbot (chromium:866231).
if (loop_device_) {
UdevDevice device(std::move(loop_device_));
EXPECT_FALSE(device.IsOnBootDevice());
}
#endif
}
TEST_F(UdevDeviceTest, IsOnRemovableDevice) {
if (loop_device_) {
UdevDevice device(std::move(loop_device_));
EXPECT_FALSE(device.IsOnRemovableDevice());
}
}
TEST_F(UdevDeviceTest, IsMediaAvailable) {
if (mounted_device_) {
UdevDevice device(std::move(mounted_device_));
EXPECT_TRUE(device.IsMediaAvailable());
}
}
TEST_F(UdevDeviceTest, IsMobileBroadbandDevice) {
if (boot_device_) {
UdevDevice device(std::move(boot_device_));
EXPECT_FALSE(device.IsMobileBroadbandDevice());
}
if (loop_device_) {
UdevDevice device(std::move(loop_device_));
EXPECT_FALSE(device.IsMobileBroadbandDevice());
}
}
TEST_F(UdevDeviceTest, IsVirtual) {
if (loop_device_) {
UdevDevice device(std::move(loop_device_));
EXPECT_TRUE(device.IsVirtual());
}
if (ram_device_) {
UdevDevice device(std::move(ram_device_));
EXPECT_TRUE(device.IsVirtual());
}
}
TEST_F(UdevDeviceTest, IsLoopDevice) {
if (loop_device_) {
UdevDevice device(std::move(loop_device_));
EXPECT_TRUE(device.IsLoopDevice());
}
if (ram_device_) {
UdevDevice device(std::move(ram_device_));
EXPECT_FALSE(device.IsLoopDevice());
}
}
TEST_F(UdevDeviceTest, GetSizeInfo) {
if (mounted_device_) {
UdevDevice device(std::move(mounted_device_));
uint64_t total_size = 0, remaining_size = 0;
device.GetSizeInfo(&total_size, &remaining_size);
LOG(INFO) << "GetSizeInfo: total=" << total_size
<< ", remaining=" << remaining_size;
EXPECT_GT(total_size, 0);
}
}
TEST_F(UdevDeviceTest, GetMountPaths) {
if (mounted_device_) {
UdevDevice device(std::move(mounted_device_));
std::vector<std::string> mount_paths = device.GetMountPaths();
EXPECT_FALSE(mount_paths.empty());
}
}
TEST_F(UdevDeviceTest, ToDisk) {
if (boot_device_) {
UdevDevice device(std::move(boot_device_));
Disk disk = device.ToDisk();
EXPECT_FALSE(disk.is_auto_mountable);
EXPECT_TRUE(disk.is_on_boot_device);
}
if (loop_device_) {
UdevDevice device(std::move(loop_device_));
Disk disk = device.ToDisk();
EXPECT_FALSE(disk.is_auto_mountable);
EXPECT_TRUE(disk.is_virtual);
EXPECT_EQ(kLoopDevicePrefix,
disk.device_file.substr(0, strlen(kLoopDevicePrefix)));
}
if (mounted_device_) {
UdevDevice device(std::move(mounted_device_));
Disk disk = device.ToDisk();
EXPECT_TRUE(disk.IsMounted());
EXPECT_FALSE(disk.mount_paths.empty());
}
}
} // namespace cros_disks