// Copyright 2013 The Chromium 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 "base/bind.h" #include "base/message_loop/message_loop.h" #include "chromeos/dbus/nfc_adapter_client.h" #include "chromeos/dbus/nfc_client_helpers.h" #include "chromeos/dbus/nfc_device_client.h" #include "chromeos/dbus/nfc_manager_client.h" #include "chromeos/dbus/nfc_record_client.h" #include "chromeos/dbus/nfc_tag_client.h" #include "dbus/mock_bus.h" #include "dbus/mock_object_proxy.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/cros_system_api/dbus/service_constants.h" using ::testing::_; using ::testing::Invoke; using ::testing::Mock; using ::testing::Return; using chromeos::nfc_client_helpers::ObjectPathVector; namespace chromeos { namespace { // D-Bus service name used by the test. const char kTestServiceName[] = "test.service.name"; // Object paths that are used for testing. const char kTestManagerPath[] = "/test/nfc/manager"; const char kTestAdapterPath0[] = "/test/nfc/adapter0"; const char kTestAdapterPath1[] = "/test/nfc/adapter1"; const char kTestDevicePath0[] = "/test/nfc/device0"; const char kTestDevicePath1[] = "/test/nfc/device1"; const char kTestRecordPath0[] = "/test/nfc/record0"; const char kTestRecordPath1[] = "/test/nfc/record1"; const char kTestRecordPath2[] = "/test/nfc/record2"; const char kTestRecordPath3[] = "/test/nfc/record3"; const char kTestTagPath0[] = "/test/nfc/tag0"; const char kTestTagPath1[] = "/test/nfc/tag1"; class MockNfcManagerObserver : public NfcManagerClient::Observer { public: MOCK_METHOD1(AdapterAdded, void(const dbus::ObjectPath&)); MOCK_METHOD1(AdapterRemoved, void(const dbus::ObjectPath&)); MOCK_METHOD1(ManagerPropertyChanged, void(const std::string&)); }; class MockNfcAdapterObserver : public NfcAdapterClient::Observer { public: MOCK_METHOD1(AdapterAdded, void(const dbus::ObjectPath&)); MOCK_METHOD1(AdapterRemoved, void(const dbus::ObjectPath&)); MOCK_METHOD2(AdapterPropertyChanged, void(const dbus::ObjectPath&, const std::string&)); }; class MockNfcDeviceObserver : public NfcDeviceClient::Observer { public: MOCK_METHOD1(DeviceAdded, void(const dbus::ObjectPath&)); MOCK_METHOD1(DeviceRemoved, void(const dbus::ObjectPath&)); MOCK_METHOD2(DevicePropertyChanged, void(const dbus::ObjectPath&, const std::string&)); }; class MockNfcRecordObserver : public NfcRecordClient::Observer { public: MOCK_METHOD1(RecordAdded, void(const dbus::ObjectPath&)); MOCK_METHOD1(RecordRemoved, void(const dbus::ObjectPath&)); MOCK_METHOD2(RecordPropertyChanged, void(const dbus::ObjectPath&, const std::string&)); MOCK_METHOD1(RecordPropertiesReceived, void(const dbus::ObjectPath&)); }; class MockNfcTagObserver : public NfcTagClient::Observer { public: MOCK_METHOD1(TagAdded, void(const dbus::ObjectPath&)); MOCK_METHOD1(TagRemoved, void(const dbus::ObjectPath&)); MOCK_METHOD2(TagPropertyChanged, void(const dbus::ObjectPath&, const std::string&)); }; } // namespace class NfcClientTest : public testing::Test { public: NfcClientTest() : response_(NULL) {} virtual ~NfcClientTest() {} virtual void SetUp() OVERRIDE { // Create the mock bus. dbus::Bus::Options options; options.bus_type = dbus::Bus::SYSTEM; mock_bus_ = new dbus::MockBus(options); // Create the mock proxies. mock_manager_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestManagerPath)); mock_adapter0_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestAdapterPath0)); mock_adapter1_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestAdapterPath1)); mock_device0_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestDevicePath0)); mock_device1_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestDevicePath1)); mock_record0_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestRecordPath0)); mock_record1_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestRecordPath1)); mock_record2_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestRecordPath2)); mock_record3_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestRecordPath3)); mock_tag0_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestTagPath0)); mock_tag1_proxy_ = new dbus::MockObjectProxy( mock_bus_.get(), kTestServiceName, dbus::ObjectPath(kTestTagPath1)); // Set expectations that use NfcClientTest::OnConnectToSignal when the // client connect signals on the mock proxies. EXPECT_CALL(*mock_manager_proxy_.get(), ConnectToSignal(_, _, _, _)) .WillRepeatedly(Invoke(this, &NfcClientTest::OnConnectToSignal)); EXPECT_CALL(*mock_adapter0_proxy_.get(), ConnectToSignal(_, _, _, _)) .WillRepeatedly(Invoke(this, &NfcClientTest::OnConnectToSignal)); EXPECT_CALL(*mock_adapter1_proxy_.get(), ConnectToSignal(_, _, _, _)) .WillRepeatedly(Invoke(this, &NfcClientTest::OnConnectToSignal)); // Set expectations that return our mock proxies on demand. EXPECT_CALL( *mock_bus_.get(), GetObjectProxy(nfc_manager::kNfcManagerServiceName, dbus::ObjectPath(nfc_manager::kNfcManagerServicePath))) .WillRepeatedly(Return(mock_manager_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_adapter::kNfcAdapterServiceName, dbus::ObjectPath(kTestAdapterPath0))) .WillRepeatedly(Return(mock_adapter0_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_adapter::kNfcAdapterServiceName, dbus::ObjectPath(kTestAdapterPath1))) .WillRepeatedly(Return(mock_adapter1_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_device::kNfcDeviceServiceName, dbus::ObjectPath(kTestDevicePath0))) .WillRepeatedly(Return(mock_device0_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_device::kNfcDeviceServiceName, dbus::ObjectPath(kTestDevicePath1))) .WillRepeatedly(Return(mock_device1_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_record::kNfcRecordServiceName, dbus::ObjectPath(kTestRecordPath0))) .WillRepeatedly(Return(mock_record0_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_record::kNfcRecordServiceName, dbus::ObjectPath(kTestRecordPath1))) .WillRepeatedly(Return(mock_record1_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_record::kNfcRecordServiceName, dbus::ObjectPath(kTestRecordPath2))) .WillRepeatedly(Return(mock_record2_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_record::kNfcRecordServiceName, dbus::ObjectPath(kTestRecordPath3))) .WillRepeatedly(Return(mock_record3_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_tag::kNfcTagServiceName, dbus::ObjectPath(kTestTagPath0))) .WillRepeatedly(Return(mock_tag0_proxy_.get())); EXPECT_CALL(*mock_bus_.get(), GetObjectProxy(nfc_tag::kNfcTagServiceName, dbus::ObjectPath(kTestTagPath1))) .WillRepeatedly(Return(mock_tag1_proxy_.get())); // ShutdownAndBlock will be called in TearDown. EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return()); // Create the clients. manager_client_.reset(NfcManagerClient::Create()); adapter_client_.reset(NfcAdapterClient::Create(manager_client_.get())); device_client_.reset(NfcDeviceClient::Create(adapter_client_.get())); tag_client_.reset(NfcTagClient::Create(adapter_client_.get())); record_client_.reset( NfcRecordClient::Create(device_client_.get(), tag_client_.get())); manager_client_->Init(mock_bus_.get()); adapter_client_->Init(mock_bus_.get()); device_client_->Init(mock_bus_.get()); tag_client_->Init(mock_bus_.get()); record_client_->Init(mock_bus_.get()); manager_client_->AddObserver(&mock_manager_observer_); adapter_client_->AddObserver(&mock_adapter_observer_); device_client_->AddObserver(&mock_device_observer_); tag_client_->AddObserver(&mock_tag_observer_); record_client_->AddObserver(&mock_record_observer_); message_loop_.RunUntilIdle(); } virtual void TearDown() OVERRIDE { tag_client_->RemoveObserver(&mock_tag_observer_); device_client_->RemoveObserver(&mock_device_observer_); adapter_client_->RemoveObserver(&mock_adapter_observer_); manager_client_->RemoveObserver(&mock_manager_observer_); mock_bus_->ShutdownAndBlock(); } void SimulateAdaptersChanged( const ObjectPathVector& adapter_paths) { NfcManagerClient::Properties* properties = manager_client_->GetProperties(); ASSERT_TRUE(properties); EXPECT_CALL(mock_manager_observer_, ManagerPropertyChanged(nfc_manager::kAdaptersProperty)); SendArrayPropertyChangedSignal( properties, nfc_manager::kNfcManagerInterface, nfc_manager::kAdaptersProperty, adapter_paths); Mock::VerifyAndClearExpectations(&mock_manager_observer_); } void SimulateTagsChanged(const ObjectPathVector& tag_paths, const dbus::ObjectPath& adapter_path) { NfcAdapterClient::Properties* properties = adapter_client_->GetProperties(adapter_path); ASSERT_TRUE(properties); EXPECT_CALL(mock_adapter_observer_, AdapterPropertyChanged(adapter_path, nfc_adapter::kTagsProperty)); SendArrayPropertyChangedSignal( properties, nfc_adapter::kNfcAdapterInterface, nfc_adapter::kTagsProperty, tag_paths); Mock::VerifyAndClearExpectations(&mock_adapter_observer_); } void SimulateDevicesChanged(const ObjectPathVector& device_paths, const dbus::ObjectPath& adapter_path) { NfcAdapterClient::Properties* properties = adapter_client_->GetProperties(adapter_path); ASSERT_TRUE(properties); EXPECT_CALL(mock_adapter_observer_, AdapterPropertyChanged(adapter_path, nfc_adapter::kDevicesProperty)); SendArrayPropertyChangedSignal( properties, nfc_adapter::kNfcAdapterInterface, nfc_adapter::kDevicesProperty, device_paths); Mock::VerifyAndClearExpectations(&mock_adapter_observer_); } void SimulateDeviceRecordsChanged( const ObjectPathVector& record_paths, const dbus::ObjectPath& device_path) { NfcDeviceClient::Properties* properties = device_client_->GetProperties(device_path); ASSERT_TRUE(properties); EXPECT_CALL(mock_device_observer_, DevicePropertyChanged(device_path, nfc_device::kRecordsProperty)); SendArrayPropertyChangedSignal( properties, nfc_device::kNfcDeviceInterface, nfc_device::kRecordsProperty, record_paths); Mock::VerifyAndClearExpectations(&mock_device_observer_); } void SimulateTagRecordsChanged( const ObjectPathVector& record_paths, const dbus::ObjectPath& tag_path) { NfcTagClient::Properties* properties = tag_client_->GetProperties(tag_path); ASSERT_TRUE(properties); EXPECT_CALL(mock_tag_observer_, TagPropertyChanged(tag_path, nfc_tag::kRecordsProperty)); SendArrayPropertyChangedSignal( properties, nfc_tag::kNfcTagInterface, nfc_tag::kRecordsProperty, record_paths); Mock::VerifyAndClearExpectations(&mock_tag_observer_); } void SendArrayPropertyChangedSignal( dbus::PropertySet* properties, const std::string& interface, const std::string& property_name, ObjectPathVector object_paths) { dbus::Signal signal(interface, nfc_common::kPropertyChangedSignal); dbus::MessageWriter writer(&signal); writer.AppendString(property_name); dbus::MessageWriter variant_writer(NULL); writer.OpenVariant("ao", &variant_writer); variant_writer.AppendArrayOfObjectPaths(object_paths); writer.CloseContainer(&variant_writer); properties->ChangedReceived(&signal); } MOCK_METHOD0(SuccessCallback, void(void)); MOCK_METHOD2(ErrorCallback, void(const std::string& error_name, const std::string& error_message)); protected: // The mock object proxies. scoped_refptr<dbus::MockObjectProxy> mock_manager_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_adapter0_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_adapter1_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_device0_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_device1_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_record0_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_record1_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_record2_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_record3_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_tag0_proxy_; scoped_refptr<dbus::MockObjectProxy> mock_tag1_proxy_; // The mock bus. scoped_refptr<dbus::MockBus> mock_bus_; // A message loop to emulate asynchronous behavior. base::MessageLoop message_loop_; // Response returned by mock methods. dbus::Response* response_; // The D-Bus client objects under test. scoped_ptr<NfcManagerClient> manager_client_; scoped_ptr<NfcAdapterClient> adapter_client_; scoped_ptr<NfcDeviceClient> device_client_; scoped_ptr<NfcTagClient> tag_client_; scoped_ptr<NfcRecordClient> record_client_; // Mock observers. MockNfcManagerObserver mock_manager_observer_; MockNfcAdapterObserver mock_adapter_observer_; MockNfcDeviceObserver mock_device_observer_; MockNfcTagObserver mock_tag_observer_; MockNfcRecordObserver mock_record_observer_; // The signal callbacks used to simulate asychronous signals. dbus::ObjectProxy::SignalCallback manager_adapter_added_signal_callback_; dbus::ObjectProxy::SignalCallback manager_adapter_removed_signal_callback_; private: // Used to implement the mock proxy. void OnConnectToSignal( const std::string& interface_name, const std::string& signal_name, const dbus::ObjectProxy::SignalCallback& signal_callback, const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) { if (interface_name == nfc_manager::kNfcManagerInterface) { if (signal_name == nfc_manager::kAdapterAddedSignal) manager_adapter_added_signal_callback_ = signal_callback; else if (signal_name == nfc_manager::kAdapterRemovedSignal) manager_adapter_removed_signal_callback_ = signal_callback; } message_loop_.PostTask(FROM_HERE, base::Bind(on_connected_callback, interface_name, signal_name, true)); } }; // Tests that when adapters are added and removed through the manager, all // observers are notified and the proxies are created and removed // accordingly. TEST_F(NfcClientTest, AdaptersAddedAndRemoved) { // Invoking methods on adapters that haven't been added should fail. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath0), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); // Add adapter 0. ObjectPathVector adapter_paths; adapter_paths.push_back(dbus::ObjectPath(kTestAdapterPath0)); EXPECT_CALL(mock_adapter_observer_, AdapterAdded(dbus::ObjectPath(kTestAdapterPath0))); SimulateAdaptersChanged(adapter_paths); // Invoking methods should succeed on adapter 0 but fail on adapter 1. EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath0), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(&mock_adapter0_proxy_); EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); EXPECT_CALL(*mock_adapter1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath1), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); Mock::VerifyAndClearExpectations(&mock_adapter1_proxy_); // Add adapter 1. adapter_paths.push_back(dbus::ObjectPath(kTestAdapterPath1)); EXPECT_CALL(mock_adapter_observer_, AdapterAdded(dbus::ObjectPath(kTestAdapterPath1))); SimulateAdaptersChanged(adapter_paths); // Invoking methods should succeed on both adapters. EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); EXPECT_CALL(*mock_adapter1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath0), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath1), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(&mock_adapter0_proxy_); Mock::VerifyAndClearExpectations(&mock_adapter1_proxy_); // Remove adapter 0. adapter_paths.erase(adapter_paths.begin()); EXPECT_CALL(mock_adapter_observer_, AdapterRemoved(dbus::ObjectPath(kTestAdapterPath0))); SimulateAdaptersChanged(adapter_paths); // Invoking methods should succeed on adapter 1 but fail on adapter 0. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath0), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); EXPECT_CALL(*mock_adapter1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath1), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(&mock_adapter0_proxy_); Mock::VerifyAndClearExpectations(&mock_adapter1_proxy_); // Remove adapter 1. adapter_paths.clear(); EXPECT_CALL(mock_adapter_observer_, AdapterRemoved(dbus::ObjectPath(kTestAdapterPath1))); SimulateAdaptersChanged(adapter_paths); // Invoking methods should fail on both adapters. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)) .Times(2); EXPECT_CALL(*mock_adapter0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); EXPECT_CALL(*mock_adapter1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0);; adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath0), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); adapter_client_->StartPollLoop( dbus::ObjectPath(kTestAdapterPath1), nfc_adapter::kModeInitiator, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); } // Tests that when tags are added and removed through an adapter, all // observers are notified and the proxies are created and removed // accordingly. TEST_F(NfcClientTest, TagsAddedAndRemoved) { // Invoking methods on tags that haven't been added should fail. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); base::DictionaryValue write_data; write_data.SetString(nfc_record::kTypeProperty, nfc_record::kTypeText); tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); // Add adapter 0. ObjectPathVector adapter_paths; adapter_paths.push_back(dbus::ObjectPath(kTestAdapterPath0)); EXPECT_CALL(mock_adapter_observer_, AdapterAdded(dbus::ObjectPath(kTestAdapterPath0))); SimulateAdaptersChanged(adapter_paths); Mock::VerifyAndClearExpectations(&mock_adapter_observer_); // Add tag 0. ObjectPathVector tag_paths; tag_paths.push_back(dbus::ObjectPath(kTestTagPath0)); EXPECT_CALL(mock_tag_observer_, TagAdded(dbus::ObjectPath(kTestTagPath0))); SimulateTagsChanged(tag_paths, dbus::ObjectPath(kTestAdapterPath0)); Mock::VerifyAndClearExpectations(&mock_tag_observer_); // Invoking methods should succeed on tag 0 but fail on tag 1. EXPECT_CALL(*mock_tag0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(&mock_tag0_proxy_); EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); EXPECT_CALL(*mock_tag1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); tag_client_->Write(dbus::ObjectPath(kTestTagPath1), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); Mock::VerifyAndClearExpectations(&mock_tag1_proxy_); // Add tag 1. tag_paths.push_back(dbus::ObjectPath(kTestTagPath1)); EXPECT_CALL(mock_tag_observer_, TagAdded(dbus::ObjectPath(kTestTagPath1))); SimulateTagsChanged(tag_paths, dbus::ObjectPath(kTestAdapterPath0)); Mock::VerifyAndClearExpectations(&mock_tag_observer_); // Invoking methods should succeed on both tags. EXPECT_CALL(*mock_tag0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); EXPECT_CALL(*mock_tag1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); tag_client_->Write(dbus::ObjectPath(kTestTagPath1), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(&mock_tag0_proxy_); Mock::VerifyAndClearExpectations(&mock_tag1_proxy_); // Remove tag 0. tag_paths.erase(tag_paths.begin()); EXPECT_CALL(mock_tag_observer_, TagRemoved(dbus::ObjectPath(kTestTagPath0))); SimulateTagsChanged(tag_paths, dbus::ObjectPath(kTestAdapterPath0)); Mock::VerifyAndClearExpectations(&mock_tag_observer_); // Invoking methods should succeed on tag 1 but fail on tag 0. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); EXPECT_CALL(*mock_tag0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); Mock::VerifyAndClearExpectations(&mock_tag0_proxy_); EXPECT_CALL(*mock_tag1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); tag_client_->Write(dbus::ObjectPath(kTestTagPath1), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(&mock_tag1_proxy_); // Remove tag 1. tag_paths.clear(); EXPECT_CALL(mock_tag_observer_, TagRemoved(dbus::ObjectPath(kTestTagPath1))); SimulateTagsChanged(tag_paths, dbus::ObjectPath(kTestAdapterPath0)); Mock::VerifyAndClearExpectations(&mock_tag_observer_); // Invoking methods should fail on both tags. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)) .Times(2); EXPECT_CALL(*mock_tag0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); EXPECT_CALL(*mock_tag1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); tag_client_->Write(dbus::ObjectPath(kTestTagPath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); tag_client_->Write(dbus::ObjectPath(kTestTagPath1), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); } // Tests that when devices are added and removed through an adapter, all // observers are notified and the proxies are created and removed // accordingly. TEST_F(NfcClientTest, DevicesAddedAndRemoved) { // Invoking methods on devices that haven't been added should fail. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); base::DictionaryValue write_data; write_data.SetString(nfc_record::kTypeProperty, nfc_record::kTypeText); device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); // Add adapter 0. ObjectPathVector adapter_paths; adapter_paths.push_back(dbus::ObjectPath(kTestAdapterPath0)); EXPECT_CALL(mock_adapter_observer_, AdapterAdded(dbus::ObjectPath(kTestAdapterPath0))); SimulateAdaptersChanged(adapter_paths); // Add device 0. ObjectPathVector device_paths; device_paths.push_back(dbus::ObjectPath(kTestDevicePath0)); EXPECT_CALL(mock_device_observer_, DeviceAdded(dbus::ObjectPath(kTestDevicePath0))); SimulateDevicesChanged(device_paths, dbus::ObjectPath(kTestAdapterPath0)); Mock::VerifyAndClearExpectations(&mock_device_observer_); // Invoking methods should succeed on device 0 but fail on device 1. EXPECT_CALL(*mock_device0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(&mock_device0_proxy_); EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); EXPECT_CALL(*mock_device1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); device_client_->Push(dbus::ObjectPath(kTestDevicePath1), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); Mock::VerifyAndClearExpectations(&mock_device1_proxy_); // Add device 1. device_paths.push_back(dbus::ObjectPath(kTestDevicePath1)); EXPECT_CALL(mock_device_observer_, DeviceAdded(dbus::ObjectPath(kTestDevicePath1))); SimulateDevicesChanged(device_paths, dbus::ObjectPath(kTestAdapterPath0)); Mock::VerifyAndClearExpectations(&mock_device_observer_); // Invoking methods should succeed on both devices. EXPECT_CALL(*mock_device0_proxy_, CallMethodWithErrorCallback(_, _, _, _)); EXPECT_CALL(*mock_device1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); device_client_->Push(dbus::ObjectPath(kTestDevicePath1), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(&mock_device0_proxy_); Mock::VerifyAndClearExpectations(&mock_device1_proxy_); // Remove device 0. device_paths.erase(device_paths.begin()); EXPECT_CALL(mock_device_observer_, DeviceRemoved(dbus::ObjectPath(kTestDevicePath0))); SimulateDevicesChanged(device_paths, dbus::ObjectPath(kTestAdapterPath0)); Mock::VerifyAndClearExpectations(&mock_device_observer_); // Invoking methods should succeed on device 1 but fail on device 0. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)); EXPECT_CALL(*mock_device0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(this); Mock::VerifyAndClearExpectations(&mock_device0_proxy_); EXPECT_CALL(*mock_device1_proxy_, CallMethodWithErrorCallback(_, _, _, _)); device_client_->Push(dbus::ObjectPath(kTestDevicePath1), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); Mock::VerifyAndClearExpectations(&mock_device1_proxy_); // Remove device 1. device_paths.clear(); EXPECT_CALL(mock_device_observer_, DeviceRemoved(dbus::ObjectPath(kTestDevicePath1))); SimulateDevicesChanged(device_paths, dbus::ObjectPath(kTestAdapterPath0)); Mock::VerifyAndClearExpectations(&mock_device_observer_); // Invoking methods should fail on both devices. EXPECT_CALL(*this, ErrorCallback(nfc_client_helpers::kUnknownObjectError, _)) .Times(2); EXPECT_CALL(*mock_device0_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); EXPECT_CALL(*mock_device1_proxy_, CallMethodWithErrorCallback(_, _, _, _)) .Times(0); device_client_->Push(dbus::ObjectPath(kTestDevicePath0), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); device_client_->Push(dbus::ObjectPath(kTestDevicePath1), write_data, base::Bind(&NfcClientTest::SuccessCallback, base::Unretained(this)), base::Bind(&NfcClientTest::ErrorCallback, base::Unretained(this))); } TEST_F(NfcClientTest, ObjectCleanup) { // Tests that when an adapter gets removed, proxies that belong to the // adapter, device, tag, and record hierarchy get cleaned up properly. ObjectPathVector object_paths; // Add adapters. EXPECT_CALL(mock_adapter_observer_, AdapterAdded(dbus::ObjectPath(kTestAdapterPath0))); EXPECT_CALL(mock_adapter_observer_, AdapterAdded(dbus::ObjectPath(kTestAdapterPath1))); object_paths.push_back(dbus::ObjectPath(kTestAdapterPath0)); object_paths.push_back(dbus::ObjectPath(kTestAdapterPath1)); SimulateAdaptersChanged(object_paths); Mock::VerifyAndClearExpectations(&mock_adapter_observer_); // Add devices and a tags. Assign them like the following: // - device 0 -> adapter 0 // - tag 0 -> adapter 0 // - device 1 -> adapter 1 // - tag 1 -> adapter 1 EXPECT_CALL(mock_device_observer_, DeviceAdded(dbus::ObjectPath(kTestDevicePath0))); EXPECT_CALL(mock_device_observer_, DeviceAdded(dbus::ObjectPath(kTestDevicePath1))); EXPECT_CALL(mock_tag_observer_, TagAdded(dbus::ObjectPath(kTestTagPath0))); EXPECT_CALL(mock_tag_observer_, TagAdded(dbus::ObjectPath(kTestTagPath1))); object_paths.clear(); object_paths.push_back(dbus::ObjectPath(kTestDevicePath0)); SimulateDevicesChanged(object_paths, dbus::ObjectPath(kTestAdapterPath0)); object_paths.clear(); object_paths.push_back(dbus::ObjectPath(kTestTagPath0)); SimulateTagsChanged(object_paths, dbus::ObjectPath(kTestAdapterPath0)); object_paths.clear(); object_paths.push_back(dbus::ObjectPath(kTestDevicePath1)); SimulateDevicesChanged(object_paths, dbus::ObjectPath(kTestAdapterPath1)); object_paths.clear(); object_paths.push_back(dbus::ObjectPath(kTestTagPath1)); SimulateTagsChanged(object_paths, dbus::ObjectPath(kTestAdapterPath1)); Mock::VerifyAndClearExpectations(&mock_device_observer_); Mock::VerifyAndClearExpectations(&mock_tag_observer_); // Add records. Assign them like the following: // - record 0 -> device 0 // - record 1 -> tag 0 // - record 2 -> device 1 // - record 3 -> tag 1 EXPECT_CALL(mock_record_observer_, RecordAdded(dbus::ObjectPath(kTestRecordPath0))); EXPECT_CALL(mock_record_observer_, RecordAdded(dbus::ObjectPath(kTestRecordPath1))); EXPECT_CALL(mock_record_observer_, RecordAdded(dbus::ObjectPath(kTestRecordPath2))); EXPECT_CALL(mock_record_observer_, RecordAdded(dbus::ObjectPath(kTestRecordPath3))); object_paths.clear(); object_paths.push_back(dbus::ObjectPath(kTestRecordPath0)); SimulateDeviceRecordsChanged(object_paths, dbus::ObjectPath(kTestDevicePath0)); object_paths.clear(); object_paths.push_back(dbus::ObjectPath(kTestRecordPath1)); SimulateTagRecordsChanged(object_paths, dbus::ObjectPath(kTestTagPath0)); object_paths.clear(); object_paths.push_back(dbus::ObjectPath(kTestRecordPath2)); SimulateDeviceRecordsChanged(object_paths, dbus::ObjectPath(kTestDevicePath1)); object_paths.clear(); object_paths.push_back(dbus::ObjectPath(kTestRecordPath3)); SimulateTagRecordsChanged(object_paths, dbus::ObjectPath(kTestTagPath1)); Mock::VerifyAndClearExpectations(&mock_record_observer_); // Check that the records have been assigned to the correct device or tag. NfcTagClient::Properties* tag_properties = tag_client_->GetProperties(dbus::ObjectPath(kTestTagPath0)); EXPECT_EQ((size_t)1, tag_properties->records.value().size()); EXPECT_EQ(dbus::ObjectPath(kTestRecordPath1), tag_properties->records.value()[0]); NfcDeviceClient::Properties* device_properties = device_client_->GetProperties(dbus::ObjectPath(kTestDevicePath0)); EXPECT_EQ((size_t)1, device_properties->records.value().size()); EXPECT_EQ(dbus::ObjectPath(kTestRecordPath0), device_properties->records.value()[0]); // Remove adapter 0. Make sure that all of the tag, device, and records that // are in the adapter 0 hierarchy are removed. object_paths.clear(); object_paths.push_back(dbus::ObjectPath(kTestAdapterPath1)); EXPECT_CALL(mock_adapter_observer_, AdapterRemoved(dbus::ObjectPath(kTestAdapterPath0))); EXPECT_CALL(mock_device_observer_, DeviceRemoved(dbus::ObjectPath(kTestDevicePath0))); EXPECT_CALL(mock_tag_observer_, TagRemoved(dbus::ObjectPath(kTestTagPath0))); EXPECT_CALL(mock_record_observer_, RecordRemoved(dbus::ObjectPath(kTestRecordPath0))); EXPECT_CALL(mock_record_observer_, RecordRemoved(dbus::ObjectPath(kTestRecordPath1))); SimulateAdaptersChanged(object_paths); Mock::VerifyAndClearExpectations(&mock_adapter_observer_); Mock::VerifyAndClearExpectations(&mock_device_observer_); Mock::VerifyAndClearExpectations(&mock_tag_observer_); Mock::VerifyAndClearExpectations(&mock_record_observer_); // Remove adapter 1. object_paths.clear(); EXPECT_CALL(mock_adapter_observer_, AdapterRemoved(dbus::ObjectPath(kTestAdapterPath1))); EXPECT_CALL(mock_device_observer_, DeviceRemoved(dbus::ObjectPath(kTestDevicePath1))); EXPECT_CALL(mock_tag_observer_, TagRemoved(dbus::ObjectPath(kTestTagPath1))); EXPECT_CALL(mock_record_observer_, RecordRemoved(dbus::ObjectPath(kTestRecordPath2))); EXPECT_CALL(mock_record_observer_, RecordRemoved(dbus::ObjectPath(kTestRecordPath3))); SimulateAdaptersChanged(object_paths); } } // namespace chromeos