Index: chrome/browser/extensions/api/mdns/mdns_api_unittest.cc |
diff --git a/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ede2a2b50d4a03491f54e9f4e8e34ff72d3e852d |
--- /dev/null |
+++ b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc |
@@ -0,0 +1,217 @@ |
+// Copyright 2015 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 "chrome/browser/extensions/api/mdns/mdns_api.h" |
+#include "chrome/browser/extensions/extension_service.h" |
+#include "chrome/browser/extensions/extension_service_test_base.h" |
+#include "chrome/browser/extensions/test_extension_system.h" |
+#include "chrome/common/extensions/api/mdns.h" |
+#include "content/public/browser/browser_context.h" |
+#include "content/public/test/mock_render_process_host.h" |
+#include "extensions/browser/extension_prefs_factory.h" |
+#include "extensions/browser/extension_registry.h" |
+#include "extensions/common/manifest_constants.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace extensions { |
+ |
+namespace { |
+ |
+KeyedService* MDnsAPITestingFactoryFunction(content::BrowserContext* context) { |
+ return new MDnsAPI(context); |
+} |
+ |
+// For ExtensionService interface when it requires a path that is not used. |
+base::FilePath bogus_file_pathname(const std::string& name) { |
+ return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent")) |
+ .AppendASCII(name); |
+} |
+ |
+class MockDnsSdRegistry : public DnsSdRegistry { |
+ public: |
+ explicit MockDnsSdRegistry(extensions::MDnsAPI* api) : api_(api) {} |
+ virtual ~MockDnsSdRegistry() {} |
+ |
+ MOCK_METHOD1(AddObserver, void(DnsSdObserver* observer)); |
+ MOCK_METHOD1(RemoveObserver, void(DnsSdObserver* observer)); |
+ MOCK_METHOD1(RegisterDnsSdListener, void(std::string service_type)); |
+ MOCK_METHOD1(UnregisterDnsSdListener, void(std::string service_type)); |
+ |
+ void DispatchMDnsEvent(const std::string& service_type, |
+ const DnsSdServiceList& services) { |
+ api_->OnDnsSdEvent(service_type, services); |
+ } |
+ |
+ private: |
+ extensions::DnsSdRegistry::DnsSdObserver* api_; |
+}; |
+ |
+class MDnsAPITest : public extensions::ExtensionServiceTestBase { |
+ public: |
+ void SetUp() override { |
+ extensions::ExtensionServiceTestBase::SetUp(); |
+ |
+ // Set up browser_context(). |
+ InitializeEmptyExtensionService(); |
+ |
+ // A custom TestingFactoryFunction is required for an MDnsAPI to actually be |
+ // constructed. |
+ MDnsAPI::GetFactoryInstance()->SetTestingFactory( |
+ browser_context(), |
+ MDnsAPITestingFactoryFunction); |
+ |
+ // Create an event router and associate it with the context. |
+ extensions::EventRouter* event_router = new extensions::EventRouter( |
+ browser_context(), |
+ ExtensionPrefsFactory::GetInstance()->GetForBrowserContext( |
+ browser_context())); |
+ static_cast<TestExtensionSystem*>( |
+ ExtensionSystem::Get(browser_context()))->SetEventRouter( |
+ scoped_ptr<extensions::EventRouter>(event_router)); |
+ |
+ // Do some sanity checking |
+ ASSERT_EQ(event_router, EventRouter::Get(browser_context())); |
+ ASSERT_TRUE(MDnsAPI::Get(browser_context())); // constructs MDnsAPI |
+ |
+ registry_ = new MockDnsSdRegistry(MDnsAPI::Get(browser_context())); |
+ EXPECT_CALL(*dns_sd_registry(), |
+ AddObserver(MDnsAPI::Get(browser_context()))) |
+ .Times(1); |
+ MDnsAPI::Get(browser_context())->SetDnsSdRegistryForTesting( |
+ scoped_ptr<DnsSdRegistry>(registry_)); |
+ |
+ render_process_host_.reset( |
+ new content::MockRenderProcessHost(browser_context())); |
+ } |
+ |
+ void TearDown() override { |
+ EXPECT_CALL(*dns_sd_registry(), |
+ RemoveObserver(MDnsAPI::Get(browser_context()))) |
+ .Times(1); |
+ render_process_host_.reset(); |
+ extensions::ExtensionServiceTestBase::TearDown(); |
+ MDnsAPI::GetFactoryInstance()->SetTestingFactory( |
+ browser_context(), |
+ nullptr); |
+ |
+ registry_ = nullptr; |
+ } |
+ |
+ virtual MockDnsSdRegistry* dns_sd_registry() { |
+ return registry_; |
+ } |
+ |
+ // Constructs an extension according to the parameters that matter most to |
+ // MDnsAPI the local unit tests. |
+ const scoped_refptr<extensions::Extension> CreateExtension( |
+ std::string name, |
+ bool is_platform_app, |
+ std::string extension_id) { |
+ base::DictionaryValue manifest; |
+ manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0"); |
+ manifest.SetString(extensions::manifest_keys::kName, name); |
+ if (is_platform_app) { |
+ // Setting app.background.page = "background.html" is sufficient to make |
+ // the extension type TYPE_PLATFORM_APP. |
+ manifest.Set(extensions::manifest_keys::kPlatformAppBackgroundPage, |
+ new base::StringValue("background.html")); |
+ } |
+ |
+ std::string error; |
+ return extensions::Extension::Create( |
+ bogus_file_pathname(name), |
+ extensions::Manifest::INVALID_LOCATION, |
+ manifest, |
+ Extension::NO_FLAGS, |
+ extension_id, |
+ &error); |
+ } |
+ |
+ content::RenderProcessHost* render_process_host() const { |
+ return render_process_host_.get(); |
+ } |
+ |
+ private: |
+ // The registry is owned by MDnsAPI, but MDnsAPI does not have an accessor |
+ // for it, so use a private member. |
+ MockDnsSdRegistry* registry_; |
+ |
+ scoped_ptr<content::RenderProcessHost> render_process_host_; |
+ |
+}; |
+ |
+TEST_F(MDnsAPITest, ExtensionRespectsWhitelist) { |
+ const std::string ext_id("mbflcebpggnecokmikipoihdbecnjfoj"); |
+ scoped_refptr<extensions::Extension> extension = |
+ CreateExtension("Dinosaur networker", false, ext_id); |
+ ExtensionRegistry::Get(browser_context())->AddEnabled(extension); |
+ ASSERT_EQ(Manifest::TYPE_EXTENSION, extension.get()->GetType()); |
+ |
+ // There is a whitelist of mdns service types extensions may access, which |
+ // includes "_testing._tcp.local" and exludes "_trex._tcp.local" |
+ { |
+ base::DictionaryValue filter; |
+ filter.SetString(kEventFilterServiceTypeKey, "_trex._tcp.local"); |
+ |
+ ASSERT_TRUE(dns_sd_registry()); |
+ // Test that the extension is able to listen to a non-whitelisted service |
+ EXPECT_CALL(*dns_sd_registry(), RegisterDnsSdListener("_trex._tcp.local")) |
+ .Times(0); |
+ EventRouter::Get(browser_context())->AddFilteredEventListener( |
+ api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
+ filter, false); |
+ |
+ EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local")) |
+ .Times(0); |
+ EventRouter::Get(browser_context())->RemoveFilteredEventListener( |
+ api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
+ filter, false); |
+ } |
+ { |
+ base::DictionaryValue filter; |
+ filter.SetString(kEventFilterServiceTypeKey, "_testing._tcp.local"); |
+ |
+ ASSERT_TRUE(dns_sd_registry()); |
+ // Test that the extension is able to listen to a whitelisted service |
+ EXPECT_CALL(*dns_sd_registry(), |
+ RegisterDnsSdListener("_testing._tcp.local")); |
+ EventRouter::Get(browser_context())->AddFilteredEventListener( |
+ api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
+ filter, false); |
+ |
+ EXPECT_CALL(*dns_sd_registry(), |
+ UnregisterDnsSdListener("_testing._tcp.local")); |
+ EventRouter::Get(browser_context())->RemoveFilteredEventListener( |
+ api::mdns::OnServiceList::kEventName, render_process_host(), |
+ ext_id, filter, false); |
+ } |
+} |
+ |
+TEST_F(MDnsAPITest, PlatformAppsNotSubjectToWhitelist) { |
+ const std::string ext_id("mbflcebpggnecokmikipoihdbecnjfoj"); |
+ scoped_refptr<extensions::Extension> extension = |
+ CreateExtension("Dinosaur networker", true, ext_id); |
+ ExtensionRegistry::Get(browser_context())->AddEnabled(extension); |
+ ASSERT_TRUE(extension.get()->is_platform_app()); |
+ |
+ base::DictionaryValue filter; |
+ filter.SetString(kEventFilterServiceTypeKey, "_trex._tcp.local"); |
+ |
+ ASSERT_TRUE(dns_sd_registry()); |
+ // Test that the extension is able to listen to a non-whitelisted service |
+ EXPECT_CALL(*dns_sd_registry(), RegisterDnsSdListener("_trex._tcp.local")); |
+ EventRouter::Get(browser_context())->AddFilteredEventListener( |
+ api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
+ filter, false); |
+ |
+ EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local")); |
+ EventRouter::Get(browser_context())->RemoveFilteredEventListener( |
+ api::mdns::OnServiceList::kEventName, render_process_host(), ext_id, |
+ filter, false); |
+} |
+ |
+} // empty namespace |
+ |
+} // namespace extensions |