Index: components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc |
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..fa00af876a6f97e6a2ee9852cfd4897d1ad92f6c |
--- /dev/null |
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc |
@@ -0,0 +1,231 @@ |
+// Copyright 2016 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 "components/subresource_filter/content/renderer/subresource_filter_agent.h" |
+ |
+#include <memory> |
+#include <utility> |
+ |
+#include "base/macros.h" |
+#include "base/strings/string_piece.h" |
+#include "components/subresource_filter/content/common/subresource_filter_messages.h" |
+#include "components/subresource_filter/content/renderer/ruleset_dealer.h" |
+#include "components/subresource_filter/core/common/test_ruleset_creator.h" |
+#include "components/test_runner/test_common.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h" |
+#include "third_party/WebKit/public/platform/WebURL.h" |
+#include "third_party/WebKit/public/platform/WebURLRequest.h" |
+#include "url/gurl.h" |
+ |
+namespace subresource_filter { |
+ |
+namespace { |
+ |
+// The SubresourceFilterAgent with its dependencies on Blink mocked out. |
+// |
+// This approach is somewhat rudimentary, but appears to be the best compromise |
+// considering the alternatives: |
+// -- Passing in a TestRenderFrame would itself require bringing up a |
+// significant number of supporting classes. |
+// -- Using a RenderViewTest would not allow having any non-filtered resource |
+// loads due to not having a child thread and ResourceDispatcher. |
+// The real implementations of the mocked-out methods are exercised in: |
+// chrome/browser/subresource_filter/subresource_filter_browsertest.cc. |
+class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent { |
+ public: |
+ explicit SubresourceFilterAgentUnderTest(RulesetDealer* ruleset_dealer) |
+ : SubresourceFilterAgent(nullptr /* RenderFrame */, ruleset_dealer) {} |
+ ~SubresourceFilterAgentUnderTest() = default; |
+ |
+ MOCK_METHOD0(GetAncestorDocumentURLs, std::vector<GURL>()); |
+ MOCK_METHOD0(OnSetSubresourceFilterForCommittedLoadCalled, void()); |
+ void SetSubresourceFilterForCommittedLoad( |
+ std::unique_ptr<blink::WebDocumentSubresourceFilter> filter) override { |
+ last_injected_filter_ = std::move(filter); |
+ OnSetSubresourceFilterForCommittedLoadCalled(); |
+ } |
+ |
+ blink::WebDocumentSubresourceFilter* filter() { |
+ return last_injected_filter_.get(); |
+ } |
+ |
+ private: |
+ std::unique_ptr<blink::WebDocumentSubresourceFilter> last_injected_filter_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterAgentUnderTest); |
+}; |
+ |
+const char kTestFirstURL[] = "http://example.com/alpha"; |
+const char kTestSecondURL[] = "http://example.com/beta"; |
+const char kTestFirstURLPathSuffix[] = "alpha"; |
+const char kTestSecondURLPathSuffix[] = "beta"; |
+const char kTestBothURLsPathSuffix[] = "a"; |
+ |
+} // namespace |
+ |
+class SubresourceFilterAgentTest : public ::testing::Test { |
+ public: |
+ SubresourceFilterAgentTest() { test_runner::EnsureBlinkInitialized(); } |
+ |
+ protected: |
+ void SetUp() override { |
+ agent_.reset(new SubresourceFilterAgentUnderTest(&ruleset_dealer_)); |
+ ON_CALL(*agent(), GetAncestorDocumentURLs()) |
+ .WillByDefault(::testing::Return(std::vector<GURL>( |
+ {GURL("http://inner.com/"), GURL("http://outer.com/")}))); |
+ } |
+ |
+ void SetTestRulesetToDisallowURLsWithPathSuffix(base::StringPiece suffix) { |
+ base::File ruleset_file; |
+ ASSERT_NO_FATAL_FAILURE( |
+ test_ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix( |
+ suffix, &ruleset_file)); |
+ ruleset_dealer_.SetRulesetFile(std::move(ruleset_file)); |
+ } |
+ |
+ void StartLoadWithoutSettingActivationState() { |
+ agent_as_rfo()->DidStartProvisionalLoad(); |
+ agent_as_rfo()->DidCommitProvisionalLoad( |
+ true /* is_new_navigation */, false /* is_same_page_navigation */); |
+ } |
+ |
+ void StartLoadAndSetActivationState(ActivationState activation_state) { |
+ agent_as_rfo()->DidStartProvisionalLoad(); |
+ EXPECT_TRUE(agent_as_rfo()->OnMessageReceived( |
+ SubresourceFilterMsg_ActivateForProvisionalLoad(0, activation_state))); |
+ agent_as_rfo()->DidCommitProvisionalLoad( |
+ true /* is_new_navigation */, false /* is_same_page_navigation */); |
+ } |
+ |
+ void FinishLoad() { agent_as_rfo()->DidFinishLoad(); } |
+ |
+ void ExpectSubresourceFilterGetsInjected() { |
+ EXPECT_CALL(*agent(), GetAncestorDocumentURLs()); |
+ EXPECT_CALL(*agent(), OnSetSubresourceFilterForCommittedLoadCalled()); |
+ } |
+ |
+ void ExpectNoSubresourceFilterGetsInjected() { |
+ EXPECT_CALL(*agent(), OnSetSubresourceFilterForCommittedLoadCalled()) |
+ .Times(0); |
+ } |
+ |
+ void ExpectLoadAllowed(base::StringPiece url_spec, bool allowed) { |
+ blink::WebURL url = GURL(url_spec); |
+ blink::WebURLRequest::RequestContext request_context = |
+ blink::WebURLRequest::RequestContextUnspecified; |
+ EXPECT_EQ(allowed, agent()->filter()->allowLoad(url, request_context)); |
+ } |
+ |
+ SubresourceFilterAgentUnderTest* agent() { return agent_.get(); } |
+ content::RenderFrameObserver* agent_as_rfo() { |
+ return static_cast<content::RenderFrameObserver*>(agent_.get()); |
+ } |
+ |
+ private: |
+ testing::TestRulesetCreator test_ruleset_creator_; |
+ RulesetDealer ruleset_dealer_; |
+ |
+ std::unique_ptr<SubresourceFilterAgentUnderTest> agent_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterAgentTest); |
+}; |
+ |
+TEST_F(SubresourceFilterAgentTest, DisabledByDefault_NoFilterIsInjected) { |
+ ASSERT_NO_FATAL_FAILURE( |
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix)); |
+ ExpectNoSubresourceFilterGetsInjected(); |
+ StartLoadWithoutSettingActivationState(); |
+ FinishLoad(); |
+} |
+ |
+TEST_F(SubresourceFilterAgentTest, Disabled_NoFilterIsInjected) { |
+ ASSERT_NO_FATAL_FAILURE( |
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix)); |
+ ExpectNoSubresourceFilterGetsInjected(); |
+ StartLoadAndSetActivationState(ActivationState::DISABLED); |
+ FinishLoad(); |
+} |
+ |
+TEST_F(SubresourceFilterAgentTest, |
+ EnabledButRulesetUnavailable_NoFilterIsInjected) { |
+ ExpectNoSubresourceFilterGetsInjected(); |
+ StartLoadAndSetActivationState(ActivationState::ENABLED); |
+ FinishLoad(); |
+} |
+ |
+TEST_F(SubresourceFilterAgentTest, Enabled_FilteringIsInEffectForOneLoad) { |
+ ASSERT_NO_FATAL_FAILURE( |
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix)); |
+ ExpectSubresourceFilterGetsInjected(); |
+ StartLoadAndSetActivationState(ActivationState::ENABLED); |
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); |
+ |
+ ExpectLoadAllowed(kTestFirstURL, false); |
+ ExpectLoadAllowed(kTestSecondURL, true); |
+ FinishLoad(); |
+ |
+ ExpectNoSubresourceFilterGetsInjected(); |
+ StartLoadWithoutSettingActivationState(); |
+ FinishLoad(); |
+} |
+ |
+TEST_F(SubresourceFilterAgentTest, Enabled_NewRulesetIsPickedUpAtNextLoad) { |
+ ASSERT_NO_FATAL_FAILURE( |
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix)); |
+ ExpectSubresourceFilterGetsInjected(); |
+ StartLoadAndSetActivationState(ActivationState::ENABLED); |
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); |
+ |
+ // Set the new ruleset just after the deadline for being used for the current |
+ // load, to exercises doing filtering based on obseleted rulesets. |
+ ASSERT_NO_FATAL_FAILURE( |
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestSecondURLPathSuffix)); |
+ |
+ ExpectLoadAllowed(kTestFirstURL, false); |
+ ExpectLoadAllowed(kTestSecondURL, true); |
+ FinishLoad(); |
+ |
+ ExpectSubresourceFilterGetsInjected(); |
+ StartLoadAndSetActivationState(ActivationState::ENABLED); |
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); |
+ |
+ ExpectLoadAllowed(kTestFirstURL, true); |
+ ExpectLoadAllowed(kTestSecondURL, false); |
+ FinishLoad(); |
+} |
+ |
+// If a provisional load is aborted, the RenderFrameObservers might not receive |
+// any further notifications about that load. It is thus possible that there |
+// will be two RenderFrameObserver::DidStartProvisionalLoad in a row. Make sure |
+// that the activation decision does not outlive the first provisional load. |
+TEST_F(SubresourceFilterAgentTest, |
+ Enabled_FilteringNoLongerEffectAfterProvisionalLoadIsCancelled) { |
+ ASSERT_NO_FATAL_FAILURE( |
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix)); |
+ ExpectNoSubresourceFilterGetsInjected(); |
+ agent_as_rfo()->DidStartProvisionalLoad(); |
+ EXPECT_TRUE(agent_as_rfo()->OnMessageReceived( |
+ SubresourceFilterMsg_ActivateForProvisionalLoad( |
+ 0, ActivationState::ENABLED))); |
+ agent_as_rfo()->DidStartProvisionalLoad(); |
+ agent_as_rfo()->DidCommitProvisionalLoad(true /* is_new_navigation */, |
+ false /* is_same_page_navigation */); |
+ FinishLoad(); |
+} |
+ |
+TEST_F(SubresourceFilterAgentTest, DryRun_ResourcesAreEvaluatedButNotFiltered) { |
+ ASSERT_NO_FATAL_FAILURE( |
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix)); |
+ ExpectSubresourceFilterGetsInjected(); |
+ StartLoadAndSetActivationState(ActivationState::DRYRUN); |
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); |
+ |
+ ExpectLoadAllowed(kTestFirstURL, true); |
+ ExpectLoadAllowed(kTestSecondURL, true); |
+ FinishLoad(); |
+} |
+ |
+} // namespace subresource_filter |