OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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 "chrome/browser/extensions/api/mdns/mdns_api.h" |
| 6 #include "chrome/browser/extensions/extension_service.h" |
| 7 #include "chrome/browser/extensions/extension_service_test_base.h" |
| 8 #include "chrome/browser/extensions/test_extension_system.h" |
| 9 #include "chrome/common/extensions/api/mdns.h" |
| 10 #include "content/public/browser/browser_context.h" |
| 11 #include "content/public/test/mock_render_process_host.h" |
| 12 #include "extensions/browser/extension_prefs_factory.h" |
| 13 #include "extensions/browser/extension_registry.h" |
| 14 #include "extensions/common/manifest_constants.h" |
| 15 #include "testing/gmock/include/gmock/gmock.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" |
| 17 |
| 18 namespace extensions { |
| 19 |
| 20 namespace { |
| 21 |
| 22 KeyedService* MDnsAPITestingFactoryFunction(content::BrowserContext* context) { |
| 23 return new MDnsAPI(context); |
| 24 } |
| 25 |
| 26 // For ExtensionService interface when it requires a path that is not used. |
| 27 base::FilePath bogus_file_pathname(const std::string& name) { |
| 28 return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent")) |
| 29 .AppendASCII(name); |
| 30 } |
| 31 |
| 32 class MockDnsSdRegistry : public DnsSdRegistry { |
| 33 public: |
| 34 explicit MockDnsSdRegistry(extensions::MDnsAPI* api) : api_(api) {} |
| 35 virtual ~MockDnsSdRegistry() {} |
| 36 |
| 37 MOCK_METHOD1(AddObserver, void(DnsSdObserver* observer)); |
| 38 MOCK_METHOD1(RemoveObserver, void(DnsSdObserver* observer)); |
| 39 MOCK_METHOD1(RegisterDnsSdListener, void(std::string service_type)); |
| 40 MOCK_METHOD1(UnregisterDnsSdListener, void(std::string service_type)); |
| 41 |
| 42 void DispatchMDnsEvent(const std::string& service_type, |
| 43 const DnsSdServiceList& services) { |
| 44 api_->OnDnsSdEvent(service_type, services); |
| 45 } |
| 46 |
| 47 private: |
| 48 extensions::DnsSdRegistry::DnsSdObserver* api_; |
| 49 }; |
| 50 |
| 51 class MDnsAPITest : public extensions::ExtensionServiceTestBase { |
| 52 public: |
| 53 void SetUp() override { |
| 54 extensions::ExtensionServiceTestBase::SetUp(); |
| 55 |
| 56 // Set up browser_context(). |
| 57 InitializeEmptyExtensionService(); |
| 58 |
| 59 // A custom TestingFactoryFunction is required for an MDnsAPI to actually be |
| 60 // constructed. |
| 61 MDnsAPI::GetFactoryInstance()->SetTestingFactory( |
| 62 browser_context(), |
| 63 MDnsAPITestingFactoryFunction); |
| 64 |
| 65 // Create an event router and associate it with the context. |
| 66 extensions::EventRouter* event_router = new extensions::EventRouter( |
| 67 browser_context(), |
| 68 ExtensionPrefsFactory::GetInstance()->GetForBrowserContext( |
| 69 browser_context())); |
| 70 static_cast<TestExtensionSystem*>( |
| 71 ExtensionSystem::Get(browser_context()))->SetEventRouter( |
| 72 scoped_ptr<extensions::EventRouter>(event_router)); |
| 73 |
| 74 // Do some sanity checking |
| 75 ASSERT_EQ(event_router, EventRouter::Get(browser_context())); |
| 76 ASSERT_TRUE(MDnsAPI::Get(browser_context())); // constructs MDnsAPI |
| 77 |
| 78 registry_ = new MockDnsSdRegistry(MDnsAPI::Get(browser_context())); |
| 79 EXPECT_CALL(*dns_sd_registry(), |
| 80 AddObserver(MDnsAPI::Get(browser_context()))) |
| 81 .Times(1); |
| 82 MDnsAPI::Get(browser_context())->SetDnsSdRegistryForTesting( |
| 83 scoped_ptr<DnsSdRegistry>(registry_)); |
| 84 |
| 85 render_process_host_.reset( |
| 86 new content::MockRenderProcessHost(browser_context())); |
| 87 } |
| 88 |
| 89 void TearDown() override { |
| 90 EXPECT_CALL(*dns_sd_registry(), |
| 91 RemoveObserver(MDnsAPI::Get(browser_context()))) |
| 92 .Times(1); |
| 93 render_process_host_.reset(); |
| 94 extensions::ExtensionServiceTestBase::TearDown(); |
| 95 MDnsAPI::GetFactoryInstance()->SetTestingFactory( |
| 96 browser_context(), |
| 97 nullptr); |
| 98 |
| 99 registry_ = nullptr; |
| 100 } |
| 101 |
| 102 virtual MockDnsSdRegistry* dns_sd_registry() { |
| 103 return registry_; |
| 104 } |
| 105 |
| 106 // Constructs an extension according to the parameters that matter most to |
| 107 // MDnsAPI the local unit tests. |
| 108 const scoped_refptr<extensions::Extension> CreateExtension( |
| 109 std::string name, |
| 110 bool is_platform_app, |
| 111 std::string extension_id) { |
| 112 base::DictionaryValue manifest; |
| 113 manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0"); |
| 114 manifest.SetString(extensions::manifest_keys::kName, name); |
| 115 if (is_platform_app) { |
| 116 // Setting app.background.page = "background.html" is sufficient to make |
| 117 // the extension type TYPE_PLATFORM_APP. |
| 118 manifest.Set(extensions::manifest_keys::kPlatformAppBackgroundPage, |
| 119 new base::StringValue("background.html")); |
| 120 } |
| 121 |
| 122 std::string error; |
| 123 return extensions::Extension::Create( |
| 124 bogus_file_pathname(name), |
| 125 extensions::Manifest::INVALID_LOCATION, |
| 126 manifest, |
| 127 Extension::NO_FLAGS, |
| 128 extension_id, |
| 129 &error); |
| 130 } |
| 131 |
| 132 content::RenderProcessHost* render_process_host() const { |
| 133 return render_process_host_.get(); |
| 134 } |
| 135 |
| 136 private: |
| 137 // The registry is owned by MDnsAPI, but MDnsAPI does not have an accessor |
| 138 // for it, so use a private member. |
| 139 MockDnsSdRegistry* registry_; |
| 140 |
| 141 scoped_ptr<content::RenderProcessHost> render_process_host_; |
| 142 |
| 143 }; |
| 144 |
| 145 TEST_F(MDnsAPITest, ExtensionRespectsWhitelist) { |
| 146 const std::string ext_id("mbflcebpggnecokmikipoihdbecnjfoj"); |
| 147 scoped_refptr<extensions::Extension> extension = |
| 148 CreateExtension("Dinosaur networker", false, ext_id); |
| 149 ExtensionRegistry::Get(browser_context())->AddEnabled(extension); |
| 150 ASSERT_EQ(Manifest::TYPE_EXTENSION, extension.get()->GetType()); |
| 151 |
| 152 // There is a whitelist of mdns service types extensions may access, which |
| 153 // includes "_testing._tcp.local" and exludes "_trex._tcp.local" |
| 154 { |
| 155 base::DictionaryValue filter; |
| 156 filter.SetString(kEventFilterServiceTypeKey, "_trex._tcp.local"); |
| 157 |
| 158 ASSERT_TRUE(dns_sd_registry()); |
| 159 // Test that the extension is able to listen to a non-whitelisted service |
| 160 EXPECT_CALL(*dns_sd_registry(), RegisterDnsSdListener("_trex._tcp.local")) |
| 161 .Times(0); |
| 162 EventRouter::Get(browser_context())->AddFilteredEventListener( |
| 163 api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
| 164 filter, false); |
| 165 |
| 166 EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local")) |
| 167 .Times(0); |
| 168 EventRouter::Get(browser_context())->RemoveFilteredEventListener( |
| 169 api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
| 170 filter, false); |
| 171 } |
| 172 { |
| 173 base::DictionaryValue filter; |
| 174 filter.SetString(kEventFilterServiceTypeKey, "_testing._tcp.local"); |
| 175 |
| 176 ASSERT_TRUE(dns_sd_registry()); |
| 177 // Test that the extension is able to listen to a whitelisted service |
| 178 EXPECT_CALL(*dns_sd_registry(), |
| 179 RegisterDnsSdListener("_testing._tcp.local")); |
| 180 EventRouter::Get(browser_context())->AddFilteredEventListener( |
| 181 api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
| 182 filter, false); |
| 183 |
| 184 EXPECT_CALL(*dns_sd_registry(), |
| 185 UnregisterDnsSdListener("_testing._tcp.local")); |
| 186 EventRouter::Get(browser_context())->RemoveFilteredEventListener( |
| 187 api::mdns::OnServiceList::kEventName, render_process_host(), |
| 188 ext_id, filter, false); |
| 189 } |
| 190 } |
| 191 |
| 192 TEST_F(MDnsAPITest, PlatformAppsNotSubjectToWhitelist) { |
| 193 const std::string ext_id("mbflcebpggnecokmikipoihdbecnjfoj"); |
| 194 scoped_refptr<extensions::Extension> extension = |
| 195 CreateExtension("Dinosaur networker", true, ext_id); |
| 196 ExtensionRegistry::Get(browser_context())->AddEnabled(extension); |
| 197 ASSERT_TRUE(extension.get()->is_platform_app()); |
| 198 |
| 199 base::DictionaryValue filter; |
| 200 filter.SetString(kEventFilterServiceTypeKey, "_trex._tcp.local"); |
| 201 |
| 202 ASSERT_TRUE(dns_sd_registry()); |
| 203 // Test that the extension is able to listen to a non-whitelisted service |
| 204 EXPECT_CALL(*dns_sd_registry(), RegisterDnsSdListener("_trex._tcp.local")); |
| 205 EventRouter::Get(browser_context())->AddFilteredEventListener( |
| 206 api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
| 207 filter, false); |
| 208 |
| 209 EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local")); |
| 210 EventRouter::Get(browser_context())->RemoveFilteredEventListener( |
| 211 api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
| 212 filter, false); |
| 213 } |
| 214 |
| 215 } // empty namespace |
| 216 |
| 217 } // namespace extensions |
OLD | NEW |