1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <string> 6 7 #include "base/memory/ref_counted.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/run_loop.h" 11 #include "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h" 12 #include "chrome/browser/extensions/event_names.h" 13 #include "chrome/browser/extensions/event_router.h" 14 #include "chrome/browser/extensions/extension_system_factory.h" 15 #include "chrome/browser/extensions/test_extension_system.h" 16 #include "chrome/test/base/testing_profile.h" 17 #include "content/public/test/test_browser_thread.h" 18 #include "device/bluetooth/test/mock_bluetooth_adapter.h" 19 #include "device/bluetooth/test/mock_bluetooth_device.h" 20 #include "device/bluetooth/test/mock_bluetooth_profile.h" 21 #include "device/bluetooth/test/mock_bluetooth_socket.h" 22 #include "testing/gmock/include/gmock/gmock.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 25 namespace { 26 27 const char kAudioProfileUuid[] = "audio profile uuid"; 28 const char kHealthProfileUuid[] = "health profile uuid"; 29 30 class FakeEventRouter : public extensions::EventRouter { 31 public: 32 explicit FakeEventRouter(Profile* profile) : EventRouter(profile, NULL) {} 33 34 virtual void DispatchEventToExtension( 35 const std::string& extension_id, 36 scoped_ptr<extensions::Event> event) OVERRIDE { 37 extension_id_ = extension_id; 38 event_ = event.Pass(); 39 } 40 41 std::string extension_id() const { 42 return extension_id_; 43 } 44 45 const extensions::Event* event() const { 46 return event_.get(); 47 } 48 49 private: 50 std::string extension_id_; 51 scoped_ptr<extensions::Event> event_; 52 53 DISALLOW_COPY_AND_ASSIGN(FakeEventRouter); 54 }; 55 56 class FakeExtensionSystem : public extensions::TestExtensionSystem { 57 public: 58 explicit FakeExtensionSystem(Profile* profile) 59 : extensions::TestExtensionSystem(profile) {} 60 61 virtual extensions::EventRouter* event_router() OVERRIDE { 62 if (!fake_event_router_) 63 fake_event_router_.reset(new FakeEventRouter(profile_)); 64 return fake_event_router_.get(); 65 } 66 67 private: 68 scoped_ptr<FakeEventRouter> fake_event_router_; 69 70 DISALLOW_COPY_AND_ASSIGN(FakeExtensionSystem); 71 }; 72 73 BrowserContextKeyedService* BuildFakeExtensionSystem( 74 content::BrowserContext* profile) { 75 return new FakeExtensionSystem(static_cast<Profile*>(profile)); 76 } 77 78 } // namespace 79 80 namespace extensions { 81 82 class ExtensionBluetoothEventRouterTest : public testing::Test { 83 public: 84 ExtensionBluetoothEventRouterTest() 85 : mock_adapter_(new testing::StrictMock<device::MockBluetoothAdapter>()), 86 test_profile_(new TestingProfile()), 87 router_(test_profile_.get()), 88 ui_thread_(content::BrowserThread::UI, &message_loop_) { 89 router_.SetAdapterForTest(mock_adapter_); 90 } 91 92 virtual void TearDown() OVERRIDE { 93 // Some profile-dependent services rely on UI thread to clean up. We make 94 // sure they are properly cleaned up by running the UI message loop until 95 // idle. 96 test_profile_.reset(NULL); 97 base::RunLoop run_loop; 98 run_loop.RunUntilIdle(); 99 } 100 101 protected: 102 testing::StrictMock<device::MockBluetoothAdapter>* mock_adapter_; 103 testing::NiceMock<device::MockBluetoothProfile> mock_audio_profile_; 104 testing::NiceMock<device::MockBluetoothProfile> mock_health_profile_; 105 scoped_ptr<TestingProfile> test_profile_; 106 ExtensionBluetoothEventRouter router_; 107 base::MessageLoopForUI message_loop_; 108 content::TestBrowserThread ui_thread_; 109 }; 110 111 TEST_F(ExtensionBluetoothEventRouterTest, BluetoothEventListener) { 112 router_.OnListenerAdded(); 113 EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)).Times(1); 114 router_.OnListenerRemoved(); 115 } 116 117 TEST_F(ExtensionBluetoothEventRouterTest, MultipleBluetoothEventListeners) { 118 router_.OnListenerAdded(); 119 router_.OnListenerAdded(); 120 router_.OnListenerAdded(); 121 router_.OnListenerRemoved(); 122 router_.OnListenerRemoved(); 123 EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)).Times(1); 124 router_.OnListenerRemoved(); 125 } 126 127 TEST_F(ExtensionBluetoothEventRouterTest, Profiles) { 128 EXPECT_FALSE(router_.HasProfile(kAudioProfileUuid)); 129 EXPECT_FALSE(router_.HasProfile(kHealthProfileUuid)); 130 131 router_.AddProfile(kAudioProfileUuid, &mock_audio_profile_); 132 router_.AddProfile(kHealthProfileUuid, &mock_health_profile_); 133 EXPECT_TRUE(router_.HasProfile(kAudioProfileUuid)); 134 EXPECT_TRUE(router_.HasProfile(kHealthProfileUuid)); 135 136 EXPECT_CALL(mock_audio_profile_, Unregister()).Times(1); 137 router_.RemoveProfile(kAudioProfileUuid); 138 EXPECT_FALSE(router_.HasProfile(kAudioProfileUuid)); 139 EXPECT_TRUE(router_.HasProfile(kHealthProfileUuid)); 140 141 // Make sure remaining profiles are unregistered in destructor. 142 EXPECT_CALL(mock_health_profile_, Unregister()).Times(1); 143 EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)).Times(1); 144 } 145 146 TEST_F(ExtensionBluetoothEventRouterTest, DispatchConnectionEvent) { 147 router_.AddProfile(kAudioProfileUuid, &mock_audio_profile_); 148 149 FakeExtensionSystem* fake_extension_system = 150 static_cast<FakeExtensionSystem*>(ExtensionSystemFactory::GetInstance()-> 151 SetTestingFactoryAndUse(test_profile_.get(), 152 &BuildFakeExtensionSystem)); 153 154 const char test_extension_id[] = "test extension id"; 155 testing::NiceMock<device::MockBluetoothDevice> mock_device( 156 mock_adapter_, 0, "device name", "device address", true, false); 157 scoped_refptr<testing::NiceMock<device::MockBluetoothSocket> > mock_socket( 158 new testing::NiceMock<device::MockBluetoothSocket>()); 159 160 router_.DispatchConnectionEvent(test_extension_id, 161 kAudioProfileUuid, 162 &mock_device, 163 mock_socket); 164 165 FakeEventRouter* fake_event_router = 166 static_cast<FakeEventRouter*>(fake_extension_system->event_router()); 167 168 EXPECT_STREQ(test_extension_id, fake_event_router->extension_id().c_str()); 169 EXPECT_STREQ(event_names::kBluetoothOnConnection, 170 fake_event_router->event()->event_name.c_str()); 171 172 base::ListValue* event_args = fake_event_router->event()->event_args.get(); 173 base::DictionaryValue* socket_value = NULL; 174 ASSERT_TRUE(event_args->GetDictionary(0, &socket_value)); 175 int socket_id; 176 ASSERT_TRUE(socket_value->GetInteger("id", &socket_id)); 177 EXPECT_EQ(mock_socket.get(), router_.GetSocket(socket_id).get()); 178 179 base::DictionaryValue* profile_value = NULL; 180 ASSERT_TRUE(socket_value->GetDictionary("profile", &profile_value)); 181 std::string profile_uuid; 182 ASSERT_TRUE(profile_value->GetString("uuid", &profile_uuid)); 183 EXPECT_STREQ(kAudioProfileUuid, profile_uuid.c_str()); 184 185 EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)).Times(1); 186 router_.ReleaseSocket(socket_id); 187 } 188 189 TEST_F(ExtensionBluetoothEventRouterTest, DoNotDispatchConnectionEvent) { 190 FakeExtensionSystem* fake_extension_system = 191 static_cast<FakeExtensionSystem*>(ExtensionSystemFactory::GetInstance()-> 192 SetTestingFactoryAndUse(test_profile_.get(), 193 &BuildFakeExtensionSystem)); 194 testing::NiceMock<device::MockBluetoothDevice> mock_device( 195 mock_adapter_, 0, "device name", "device address", true, false); 196 scoped_refptr<testing::NiceMock<device::MockBluetoothSocket> > mock_socket( 197 new testing::NiceMock<device::MockBluetoothSocket>()); 198 199 // Connection event won't be dispatched for non-registered profiles. 200 router_.DispatchConnectionEvent("test extension id", 201 kAudioProfileUuid, 202 &mock_device, 203 mock_socket); 204 FakeEventRouter* fake_event_router = 205 static_cast<FakeEventRouter*>(fake_extension_system->event_router()); 206 EXPECT_TRUE(fake_event_router->event() == NULL); 207 208 EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)).Times(1); 209 } 210 211 } // namespace extensions 212