blob: 315673c8525f0c384f62a36d76fa1650c817fb70 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/content_settings/browser/ui/cookie_controls_controller.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/content_settings/page_specific_content_settings_delegate.h"
#include "chrome/browser/ui/cookie_controls/cookie_controls_service.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/content_settings/browser/ui/cookie_controls_view.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/cookie_controls_enforcement.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using StorageType =
content_settings::mojom::ContentSettingsManager::StorageType;
class MockCookieControlsView : public content_settings::CookieControlsView {
public:
MOCK_METHOD(void,
OnStatusChanged,
(CookieControlsStatus, CookieControlsEnforcement, int, int));
MOCK_METHOD(void, OnCookiesCountChanged, (int, int));
};
} // namespace
// More readable output for test expectation.
std::ostream& operator<<(std::ostream& os, const CookieControlsStatus& status) {
switch (status) {
case CookieControlsStatus::kDisabled:
return os << "kDisabled";
case CookieControlsStatus::kEnabled:
return os << "kEnabled";
case CookieControlsStatus::kDisabledForSite:
return os << "kDisabledForSite";
case CookieControlsStatus::kUninitialized:
return os << "kUninitialized";
}
}
std::ostream& operator<<(std::ostream& os,
const CookieControlsEnforcement& enforcement) {
switch (enforcement) {
case CookieControlsEnforcement::kNoEnforcement:
return os << "kNoEnforcement";
case CookieControlsEnforcement::kEnforcedByCookieSetting:
return os << "kEnforcedByCookieSetting";
case CookieControlsEnforcement::kEnforcedByExtension:
return os << "kEnforcedByExtension";
case CookieControlsEnforcement::kEnforcedByPolicy:
return os << "kEnforcedByPolicy";
}
}
class CookieControlsTest : public ChromeRenderViewHostTestHarness {
protected:
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
content_settings::PageSpecificContentSettings::CreateForWebContents(
web_contents(),
std::make_unique<chrome::PageSpecificContentSettingsDelegate>(
web_contents()));
profile()->GetPrefs()->SetInteger(
prefs::kCookieControlsMode,
static_cast<int>(
content_settings::CookieControlsMode::kBlockThirdParty));
NavigateAndCommit(GURL("chrome://newtab"));
cookie_settings_ = CookieSettingsFactory::GetForProfile(profile());
cookie_controls_ =
std::make_unique<content_settings::CookieControlsController>(
cookie_settings_, nullptr);
cookie_controls_->AddObserver(mock());
testing::Mock::VerifyAndClearExpectations(mock());
}
void TearDown() override {
cookie_controls_->RemoveObserver(mock());
cookie_controls_.reset();
ChromeRenderViewHostTestHarness::TearDown();
}
content_settings::CookieControlsController* cookie_controls() {
return cookie_controls_.get();
}
content_settings::CookieSettings* cookie_settings() {
return cookie_settings_.get();
}
MockCookieControlsView* mock() { return &mock_; }
content_settings::PageSpecificContentSettings*
page_specific_content_settings() {
return content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
}
private:
MockCookieControlsView mock_;
std::unique_ptr<content_settings::CookieControlsController> cookie_controls_;
scoped_refptr<content_settings::CookieSettings> cookie_settings_;
};
TEST_F(CookieControlsTest, NewTabPage) {
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kDisabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->Update(web_contents());
}
TEST_F(CookieControlsTest, SomeWebSite) {
// Visiting a website should enable the UI.
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Accessing cookies should be notified.
EXPECT_CALL(*mock(), OnCookiesCountChanged(1, 0));
page_specific_content_settings()->OnStorageAccessed(
StorageType::DATABASE, GURL("https://example.com"),
/*blocked_by_policy=*/false);
testing::Mock::VerifyAndClearExpectations(mock());
// Manually trigger a full update to check that the cookie count changed.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 1, 0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Blocking cookies should update the blocked cookie count.
EXPECT_CALL(*mock(), OnCookiesCountChanged(1, 1));
page_specific_content_settings()->OnStorageAccessed(
StorageType::DATABASE, GURL("https://thirdparty.com"),
/*blocked_by_policy=*/true);
testing::Mock::VerifyAndClearExpectations(mock());
// Manually trigger a full update to check that the cookie count changed.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 1, 1));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Navigating somewhere else should reset the cookie count.
NavigateAndCommit(GURL("https://somethingelse.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->Update(web_contents());
}
TEST_F(CookieControlsTest, PreferenceDisabled) {
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Disabling the feature should disable the UI.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kDisabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
profile()->GetPrefs()->SetInteger(
prefs::kCookieControlsMode,
static_cast<int>(content_settings::CookieControlsMode::kOff));
testing::Mock::VerifyAndClearExpectations(mock());
}
TEST_F(CookieControlsTest, AllCookiesBlocked) {
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Disable all cookies - an OnStatusCallback should get triggered.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_settings()->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
testing::Mock::VerifyAndClearExpectations(mock());
// Disable cookie blocking for example.com.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kDisabledForSite,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->OnCookieBlockingEnabledForSite(false);
testing::Mock::VerifyAndClearExpectations(mock());
}
TEST_F(CookieControlsTest, DisableForSite) {
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Disabling cookie blocking for example.com should update the ui.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kDisabledForSite,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->OnCookieBlockingEnabledForSite(false);
testing::Mock::VerifyAndClearExpectations(mock());
// Visiting some other site, should switch back to kEnabled.
NavigateAndCommit(GURL("https://somethingelse.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Visiting example.com should set status to kDisabledForSite.
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kDisabledForSite,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Enabling example.com again should change status to kEnabled.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->OnCookieBlockingEnabledForSite(true);
testing::Mock::VerifyAndClearExpectations(mock());
}
TEST_F(CookieControlsTest, Incognito) {
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Create incognito web_contents and
// content_settings::CookieControlsController.
std::unique_ptr<content::WebContents> incognito_web_contents =
content::WebContentsTester::CreateTestWebContents(
profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true), nullptr);
content_settings::PageSpecificContentSettings::CreateForWebContents(
incognito_web_contents.get(),
std::make_unique<chrome::PageSpecificContentSettingsDelegate>(
incognito_web_contents.get()));
auto* tester = content::WebContentsTester::For(incognito_web_contents.get());
MockCookieControlsView incognito_mock_;
content_settings::CookieControlsController incognito_cookie_controls(
CookieSettingsFactory::GetForProfile(
profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true)),
CookieSettingsFactory::GetForProfile(profile()));
incognito_cookie_controls.AddObserver(&incognito_mock_);
// Navigate incognito web_contents to the same URL.
tester->NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(incognito_mock_,
OnStatusChanged(CookieControlsStatus::kEnabled,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
incognito_cookie_controls.Update(incognito_web_contents.get());
testing::Mock::VerifyAndClearExpectations(mock());
testing::Mock::VerifyAndClearExpectations(&incognito_mock_);
// Allow cookies in regular mode should also allow in incognito but enforced
// through regular mode.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsStatus::kDisabledForSite,
CookieControlsEnforcement::kNoEnforcement, 0, 0));
EXPECT_CALL(incognito_mock_,
OnStatusChanged(
CookieControlsStatus::kDisabledForSite,
CookieControlsEnforcement::kEnforcedByCookieSetting, 0, 0));
cookie_controls()->OnCookieBlockingEnabledForSite(false);
testing::Mock::VerifyAndClearExpectations(mock());
testing::Mock::VerifyAndClearExpectations(&incognito_mock_);
}