| // Copyright 2022 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 "permission_broker/usb_driver_tracker.h" |
| |
| #include <string> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <gtest/gtest-death-test.h> |
| |
| #include <base/containers/contains.h> |
| #include <base/files/file_descriptor_watcher_posix.h> |
| #include <base/files/file_util.h> |
| #include <base/files/scoped_file.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/test/task_environment.h> |
| |
| using ::testing::DoAll; |
| using ::testing::Return; |
| |
| namespace permission_broker { |
| |
| namespace { |
| |
| static constexpr int kMaxNumClients = 2; |
| static constexpr uint8_t kIface0 = 0; |
| static constexpr uint8_t kIface1 = 1; |
| static constexpr uint8_t kIface2 = 2; |
| static constexpr int kClient0 = 0; |
| static constexpr int kClient1 = 1; |
| |
| ACTION_P(QuitRunLoop, run_loop) { |
| run_loop->Quit(); |
| } |
| |
| } // namespace |
| |
| class MockUsbDriverTracker : public UsbDriverTracker { |
| public: |
| MockUsbDriverTracker() { |
| ON_CALL(*this, WatchLifelineFd) |
| .WillByDefault([this](const std::string& client_id, int lifeline_fd) { |
| // The injection for WatchLifelineFd is not only for mocking return |
| // null case, but also to register HandleClosedFd with mock object so |
| // mocked methods can be called when HandleClosedFd is invoked when |
| // lifeline_fd closes. |
| return base::FileDescriptorWatcher::WatchReadable( |
| lifeline_fd, |
| base::BindRepeating(&UsbDriverTracker::HandleClosedFd, |
| weak_ptr_factory_.GetWeakPtr(), client_id)); |
| }); |
| ON_CALL(*this, ConnectInterface).WillByDefault(Return(true)); |
| ON_CALL(*this, DisconnectInterface).WillByDefault(Return(true)); |
| } |
| MockUsbDriverTracker(const MockUsbDriverTracker&) = delete; |
| MockUsbDriverTracker& operator=(const MockUsbDriverTracker&) = delete; |
| ~MockUsbDriverTracker() override = default; |
| |
| MOCK_METHOD(std::unique_ptr<base::FileDescriptorWatcher::Controller>, |
| WatchLifelineFd, |
| (const std::string&, int), |
| (override)); |
| MOCK_METHOD(bool, DisconnectInterface, (int, uint8_t), (override)); |
| MOCK_METHOD(bool, ConnectInterface, (int, uint8_t), (override)); |
| }; |
| |
| class UsbDriverTrackerTest : public testing::Test { |
| public: |
| UsbDriverTrackerTest() = default; |
| UsbDriverTrackerTest(const UsbDriverTrackerTest&) = delete; |
| UsbDriverTrackerTest& operator=(const UsbDriverTrackerTest&) = delete; |
| ~UsbDriverTrackerTest() override = default; |
| |
| void SetUp() override { |
| ASSERT_TRUE(CreateTemporaryFile(&temp_file_path_)); |
| for (int client = 0; client < kMaxNumClients; client++) { |
| ASSERT_TRUE(base::CreatePipe(/*read_fd*/ &pipe_fds_[client][0], |
| /*write_fd*/ &pipe_fds_[client][1], |
| /*non_blocking*/ true)); |
| } |
| } |
| |
| void TearDown() override { |
| testing::Mock::VerifyAndClearExpectations(&usb_driver_tracker_); |
| // Doing this to use mock CleanUpTracking to avoid warning message of |
| // connect ioctl() failure from the destructor when there is left record in |
| // the end of the test. |
| usb_driver_tracker_.CleanUpTracking(); |
| } |
| |
| std::string SetupClient(int client, |
| const base::FilePath& path, |
| std::vector<uint8_t>& ifaces) { |
| EXPECT_LT(client, kMaxNumClients); |
| return SetupClientWithLifelineFd(pipe_fds_[client][0].get(), path, ifaces); |
| } |
| |
| std::string SetupClientWithLifelineFd(int lifeline_fd, |
| const base::FilePath& path, |
| std::vector<uint8_t>& ifaces) { |
| EXPECT_CALL(usb_driver_tracker_, WatchLifelineFd).Times(1); |
| |
| auto maybe_client_id = |
| usb_driver_tracker_.RegisterClient(lifeline_fd, path); |
| EXPECT_TRUE(maybe_client_id.has_value()); |
| |
| const auto& client_id = maybe_client_id.value(); |
| EXPECT_EQ(client_id.size(), 32); // hex representation of a 128-bit token. |
| EXPECT_TRUE(base::Contains(usb_driver_tracker_.dev_fds_, client_id)); |
| EXPECT_EQ(usb_driver_tracker_.dev_fds_[client_id].path, path); |
| |
| for (auto iface : ifaces) { |
| usb_driver_tracker_.dev_fds_[client_id].interfaces.push_back(iface); |
| usb_driver_tracker_.dev_ifaces_[path][iface] = client_id; |
| } |
| |
| return client_id; |
| } |
| |
| protected: |
| testing::NiceMock<MockUsbDriverTracker> usb_driver_tracker_; |
| base::ScopedFD pipe_fds_[kMaxNumClients][2]; |
| base::FilePath temp_file_path_; |
| |
| private: |
| base::test::TaskEnvironment task_environment_ = base::test::TaskEnvironment( |
| base::test::TaskEnvironment::MainThreadType::IO); |
| }; |
| |
| class UsbDriverTrackerDeathTest : public UsbDriverTrackerTest { |
| public: |
| void SetUp() override { |
| testing::FLAGS_gtest_death_test_style = "threadsafe"; |
| UsbDriverTrackerTest::SetUp(); |
| } |
| }; |
| |
| TEST_F(UsbDriverTrackerTest, RegisterClientSuccess) { |
| std::vector<uint8_t> client_0_ifaces = {}; |
| const auto& path = temp_file_path_; |
| SetupClient(kClient0, path, client_0_ifaces); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, RegisterClientOpenPathFail) { |
| auto path = base::FilePath("notexist"); |
| auto maybe_client_id = |
| usb_driver_tracker_.RegisterClient(pipe_fds_[kClient0][0].get(), path); |
| ASSERT_FALSE(maybe_client_id.has_value()); |
| ASSERT_EQ(0, usb_driver_tracker_.dev_fds_.size()); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, RegisterClientDupLifelineFdFail) { |
| const auto& path = temp_file_path_; |
| auto maybe_client_id = usb_driver_tracker_.RegisterClient(-1, path); |
| ASSERT_FALSE(maybe_client_id.has_value()); |
| ASSERT_EQ(0, usb_driver_tracker_.dev_fds_.size()); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, RegisterClientWatchLifelineFdFail) { |
| const auto& path = temp_file_path_; |
| EXPECT_CALL(usb_driver_tracker_, WatchLifelineFd) |
| .WillOnce(Return(testing::ByMove(nullptr))); |
| auto maybe_client_id = |
| usb_driver_tracker_.RegisterClient(pipe_fds_[kClient0][0].get(), path); |
| ASSERT_FALSE(maybe_client_id.has_value()); |
| ASSERT_EQ(0, usb_driver_tracker_.dev_fds_.size()); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, RegisterClientDifferentIds) { |
| std::vector<uint8_t> client_0_ifaces = {}; |
| std::vector<uint8_t> client_1_ifaces = {}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| auto client_1_id = SetupClient(kClient1, path, client_1_ifaces); |
| ASSERT_NE(client_0_id, client_1_id); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, CleanUpTracking) { |
| std::vector<uint8_t> client_0_ifaces = {kIface0}; |
| std::vector<uint8_t> client_1_ifaces = {kIface1}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| auto client_1_id = SetupClient(kClient1, path, client_1_ifaces); |
| EXPECT_CALL(usb_driver_tracker_, |
| ConnectInterface( |
| usb_driver_tracker_.dev_fds_[client_0_id].fd.get(), kIface0)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(usb_driver_tracker_, |
| ConnectInterface( |
| usb_driver_tracker_.dev_fds_[client_1_id].fd.get(), kIface1)) |
| .WillOnce(Return(true)); |
| usb_driver_tracker_.CleanUpTracking(); |
| ASSERT_EQ(usb_driver_tracker_.dev_fds_.size(), 0); |
| ASSERT_FALSE(base::Contains(usb_driver_tracker_.dev_ifaces_, path)); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, CleanUpTrackingConnectInterfaceFail) { |
| std::vector<uint8_t> client_0_ifaces = {kIface0}; |
| std::vector<uint8_t> client_1_ifaces = {kIface1}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| auto client_1_id = SetupClient(kClient1, path, client_1_ifaces); |
| EXPECT_CALL(usb_driver_tracker_, |
| ConnectInterface( |
| usb_driver_tracker_.dev_fds_[client_0_id].fd.get(), kIface0)) |
| .WillOnce(Return(false)); |
| EXPECT_CALL(usb_driver_tracker_, |
| ConnectInterface( |
| usb_driver_tracker_.dev_fds_[client_1_id].fd.get(), kIface1)) |
| .WillOnce(Return(false)); |
| usb_driver_tracker_.CleanUpTracking(); |
| // Even reattach IOCTL fails, the client's tracking should be cleared. |
| ASSERT_EQ(usb_driver_tracker_.dev_fds_.size(), 0); |
| ASSERT_FALSE(base::Contains(usb_driver_tracker_.dev_ifaces_, path)); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, HandleClosedFd) { |
| base::RunLoop run_loop; |
| std::vector<uint8_t> client_0_ifaces = {kIface0, kIface1, kIface2}; |
| std::string client_0_id; |
| const auto& path = temp_file_path_; |
| |
| { |
| base::ScopedFD pipe_fds[2]; |
| ASSERT_TRUE(base::CreatePipe(/*read_fd*/ &pipe_fds[0], |
| /*write_fd*/ &pipe_fds[1], |
| /*non_blocking*/ true)); |
| client_0_id = |
| SetupClientWithLifelineFd(pipe_fds[0].get(), path, client_0_ifaces); |
| for (auto iface : client_0_ifaces) { |
| EXPECT_CALL( |
| usb_driver_tracker_, |
| ConnectInterface(usb_driver_tracker_.dev_fds_[client_0_id].fd.get(), |
| iface)) |
| .WillOnce(DoAll(QuitRunLoop(&run_loop), Return(true))); |
| } |
| } |
| run_loop.Run(); |
| ASSERT_FALSE(usb_driver_tracker_.IsClientIdTracked(client_0_id)); |
| ASSERT_FALSE(base::Contains(usb_driver_tracker_.dev_ifaces_, path)); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, HandleClosedFdConnectInterfaceError) { |
| base::RunLoop run_loop; |
| std::vector<uint8_t> client_0_ifaces = {kIface0}; |
| std::string client_0_id; |
| const auto& path = temp_file_path_; |
| |
| { |
| base::ScopedFD pipe_fds[2]; |
| ASSERT_TRUE(base::CreatePipe(/*read_fd*/ &pipe_fds[0], |
| /*write_fd*/ &pipe_fds[1], |
| /*non_blocking*/ true)); |
| client_0_id = |
| SetupClientWithLifelineFd(pipe_fds[0].get(), path, client_0_ifaces); |
| EXPECT_CALL( |
| usb_driver_tracker_, |
| ConnectInterface(usb_driver_tracker_.dev_fds_[client_0_id].fd.get(), |
| kIface0)) |
| .WillOnce(DoAll(QuitRunLoop(&run_loop), Return(false))); |
| } |
| // After client closes, even reattach IOCTL fails, the client's tracking |
| // should be cleared. |
| run_loop.Run(); |
| ASSERT_FALSE(usb_driver_tracker_.IsClientIdTracked(client_0_id)); |
| ASSERT_FALSE(base::Contains(usb_driver_tracker_.dev_ifaces_, path)); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, HandleClosedFdUnTrackedClientId) { |
| std::string untracked_client_id = "abc"; |
| usb_driver_tracker_.HandleClosedFd(untracked_client_id); |
| ASSERT_EQ(usb_driver_tracker_.dev_fds_.size(), 0); |
| ASSERT_EQ(usb_driver_tracker_.dev_ifaces_.size(), 0); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, HandleClosedFdTwoClientsOnDifferentPaths) { |
| base::RunLoop run_loop[kMaxNumClients]; |
| std::vector<uint8_t> client_ifaces[kMaxNumClients] = { |
| {kIface0, kIface1}, // kClient0 ifaces |
| {kIface1, kIface0}, // kClient1 ifaces |
| }; |
| std::string client_id[kMaxNumClients]; |
| |
| base::FilePath another_file_path; |
| ASSERT_TRUE(CreateTemporaryFile(&another_file_path)); |
| |
| base::FilePath paths[kMaxNumClients] = { |
| temp_file_path_, // kClient0 path |
| another_file_path, // kClient1 path |
| }; |
| ASSERT_NE(paths[kClient0], paths[kClient1]); |
| |
| { |
| base::ScopedFD pipe_fds[kMaxNumClients][2]; |
| for (auto client = 0; client < kMaxNumClients; client++) { |
| ASSERT_TRUE(base::CreatePipe(/*read_fd*/ &pipe_fds[client][0], |
| /*write_fd*/ &pipe_fds[client][1], |
| /*non_blocking*/ true)); |
| client_id[client] = SetupClientWithLifelineFd( |
| pipe_fds[client][0].get(), paths[client], client_ifaces[client]); |
| for (auto iface : client_ifaces[client]) { |
| EXPECT_CALL( |
| usb_driver_tracker_, |
| ConnectInterface( |
| usb_driver_tracker_.dev_fds_[client_id[client]].fd.get(), |
| iface)) |
| .WillOnce(DoAll(QuitRunLoop(&run_loop[client]), Return(true))); |
| } |
| } |
| } |
| for (auto client = 0; client < kMaxNumClients; client++) { |
| run_loop[client].Run(); |
| ASSERT_FALSE(usb_driver_tracker_.IsClientIdTracked(client_id[client])); |
| ASSERT_FALSE( |
| base::Contains(usb_driver_tracker_.dev_ifaces_, paths[client])); |
| } |
| ASSERT_EQ(0, usb_driver_tracker_.dev_fds_.size()); |
| ASSERT_EQ(0, usb_driver_tracker_.dev_ifaces_.size()); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, HandleClosedFdTwoClientsOnSamePath) { |
| base::RunLoop run_loop[kMaxNumClients]; |
| std::vector<uint8_t> client_ifaces[kMaxNumClients] = { |
| {kIface0, kIface1}, // kClient0 ifaces |
| {kIface2}, // kClient1 ifaces |
| }; |
| std::string client_id[kMaxNumClients]; |
| const auto& path = temp_file_path_; |
| |
| { |
| base::ScopedFD pipe_fds[kMaxNumClients][2]; |
| for (auto client = 0; client < kMaxNumClients; client++) { |
| ASSERT_TRUE(base::CreatePipe(/*read_fd*/ &pipe_fds[client][0], |
| /*write_fd*/ &pipe_fds[client][1], |
| /*non_blocking*/ true)); |
| client_id[client] = SetupClientWithLifelineFd( |
| pipe_fds[client][0].get(), path, client_ifaces[client]); |
| for (auto iface : client_ifaces[client]) { |
| EXPECT_CALL( |
| usb_driver_tracker_, |
| ConnectInterface( |
| usb_driver_tracker_.dev_fds_[client_id[client]].fd.get(), |
| iface)) |
| .WillOnce(DoAll(QuitRunLoop(&run_loop[client]), Return(true))); |
| } |
| } |
| } |
| for (auto client = 0; client < kMaxNumClients; client++) { |
| run_loop[client].Run(); |
| ASSERT_FALSE(usb_driver_tracker_.IsClientIdTracked(client_id[client])); |
| } |
| ASSERT_FALSE(base::Contains(usb_driver_tracker_.dev_ifaces_, path)); |
| ASSERT_EQ(0, usb_driver_tracker_.dev_fds_.size()); |
| ASSERT_EQ(0, usb_driver_tracker_.dev_ifaces_.size()); |
| } |
| TEST_F(UsbDriverTrackerTest, RecordInterfaceDetached) { |
| std::vector<uint8_t> client_0_ifaces = {}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| ASSERT_FALSE(base::Contains(usb_driver_tracker_.dev_ifaces_, path)); |
| usb_driver_tracker_.RecordInterfaceDetached(client_0_id, path, kIface0); |
| ASSERT_EQ(usb_driver_tracker_.dev_ifaces_[path][kIface0], client_0_id); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, ClearDetachedInterfaceRecord) { |
| std::vector<uint8_t> client_0_ifaces = {kIface0}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| ASSERT_TRUE(usb_driver_tracker_.dev_ifaces_[path][kIface0] == client_0_id); |
| usb_driver_tracker_.ClearDetachedInterfaceRecord(client_0_id, path, kIface0); |
| ASSERT_FALSE(base::Contains(usb_driver_tracker_.dev_ifaces_, path)); |
| } |
| |
| TEST_F(UsbDriverTrackerDeathTest, RecordInterfaceDetachedUntrackedClient) { |
| std::string untracked_client_id = "abc"; |
| const auto& path = temp_file_path_; |
| ASSERT_DEBUG_DEATH(usb_driver_tracker_.RecordInterfaceDetached( |
| untracked_client_id, path, kIface0), |
| ""); |
| } |
| |
| TEST_F(UsbDriverTrackerDeathTest, RecordInterfaceDetachedIfaceWatched) { |
| std::vector<uint8_t> client_0_ifaces = {kIface0}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| ASSERT_DEBUG_DEATH( |
| usb_driver_tracker_.RecordInterfaceDetached(client_0_id, path, kIface0), |
| ""); |
| } |
| |
| TEST_F(UsbDriverTrackerDeathTest, ClearDetachedInterfaceRecordUntrackedClient) { |
| std::string untracked_client_id = "abc"; |
| const auto& path = temp_file_path_; |
| ASSERT_DEBUG_DEATH(usb_driver_tracker_.ClearDetachedInterfaceRecord( |
| untracked_client_id, path, kIface0), |
| ""); |
| } |
| |
| TEST_F(UsbDriverTrackerDeathTest, ClearDetachedInterfaceRecordUnknownPath) { |
| std::vector<uint8_t> client_0_ifaces = {kIface0}; |
| const auto& path = temp_file_path_; |
| base::FilePath unknown_file_path("unknown_path"); |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| ASSERT_DEBUG_DEATH(usb_driver_tracker_.ClearDetachedInterfaceRecord( |
| client_0_id, unknown_file_path, kIface0), |
| ""); |
| } |
| |
| TEST_F(UsbDriverTrackerDeathTest, ClearDetachedInterfaceRecordDupIface) { |
| std::vector<uint8_t> client_0_ifaces = {kIface0, kIface0}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| ASSERT_DEBUG_DEATH(usb_driver_tracker_.ClearDetachedInterfaceRecord( |
| client_0_id, path, kIface0), |
| ""); |
| // Explicitly clear the tracking structure to avoid DCHECK failure in |
| // destructor. |
| usb_driver_tracker_.dev_fds_.clear(); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, DetachInterfaceSuccess) { |
| std::vector<uint8_t> client_0_ifaces = {}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| EXPECT_CALL(usb_driver_tracker_, |
| DisconnectInterface( |
| usb_driver_tracker_.dev_fds_[client_0_id].fd.get(), kIface0)) |
| .WillOnce(Return(true)); |
| ASSERT_TRUE(usb_driver_tracker_.DetachInterface(client_0_id, kIface0)); |
| ASSERT_EQ(usb_driver_tracker_.dev_fds_[client_0_id].interfaces[0], kIface0); |
| ASSERT_EQ(usb_driver_tracker_.dev_ifaces_[path][kIface0], client_0_id); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, DetachInterfaceUnTrackedClientFail) { |
| std::string untracked_client_id = "abc"; |
| ASSERT_FALSE( |
| usb_driver_tracker_.DetachInterface(untracked_client_id, kIface0)); |
| ASSERT_EQ(usb_driver_tracker_.dev_fds_.size(), 0); |
| ASSERT_EQ(usb_driver_tracker_.dev_ifaces_.size(), 0); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, DetachInterfaceIfaceAlreadyDetachedByOtherClient) { |
| std::vector<uint8_t> client_0_ifaces = {}; |
| std::vector<uint8_t> client_1_ifaces = {kIface0}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| SetupClient(kClient1, path, client_1_ifaces); |
| ASSERT_FALSE(usb_driver_tracker_.DetachInterface(client_0_id, kIface0)); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, |
| DetachInterfaceIfaceAlreadyDetachedByTheClientNoOp) { |
| std::vector<uint8_t> client_0_ifaces = {kIface0}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| ASSERT_TRUE(usb_driver_tracker_.DetachInterface(client_0_id, kIface0)); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, DetachInterfaceIfaceDisconnectFail) { |
| std::vector<uint8_t> client_0_ifaces = {}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| EXPECT_CALL(usb_driver_tracker_, |
| DisconnectInterface( |
| usb_driver_tracker_.dev_fds_[client_0_id].fd.get(), kIface0)) |
| .WillOnce(Return(false)); |
| ASSERT_FALSE(usb_driver_tracker_.DetachInterface(client_0_id, kIface0)); |
| ASSERT_EQ(usb_driver_tracker_.dev_ifaces_.size(), 0); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, ReattachInterfaceSuccess) { |
| std::vector<uint8_t> client_0_ifaces = {kIface0}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| EXPECT_CALL(usb_driver_tracker_, |
| ConnectInterface( |
| usb_driver_tracker_.dev_fds_[client_0_id].fd.get(), kIface0)) |
| .WillOnce(Return(true)); |
| ASSERT_TRUE(usb_driver_tracker_.ReattachInterface(client_0_id, kIface0)); |
| ASSERT_EQ(usb_driver_tracker_.dev_ifaces_.size(), 0); |
| // The client id should still be tracked even it doesn't have any ifaces |
| // detached. |
| ASSERT_TRUE(usb_driver_tracker_.IsClientIdTracked(client_0_id)); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, ReattachInterfaceUntrackedClientFail) { |
| std::string untracked_client_id = "abc"; |
| ASSERT_FALSE( |
| usb_driver_tracker_.ReattachInterface(untracked_client_id, kIface0)); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, ReattachInterfacePathNoIfaceDetachedNoOp) { |
| std::vector<uint8_t> client_0_ifaces = {}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| ASSERT_TRUE(usb_driver_tracker_.ReattachInterface(client_0_id, kIface0)); |
| ASSERT_EQ(usb_driver_tracker_.dev_ifaces_.size(), 0); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, ReattachInterfaceIfaceNotDetachedNoOp) { |
| std::vector<uint8_t> client_0_ifaces = {kIface1}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| ASSERT_TRUE(usb_driver_tracker_.ReattachInterface(client_0_id, kIface0)); |
| ASSERT_EQ(usb_driver_tracker_.dev_ifaces_[path][kIface1], client_0_id); |
| } |
| |
| TEST_F(UsbDriverTrackerTest, ReattachInterfaceIfaceDetachedByOtherClient) { |
| std::vector<uint8_t> client_0_ifaces = {}; |
| std::vector<uint8_t> client_1_ifaces = {kIface0}; |
| const auto& path = temp_file_path_; |
| auto client_0_id = SetupClient(kClient0, path, client_0_ifaces); |
| SetupClient(kClient1, path, client_1_ifaces); |
| ASSERT_FALSE(usb_driver_tracker_.ReattachInterface(client_0_id, kIface0)); |
| } |
| |
| } // namespace permission_broker |