blob: 8ca6aa2469d7665f2eae042a2c9b89e7f05398c9 [file] [log] [blame]
// Copyright (c) 2013 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 "mist/usb_device_event_notifier.h"
#include <gtest/gtest.h>
#include "mist/event_dispatcher.h"
#include "mist/mock_udev.h"
#include "mist/mock_udev_device.h"
#include "mist/mock_udev_enumerate.h"
#include "mist/mock_udev_list_entry.h"
#include "mist/mock_udev_monitor.h"
#include "mist/mock_usb_device_event_observer.h"
using testing::InSequence;
using testing::Return;
using testing::StrEq;
using testing::_;
namespace mist {
namespace {
const int kFakeUdevMonitorFileDescriptor = 999;
const char kUdevActionAdd[] = "add";
const char kUdevActionChange[] = "change";
const char kUdevActionRemove[] = "remove";
const char kFakeUsbDevice1SysPath[] = "/sys/devices/fake/1";
const uint16_t kFakeUsbDevice1BusNumber = 1;
const char kFakeUsbDevice1BusNumberString[] = "1";
const uint16_t kFakeUsbDevice1DeviceAddress = 2;
const char kFakeUsbDevice1DeviceAddressString[] = "2";
const uint16_t kFakeUsbDevice1VendorId = 0x0123;
const char kFakeUsbDevice1VendorIdString[] = "0123";
const uint16_t kFakeUsbDevice1ProductId = 0x4567;
const char kFakeUsbDevice1ProductIdString[] = "4567";
const char kFakeUsbDevice2SysPath[] = "/sys/devices/fake/2";
const uint16_t kFakeUsbDevice2BusNumber = 3;
const char kFakeUsbDevice2BusNumberString[] = "3";
const uint16_t kFakeUsbDevice2DeviceAddress = 4;
const char kFakeUsbDevice2DeviceAddressString[] = "4";
const uint16_t kFakeUsbDevice2VendorId = 0x89ab;
const char kFakeUsbDevice2VendorIdString[] = "89ab";
const uint16_t kFakeUsbDevice2ProductId = 0xcdef;
const char kFakeUsbDevice2ProductIdString[] = "cdef";
} // namespace
class UsbDeviceEventNotifierTest : public testing::Test {
protected:
UsbDeviceEventNotifierTest() : notifier_(&dispatcher_, &udev_) {}
EventDispatcher dispatcher_;
MockUdev udev_;
MockUsbDeviceEventObserver observer_;
UsbDeviceEventNotifier notifier_;
};
TEST_F(UsbDeviceEventNotifierTest, ConvertNullToEmptyString) {
EXPECT_EQ("", UsbDeviceEventNotifier::ConvertNullToEmptyString(nullptr));
EXPECT_EQ("", UsbDeviceEventNotifier::ConvertNullToEmptyString(""));
EXPECT_EQ("a", UsbDeviceEventNotifier::ConvertNullToEmptyString("a"));
EXPECT_EQ("test string",
UsbDeviceEventNotifier::ConvertNullToEmptyString("test string"));
}
TEST_F(UsbDeviceEventNotifierTest, ConvertHexStringToUint16) {
uint16_t value = 0x0000;
EXPECT_FALSE(UsbDeviceEventNotifier::ConvertHexStringToUint16("", &value));
EXPECT_FALSE(UsbDeviceEventNotifier::ConvertHexStringToUint16("0", &value));
EXPECT_FALSE(UsbDeviceEventNotifier::ConvertHexStringToUint16("00", &value));
EXPECT_FALSE(UsbDeviceEventNotifier::ConvertHexStringToUint16("000", &value));
EXPECT_FALSE(
UsbDeviceEventNotifier::ConvertHexStringToUint16("00000", &value));
EXPECT_FALSE(
UsbDeviceEventNotifier::ConvertHexStringToUint16("000z", &value));
EXPECT_TRUE(UsbDeviceEventNotifier::ConvertHexStringToUint16("abcd", &value));
EXPECT_EQ(0xabcd, value);
EXPECT_TRUE(UsbDeviceEventNotifier::ConvertHexStringToUint16("0000", &value));
EXPECT_EQ(0x0000, value);
EXPECT_TRUE(UsbDeviceEventNotifier::ConvertHexStringToUint16("ffff", &value));
EXPECT_EQ(0xffff, value);
}
TEST_F(UsbDeviceEventNotifierTest, ConvertStringToUint8) {
uint8_t value = 0;
EXPECT_FALSE(UsbDeviceEventNotifier::ConvertStringToUint8("", &value));
EXPECT_FALSE(UsbDeviceEventNotifier::ConvertStringToUint8("z", &value));
EXPECT_FALSE(UsbDeviceEventNotifier::ConvertStringToUint8("-1", &value));
EXPECT_FALSE(UsbDeviceEventNotifier::ConvertStringToUint8("256", &value));
EXPECT_TRUE(UsbDeviceEventNotifier::ConvertStringToUint8("1", &value));
EXPECT_EQ(1, value);
EXPECT_TRUE(UsbDeviceEventNotifier::ConvertStringToUint8("0", &value));
EXPECT_EQ(0, value);
EXPECT_TRUE(UsbDeviceEventNotifier::ConvertStringToUint8("255", &value));
EXPECT_EQ(255, value);
}
TEST_F(UsbDeviceEventNotifierTest, GetDeviceAttributes) {
uint8_t bus_number;
uint8_t device_address;
uint16_t vendor_id;
uint16_t product_id;
// Invalid bus number.
MockUdevDevice device1;
EXPECT_CALL(device1, GetSysAttributeValue(_)).WillOnce(Return(""));
EXPECT_FALSE(UsbDeviceEventNotifier::GetDeviceAttributes(
&device1, &bus_number, &device_address, &vendor_id, &product_id));
// Invalid device address.
MockUdevDevice device2;
EXPECT_CALL(device2, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice1BusNumberString))
.WillOnce(Return(""));
EXPECT_FALSE(UsbDeviceEventNotifier::GetDeviceAttributes(
&device2, &bus_number, &device_address, &vendor_id, &product_id));
// Invalid vendor ID.
MockUdevDevice device3;
EXPECT_CALL(device3, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice1BusNumberString))
.WillOnce(Return(kFakeUsbDevice1DeviceAddressString))
.WillOnce(Return(""));
EXPECT_FALSE(UsbDeviceEventNotifier::GetDeviceAttributes(
&device3, &bus_number, &device_address, &vendor_id, &product_id));
// Invalid product ID.
MockUdevDevice device4;
EXPECT_CALL(device4, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice1BusNumberString))
.WillOnce(Return(kFakeUsbDevice1DeviceAddressString))
.WillOnce(Return(kFakeUsbDevice1VendorIdString))
.WillOnce(Return(""));
EXPECT_FALSE(UsbDeviceEventNotifier::GetDeviceAttributes(
&device4, &bus_number, &device_address, &vendor_id, &product_id));
// Valid bus number, device address, vendor ID, and product ID.
MockUdevDevice device5;
EXPECT_CALL(device5, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice1BusNumberString))
.WillOnce(Return(kFakeUsbDevice1DeviceAddressString))
.WillOnce(Return(kFakeUsbDevice1VendorIdString))
.WillOnce(Return(kFakeUsbDevice1ProductIdString));
EXPECT_TRUE(UsbDeviceEventNotifier::GetDeviceAttributes(
&device5, &bus_number, &device_address, &vendor_id, &product_id));
EXPECT_EQ(kFakeUsbDevice1BusNumber, bus_number);
EXPECT_EQ(kFakeUsbDevice1DeviceAddress, device_address);
EXPECT_EQ(kFakeUsbDevice1VendorId, vendor_id);
EXPECT_EQ(kFakeUsbDevice1ProductId, product_id);
}
TEST_F(UsbDeviceEventNotifierTest, OnUsbDeviceEvents) {
MockUdevMonitor* monitor = new MockUdevMonitor();
// Ownership of |monitor| is transferred.
notifier_.udev_monitor_.reset(monitor);
MockUdevDevice* device1 = new MockUdevDevice();
MockUdevDevice* device2 = new MockUdevDevice();
MockUdevDevice* device3 = new MockUdevDevice();
MockUdevDevice* device4 = new MockUdevDevice();
// Ownership of |device*| is transferred.
EXPECT_CALL(*monitor, ReceiveDevice())
.WillOnce(Return(device1))
.WillOnce(Return(device2))
.WillOnce(Return(device3))
.WillOnce(Return(device4));
EXPECT_CALL(*device1, GetSysPath()).WillOnce(Return(kFakeUsbDevice1SysPath));
EXPECT_CALL(*device1, GetAction()).WillOnce(Return(kUdevActionAdd));
EXPECT_CALL(*device2, GetSysPath()).WillOnce(Return(kFakeUsbDevice2SysPath));
EXPECT_CALL(*device2, GetAction()).WillOnce(Return(kUdevActionAdd));
EXPECT_CALL(*device2, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice2BusNumberString))
.WillOnce(Return(kFakeUsbDevice2DeviceAddressString))
.WillOnce(Return(kFakeUsbDevice2VendorIdString))
.WillOnce(Return(kFakeUsbDevice2ProductIdString));
EXPECT_CALL(*device3, GetSysPath()).WillOnce(Return(kFakeUsbDevice1SysPath));
EXPECT_CALL(*device3, GetAction()).WillOnce(Return(kUdevActionRemove));
EXPECT_CALL(*device4, GetSysPath()).WillOnce(Return(kFakeUsbDevice2SysPath));
EXPECT_CALL(*device4, GetAction()).WillOnce(Return(kUdevActionRemove));
EXPECT_CALL(observer_,
OnUsbDeviceAdded(kFakeUsbDevice2SysPath,
kFakeUsbDevice2BusNumber,
kFakeUsbDevice2DeviceAddress,
kFakeUsbDevice2VendorId,
kFakeUsbDevice2ProductId));
EXPECT_CALL(observer_, OnUsbDeviceRemoved(kFakeUsbDevice1SysPath));
notifier_.OnFileCanReadWithoutBlocking(kFakeUdevMonitorFileDescriptor);
notifier_.AddObserver(&observer_);
notifier_.OnFileCanReadWithoutBlocking(kFakeUdevMonitorFileDescriptor);
notifier_.OnFileCanReadWithoutBlocking(kFakeUdevMonitorFileDescriptor);
notifier_.RemoveObserver(&observer_);
notifier_.OnFileCanReadWithoutBlocking(kFakeUdevMonitorFileDescriptor);
}
TEST_F(UsbDeviceEventNotifierTest, OnUsbDeviceEventNotAddOrRemove) {
MockUdevMonitor* monitor = new MockUdevMonitor();
// Ownership of |monitor| is transferred.
notifier_.udev_monitor_.reset(monitor);
MockUdevDevice* device = new MockUdevDevice();
// Ownership of |device| is transferred.
EXPECT_CALL(*monitor, ReceiveDevice()).WillOnce(Return(device));
EXPECT_CALL(*device, GetSysPath()).WillOnce(Return(kFakeUsbDevice1SysPath));
EXPECT_CALL(*device, GetAction()).WillOnce(Return(kUdevActionChange));
EXPECT_CALL(observer_, OnUsbDeviceAdded(_, _, _, _, _)).Times(0);
EXPECT_CALL(observer_, OnUsbDeviceRemoved(_)).Times(0);
notifier_.AddObserver(&observer_);
notifier_.OnFileCanReadWithoutBlocking(kFakeUdevMonitorFileDescriptor);
}
TEST_F(UsbDeviceEventNotifierTest, OnUsbDeviceEventWithInvalidBusNumber) {
MockUdevMonitor* monitor = new MockUdevMonitor();
// Ownership of |monitor| is transferred.
notifier_.udev_monitor_.reset(monitor);
MockUdevDevice* device = new MockUdevDevice();
// Ownership of |device| is transferred.
EXPECT_CALL(*monitor, ReceiveDevice()).WillOnce(Return(device));
EXPECT_CALL(*device, GetSysPath()).WillOnce(Return(kFakeUsbDevice1SysPath));
EXPECT_CALL(*device, GetAction()).WillOnce(Return(kUdevActionAdd));
EXPECT_CALL(*device, GetSysAttributeValue(_)).WillOnce(Return(""));
EXPECT_CALL(observer_, OnUsbDeviceAdded(_, _, _, _, _)).Times(0);
EXPECT_CALL(observer_, OnUsbDeviceRemoved(_)).Times(0);
notifier_.AddObserver(&observer_);
notifier_.OnFileCanReadWithoutBlocking(kFakeUdevMonitorFileDescriptor);
}
TEST_F(UsbDeviceEventNotifierTest, OnUsbDeviceEventWithInvalidDeviceAddress) {
MockUdevMonitor* monitor = new MockUdevMonitor();
// Ownership of |monitor| is transferred.
notifier_.udev_monitor_.reset(monitor);
MockUdevDevice* device = new MockUdevDevice();
// Ownership of |device| is transferred.
EXPECT_CALL(*monitor, ReceiveDevice()).WillOnce(Return(device));
EXPECT_CALL(*device, GetSysPath()).WillOnce(Return(kFakeUsbDevice1SysPath));
EXPECT_CALL(*device, GetAction()).WillOnce(Return(kUdevActionAdd));
EXPECT_CALL(*device, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice1BusNumberString))
.WillOnce(Return(""));
EXPECT_CALL(observer_, OnUsbDeviceAdded(_, _, _, _, _)).Times(0);
EXPECT_CALL(observer_, OnUsbDeviceRemoved(_)).Times(0);
notifier_.AddObserver(&observer_);
notifier_.OnFileCanReadWithoutBlocking(kFakeUdevMonitorFileDescriptor);
}
TEST_F(UsbDeviceEventNotifierTest, OnUsbDeviceEventWithInvalidVendorId) {
MockUdevMonitor* monitor = new MockUdevMonitor();
// Ownership of |monitor| is transferred.
notifier_.udev_monitor_.reset(monitor);
MockUdevDevice* device = new MockUdevDevice();
// Ownership of |device| is transferred.
EXPECT_CALL(*monitor, ReceiveDevice()).WillOnce(Return(device));
EXPECT_CALL(*device, GetSysPath()).WillOnce(Return(kFakeUsbDevice1SysPath));
EXPECT_CALL(*device, GetAction()).WillOnce(Return(kUdevActionAdd));
EXPECT_CALL(*device, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice1BusNumberString))
.WillOnce(Return(kFakeUsbDevice1DeviceAddressString))
.WillOnce(Return(""));
EXPECT_CALL(observer_, OnUsbDeviceAdded(_, _, _, _, _)).Times(0);
EXPECT_CALL(observer_, OnUsbDeviceRemoved(_)).Times(0);
notifier_.AddObserver(&observer_);
notifier_.OnFileCanReadWithoutBlocking(kFakeUdevMonitorFileDescriptor);
}
TEST_F(UsbDeviceEventNotifierTest, OnUsbDeviceEventWithInvalidProductId) {
MockUdevMonitor* monitor = new MockUdevMonitor();
// Ownership of |monitor| is transferred.
notifier_.udev_monitor_.reset(monitor);
MockUdevDevice* device = new MockUdevDevice();
// Ownership of |device| is transferred.
EXPECT_CALL(*monitor, ReceiveDevice()).WillOnce(Return(device));
EXPECT_CALL(*device, GetSysPath()).WillOnce(Return(kFakeUsbDevice1SysPath));
EXPECT_CALL(*device, GetAction()).WillOnce(Return(kUdevActionAdd));
EXPECT_CALL(*device, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice1BusNumberString))
.WillOnce(Return(kFakeUsbDevice1DeviceAddressString))
.WillOnce(Return(kFakeUsbDevice1VendorIdString))
.WillOnce(Return(""));
EXPECT_CALL(observer_, OnUsbDeviceAdded(_, _, _, _, _)).Times(0);
EXPECT_CALL(observer_, OnUsbDeviceRemoved(_)).Times(0);
notifier_.AddObserver(&observer_);
notifier_.OnFileCanReadWithoutBlocking(kFakeUdevMonitorFileDescriptor);
}
TEST_F(UsbDeviceEventNotifierTest, ScanExistingDevices) {
// Ownership of |enumerate|, |list_entry*|, and |device*| is transferred
// to and managed inside ScanExistingDevices().
MockUdevEnumerate* enumerate = new MockUdevEnumerate();
MockUdevListEntry* list_entry1 = new MockUdevListEntry();
MockUdevListEntry* list_entry2 = new MockUdevListEntry();
MockUdevDevice* device1 = new MockUdevDevice();
MockUdevDevice* device2 = new MockUdevDevice();
EXPECT_CALL(udev_, CreateEnumerate()).WillOnce(Return(enumerate));
EXPECT_CALL(*enumerate,
AddMatchSubsystem(StrEq("usb"))).WillOnce(Return(true));
EXPECT_CALL(*enumerate,
AddMatchProperty(StrEq("DEVTYPE"), StrEq("usb_device")))
.WillOnce(Return(true));
EXPECT_CALL(*enumerate, ScanDevices()).WillOnce(Return(true));
EXPECT_CALL(*enumerate, GetListEntry()).WillOnce(Return(list_entry1));
EXPECT_CALL(*list_entry1, GetName()).WillOnce(Return(kFakeUsbDevice1SysPath));
EXPECT_CALL(*list_entry1, GetNext()).WillOnce(Return(list_entry2));
EXPECT_CALL(*list_entry2, GetName()).WillOnce(Return(kFakeUsbDevice2SysPath));
EXPECT_CALL(*list_entry2, GetNext())
.WillOnce(Return(static_cast<UdevListEntry*>(nullptr)));
EXPECT_CALL(udev_, CreateDeviceFromSysPath(_))
.WillOnce(Return(device1))
.WillOnce(Return(device2));
EXPECT_CALL(*device1, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice1BusNumberString))
.WillOnce(Return(kFakeUsbDevice1DeviceAddressString))
.WillOnce(Return(kFakeUsbDevice1VendorIdString))
.WillOnce(Return(kFakeUsbDevice1ProductIdString));
EXPECT_CALL(*device2, GetSysAttributeValue(_))
.WillOnce(Return(kFakeUsbDevice2BusNumberString))
.WillOnce(Return(kFakeUsbDevice2DeviceAddressString))
.WillOnce(Return(kFakeUsbDevice2VendorIdString))
.WillOnce(Return(kFakeUsbDevice2ProductIdString));
InSequence sequence;
EXPECT_CALL(observer_,
OnUsbDeviceAdded(kFakeUsbDevice1SysPath,
kFakeUsbDevice1BusNumber,
kFakeUsbDevice1DeviceAddress,
kFakeUsbDevice1VendorId,
kFakeUsbDevice1ProductId));
EXPECT_CALL(observer_,
OnUsbDeviceAdded(kFakeUsbDevice2SysPath,
kFakeUsbDevice2BusNumber,
kFakeUsbDevice2DeviceAddress,
kFakeUsbDevice2VendorId,
kFakeUsbDevice2ProductId));
EXPECT_CALL(observer_, OnUsbDeviceRemoved(_)).Times(0);
notifier_.AddObserver(&observer_);
notifier_.ScanExistingDevices();
}
} // namespace mist