| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stddef.h> |
| |
| #include <array> |
| #include <memory> |
| #include <string> |
| |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/metrics/histogram_samples.h" |
| #include "base/path_service.h" |
| #include "base/run_loop.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/test/bind.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/simple_test_clock.h" |
| #include "base/test/test_future.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/browsing_data/browsing_data_remover_browsertest_base.h" |
| #include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h" |
| #include "chrome/browser/browsing_data/counters/cache_counter.h" |
| #include "chrome/browser/browsing_data/counters/site_data_counting_helper.h" |
| #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| #include "chrome/browser/external_protocol/external_protocol_handler.h" |
| #include "chrome/browser/media/clear_key_cdm_test_helper.h" |
| #include "chrome/browser/prefs/session_startup_pref.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/signin/account_reconcilor_factory.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "chrome/browser/sync/sync_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "components/browsing_data/content/browsing_data_model.h" |
| #include "components/browsing_data/core/features.h" |
| #include "components/content_settings/core/browser/host_content_settings_map.h" |
| #include "components/content_settings/core/common/content_settings_utils.h" |
| #include "components/history/core/common/pref_names.h" |
| #include "components/metrics/content/subprocess_metrics_provider.h" |
| #include "components/password_manager/core/browser/features/password_features.h" |
| #include "components/password_manager/core/browser/features/password_manager_features_util.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/core/browser/account_reconcilor.h" |
| #include "components/signin/public/base/signin_switches.h" |
| #include "components/signin/public/identity_manager/identity_manager.h" |
| #include "components/signin/public/identity_manager/identity_test_utils.h" |
| #include "components/sync/base/user_selectable_type.h" |
| #include "components/sync/service/sync_user_settings.h" |
| #include "components/sync/test/test_sync_service.h" |
| #include "content/public/browser/browsing_data_filter_builder.h" |
| #include "content/public/browser/clear_site_data_utils.h" |
| #include "content/public/browser/network_service_util.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/public/browser/storage_usage_info.h" |
| #include "content/public/common/content_client.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/content_paths.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/browsing_data_remover_test_util.h" |
| #include "google_apis/gaia/google_service_auth_error.h" |
| #include "media/base/media_switches.h" |
| #include "media/mojo/mojom/media_types.mojom.h" |
| #include "media/mojo/services/video_decode_perf_history.h" |
| #include "media/mojo/services/webrtc_video_perf_history.h" |
| #include "net/base/features.h" |
| #include "net/cookies/cookie_partition_key.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "storage/browser/quota/quota_manager.h" |
| #include "storage/browser/quota/quota_manager_proxy.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "third_party/blink/public/common/features_generated.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| #if BUILDFLAG(IS_MAC) |
| #include "base/threading/platform_thread.h" |
| #endif |
| #include "base/memory/scoped_refptr.h" |
| #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| #include "chrome/browser/ash/net/system_proxy_manager.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/browser_process_platform_part.h" |
| #include "chromeos/ash/components/dbus/system_proxy/system_proxy_client.h" |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| using content::BrowserThread; |
| using content::BrowsingDataFilterBuilder; |
| |
| using testing::UnorderedElementsAre; |
| using testing::UnorderedElementsAreArray; |
| |
| namespace { |
| static const char* kExampleHost = "example.com"; |
| static const char* kLocalHost = "localhost"; |
| static const base::Time kStartTime = base::Time::Now(); |
| static const base::Time kLastHourTime = kStartTime - base::Hours(1); |
| |
| // This enum is used in the place of base::Time because using base::Time |
| // as a test param causes problems on Fuchsia. See https://crbug.com/1308948 for |
| // details. |
| enum TimeEnum { |
| kDefault, |
| kStart, |
| kLastHour, |
| kMax, |
| }; |
| |
| base::Time TimeEnumToTime(TimeEnum time) { |
| switch (time) { |
| case TimeEnum::kStart: |
| return kStartTime; |
| case TimeEnum::kLastHour: |
| return kLastHourTime; |
| case TimeEnum::kMax: |
| return base::Time::Max(); |
| default: |
| return base::Time(); |
| } |
| } |
| |
| std::vector<std::string> GetHistogramSuffixes( |
| const base::HistogramTester& tester, |
| const std::string& prefix) { |
| std::vector<std::string> types; |
| for (const auto& entry : tester.GetTotalCountsForPrefix(prefix)) { |
| types.push_back(entry.first.substr(prefix.length())); |
| } |
| return types; |
| } |
| |
| void AppendRange(std::vector<std::string>& target, |
| const std::vector<std::string_view>& append) { |
| // Use std append_range() when c++23 is available. |
| target.insert(target.end(), append.begin(), append.end()); |
| } |
| |
| } // namespace |
| |
| class BrowsingDataRemoverBrowserTest |
| : public BrowsingDataRemoverBrowserTestBase { |
| public: |
| BrowsingDataRemoverBrowserTest() { |
| std::vector<base::test::FeatureRef> enabled_features = {}; |
| std::vector<base::test::FeatureRef> disabled_features = {}; |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| enabled_features.push_back(media::kExternalClearKeyForTesting); |
| #endif |
| #if !BUILDFLAG(IS_ANDROID) |
| enabled_features.push_back(browsing_data::features::kDbdRevampDesktop); |
| #endif // !BUILDFLAG(IS_ANDROID) |
| InitFeatureLists(std::move(enabled_features), std::move(disabled_features)); |
| } |
| |
| void SetUpOnMainThread() override { |
| BrowsingDataRemoverBrowserTestBase::SetUpOnMainThread(); |
| host_resolver()->AddRule(kExampleHost, "127.0.0.1"); |
| |
| // Explicitly disable session restore. Otherwise tests that restart the |
| // browser can get tab data persisted across sessions when we thought we |
| // deleted it. |
| SessionStartupPref::SetStartupPref( |
| GetProfile()->GetPrefs(), |
| SessionStartupPref(SessionStartupPref::DEFAULT)); |
| } |
| void RemoveAndWait(uint64_t remove_mask) { |
| RemoveAndWait(remove_mask, TimeEnum::kDefault, TimeEnum::kMax); |
| } |
| |
| void RemoveAndWait(uint64_t remove_mask, TimeEnum delete_begin) { |
| RemoveAndWait(remove_mask, delete_begin, TimeEnum::kMax); |
| } |
| |
| void RemoveAndWait(uint64_t remove_mask, |
| TimeEnum delete_begin, |
| TimeEnum delete_end) { |
| content::BrowsingDataRemover* remover = |
| GetBrowser()->profile()->GetBrowsingDataRemover(); |
| content::BrowsingDataRemoverCompletionObserver completion_observer(remover); |
| remover->RemoveAndReply( |
| TimeEnumToTime(delete_begin), TimeEnumToTime(delete_end), remove_mask, |
| content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, |
| &completion_observer); |
| completion_observer.BlockUntilCompletion(); |
| } |
| |
| void RemoveWithFilterAndWait( |
| uint64_t remove_mask, |
| std::unique_ptr<BrowsingDataFilterBuilder> filter_builder) { |
| content::BrowsingDataRemover* remover = |
| GetBrowser()->profile()->GetBrowsingDataRemover(); |
| content::BrowsingDataRemoverCompletionObserver completion_observer(remover); |
| remover->RemoveWithFilterAndReply( |
| base::Time(), base::Time::Max(), remove_mask, |
| content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, |
| std::move(filter_builder), &completion_observer); |
| completion_observer.BlockUntilCompletion(); |
| } |
| |
| // Test a data type by creating a value and checking it is counted by the |
| // cookie counter. Then it deletes the value and checks that it has been |
| // deleted and the cookie counter is back to zero. |
| void TestSiteData(const std::string& type, TimeEnum delete_begin) { |
| EXPECT_EQ(0, GetSiteDataCount()); |
| GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(GetBrowser(), url)); |
| |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| EXPECT_FALSE(HasDataForType(type)); |
| |
| SetDataForType(type); |
| EXPECT_EQ(1, GetSiteDataCount()); |
| // TODO(crbug.com/40218898): Use a different approach to determine presence |
| // of data that does not depend on UI code and has a better resolution when |
| // 3PSP is fully enabled. ExpectTotalModelCount(1) is not always true |
| // here. |
| EXPECT_TRUE(HasDataForType(type)); |
| |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA, |
| delete_begin); |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| EXPECT_FALSE(HasDataForType(type)); |
| } |
| |
| // Test that storage systems like filesystem, where just an access |
| // creates an empty store, are counted and deleted correctly. |
| void TestEmptySiteData(const std::string& type, TimeEnum delete_begin) { |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(GetBrowser(), url)); |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| // Opening a store of this type creates a site data entry. |
| EXPECT_FALSE(HasDataForType(type)); |
| EXPECT_EQ(1, GetSiteDataCount()); |
| // TODO(crbug.com/40218898): Use a different approach to determine presence |
| // of data that does not depend on UI code and has a better resolution when |
| // 3PSP is fully enabled. ExpectTotalModelCount(1) is not always true |
| // here. |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA, |
| delete_begin); |
| |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| } |
| |
| inline void ExpectTotalModelCount(size_t expected) { |
| std::unique_ptr<BrowsingDataModel> browsing_data_model = |
| GetBrowsingDataModel(GetProfile()); |
| |
| EXPECT_EQ(expected, browsing_data_model->size()); |
| } |
| |
| void OnVideoDecodePerfInfo(base::RunLoop* run_loop, |
| bool* out_is_smooth, |
| bool* out_is_power_efficient, |
| bool is_smooth, |
| bool is_power_efficient) { |
| *out_is_smooth = is_smooth; |
| *out_is_power_efficient = is_power_efficient; |
| run_loop->QuitWhenIdle(); |
| } |
| |
| network::mojom::NetworkContext* network_context() const { |
| return GetBrowser() |
| ->profile() |
| ->GetDefaultStoragePartition() |
| ->GetNetworkContext(); |
| } |
| |
| void ClearSiteDataAndWait( |
| const url::Origin& origin, |
| const std::optional<net::CookiePartitionKey>& cookie_partition_key, |
| const std::optional<blink::StorageKey>& storage_key, |
| const std::set<std::string>& storage_buckets_to_remove) { |
| bool partitioned_state_allowed_only = |
| cookie_partition_key.has_value() && |
| !origin.DomainIs(cookie_partition_key->site() |
| .registrable_domain_or_host_for_testing()); |
| base::RunLoop loop; |
| content::ClearSiteData( |
| GetBrowser()->profile()->GetWeakPtr(), |
| /*storage_partition_config=*/std::nullopt, |
| /*origin=*/origin, content::ClearSiteDataTypeSet::All(), |
| /*storage_buckets_to_remove=*/storage_buckets_to_remove, |
| /*avoid_closing_connections=*/true, |
| /*cookie_partition_key=*/cookie_partition_key, |
| /*storage_key=*/storage_key, |
| /*partitioned_state_allowed_only=*/partitioned_state_allowed_only, |
| /*callback=*/loop.QuitClosure()); |
| loop.Run(); |
| } |
| |
| private: |
| void OnCacheSizeResult( |
| base::RunLoop* run_loop, |
| browsing_data::BrowsingDataCounter::ResultInt* out_size, |
| std::unique_ptr<browsing_data::BrowsingDataCounter::Result> result) { |
| if (!result->Finished()) |
| return; |
| |
| *out_size = |
| static_cast<browsing_data::BrowsingDataCounter::FinishedResult*>( |
| result.get()) |
| ->Value(); |
| run_loop->Quit(); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| // Testing MediaLicenses requires additional command line parameters as |
| // it uses the External Clear Key CDM. |
| RegisterClearKeyCdm(command_line); |
| #endif |
| } |
| }; |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| // Same as BrowsingDataRemoverBrowserTest, but forces Dice to be enabled. |
| class DiceBrowsingDataRemoverBrowserTest |
| : public BrowsingDataRemoverBrowserTest { |
| public: |
| AccountInfo AddAccountToProfile(const std::string& account_id, |
| Profile* profile, |
| bool is_primary) { |
| auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); |
| if (is_primary) { |
| DCHECK(!identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)); |
| return signin::MakePrimaryAccountAvailable(identity_manager, |
| account_id + "@gmail.com", |
| signin::ConsentLevel::kSync); |
| } |
| auto account_info = |
| signin::MakeAccountAvailable(identity_manager, account_id); |
| DCHECK( |
| identity_manager->HasAccountWithRefreshToken(account_info.account_id)); |
| return account_info; |
| } |
| }; |
| #endif |
| |
| // Test BrowsingDataRemover for downloads. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, Download) { |
| DownloadAnItem(); |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_DOWNLOADS); |
| VerifyDownloadCount(0u); |
| } |
| |
| // Test that the salt for media device IDs is reset when cookies are cleared. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, MediaDeviceIdSalt) { |
| content::RenderFrameHost* frame_host = GetBrowser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame(); |
| url::Origin origin = frame_host->GetLastCommittedOrigin(); |
| net::SiteForCookies site_for_cookies = |
| net::SiteForCookies::FromOrigin(origin); |
| blink::StorageKey storage_key = blink::StorageKey::CreateFirstParty(origin); |
| |
| base::test::TestFuture<bool, const std::string&> future; |
| content::GetContentClientForTesting()->browser()->GetMediaDeviceIDSalt( |
| frame_host, site_for_cookies, storage_key, future.GetCallback()); |
| std::string original_salt = future.Get<1>(); |
| |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_COOKIES); |
| |
| future.Clear(); |
| content::GetContentClientForTesting()->browser()->GetMediaDeviceIDSalt( |
| frame_host, site_for_cookies, storage_key, future.GetCallback()); |
| std::string new_salt = future.Get<1>(); |
| |
| EXPECT_NE(original_salt, new_salt); |
| } |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| // Test that Sync is not paused when cookies are cleared. |
| IN_PROC_BROWSER_TEST_F(DiceBrowsingDataRemoverBrowserTest, SyncToken) { |
| Profile* profile = browser()->profile(); |
| // Set a Gaia cookie. |
| ASSERT_TRUE(SetGaiaCookieForProfile(profile)); |
| // Set a Sync account and a secondary account. |
| const char kPrimaryAccountId[] = "primary_account_id"; |
| AccountInfo primary_account = |
| AddAccountToProfile(kPrimaryAccountId, profile, /*is_primary=*/true); |
| const char kSecondaryAccountId[] = "secondary_account_id"; |
| AccountInfo secondary_account = |
| AddAccountToProfile(kSecondaryAccountId, profile, /*is_primary=*/false); |
| // Clear cookies. |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_COOKIES); |
| // Check that the primary account was not removed and has valid auth. |
| signin::IdentityManager* identity_manager = |
| IdentityManagerFactory::GetForProfile(profile); |
| EXPECT_TRUE( |
| identity_manager->HasAccountWithRefreshToken(primary_account.account_id)); |
| EXPECT_FALSE( |
| identity_manager->HasAccountWithRefreshTokenInPersistentErrorState( |
| primary_account.account_id)); |
| // Check that the secondary token was revoked. |
| EXPECT_FALSE(identity_manager->HasAccountWithRefreshToken( |
| secondary_account.account_id)); |
| } |
| |
| // Test that Sync is not paused when cookies are cleared. |
| IN_PROC_BROWSER_TEST_F(DiceBrowsingDataRemoverBrowserTest, |
| SyncTokenScopedDeletion) { |
| Profile* profile = browser()->profile(); |
| // Set a Gaia cookie. |
| ASSERT_TRUE(SetGaiaCookieForProfile(profile)); |
| // Set a Sync account and a secondary account. |
| const char kPrimaryAccountId[] = "primary_account_id"; |
| AccountInfo primary_account = |
| AddAccountToProfile(kPrimaryAccountId, profile, /*is_primary=*/true); |
| const char kSecondaryAccountId[] = "secondary_account_id"; |
| AccountInfo secondary_account = |
| AddAccountToProfile(kSecondaryAccountId, profile, /*is_primary=*/false); |
| // Clear cookies. |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_COOKIES); |
| // Check that the Sync token was not revoked. |
| auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); |
| EXPECT_TRUE( |
| identity_manager->HasAccountWithRefreshToken(primary_account.account_id)); |
| EXPECT_FALSE( |
| identity_manager->HasAccountWithRefreshTokenInPersistentErrorState( |
| primary_account.account_id)); |
| // Check that the secondary token was revoked. |
| EXPECT_FALSE(identity_manager->HasAccountWithRefreshToken( |
| secondary_account.account_id)); |
| } |
| |
| // Test that Sync is left in error when cookies are cleared. |
| IN_PROC_BROWSER_TEST_F(DiceBrowsingDataRemoverBrowserTest, SyncTokenError) { |
| Profile* profile = browser()->profile(); |
| // Set a Gaia cookie. |
| ASSERT_TRUE(SetGaiaCookieForProfile(profile)); |
| // Set a Sync account with authentication error. |
| const char kAccountId[] = "account_id"; |
| |
| AccountInfo primary_account = |
| AddAccountToProfile(kAccountId, profile, /*is_primary=*/true); |
| auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); |
| signin::UpdatePersistentErrorOfRefreshTokenForAccount( |
| identity_manager, primary_account.account_id, |
| GoogleServiceAuthError::FromInvalidGaiaCredentialsReason( |
| GoogleServiceAuthError::InvalidGaiaCredentialsReason:: |
| CREDENTIALS_REJECTED_BY_SERVER)); |
| |
| // Clear cookies. |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_COOKIES); |
| // Check that the account was not removed and Sync was paused. |
| EXPECT_TRUE( |
| identity_manager->HasAccountWithRefreshToken(primary_account.account_id)); |
| EXPECT_EQ( |
| GoogleServiceAuthError::InvalidGaiaCredentialsReason:: |
| CREDENTIALS_REJECTED_BY_SERVER, |
| identity_manager |
| ->GetErrorStateOfRefreshTokenForAccount(primary_account.account_id) |
| .GetInvalidGaiaCredentialsReason()); |
| } |
| |
| // Test that the tokens are revoked when cookies are cleared when there is no |
| // primary account. |
| IN_PROC_BROWSER_TEST_F(DiceBrowsingDataRemoverBrowserTest, NoSync) { |
| Profile* profile = browser()->profile(); |
| // Set a Gaia cookie. |
| ASSERT_TRUE(SetGaiaCookieForProfile(profile)); |
| // Set a non-Sync account. |
| const char kAccountId[] = "account_id"; |
| AccountInfo secondary_account = |
| AddAccountToProfile(kAccountId, profile, /*is_primary=*/false); |
| // Clear cookies. |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_COOKIES); |
| // Check that the account was removed. |
| auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); |
| EXPECT_FALSE(identity_manager->HasAccountWithRefreshToken( |
| secondary_account.account_id)); |
| } |
| #endif |
| |
| // The call to Remove() should crash in debug (DCHECK), but the browser-test |
| // process model prevents using a death test. |
| #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) |
| // Test BrowsingDataRemover for prohibited downloads. Note that this only |
| // really exercises the code in a Release build. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, DownloadProhibited) { |
| PrefService* prefs = GetBrowser()->profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kAllowDeletingBrowserHistory, false); |
| |
| DownloadAnItem(); |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_DOWNLOADS); |
| VerifyDownloadCount(1u); |
| } |
| #endif |
| |
| // Verify VideoDecodePerfHistory is cleared when deleting all history from |
| // beginning of time. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, VideoDecodePerfHistory) { |
| media::VideoDecodePerfHistory* video_decode_perf_history = |
| GetBrowser()->profile()->GetVideoDecodePerfHistory(); |
| |
| // Save a video decode record. Note: we avoid using a web page to generate the |
| // stats as this takes at least 5 seconds and even then is not a guarantee |
| // depending on scheduler. Manual injection is quick and non-flaky. |
| const media::VideoCodecProfile kProfile = media::VP9PROFILE_PROFILE0; |
| const gfx::Size kSize(100, 200); |
| const int kFrameRate = 30; |
| const int kFramesDecoded = 1000; |
| const int kFramesDropped = .9 * kFramesDecoded; |
| const int kFramesPowerEfficient = 0; |
| const url::Origin kOrigin = url::Origin::Create(GURL("http://example.com")); |
| const bool kIsTopFrame = true; |
| const uint64_t kPlayerId = 1234u; |
| |
| media::mojom::PredictionFeatures prediction_features; |
| prediction_features.profile = kProfile; |
| prediction_features.video_size = kSize; |
| prediction_features.frames_per_sec = kFrameRate; |
| |
| media::mojom::PredictionTargets prediction_targets; |
| prediction_targets.frames_decoded = kFramesDecoded; |
| prediction_targets.frames_dropped = kFramesDropped; |
| prediction_targets.frames_power_efficient = kFramesPowerEfficient; |
| |
| { |
| base::RunLoop run_loop; |
| video_decode_perf_history->GetSaveCallback().Run( |
| ukm::kInvalidSourceId, kIsTopFrame, prediction_features, |
| prediction_targets, kPlayerId, run_loop.QuitWhenIdleClosure()); |
| run_loop.Run(); |
| } |
| |
| // Verify history exists. |
| // Expect |is_smooth| = false and |is_power_efficient| = false given that 90% |
| // of recorded frames were dropped and 0 were power efficient. |
| bool is_smooth = true; |
| bool is_power_efficient = true; |
| { |
| base::RunLoop run_loop; |
| video_decode_perf_history->GetPerfInfo( |
| media::mojom::PredictionFeatures::New(prediction_features), |
| base::BindOnce(&BrowsingDataRemoverBrowserTest::OnVideoDecodePerfInfo, |
| base::Unretained(this), &run_loop, &is_smooth, |
| &is_power_efficient)); |
| run_loop.Run(); |
| } |
| EXPECT_FALSE(is_smooth); |
| EXPECT_FALSE(is_power_efficient); |
| |
| // Clear history. |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_HISTORY); |
| |
| // Verify history no longer exists. Both |is_smooth| and |is_power_efficient| |
| // should now report true because the VideoDecodePerfHistory optimistically |
| // returns true when it has no data. |
| { |
| base::RunLoop run_loop; |
| video_decode_perf_history->GetPerfInfo( |
| media::mojom::PredictionFeatures::New(prediction_features), |
| base::BindOnce(&BrowsingDataRemoverBrowserTest::OnVideoDecodePerfInfo, |
| base::Unretained(this), &run_loop, &is_smooth, |
| &is_power_efficient)); |
| run_loop.Run(); |
| } |
| EXPECT_TRUE(is_smooth); |
| EXPECT_TRUE(is_power_efficient); |
| } |
| |
| // Verify WebrtcVideoPerfHistory is cleared when deleting all history from |
| // beginning of time. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, WebrtcVideoPerfHistory) { |
| media::WebrtcVideoPerfHistory* webrtc_video_perf_history = |
| GetBrowser()->profile()->GetWebrtcVideoPerfHistory(); |
| |
| // Save a video decode record. Note: we avoid using a web page to generate the |
| // stats as this takes at least 5 seconds and even then is not a guarantee |
| // depending on scheduler. Manual injection is quick and non-flaky. |
| const media::VideoCodecProfile kProfile = media::VP9PROFILE_PROFILE0; |
| const int kVideoPixels = 1920 * 1080; |
| const int kFrameRate = 30; |
| |
| const int kFramesProcessed = 1000; |
| const int kKeyFramesProcessed = 11; |
| const float kP99ProcessingTimeMs = 100.0; |
| |
| media::mojom::WebrtcPredictionFeatures features; |
| features.is_decode_stats = true; |
| features.profile = kProfile; |
| features.video_pixels = kVideoPixels; |
| features.hardware_accelerated = false; |
| |
| media::mojom::WebrtcVideoStats video_stats; |
| video_stats.frames_processed = kFramesProcessed; |
| video_stats.key_frames_processed = kKeyFramesProcessed; |
| video_stats.p99_processing_time_ms = kP99ProcessingTimeMs; |
| |
| { |
| base::RunLoop run_loop; |
| webrtc_video_perf_history->GetSaveCallback().Run(features, video_stats, |
| run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| // Verify history exists. |
| // Expect |is_smooth| = false given that the 99th percentile processing time |
| // is 100 ms. |
| { |
| base::RunLoop run_loop; |
| webrtc_video_perf_history->GetPerfInfo( |
| media::mojom::WebrtcPredictionFeatures::New(features), kFrameRate, |
| base::BindLambdaForTesting([&](bool smooth) { |
| EXPECT_FALSE(smooth); |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| } |
| |
| auto filter_builder = BrowsingDataFilterBuilder::Create( |
| BrowsingDataFilterBuilder::Mode::kDelete); |
| filter_builder->AddRegisterableDomain("example.com"); |
| RemoveWithFilterAndWait(chrome_browsing_data_remover::FILTERABLE_DATA_TYPES, |
| std::move(filter_builder)); |
| |
| // This data type doesn't implement per-origin deletion so just test that |
| // nothing got removed. |
| { |
| base::RunLoop run_loop; |
| webrtc_video_perf_history->GetPerfInfo( |
| media::mojom::WebrtcPredictionFeatures::New(features), kFrameRate, |
| base::BindLambdaForTesting([&](bool smooth) { |
| EXPECT_FALSE(smooth); |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| } |
| |
| // Clear history. |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_HISTORY); |
| |
| // Verify history no longer exists. |is_smooth| should now report true because |
| // the WebrtcVideoPerfHistory optimistically returns true when it has no data. |
| { |
| base::RunLoop run_loop; |
| webrtc_video_perf_history->GetPerfInfo( |
| media::mojom::WebrtcPredictionFeatures::New(features), kFrameRate, |
| base::BindLambdaForTesting([&](bool smooth) { |
| EXPECT_TRUE(smooth); |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| } |
| } |
| |
| // Verifies that cache deletion finishes successfully. Completes deletion of |
| // cache should leave it empty, and partial deletion should leave nonzero |
| // amount of data. Note that this tests the integration of BrowsingDataRemover |
| // with ConditionalCacheDeletionHelper. Whether ConditionalCacheDeletionHelper |
| // actually deletes the correct entries is tested |
| // in ConditionalCacheDeletionHelperBrowsertest. |
| // TODO(crbug.com/41373874): check the cache size instead of stopping the server |
| // and loading the request again. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, Cache) { |
| // Load several resources. |
| GURL url1 = embedded_test_server()->GetURL("/cachetime"); |
| GURL url2 = embedded_test_server()->GetURL(kExampleHost, "/cachetime"); |
| ASSERT_FALSE(url::IsSameOriginWith(url1, url2)); |
| |
| EXPECT_EQ(net::OK, content::LoadBasicRequest(network_context(), url1)); |
| EXPECT_EQ(net::OK, content::LoadBasicRequest(network_context(), url2)); |
| |
| // Check that the cache has been populated by revisiting these pages with the |
| // server stopped. |
| ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); |
| EXPECT_EQ(net::OK, content::LoadBasicRequest(network_context(), url1)); |
| EXPECT_EQ(net::OK, content::LoadBasicRequest(network_context(), url2)); |
| |
| // Partially delete cache data. Delete data for localhost, which is the origin |
| // of |url1|, but not for |kExampleHost|, which is the origin of |url2|. |
| std::unique_ptr<BrowsingDataFilterBuilder> filter_builder = |
| BrowsingDataFilterBuilder::Create( |
| BrowsingDataFilterBuilder::Mode::kDelete); |
| filter_builder->AddOrigin(url::Origin::Create(url1)); |
| RemoveWithFilterAndWait(content::BrowsingDataRemover::DATA_TYPE_CACHE, |
| std::move(filter_builder)); |
| |
| // After the partial deletion, the cache should be smaller but still nonempty. |
| EXPECT_NE(net::OK, content::LoadBasicRequest(network_context(), url1)); |
| EXPECT_EQ(net::OK, content::LoadBasicRequest(network_context(), url2)); |
| |
| // Another partial deletion with the same filter should have no effect. |
| filter_builder = BrowsingDataFilterBuilder::Create( |
| BrowsingDataFilterBuilder::Mode::kDelete); |
| filter_builder->AddOrigin(url::Origin::Create(url1)); |
| RemoveWithFilterAndWait(content::BrowsingDataRemover::DATA_TYPE_CACHE, |
| std::move(filter_builder)); |
| EXPECT_NE(net::OK, content::LoadBasicRequest(network_context(), url1)); |
| EXPECT_EQ(net::OK, content::LoadBasicRequest(network_context(), url2)); |
| |
| // Delete the remaining data. |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_CACHE); |
| |
| // The cache should be empty. |
| EXPECT_NE(net::OK, content::LoadBasicRequest(network_context(), url1)); |
| EXPECT_NE(net::OK, content::LoadBasicRequest(network_context(), url2)); |
| } |
| |
| // Crashes the network service while clearing the HTTP cache to make sure the |
| // clear operation does complete. |
| // Note that there is a race between crashing the network service and clearing |
| // the cache, so the test might flakily fail if the tested behavior does not |
| // work. |
| // TODO(crbug.com/40563720): test retry behavior by validating the cache is |
| // empty after the crash. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| ClearCacheAndNetworkServiceCrashes) { |
| if (!content::IsOutOfProcessNetworkService()) |
| return; |
| |
| // Clear the cached data with a task posted to crash the network service. |
| // The task should be run while waiting for the cache clearing operation to |
| // complete, hopefully it happens before the cache has been cleared. |
| base::SequencedTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&content::BrowserTestBase::SimulateNetworkServiceCrash, |
| base::Unretained(this))); |
| |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_CACHE); |
| } |
| |
| // Verifies that the network quality prefs are cleared. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, VerifyNQECacheCleared) { |
| base::HistogramTester histogram_tester; |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_CACHE); |
| |
| // Wait until there is at least one sample in NQE.PrefsSizeOnClearing. |
| bool histogram_populated = false; |
| for (size_t attempt = 0; attempt < 3; ++attempt) { |
| const std::vector<base::Bucket> buckets = |
| histogram_tester.GetAllSamples("NQE.PrefsSizeOnClearing"); |
| for (const auto& bucket : buckets) { |
| if (bucket.count > 0) { |
| histogram_populated = true; |
| break; |
| } |
| } |
| if (histogram_populated) |
| break; |
| |
| // Retry fetching the histogram since it's not populated yet. |
| content::FetchHistogramsFromChildProcesses(); |
| metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| histogram_tester.ExpectTotalCount("NQE.PrefsSizeOnClearing", 1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| ExternalProtocolHandlerPerOriginPrefs) { |
| Profile* profile = GetBrowser()->profile(); |
| url::Origin test_origin = url::Origin::Create(GURL("https://example.test/")); |
| const std::string serialized_test_origin = test_origin.Serialize(); |
| base::Value::Dict allowed_protocols_for_origin; |
| allowed_protocols_for_origin.Set("tel", true); |
| base::Value::Dict origin_pref; |
| origin_pref.Set(serialized_test_origin, |
| std::move(allowed_protocols_for_origin)); |
| profile->GetPrefs()->SetDict(prefs::kProtocolHandlerPerOriginAllowedProtocols, |
| std::move(origin_pref)); |
| ExternalProtocolHandler::BlockState block_state = |
| ExternalProtocolHandler::GetBlockState("tel", &test_origin, profile); |
| ASSERT_EQ(ExternalProtocolHandler::DONT_BLOCK, block_state); |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA); |
| block_state = |
| ExternalProtocolHandler::GetBlockState("tel", &test_origin, profile); |
| ASSERT_EQ(ExternalProtocolHandler::UNKNOWN, block_state); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, HistoryDeletion) { |
| const std::string kType = "History"; |
| GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html"); |
| // Create a new tab to avoid confusion from having a NTP navigation entry. |
| ui_test_utils::NavigateToURLWithDisposition( |
| GetBrowser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); |
| EXPECT_FALSE(HasDataForType(kType)); |
| SetDataForType(kType); |
| EXPECT_TRUE(HasDataForType(kType)); |
| // Remove history from navigation to site_data.html. |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_HISTORY); |
| EXPECT_FALSE(HasDataForType(kType)); |
| SetDataForType(kType); |
| EXPECT_TRUE(HasDataForType(kType)); |
| // Remove history from previous pushState() call in setHistory(). |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_HISTORY); |
| EXPECT_FALSE(HasDataForType(kType)); |
| } |
| |
| // Storage Buckets |
| |
| class BrowsingDataRemoverStorageBucketsBrowserTest |
| : public BrowsingDataRemoverBrowserTest { |
| public: |
| BrowsingDataRemoverStorageBucketsBrowserTest() { |
| features_.InitWithFeatures({blink::features::kStorageBuckets, |
| net::features::kThirdPartyStoragePartitioning}, |
| {}); |
| } |
| |
| void ClearSiteDataAndWait( |
| const url::Origin& origin, |
| const std::optional<blink::StorageKey>& storage_key, |
| const std::set<std::string>& storage_buckets_to_remove) { |
| base::RunLoop loop; |
| content::ClearSiteDataTypeSet clear_site_data_types = |
| content::ClearSiteDataTypeSet::All(); |
| // We're clearing some storage buckets and not all of them. |
| clear_site_data_types.Remove(content::ClearSiteDataType::kStorage); |
| content::ClearSiteData( |
| GetBrowser()->profile()->GetWeakPtr(), |
| /*storage_partition_config=*/std::nullopt, |
| /*origin=*/origin, clear_site_data_types, |
| /*storage_buckets_to_remove=*/storage_buckets_to_remove, |
| /*avoid_closing_connections=*/true, |
| /*cookie_partition_key=*/std::nullopt, |
| /*storage_key=*/storage_key, |
| /*partitioned_state_allowed_only=*/false, |
| /*callback=*/loop.QuitClosure()); |
| loop.Run(); |
| } |
| |
| private: |
| base::test::ScopedFeatureList features_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverStorageBucketsBrowserTest, |
| ClearSiteDataStorageBuckets) { |
| GURL url("https://example.com"); |
| url::Origin origin = url::Origin::Create(url); |
| const auto storage_key = blink::StorageKey::CreateFirstParty(origin); |
| |
| storage::QuotaManager* quota_manager = |
| GetBrowser()->profile()->GetDefaultStoragePartition()->GetQuotaManager(); |
| |
| auto* quota_manager_proxy = quota_manager->proxy(); |
| |
| quota_manager_proxy->CreateBucketForTesting( |
| storage_key, "drafts", base::SequencedTaskRunner::GetCurrentDefault(), |
| base::BindOnce( |
| [](storage::QuotaErrorOr<storage::BucketInfo> error_or_bucket_info) { |
| })); |
| quota_manager_proxy->CreateBucketForTesting( |
| storage_key, "inbox", base::SequencedTaskRunner::GetCurrentDefault(), |
| base::BindOnce( |
| [](storage::QuotaErrorOr<storage::BucketInfo> error_or_bucket_info) { |
| })); |
| quota_manager_proxy->CreateBucketForTesting( |
| storage_key, "attachments", |
| base::SequencedTaskRunner::GetCurrentDefault(), |
| base::BindOnce( |
| [](storage::QuotaErrorOr<storage::BucketInfo> error_or_bucket_info) { |
| })); |
| |
| ClearSiteDataAndWait(origin, storage_key, {"drafts", "attachments"}); |
| |
| quota_manager_proxy->GetBucketsForStorageKey( |
| storage_key, |
| /*delete_expired*/ false, base::SequencedTaskRunner::GetCurrentDefault(), |
| base::BindOnce([](storage::QuotaErrorOr<std::set<storage::BucketInfo>> |
| error_or_buckets) { |
| EXPECT_EQ(1u, error_or_buckets.value().size()); |
| })); |
| } |
| |
| const char kDelegateHistogramPrefix[] = |
| "History.ClearBrowsingData.Duration.ChromeTask."; |
| const char kImplHistogramPrefix[] = "History.ClearBrowsingData.Duration.Task."; |
| |
| // Add data types here that support filtering and only delete data that matches |
| // the BrowsingDataFilterBuilder. |
| const std::vector<std::string_view> kSupportsOriginFilteringImpl{ |
| "AuthCache", "EmbedderData", "HttpCache", |
| "NetworkErrorLogging", "PrefetchCache", "PreflightCache", |
| "PrerenderCache", "ReportingCache", "SharedDictionary", |
| "StoragePartition", "Synchronous", "TrustTokens", |
| }; |
| const std::vector<std::string_view> kSupportsOriginFilteringDelegate{ |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) |
| "CdmLicenses", |
| #endif |
| "Cookies", "DisableAutoSigninForProfilePasswords", |
| "DomainReliability", "MediaDeviceSalts", |
| "Synchronous", |
| }; |
| |
| // This test ensures that all deletions that are part of FILTERABLE_DATA_TYPES |
| // fully support the BrowsingDataFilterBuilder if they are running for |
| // origin-specific deletions. Ideally, every web-visible data type should |
| // support filtering. If you implemented filtering already, just add your type |
| // to kSupportsOriginFiltering above. |
| // |
| // If it is not important that your data is cleared with per-origin deletions, |
| // you can add your type to kDoesNotSupportOriginFiltering and ensure that |
| // deletions are only performed when the filter builder |
| // MatchesMostOriginsAndDomains(). |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, FullyFilteredDataTypes) { |
| base::HistogramTester tester; |
| auto filter_builder = BrowsingDataFilterBuilder::Create( |
| BrowsingDataFilterBuilder::Mode::kDelete); |
| filter_builder->AddRegisterableDomain("example.com"); |
| RemoveWithFilterAndWait(chrome_browsing_data_remover::FILTERABLE_DATA_TYPES, |
| std::move(filter_builder)); |
| |
| EXPECT_THAT(GetHistogramSuffixes(tester, kImplHistogramPrefix), |
| UnorderedElementsAreArray(kSupportsOriginFilteringImpl)); |
| EXPECT_THAT(GetHistogramSuffixes(tester, kDelegateHistogramPrefix), |
| UnorderedElementsAreArray(kSupportsOriginFilteringDelegate)); |
| } |
| |
| // Add data types here that do not support the BrowsingDataFilterBuilder. |
| // These deletions should only run when the mode of the filter builder is |
| // "kPreserve" and MatchesMostOriginsAndDomains() is true. Otherwise data for |
| // these types will be cleared when per-origin deletions like those from the |
| // Clear-Site-Data header are performed. |
| const std::vector<std::string_view> kDoesNotSupportOriginFilteringImpl{ |
| "CodeCaches", |
| "NetworkHistory", |
| }; |
| const std::vector<std::string_view> kDoesNotSupportOriginFilteringDelegate{ |
| "FaviconCacheExpiration", |
| #if BUILDFLAG(ENABLE_DOWNGRADE_PROCESSING) |
| "UserDataSnapshot", |
| #endif |
| "WebrtcEventLogs", |
| #if BUILDFLAG(IS_CHROMEOS) |
| "TpmAttestationKeys", |
| #endif |
| }; |
| |
| // See comment on FullyFilteredDataTypes test for advice when this test fails. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, AllFilterableDataTypes) { |
| base::HistogramTester tester; |
| auto filter_builder = BrowsingDataFilterBuilder::Create( |
| BrowsingDataFilterBuilder::Mode::kPreserve); |
| filter_builder->AddRegisterableDomain("example.com"); |
| RemoveWithFilterAndWait(chrome_browsing_data_remover::FILTERABLE_DATA_TYPES, |
| std::move(filter_builder)); |
| |
| std::vector<std::string> all_impl_types; |
| AppendRange(all_impl_types, kSupportsOriginFilteringImpl); |
| AppendRange(all_impl_types, kDoesNotSupportOriginFilteringImpl); |
| EXPECT_THAT(GetHistogramSuffixes(tester, kImplHistogramPrefix), |
| UnorderedElementsAreArray(all_impl_types)); |
| |
| std::vector<std::string> all_delegate_types; |
| AppendRange(all_delegate_types, kSupportsOriginFilteringDelegate); |
| AppendRange(all_delegate_types, kDoesNotSupportOriginFilteringDelegate); |
| EXPECT_THAT(GetHistogramSuffixes(tester, kDelegateHistogramPrefix), |
| UnorderedElementsAreArray(all_delegate_types)); |
| } |
| |
| // Parameterized to run tests for different deletion time ranges. |
| class BrowsingDataRemoverBrowserTestP |
| : public BrowsingDataRemoverBrowserTest, |
| public testing::WithParamInterface<TimeEnum> {}; |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, CookieDeletion) { |
| TestSiteData("Cookie", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| CookieIncognitoDeletion) { |
| UseIncognitoBrowser(); |
| TestSiteData("Cookie", GetParam()); |
| } |
| |
| // Regression test for https://crbug.com/1216406. |
| // TODO(crbug.com/413259587): Re-enable this test once the flakiness is fixed. |
| #if BUILDFLAG(IS_WIN) |
| #define MAYBE_BrowserContextDestructionVsCookieRemoval \ |
| DISABLED_BrowserContextDestructionVsCookieRemoval |
| #else |
| #define MAYBE_BrowserContextDestructionVsCookieRemoval \ |
| BrowserContextDestructionVsCookieRemoval |
| #endif |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| MAYBE_BrowserContextDestructionVsCookieRemoval) { |
| // Open an incognito browser. |
| UseIncognitoBrowser(); |
| |
| // Set a cookie. |
| const char kDataType[] = "Cookie"; |
| GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(GetBrowser(), url)); |
| SetDataForType(kDataType); |
| EXPECT_EQ(1, GetSiteDataCount()); |
| ExpectTotalModelCount(1); |
| EXPECT_TRUE(HasDataForType(kDataType)); |
| |
| // Start data removal. This will CreateTaskCompletionClosureForMojo and |
| // register it as a completion callback for mojo calls to NetworkContext |
| // and other StorageParition-owned mojo::Remote(s). |
| // |
| // kRemoveMask contains: |
| // - DATA_TYPE_SITE_DATA - cargo-culted default from other tests |
| // - DEFERRED_COOKIE_DELETION_DATA_TYPES - to get non-empty result from |
| // ChromeBrowsingDataRemoverDelegate::GetDomainsForDeferredCookieDeletion |
| // (which is needed to touch StoragePartition in |
| // BrowsingDataRemoverImpl::OnTaskComplete when it is called later, |
| // after starting destruction of the BrowserContext - see the description |
| // of the next test step below). |
| constexpr uint64_t kRemoveMask = |
| chrome_browsing_data_remover::DATA_TYPE_SITE_DATA | |
| chrome_browsing_data_remover::DEFERRED_COOKIE_DELETION_DATA_TYPES; |
| content::BrowserContext* browser_context = GetBrowser()->profile(); |
| content::BrowsingDataRemover* remover = |
| browser_context->GetBrowsingDataRemover(); |
| content::BrowsingDataRemoverCompletionObserver completion_observer(remover); |
| remover->RemoveAndReply( |
| base::Time(), // delete_begin |
| base::Time::Max(), // delete_end |
| kRemoveMask, content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, |
| &completion_observer); |
| |
| // Close the incognito browser. This will tear down its |
| // Profile/BrowserContext, which will tear down the StoragePartition, which |
| // will tear down some mojo::Remote(s), which will end up running the closures |
| // returned from CreateTaskCompletionClosureForMojo (see the previous test |
| // step), which will run BrowsingDataRemoverImpl::OnTaskComplete. In |
| // https://crbug.com/1216406 OnTaskComplete would attempt to use its |
| // `browser_context_` (half-way destructed at this point) to get a |
| // StoragePartition and this would lead to DumpWithoutCrashing initially (and |
| // potentially crashes down the line). |
| CloseBrowserSynchronously(GetBrowser()); |
| |
| // Verify that the completion observer will get notified, even if there might |
| // have been a failure with the removal. |
| completion_observer.BlockUntilCompletion(); |
| |
| // Expect that removing the cookies failed, because the StoragePartition has |
| // been already gone by the time BrowsingDataRemoverImpl::OnTaskComplete run. |
| EXPECT_TRUE(content::StoragePartition::REMOVE_DATA_MASK_COOKIES & |
| completion_observer.failed_data_types()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, SessionCookieDeletion) { |
| TestSiteData("SessionCookie", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, LocalStorageDeletion) { |
| TestSiteData("LocalStorage", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| LocalStorageIncognitoDeletion) { |
| UseIncognitoBrowser(); |
| TestSiteData("LocalStorage", GetParam()); |
| } |
| |
| // TODO(crbug.com/41348517): DISABLED until session storage is working |
| // correctly. Add Incognito variant when this is re-enabled. |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| DISABLED_SessionStorageDeletion) { |
| TestSiteData("SessionStorage", GetParam()); |
| } |
| |
| // SessionStorage is not supported by site data counting and the cookie tree |
| // model but we can test the web visible behavior. |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| SessionStorageDeletionWebOnly) { |
| GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(GetBrowser(), url)); |
| const std::string type = "SessionStorage"; |
| EXPECT_FALSE(HasDataForType(type)); |
| SetDataForType(type); |
| EXPECT_TRUE(HasDataForType(type)); |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA, GetParam()); |
| EXPECT_FALSE(HasDataForType(type)); |
| } |
| |
| // Test that session storage is not counted until crbug.com/772337 is fixed. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, SessionStorageCounting) { |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(GetBrowser(), url)); |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| SetDataForType("SessionStorage"); |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| EXPECT_TRUE(HasDataForType("SessionStorage")); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, ServiceWorkerDeletion) { |
| TestSiteData("ServiceWorker", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| ServiceWorkerIncognitoDeletion) { |
| UseIncognitoBrowser(); |
| TestSiteData("ServiceWorker", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, CacheStorageDeletion) { |
| TestSiteData("CacheStorage", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| CacheStorageIncognitoDeletion) { |
| UseIncognitoBrowser(); |
| TestSiteData("CacheStorage", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, FileSystemDeletion) { |
| TestSiteData("FileSystem", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| FileSystemIncognitoDeletion) { |
| UseIncognitoBrowser(); |
| TestSiteData("FileSystem", GetParam()); |
| } |
| |
| // Test that empty filesystems are deleted correctly. |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| EmptyFileSystemDeletion) { |
| TestEmptySiteData("FileSystem", GetParam()); |
| } |
| |
| // Test that empty filesystems are deleted correctly in incognito mode. |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| EmptyFileSystemIncognitoDeletion) { |
| UseIncognitoBrowser(); |
| TestEmptySiteData("FileSystem", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, IndexedDbDeletion) { |
| TestSiteData("IndexedDb", GetParam()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, |
| IndexedDbIncognitoDeletion) { |
| UseIncognitoBrowser(); |
| TestSiteData("IndexedDb", GetParam()); |
| } |
| |
| // Test that empty indexed dbs are deleted correctly. |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, EmptyIndexedDb) { |
| TestEmptySiteData("IndexedDb", GetParam()); |
| } |
| |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| // Test Media Licenses by creating one and checking it is counted by the |
| // cookie counter. Then delete it and check that the cookie counter is back |
| // to zero. |
| IN_PROC_BROWSER_TEST_P(BrowsingDataRemoverBrowserTestP, MediaLicenseDeletion) { |
| const std::string kMediaLicenseType = "MediaLicense"; |
| const TimeEnum delete_begin = GetParam(); |
| |
| EXPECT_EQ(0, GetSiteDataCount()); |
| GURL url = |
| embedded_test_server()->GetURL("/browsing_data/media_license.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| EXPECT_FALSE(HasDataForType(kMediaLicenseType)); |
| |
| SetDataForType(kMediaLicenseType); |
| EXPECT_EQ(1, GetSiteDataCount()); |
| ExpectTotalModelCount(1); |
| EXPECT_TRUE(HasDataForType(kMediaLicenseType)); |
| |
| // Try to remove the Media Licenses using a time frame up until an hour ago, |
| // which should not remove the recently created Media License. |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA, delete_begin, |
| TimeEnum::kLastHour); |
| EXPECT_EQ(1, GetSiteDataCount()); |
| ExpectTotalModelCount(1); |
| EXPECT_TRUE(HasDataForType(kMediaLicenseType)); |
| |
| // Now try with a time range that includes the current time, which should |
| // clear the Media License created for this test. |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA, delete_begin, |
| TimeEnum::kMax); |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| EXPECT_FALSE(HasDataForType(kMediaLicenseType)); |
| } |
| |
| // Create and save a media license (which will be deleted in the following |
| // test). |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| PRE_MediaLicenseTimedDeletion) { |
| const std::string kMediaLicenseType = "MediaLicense"; |
| |
| EXPECT_EQ(0, GetSiteDataCount()); |
| |
| GURL url = |
| embedded_test_server()->GetURL("/browsing_data/media_license.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| EXPECT_FALSE(HasDataForType(kMediaLicenseType)); |
| |
| SetDataForType(kMediaLicenseType); |
| EXPECT_EQ(1, GetSiteDataCount()); |
| ExpectTotalModelCount(1); |
| EXPECT_TRUE(HasDataForType(kMediaLicenseType)); |
| } |
| |
| // Create and save a second media license, and then verify that timed deletion |
| // selects the correct license to delete. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| MediaLicenseTimedDeletion) { |
| const std::string kMediaLicenseType = "MediaLicense"; |
| |
| // As the PRE_ test should run first, there should be one media license |
| // still stored. The time of it's creation should be sometime before |
| // this test starts. This license will be for a different origin, and so wont |
| // affect HasDataForType, but it still exists. |
| LOG(INFO) << "MediaLicenseTimedDeletion starting @ " << kStartTime; |
| EXPECT_EQ(1, GetSiteDataCount()); |
| |
| GURL url = |
| embedded_test_server()->GetURL("/browsing_data/media_license.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| #if BUILDFLAG(IS_MAC) |
| // On some Macs the file system uses second granularity. So before |
| // creating the second license, delay for 1 second so that the new |
| // license's time is not the same second as |kStartTime|. |
| base::PlatformThread::Sleep(base::Seconds(1)); |
| #endif |
| |
| // This test should use a different domain than the PRE_ test, so there |
| // should be no existing media license for it. |
| // Note that checking HasDataForType() may result in an empty file being |
| // created. Deleting licenses checks for any file within the time range |
| // specified in order to delete all the files for the domain, so this may |
| // cause problems (especially with Macs that use second granularity). |
| // http://crbug.com/909829. |
| EXPECT_FALSE(HasDataForType(kMediaLicenseType)); |
| |
| SetDataForType(kMediaLicenseType); |
| ExpectTotalModelCount(1); |
| EXPECT_TRUE(HasDataForType(kMediaLicenseType)); |
| |
| // As Clear Browsing Data typically deletes recent data (e.g. last hour, |
| // last day, etc.), try to remove the Media Licenses created since the |
| // the start of this test, which should only delete the just created |
| // media license, and leave the one created by the PRE_ test. |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA, |
| TimeEnum::kStart); |
| EXPECT_EQ(1, GetSiteDataCount()); |
| ExpectTotalModelCount(1); |
| EXPECT_FALSE(HasDataForType(kMediaLicenseType)); |
| |
| // Now try with a time range that includes all time, which should |
| // clear the media license created by the PRE_ test. |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA); |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| MediaLicenseDeletionWithFilter) { |
| const std::string kMediaLicenseType = "MediaLicense"; |
| |
| GURL url = |
| embedded_test_server()->GetURL("/browsing_data/media_license.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| ExpectTotalModelCount(0); |
| EXPECT_FALSE(HasDataForType(kMediaLicenseType)); |
| |
| SetDataForType(kMediaLicenseType); |
| |
| ExpectTotalModelCount(1); |
| EXPECT_TRUE(HasDataForType(kMediaLicenseType)); |
| |
| // Try to remove the Media Licenses using a deletelist that doesn't include |
| // the current URL. Media License should not be deleted. |
| std::unique_ptr<BrowsingDataFilterBuilder> filter_builder = |
| BrowsingDataFilterBuilder::Create( |
| BrowsingDataFilterBuilder::Mode::kDelete); |
| filter_builder->AddOrigin( |
| url::Origin::CreateFromNormalizedTuple("https", "test-origin", 443)); |
| RemoveWithFilterAndWait( |
| content::BrowsingDataRemover::DATA_TYPE_MEDIA_LICENSES, |
| std::move(filter_builder)); |
| ExpectTotalModelCount(1); |
| |
| // Now try with a preservelist that includes the current URL. Media License |
| // should not be deleted. |
| filter_builder = BrowsingDataFilterBuilder::Create( |
| BrowsingDataFilterBuilder::Mode::kPreserve); |
| filter_builder->AddOrigin(url::Origin::Create(url)); |
| RemoveWithFilterAndWait( |
| content::BrowsingDataRemover::DATA_TYPE_MEDIA_LICENSES, |
| std::move(filter_builder)); |
| ExpectTotalModelCount(1); |
| |
| // Now try with a deletelist that includes the current URL. Media License |
| // should be deleted this time. |
| filter_builder = BrowsingDataFilterBuilder::Create( |
| BrowsingDataFilterBuilder::Mode::kDelete); |
| filter_builder->AddOrigin(url::Origin::Create(url)); |
| RemoveWithFilterAndWait( |
| content::BrowsingDataRemover::DATA_TYPE_MEDIA_LICENSES, |
| std::move(filter_builder)); |
| ExpectTotalModelCount(0); |
| } |
| #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| |
| const std::vector<std::string> kStorageTypes{ |
| "Cookie", "LocalStorage", "FileSystem", "SessionStorage", |
| "IndexedDb", "ServiceWorker", "CacheStorage", "MediaLicense", |
| }; |
| |
| // Test that storage doesn't leave any traces on disk. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| PRE_PRE_StorageRemovedFromDisk) { |
| // Checking leveldb content fails in most cases. See |
| // https://crbug.com/1238325. |
| ASSERT_EQ(0, CheckUserDirectoryForString(kLocalHost, {}, |
| /*check_leveldb_content=*/false)); |
| ASSERT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| |
| // To use secure-only features on a host name, we need an https server. |
| net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| https_server.SetSSLConfig( |
| net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN); |
| base::FilePath path; |
| base::PathService::Get(content::DIR_TEST_DATA, &path); |
| https_server.ServeFilesFromDirectory(path); |
| ASSERT_TRUE(https_server.Start()); |
| |
| GURL url = https_server.GetURL(kLocalHost, "/browsing_data/site_data.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(GetBrowser(), url)); |
| |
| for (const std::string& type : kStorageTypes) { |
| SetDataForType(type); |
| EXPECT_TRUE(HasDataForType(type)); |
| } |
| // TODO(crbug.com/40577815): Add more datatypes for testing. E.g. |
| // notifications, payment handler, content settings, autofill, ...? |
| } |
| |
| // Restart after creating the data to ensure that everything was written to |
| // disk. |
| // |
| // This depends on session restore being explicitly disabled by the test harness |
| // above. Otherwise, we'll restore the tabs, delete the data on disk, and the |
| // still-open tabs can get re-persisted. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| PRE_StorageRemovedFromDisk) { |
| EXPECT_EQ(1, GetSiteDataCount()); |
| ExpectTotalModelCount(1); |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA | |
| content::BrowsingDataRemover::DATA_TYPE_CACHE | |
| chrome_browsing_data_remover::DATA_TYPE_HISTORY | |
| chrome_browsing_data_remover::DATA_TYPE_CONTENT_SETTINGS); |
| EXPECT_EQ(0, GetSiteDataCount()); |
| ExpectTotalModelCount(0); |
| } |
| |
| // Check if any data remains after a deletion and a Chrome restart to force |
| // all writes to be finished. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, StorageRemovedFromDisk) { |
| // Deletions should remove all traces of browsing data from disk |
| // but there are a few bugs that need to be fixed. |
| // Any addition to this list must have an associated TODO. |
| static const std::vector<std::string> ignore_file_patterns = { |
| #if BUILDFLAG(IS_CHROMEOS) |
| // TODO(crbug.com/40577815): Many leveldb files remain on ChromeOS. I |
| // couldn't reproduce this in manual testing, so it might be a timing |
| // issue when Chrome is closed after the second test? |
| "[0-9]{6}", |
| #endif |
| }; |
| int found = CheckUserDirectoryForString(kLocalHost, ignore_file_patterns, |
| /*check_leveldb_content=*/false); |
| EXPECT_EQ(0, found) << "A non-ignored file contains the hostname."; |
| } |
| |
| const std::vector<std::string> kSessionOnlyStorageTestTypes{ |
| "Cookie", "LocalStorage", "FileSystem", "SessionStorage", |
| "IndexedDb", "ServiceWorker", "CacheStorage", "MediaLicense", |
| }; |
| |
| // Test that storage gets deleted if marked as SessionOnly. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| PRE_SessionOnlyStorageRemoved) { |
| ExpectTotalModelCount(0); |
| GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(GetBrowser(), url)); |
| |
| for (const std::string& type : kSessionOnlyStorageTestTypes) { |
| SetDataForType(type); |
| EXPECT_TRUE(HasDataForType(type)); |
| } |
| |
| ExpectTotalModelCount(1); |
| HostContentSettingsMapFactory::GetForProfile(GetBrowser()->profile()) |
| ->SetDefaultContentSetting(ContentSettingsType::COOKIES, |
| CONTENT_SETTING_SESSION_ONLY); |
| } |
| |
| // TODO(crbug.com/40925336): Test is flaky on Mac. |
| #if BUILDFLAG(IS_MAC) |
| #define MAYBE_SessionOnlyStorageRemoved DISABLED_SessionOnlyStorageRemoved |
| #else |
| #define MAYBE_SessionOnlyStorageRemoved SessionOnlyStorageRemoved |
| #endif |
| // Restart to delete session only storage. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| MAYBE_SessionOnlyStorageRemoved) { |
| // All cookies should have been deleted. |
| ExpectTotalModelCount(0); |
| GURL url = embedded_test_server()->GetURL("/browsing_data/site_data.html"); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(GetBrowser(), url)); |
| for (const std::string& type : kSessionOnlyStorageTestTypes) { |
| EXPECT_FALSE(HasDataForType(type)); |
| } |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| // Test that removing passwords, when System-proxy is enabled on Chrome OS, |
| // sends a request to System-proxy to clear the cached user credentials. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| SystemProxyClearsUserCredentials_RemovePasswords) { |
| ash::SystemProxyManager::Get()->SetSystemProxyEnabledForTest(true); |
| EXPECT_EQ(0, ash::SystemProxyClient::Get() |
| ->GetTestInterface() |
| ->GetClearUserCredentialsCount()); |
| RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_PASSWORDS); |
| |
| EXPECT_EQ(1, ash::SystemProxyClient::Get() |
| ->GetTestInterface() |
| ->GetClearUserCredentialsCount()); |
| } |
| |
| // Test that removing cookies, when System-proxy is enabled on Chrome OS and |
| // kDbdRevampDesktop is enabled, sends a request to System-proxy to clear the |
| // cached user credentials. |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| SystemProxyClearsUserCredentials_RemoveCookies) { |
| ash::SystemProxyManager::Get()->SetSystemProxyEnabledForTest(true); |
| EXPECT_EQ(0, ash::SystemProxyClient::Get() |
| ->GetTestInterface() |
| ->GetClearUserCredentialsCount()); |
| RemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_COOKIES); |
| |
| EXPECT_EQ(1, ash::SystemProxyClient::Get() |
| ->GetTestInterface() |
| ->GetClearUserCredentialsCount()); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, |
| RelatedWebsiteSetsDeletion) { |
| const GURL kPrimaryUrl("https://subdomain.example.com:112"); |
| const GURL kSecondaryUrl("https://subidubi.testsite.com:55"); |
| |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(GetProfile()); |
| |
| // Setting the HostContentSettingsMap's clock to test last_modified of |
| // RuleMetaData below. |
| base::SimpleTestClock test_clock; |
| settings_map->SetClockForTesting(&test_clock); |
| test_clock.SetNow(base::Time::Now()); |
| |
| // Expected setting for the default grant. |
| const ContentSettingPatternSource kExpectedSettingDefault( |
| ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(), |
| content_settings::ContentSettingToValue(CONTENT_SETTING_ASK), |
| content_settings::ProviderType::kDefaultProvider, |
| /*incognito=*/false); |
| |
| // Check that there are only default grants. |
| ASSERT_THAT( |
| settings_map->GetSettingsForOneType(ContentSettingsType::STORAGE_ACCESS), |
| UnorderedElementsAre(kExpectedSettingDefault)); |
| ASSERT_THAT(settings_map->GetSettingsForOneType( |
| ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS), |
| UnorderedElementsAre(kExpectedSettingDefault)); |
| |
| // Set RWS grants. |
| content_settings::ContentSettingConstraints constraints; |
| constraints.set_session_model(content_settings::mojom::SessionModel::DURABLE); |
| constraints.set_decided_by_related_website_sets(true); |
| settings_map->SetContentSettingDefaultScope( |
| kPrimaryUrl, kSecondaryUrl, ContentSettingsType::STORAGE_ACCESS, |
| CONTENT_SETTING_ALLOW, constraints); |
| settings_map->SetContentSettingDefaultScope( |
| kPrimaryUrl, kSecondaryUrl, ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS, |
| CONTENT_SETTING_ALLOW, constraints); |
| |
| // Check that the grants were set. |
| content_settings::RuleMetaData expected_metadata; |
| expected_metadata.SetFromConstraints(constraints); |
| expected_metadata.set_last_modified(test_clock.Now()); |
| EXPECT_THAT( |
| settings_map->GetSettingsForOneType(ContentSettingsType::STORAGE_ACCESS), |
| UnorderedElementsAre( |
| kExpectedSettingDefault, |
| ContentSettingPatternSource( |
| ContentSettingsPattern::FromURLToSchemefulSitePattern( |
| GURL(kPrimaryUrl)), // https://[*.]example.com |
| ContentSettingsPattern::FromURLToSchemefulSitePattern( |
| GURL(kSecondaryUrl)), // https://[*.]testsite.com |
| content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW), |
| content_settings::ProviderType::kPrefProvider, |
| /*incognito=*/false, expected_metadata.Clone()))); |
| EXPECT_THAT( |
| settings_map->GetSettingsForOneType( |
| ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS), |
| UnorderedElementsAre( |
| kExpectedSettingDefault, |
| ContentSettingPatternSource( |
| ContentSettingsPattern::FromURLNoWildcard( |
| GURL(kPrimaryUrl)), // https://subdomain.example.com:112 |
| ContentSettingsPattern::FromURLToSchemefulSitePattern( |
| GURL(kSecondaryUrl)), |
| content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW), |
| content_settings::ProviderType::kPrefProvider, |
| /*incognito=*/false, expected_metadata.Clone()))); |
| |
| // Remove Related Website Sets storage grants. |
| std::unique_ptr<BrowsingDataFilterBuilder> filter_builder = |
| BrowsingDataFilterBuilder::Create( |
| BrowsingDataFilterBuilder::Mode::kDelete); |
| filter_builder->AddOrigin(url::Origin::Create(kPrimaryUrl)); |
| RemoveWithFilterAndWait( |
| content::BrowsingDataRemover::DATA_TYPE_RELATED_WEBSITE_SETS_PERMISSIONS, |
| std::move(filter_builder)); |
| |
| // Check that there's only the default grant left. |
| EXPECT_THAT( |
| settings_map->GetSettingsForOneType(ContentSettingsType::STORAGE_ACCESS), |
| UnorderedElementsAre(kExpectedSettingDefault)); |
| EXPECT_THAT(settings_map->GetSettingsForOneType( |
| ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS), |
| UnorderedElementsAre(kExpectedSettingDefault)); |
| } |
| |
| // Some storage backend use a different code path for full deletions and |
| // partial deletions, so we need to test both. |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| BrowsingDataRemoverBrowserTestP, |
| ::testing::Values(TimeEnum::kDefault, TimeEnum::kLastHour), |
| [](const ::testing::TestParamInfo< |
| BrowsingDataRemoverBrowserTestP::ParamType>& info) { |
| switch (info.param) { |
| case TimeEnum::kDefault: |
| return "kDefault"; |
| case TimeEnum::kLastHour: |
| return "kLastHour"; |
| case TimeEnum::kStart: |
| return "kStart"; |
| case TimeEnum::kMax: |
| return "kMax"; |
| } |
| }); |