| // Copyright 2013 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifdef UNSAFE_BUFFERS_BUILD | 
 | // TODO(crbug.com/342213636): Remove this and spanify to fix the errors. | 
 | #pragma allow_unsafe_buffers | 
 | #endif | 
 |  | 
 | #include "content/browser/storage_partition_impl.h" | 
 |  | 
 | #include <stddef.h> | 
 | #include <stdint.h> | 
 |  | 
 | #include <array> | 
 | #include <map> | 
 | #include <memory> | 
 | #include <set> | 
 | #include <string> | 
 | #include <utility> | 
 | #include <vector> | 
 |  | 
 | #include "base/containers/contains.h" | 
 | #include "base/containers/span.h" | 
 | #include "base/files/file_path.h" | 
 | #include "base/files/file_util.h" | 
 | #include "base/functional/bind.h" | 
 | #include "base/functional/callback.h" | 
 | #include "base/functional/callback_helpers.h" | 
 | #include "base/location.h" | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "base/memory/scoped_refptr.h" | 
 | #include "base/run_loop.h" | 
 | #include "base/scoped_observation.h" | 
 | #include "base/strings/stringprintf.h" | 
 | #include "base/task/single_thread_task_runner.h" | 
 | #include "base/task/thread_pool.h" | 
 | #include "base/test/bind.h" | 
 | #include "base/test/gmock_callback_support.h" | 
 | #include "base/test/mock_callback.h" | 
 | #include "base/test/scoped_command_line.h" | 
 | #include "base/test/scoped_feature_list.h" | 
 | #include "base/test/test_future.h" | 
 | #include "base/threading/sequence_local_storage_slot.h" | 
 | #include "base/threading/thread.h" | 
 | #include "base/time/time.h" | 
 | #include "build/build_config.h" | 
 | #include "components/services/storage/dom_storage/async_dom_storage_database.h" | 
 | #include "components/services/storage/dom_storage/dom_storage_database.h" | 
 | #include "components/services/storage/dom_storage/local_storage_database.pb.h" | 
 | #include "components/services/storage/public/cpp/constants.h" | 
 | #include "components/services/storage/public/mojom/local_storage_control.mojom.h" | 
 | #include "components/services/storage/public/mojom/storage_service.mojom.h" | 
 | #include "components/services/storage/public/mojom/storage_usage_info.mojom.h" | 
 | #include "components/services/storage/shared_storage/async_shared_storage_database_impl.h" | 
 | #include "components/services/storage/shared_storage/shared_storage_manager.h" | 
 | #include "components/services/storage/shared_storage/shared_storage_options.h" | 
 | #include "components/services/storage/storage_service_impl.h" | 
 | #include "content/browser/aggregation_service/aggregation_service_test_utils.h" | 
 | #include "content/browser/attribution_reporting/test/mock_attribution_manager.h" | 
 | #include "content/browser/code_cache/generated_code_cache.h" | 
 | #include "content/browser/code_cache/generated_code_cache_context.h" | 
 | #include "content/browser/gpu/gpu_disk_cache_factory.h" | 
 | #include "content/browser/interest_group/interest_group_manager_impl.h" | 
 | #include "content/browser/interest_group/interest_group_permissions_cache.h" | 
 | #include "content/browser/interest_group/interest_group_permissions_checker.h" | 
 | #include "content/browser/private_aggregation/private_aggregation_manager.h" | 
 | #include "content/browser/private_aggregation/private_aggregation_test_utils.h" | 
 | #include "content/browser/renderer_host/navigation_request.h" | 
 | #include "content/public/browser/browser_task_traits.h" | 
 | #include "content/public/browser/browser_thread.h" | 
 | #include "content/public/browser/browsing_data_filter_builder.h" | 
 | #include "content/public/browser/generated_code_cache_settings.h" | 
 | #include "content/public/browser/global_routing_id.h" | 
 | #include "content/public/browser/storage_partition.h" | 
 | #include "content/public/browser/storage_usage_info.h" | 
 | #include "content/public/common/content_features.h" | 
 | #include "content/public/common/content_switches.h" | 
 | #include "content/public/test/browser_task_environment.h" | 
 | #include "content/public/test/mock_render_process_host.h" | 
 | #include "content/public/test/navigation_simulator.h" | 
 | #include "content/public/test/test_browser_context.h" | 
 | #include "content/public/test/test_renderer_host.h" | 
 | #include "content/public/test/test_utils.h" | 
 | #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" | 
 | #include "net/base/network_isolation_key.h" | 
 | #include "net/base/schemeful_site.h" | 
 | #include "net/base/test_completion_callback.h" | 
 | #include "net/cookies/canonical_cookie.h" | 
 | #include "net/cookies/cookie_access_params.h" | 
 | #include "net/cookies/cookie_access_result.h" | 
 | #include "net/cookies/cookie_inclusion_status.h" | 
 | #include "net/net_buildflags.h" | 
 | #include "services/network/cookie_manager.h" | 
 | #include "services/network/public/cpp/features.h" | 
 | #include "services/network/test/mock_device_bound_session_manager.h" | 
 | #include "storage/browser/quota/quota_client_type.h" | 
 | #include "storage/browser/quota/quota_manager.h" | 
 | #include "storage/browser/quota/quota_manager_proxy.h" | 
 | #include "storage/browser/test/mock_quota_client.h" | 
 | #include "storage/browser/test/mock_quota_manager.h" | 
 | #include "storage/browser/test/mock_special_storage_policy.h" | 
 | #include "storage/common/database/db_status.h" | 
 | #include "testing/gmock/include/gmock/gmock.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 | #include "third_party/blink/public/common/features.h" | 
 | #include "third_party/blink/public/common/interest_group/interest_group.h" | 
 | #include "third_party/blink/public/common/storage_key/storage_key.h" | 
 | #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" | 
 | #include "third_party/blink/public/mojom/quota/quota_types.mojom-shared.h" | 
 | #include "third_party/leveldatabase/env_chromium.h" | 
 | #include "url/gurl.h" | 
 | #include "url/origin.h" | 
 |  | 
 | #if BUILDFLAG(IS_ANDROID) | 
 | #include "content/public/browser/android/java_interfaces.h" | 
 | #include "services/service_manager/public/cpp/interface_provider.h" | 
 | #endif  // BUILDFLAG(IS_ANDROID) | 
 |  | 
 | using net::CanonicalCookie; | 
 | using CookieDeletionFilter = network::mojom::CookieDeletionFilter; | 
 | using CookieDeletionFilterPtr = network::mojom::CookieDeletionFilterPtr; | 
 | using ::testing::_; | 
 | using ::testing::DoAll; | 
 | using ::testing::Eq; | 
 | using ::testing::Invoke; | 
 | using ::testing::SaveArgPointee; | 
 | using ::testing::WithArg; | 
 |  | 
 | namespace content { | 
 | namespace { | 
 |  | 
 | const char kCacheKey[] = "key"; | 
 | const char kCacheValue[] = "cached value"; | 
 |  | 
 | const storage::QuotaClientType kClientFile = | 
 |     storage::QuotaClientType::kFileSystem; | 
 |  | 
 | const uint32_t kAllQuotaRemoveMask = | 
 |     StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS | | 
 |     StoragePartition::REMOVE_DATA_MASK_INDEXEDDB; | 
 | class RemoveCookieTester { | 
 |  public: | 
 |   explicit RemoveCookieTester(StoragePartition* storage_partition) | 
 |       : storage_partition_(storage_partition) {} | 
 |  | 
 |   RemoveCookieTester(const RemoveCookieTester&) = delete; | 
 |   RemoveCookieTester& operator=(const RemoveCookieTester&) = delete; | 
 |  | 
 |   // Returns true, if the given cookie exists in the cookie store. | 
 |   bool ContainsCookie(const url::Origin& origin, | 
 |                       std::optional<net::CookiePartitionKey> | 
 |                           cookie_partition_key = std::nullopt) { | 
 |     get_cookie_success_ = false; | 
 |     base::RunLoop loop; | 
 |     storage_partition_->GetCookieManagerForBrowserProcess()->GetCookieList( | 
 |         origin.GetURL(), net::CookieOptions::MakeAllInclusive(), | 
 |         net::CookiePartitionKeyCollection(cookie_partition_key), | 
 |         base::BindOnce(&RemoveCookieTester::GetCookieListCallback, | 
 |                        base::Unretained(this), loop.QuitClosure())); | 
 |     loop.Run(); | 
 |     return get_cookie_success_; | 
 |   } | 
 |  | 
 |   void AddCookie(const url::Origin& origin, | 
 |                  std::optional<net::CookiePartitionKey> cookie_partition_key = | 
 |                      std::nullopt) { | 
 |     net::CookieInclusionStatus status; | 
 |     std::string cookie_str = "A=1"; | 
 |     if (cookie_partition_key) { | 
 |       cookie_str += ";Partitioned;Secure;"; | 
 |     } | 
 |     std::unique_ptr<net::CanonicalCookie> cc( | 
 |         net::CanonicalCookie::CreateForTesting( | 
 |             origin.GetURL(), cookie_str, base::Time::Now(), | 
 |             /*server_time=*/std::nullopt, cookie_partition_key, | 
 |             net::CookieSourceType::kUnknown, &status)); | 
 |     base::RunLoop loop; | 
 |     storage_partition_->GetCookieManagerForBrowserProcess()->SetCanonicalCookie( | 
 |         *cc, origin.GetURL(), net::CookieOptions::MakeAllInclusive(), | 
 |         base::BindOnce(&RemoveCookieTester::SetCookieCallback, | 
 |                        base::Unretained(this), loop.QuitClosure())); | 
 |     loop.Run(); | 
 |   } | 
 |  | 
 |  private: | 
 |   void GetCookieListCallback( | 
 |       base::OnceClosure quit_closure, | 
 |       const net::CookieAccessResultList& cookie_list, | 
 |       const net::CookieAccessResultList& excluded_cookies) { | 
 |     std::string cookie_line = | 
 |         net::CanonicalCookie::BuildCookieLine(cookie_list); | 
 |     if (cookie_line == "A=1") { | 
 |       get_cookie_success_ = true; | 
 |     } else if (cookie_line == "A=1; A=1") { | 
 |       EXPECT_NE(cookie_list[0].cookie.IsPartitioned(), | 
 |                 cookie_list[1].cookie.IsPartitioned()); | 
 |       get_cookie_success_ = true; | 
 |     } else { | 
 |       EXPECT_EQ("", cookie_line); | 
 |       get_cookie_success_ = false; | 
 |     } | 
 |     std::move(quit_closure).Run(); | 
 |   } | 
 |  | 
 |   void SetCookieCallback(base::OnceClosure quit_closure, | 
 |                          net::CookieAccessResult result) { | 
 |     ASSERT_TRUE(result.status.IsInclude()); | 
 |     std::move(quit_closure).Run(); | 
 |   } | 
 |  | 
 |   bool get_cookie_success_; | 
 |   raw_ptr<StoragePartition> storage_partition_; | 
 | }; | 
 |  | 
 | class RemoveInterestGroupTester { | 
 |  public: | 
 |   explicit RemoveInterestGroupTester(StoragePartitionImpl* storage_partition) | 
 |       : storage_partition_(storage_partition) {} | 
 |  | 
 |   RemoveInterestGroupTester(const RemoveInterestGroupTester&) = delete; | 
 |   RemoveInterestGroupTester& operator=(const RemoveInterestGroupTester&) = | 
 |       delete; | 
 |  | 
 |   // Returns true, if the given interest group owner has any interest groups in | 
 |   // InterestGroupStorage. | 
 |   bool ContainsInterestGroupOwner(const url::Origin& origin) { | 
 |     get_interest_group_success_ = false; | 
 |     EXPECT_TRUE(storage_partition_->GetInterestGroupManager()); | 
 |     base::RunLoop loop; | 
 |     static_cast<InterestGroupManagerImpl*>( | 
 |         storage_partition_->GetInterestGroupManager()) | 
 |         ->GetInterestGroupsForOwner( | 
 |             /*devtools_auction_id=*/std::nullopt, origin, | 
 |             base::BindOnce( | 
 |                 &RemoveInterestGroupTester::GetInterestGroupsCallback, | 
 |                 base::Unretained(this), loop.QuitClosure())); | 
 |     loop.Run(); | 
 |     return get_interest_group_success_; | 
 |   } | 
 |  | 
 |   bool ContainsInterestGroupKAnon(const url::Origin& origin) { | 
 |     contains_kanon_ = false; | 
 |     EXPECT_TRUE(storage_partition_->GetInterestGroupManager()); | 
 |     base::RunLoop loop; | 
 |     static_cast<InterestGroupManagerImpl*>( | 
 |         storage_partition_->GetInterestGroupManager()) | 
 |         ->GetLastKAnonymityReported( | 
 |             k_anon_key, | 
 |             base::BindOnce( | 
 |                 &RemoveInterestGroupTester::GetLastKAnonymityReportedCallback, | 
 |                 base::Unretained(this), loop.QuitClosure())); | 
 |     loop.Run(); | 
 |     return contains_kanon_; | 
 |   } | 
 |  | 
 |   void AddInterestGroup(const url::Origin& origin) { | 
 |     EXPECT_TRUE(storage_partition_->GetInterestGroupManager()); | 
 |     blink::InterestGroup group; | 
 |     group.owner = origin; | 
 |     group.name = "Name"; | 
 |     group.expiry = base::Time::Now() + base::Days(30); | 
 |     group.bidding_url = origin.GetURL().Resolve("/bidding.js"); | 
 |     group.ads.emplace(); | 
 |     group.ads->push_back(blink::InterestGroup::Ad( | 
 |         GURL("https://owner.example.com/ad1"), "metadata")); | 
 |  | 
 |     InterestGroupManagerImpl* interest_group_manager = | 
 |         static_cast<InterestGroupManagerImpl*>( | 
 |             storage_partition_->GetInterestGroupManager()); | 
 |     interest_group_manager->JoinInterestGroup(group, origin.GetURL()); | 
 |  | 
 |     // Update the K-anonymity so that we can tell when it gets removed. | 
 |     k_anon_key = HashedKAnonKeyForAdBid( | 
 |         group, GURL("https://owner.example.com/ad1").spec()); | 
 |     interest_group_manager->UpdateLastKAnonymityReported(k_anon_key); | 
 |   } | 
 |  | 
 |   void AddClick(const url::Origin& provider_origin, | 
 |                 const url::Origin& eligible_origin) { | 
 |     ASSERT_TRUE(storage_partition_->GetInterestGroupManager()); | 
 |     network::AdAuctionEventRecord event; | 
 |     event.type = network::AdAuctionEventRecord::Type::kClick; | 
 |     event.providing_origin = provider_origin; | 
 |     event.eligible_origins.push_back(eligible_origin); | 
 |     InterestGroupManagerImpl* interest_group_manager = | 
 |         static_cast<InterestGroupManagerImpl*>( | 
 |             storage_partition_->GetInterestGroupManager()); | 
 |     interest_group_manager->RecordViewClickForTesting(std::move(event)); | 
 |   } | 
 |  | 
 |   std::optional<bool> ClickInDb(const url::Origin& provider_origin, | 
 |                                 const url::Origin& eligible_origin) { | 
 |     base::test::TestFuture<std::optional<bool>> future; | 
 |     InterestGroupManagerImpl* interest_group_manager = | 
 |         static_cast<InterestGroupManagerImpl*>( | 
 |             storage_partition_->GetInterestGroupManager()); | 
 |     interest_group_manager->CheckViewClickInfoInDbForTesting( | 
 |         /*provider_origin=*/provider_origin, | 
 |         /*eligible_origin=*/eligible_origin, future.GetCallback()); | 
 |     return future.Get(); | 
 |   } | 
 |  | 
 |  private: | 
 |   void GetInterestGroupsCallback(base::OnceClosure quit_closure, | 
 |                                  scoped_refptr<StorageInterestGroups> groups) { | 
 |     get_interest_group_success_ = groups->size() > 0; | 
 |     std::move(quit_closure).Run(); | 
 |   } | 
 |  | 
 |   void GetLastKAnonymityReportedCallback( | 
 |       base::OnceClosure quit_closure, | 
 |       std::optional<base::Time> last_reported) { | 
 |     contains_kanon_ = | 
 |         last_reported.has_value() && last_reported.value() > base::Time::Min(); | 
 |     std::move(quit_closure).Run(); | 
 |   } | 
 |  | 
 |   bool get_interest_group_success_ = false; | 
 |   bool contains_kanon_ = false; | 
 |   std::string k_anon_key; | 
 |   raw_ptr<StoragePartitionImpl> storage_partition_; | 
 | }; | 
 |  | 
 | class RemoveLocalStorageTester { | 
 |  public: | 
 |   RemoveLocalStorageTester(content::BrowserTaskEnvironment* task_environment, | 
 |                            TestBrowserContext* browser_context) | 
 |       : task_environment_(task_environment), | 
 |         storage_partition_(browser_context->GetDefaultStoragePartition()), | 
 |         dom_storage_context_(storage_partition_->GetDOMStorageContext()) {} | 
 |  | 
 |   RemoveLocalStorageTester(const RemoveLocalStorageTester&) = delete; | 
 |   RemoveLocalStorageTester& operator=(const RemoveLocalStorageTester&) = delete; | 
 |  | 
 |   ~RemoveLocalStorageTester() { | 
 |     // Tests which bring up a real Local Storage context need to shut it down | 
 |     // and wait for the database to be closed before terminating; otherwise the | 
 |     // TestBrowserContext may fail to delete its temp dir, and it will not be | 
 |     // happy about that. | 
 |     static_cast<DOMStorageContextWrapper*>(dom_storage_context_)->Shutdown(); | 
 |     task_environment_->RunUntilIdle(); | 
 |   } | 
 |  | 
 |   // Returns true, if the given origin URL exists. | 
 |   bool DOMStorageExistsForOrigin(const url::Origin& origin) { | 
 |     GetLocalStorageUsage(); | 
 |     for (size_t i = 0; i < infos_.size(); ++i) { | 
 |       if (origin == infos_[i].storage_key.origin()) | 
 |         return true; | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |   void AddDOMStorageTestData(const url::Origin& origin1, | 
 |                              const url::Origin& origin2, | 
 |                              const url::Origin& origin3) { | 
 |     // NOTE: Tests which call this method depend on implementation details of | 
 |     // how exactly the Local Storage subsystem stores persistent data. | 
 |  | 
 |     base::RunLoop open_loop; | 
 |     auto database = storage::AsyncDomStorageDatabase::OpenDirectory( | 
 |         storage_partition_->GetPath().Append(storage::kLocalStoragePath), | 
 |         storage::kLocalStorageLeveldbName, std::nullopt, | 
 |         base::SingleThreadTaskRunner::GetCurrentDefault(), | 
 |         base::BindLambdaForTesting([&](storage::DbStatus status) { | 
 |           ASSERT_TRUE(status.ok()); | 
 |           open_loop.Quit(); | 
 |         })); | 
 |     open_loop.Run(); | 
 |  | 
 |     base::RunLoop populate_loop; | 
 |     database->database().PostTaskWithThisObject( | 
 |         base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) { | 
 |           PopulateDatabase(db, origin1, origin2, origin3); | 
 |           populate_loop.Quit(); | 
 |         })); | 
 |     populate_loop.Run(); | 
 |  | 
 |     // Ensure that this database is fully closed before returning. | 
 |     database.reset(); | 
 |     task_environment_->RunUntilIdle(); | 
 |  | 
 |     EXPECT_TRUE(DOMStorageExistsForOrigin(origin1)); | 
 |     EXPECT_TRUE(DOMStorageExistsForOrigin(origin2)); | 
 |     EXPECT_TRUE(DOMStorageExistsForOrigin(origin3)); | 
 |   } | 
 |  | 
 |   static void PopulateDatabase(const storage::DomStorageDatabase& db, | 
 |                                const url::Origin& origin1, | 
 |                                const url::Origin& origin2, | 
 |                                const url::Origin& origin3) { | 
 |     storage::LocalStorageAreaAccessMetaData access_data; | 
 |     storage::LocalStorageAreaWriteMetaData write_data; | 
 |     std::map<std::vector<uint8_t>, std::vector<uint8_t>> entries; | 
 |  | 
 |     base::Time now = base::Time::Now(); | 
 |     access_data.set_last_accessed(now.ToInternalValue()); | 
 |     write_data.set_last_modified(now.ToInternalValue()); | 
 |     write_data.set_size_bytes(16); | 
 |     ASSERT_TRUE(db.Put(CreateAccessMetaDataKey(origin1), | 
 |                        base::as_byte_span(access_data.SerializeAsString())) | 
 |                     .ok()); | 
 |     ASSERT_TRUE(db.Put(CreateWriteMetaDataKey(origin1), | 
 |                        base::as_byte_span(write_data.SerializeAsString())) | 
 |                     .ok()); | 
 |     ASSERT_TRUE(db.Put(CreateDataKey(origin1), {}).ok()); | 
 |  | 
 |     base::Time one_day_ago = now - base::Days(1); | 
 |     access_data.set_last_accessed(one_day_ago.ToInternalValue()); | 
 |     write_data.set_last_modified(one_day_ago.ToInternalValue()); | 
 |     ASSERT_TRUE(db.Put(CreateAccessMetaDataKey(origin2), | 
 |                        base::as_byte_span(access_data.SerializeAsString())) | 
 |                     .ok()); | 
 |     ASSERT_TRUE(db.Put(CreateWriteMetaDataKey(origin2), | 
 |                        base::as_byte_span((write_data.SerializeAsString()))) | 
 |                     .ok()); | 
 |     ASSERT_TRUE(db.Put(CreateDataKey(origin2), {}).ok()); | 
 |  | 
 |     base::Time sixty_days_ago = now - base::Days(60); | 
 |     access_data.set_last_accessed(sixty_days_ago.ToInternalValue()); | 
 |     write_data.set_last_modified(sixty_days_ago.ToInternalValue()); | 
 |     ASSERT_TRUE(db.Put(CreateAccessMetaDataKey(origin3), | 
 |                        base::as_byte_span(access_data.SerializeAsString())) | 
 |                     .ok()); | 
 |     ASSERT_TRUE(db.Put(CreateWriteMetaDataKey(origin3), | 
 |                        base::as_byte_span(write_data.SerializeAsString())) | 
 |                     .ok()); | 
 |     ASSERT_TRUE(db.Put(CreateDataKey(origin3), {}).ok()); | 
 |   } | 
 |  | 
 |  private: | 
 |   static std::vector<uint8_t> CreateDataKey(const url::Origin& origin) { | 
 |     auto origin_str = origin.Serialize(); | 
 |     std::vector<uint8_t> serialized_origin(origin_str.begin(), | 
 |                                            origin_str.end()); | 
 |     std::vector<uint8_t> key = {'_'}; | 
 |     key.insert(key.end(), serialized_origin.begin(), serialized_origin.end()); | 
 |     key.push_back(0); | 
 |     key.push_back('X'); | 
 |     return key; | 
 |   } | 
 |  | 
 |   static std::vector<uint8_t> CreateAccessMetaDataKey( | 
 |       const url::Origin& origin) { | 
 |     const auto kMetaPrefix = std::to_array<uint8_t>({ | 
 |         'M', | 
 |         'E', | 
 |         'T', | 
 |         'A', | 
 |         'A', | 
 |         'C', | 
 |         'C', | 
 |         'E', | 
 |         'S', | 
 |         'S', | 
 |         ':', | 
 |     }); | 
 |     auto origin_str = origin.Serialize(); | 
 |     std::vector<uint8_t> serialized_origin(origin_str.begin(), | 
 |                                            origin_str.end()); | 
 |     std::vector<uint8_t> key; | 
 |     key.reserve(std::size(kMetaPrefix) + serialized_origin.size()); | 
 |     key.insert(key.end(), kMetaPrefix.data(), | 
 |                base::span<const uint8_t>(kMetaPrefix) | 
 |                    .subspan(std::size(kMetaPrefix)) | 
 |                    .data()); | 
 |     key.insert(key.end(), serialized_origin.begin(), serialized_origin.end()); | 
 |     return key; | 
 |   } | 
 |  | 
 |   static std::vector<uint8_t> CreateWriteMetaDataKey( | 
 |       const url::Origin& origin) { | 
 |     const auto kMetaPrefix = std::to_array<uint8_t>({'M', 'E', 'T', 'A', ':'}); | 
 |     auto origin_str = origin.Serialize(); | 
 |     std::vector<uint8_t> serialized_origin(origin_str.begin(), | 
 |                                            origin_str.end()); | 
 |     std::vector<uint8_t> key; | 
 |     key.reserve(std::size(kMetaPrefix) + serialized_origin.size()); | 
 |     key.insert(key.end(), kMetaPrefix.data(), | 
 |                base::span<const uint8_t>(kMetaPrefix) | 
 |                    .subspan(std::size(kMetaPrefix)) | 
 |                    .data()); | 
 |     key.insert(key.end(), serialized_origin.begin(), serialized_origin.end()); | 
 |     return key; | 
 |   } | 
 |  | 
 |   void GetLocalStorageUsage() { | 
 |     base::RunLoop loop; | 
 |     dom_storage_context_->GetLocalStorageUsage( | 
 |         base::BindOnce(&RemoveLocalStorageTester::OnGotLocalStorageUsage, | 
 |                        base::Unretained(this), loop.QuitClosure())); | 
 |     loop.Run(); | 
 |   } | 
 |  | 
 |   void OnGotLocalStorageUsage( | 
 |       base::OnceClosure quit_closure, | 
 |       const std::vector<content::StorageUsageInfo>& infos) { | 
 |     infos_ = infos; | 
 |     std::move(quit_closure).Run(); | 
 |   } | 
 |  | 
 |   // We don't own these pointers. | 
 |   const raw_ptr<BrowserTaskEnvironment> task_environment_; | 
 |   const raw_ptr<StoragePartition> storage_partition_; | 
 |   raw_ptr<DOMStorageContext> dom_storage_context_; | 
 |  | 
 |   std::vector<content::StorageUsageInfo> infos_; | 
 | }; | 
 |  | 
 | class RemoveCodeCacheTester { | 
 |  public: | 
 |   explicit RemoveCodeCacheTester(GeneratedCodeCacheContext* code_cache_context) | 
 |       : code_cache_context_(code_cache_context) {} | 
 |  | 
 |   RemoveCodeCacheTester(const RemoveCodeCacheTester&) = delete; | 
 |   RemoveCodeCacheTester& operator=(const RemoveCodeCacheTester&) = delete; | 
 |  | 
 |   enum Cache { kJs, kWebAssembly, kWebUiJs }; | 
 |  | 
 |   bool ContainsEntry(Cache cache, const GURL& url, const GURL& origin_lock) { | 
 |     entry_exists_ = false; | 
 |     base::RunLoop loop; | 
 |     GeneratedCodeCacheContext::RunOrPostTask( | 
 |         code_cache_context_.get(), FROM_HERE, | 
 |         base::BindOnce(&RemoveCodeCacheTester::ContainsEntryOnThread, | 
 |                        base::Unretained(this), cache, url, origin_lock, | 
 |                        loop.QuitClosure())); | 
 |     loop.Run(); | 
 |     return entry_exists_; | 
 |   } | 
 |  | 
 |   void ContainsEntryOnThread(Cache cache, | 
 |                              const GURL& url, | 
 |                              const GURL& origin_lock, | 
 |                              base::OnceClosure quit) { | 
 |     GeneratedCodeCache::ReadDataCallback callback = | 
 |         base::BindOnce(&RemoveCodeCacheTester::FetchEntryCallback, | 
 |                        base::Unretained(this), std::move(quit)); | 
 |     GetCache(cache)->FetchEntry(url, origin_lock, net::NetworkIsolationKey(), | 
 |                                 std::move(callback)); | 
 |   } | 
 |  | 
 |   void AddEntry(Cache cache, | 
 |                 const GURL& url, | 
 |                 const GURL& origin_lock, | 
 |                 const std::string& data) { | 
 |     base::RunLoop loop; | 
 |     GeneratedCodeCacheContext::RunOrPostTask( | 
 |         code_cache_context_.get(), FROM_HERE, | 
 |         base::BindOnce(&RemoveCodeCacheTester::AddEntryOnThread, | 
 |                        base::Unretained(this), cache, url, origin_lock, data, | 
 |                        loop.QuitClosure())); | 
 |     loop.Run(); | 
 |   } | 
 |  | 
 |   void AddEntryOnThread(Cache cache, | 
 |                         const GURL& url, | 
 |                         const GURL& origin_lock, | 
 |                         const std::string& data, | 
 |                         base::OnceClosure quit) { | 
 |     GetCache(cache)->WriteEntry(url, origin_lock, net::NetworkIsolationKey(), | 
 |                                 base::Time::Now(), base::as_byte_span(data)); | 
 |     std::move(quit).Run(); | 
 |   } | 
 |  | 
 |   void SetLastUseTime(Cache cache, | 
 |                       const GURL& url, | 
 |                       const GURL& origin_lock, | 
 |                       base::Time time) { | 
 |     base::RunLoop loop; | 
 |     GeneratedCodeCacheContext::RunOrPostTask( | 
 |         code_cache_context_.get(), FROM_HERE, | 
 |         base::BindOnce(&RemoveCodeCacheTester::SetLastUseTimeOnThread, | 
 |                        base::Unretained(this), cache, url, origin_lock, time, | 
 |                        loop.QuitClosure())); | 
 |     loop.Run(); | 
 |   } | 
 |  | 
 |   void SetLastUseTimeOnThread(Cache cache, | 
 |                               const GURL& url, | 
 |                               const GURL& origin_lock, | 
 |                               base::Time time, | 
 |                               base::OnceClosure quit) { | 
 |     GetCache(cache)->SetLastUsedTimeForTest( | 
 |         url, origin_lock, net::NetworkIsolationKey(), time, std::move(quit)); | 
 |   } | 
 |  | 
 |   std::string received_data() { return received_data_; } | 
 |  | 
 |  private: | 
 |   GeneratedCodeCache* GetCache(Cache cache) { | 
 |     if (cache == kJs) | 
 |       return code_cache_context_->generated_js_code_cache(); | 
 |     else if (cache == kWebAssembly) | 
 |       return code_cache_context_->generated_wasm_code_cache(); | 
 |     else | 
 |       return code_cache_context_->generated_webui_js_code_cache(); | 
 |   } | 
 |  | 
 |   void FetchEntryCallback(base::OnceClosure quit, | 
 |                           const base::Time& response_time, | 
 |                           mojo_base::BigBuffer data) { | 
 |     if (!response_time.is_null()) { | 
 |       entry_exists_ = true; | 
 |       received_data_ = std::string(data.data(), data.data() + data.size()); | 
 |     } else { | 
 |       entry_exists_ = false; | 
 |     } | 
 |     std::move(quit).Run(); | 
 |   } | 
 |  | 
 |   bool entry_exists_; | 
 |   raw_ptr<GeneratedCodeCacheContext> code_cache_context_; | 
 |   std::string received_data_; | 
 | }; | 
 |  | 
 | class MockDataRemovalObserver : public StoragePartition::DataRemovalObserver { | 
 |  public: | 
 |   explicit MockDataRemovalObserver(StoragePartition* partition) { | 
 |     observation_.Observe(partition); | 
 |   } | 
 |  | 
 |   MOCK_METHOD4(OnStorageKeyDataCleared, | 
 |                void(uint32_t, | 
 |                     content::StoragePartition::StorageKeyMatcherFunction, | 
 |                     base::Time, | 
 |                     base::Time)); | 
 |  | 
 |  private: | 
 |   base::ScopedObservation<StoragePartition, | 
 |                           StoragePartition::DataRemovalObserver> | 
 |       observation_{this}; | 
 | }; | 
 |  | 
 | bool IsWebSafeSchemeForTest(const std::string& scheme) { | 
 |   return scheme == url::kHttpScheme; | 
 | } | 
 |  | 
 | bool DoesOriginMatchForUnprotectedWeb( | 
 |     const blink::StorageKey& storage_key, | 
 |     storage::SpecialStoragePolicy* special_storage_policy) { | 
 |   if (IsWebSafeSchemeForTest(storage_key.origin().scheme())) { | 
 |     return !special_storage_policy->IsStorageProtected( | 
 |         storage_key.origin().GetURL()); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool DoesOriginMatchForBothProtectedAndUnprotectedWeb( | 
 |     const blink::StorageKey& storage_key, | 
 |     storage::SpecialStoragePolicy* special_storage_policy) { | 
 |   return true; | 
 | } | 
 |  | 
 | bool DoesOriginMatchUnprotected( | 
 |     const url::Origin& desired_origin, | 
 |     const blink::StorageKey& storage_key, | 
 |     storage::SpecialStoragePolicy* special_storage_policy) { | 
 |   return storage_key.origin().scheme() != desired_origin.scheme(); | 
 | } | 
 |  | 
 | void ClearQuotaData(content::StoragePartition* partition, | 
 |                     base::RunLoop* loop_to_quit) { | 
 |   partition->ClearData(kAllQuotaRemoveMask, | 
 |                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |                        blink::StorageKey(), base::Time(), base::Time::Max(), | 
 |                        loop_to_quit->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearQuotaDataWithOriginMatcher( | 
 |     content::StoragePartition* partition, | 
 |     StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher, | 
 |     const base::Time delete_begin, | 
 |     base::RunLoop* loop_to_quit) { | 
 |   partition->ClearData( | 
 |       kAllQuotaRemoveMask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |       /*filter_builder=*/nullptr, std::move(storage_key_matcher), nullptr, | 
 |       false, delete_begin, base::Time::Max(), loop_to_quit->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearQuotaDataForOrigin(content::StoragePartition* partition, | 
 |                              const GURL& remove_origin, | 
 |                              const base::Time delete_begin, | 
 |                              base::RunLoop* loop_to_quit) { | 
 |   partition->ClearData( | 
 |       kAllQuotaRemoveMask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |       blink::StorageKey::CreateFirstParty(url::Origin::Create(remove_origin)), | 
 |       delete_begin, base::Time::Max(), loop_to_quit->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearQuotaDataTime(content::StoragePartition* partition, | 
 |                         const base::Time delete_begin, | 
 |                         base::RunLoop* loop_to_quit) { | 
 |   partition->ClearData(kAllQuotaRemoveMask, | 
 |                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY, | 
 |                        blink::StorageKey(), delete_begin, base::Time::Max(), | 
 |                        loop_to_quit->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearCookies(content::StoragePartition* partition, | 
 |                   const base::Time delete_begin, | 
 |                   const base::Time delete_end, | 
 |                   base::RunLoop* run_loop) { | 
 |   partition->ClearData(StoragePartition::REMOVE_DATA_MASK_COOKIES, | 
 |                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |                        blink::StorageKey(), delete_begin, delete_end, | 
 |                        run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearCookiesMatchingInfo(content::StoragePartition* partition, | 
 |                               CookieDeletionFilterPtr delete_filter, | 
 |                               base::RunLoop* run_loop) { | 
 |   base::Time delete_begin; | 
 |   if (delete_filter->created_after_time.has_value()) | 
 |     delete_begin = delete_filter->created_after_time.value(); | 
 |   base::Time delete_end; | 
 |   if (delete_filter->created_before_time.has_value()) | 
 |     delete_end = delete_filter->created_before_time.value(); | 
 |   partition->ClearData(StoragePartition::REMOVE_DATA_MASK_COOKIES, | 
 |                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |                        /*filter_builder=*/nullptr, | 
 |                        StoragePartition::StorageKeyPolicyMatcherFunction(), | 
 |                        std::move(delete_filter), false, delete_begin, | 
 |                        delete_end, run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearStuff( | 
 |     uint32_t remove_mask, | 
 |     content::StoragePartition* partition, | 
 |     const base::Time delete_begin, | 
 |     const base::Time delete_end, | 
 |     BrowsingDataFilterBuilder* filter_builder, | 
 |     StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher, | 
 |     base::RunLoop* run_loop) { | 
 |   partition->ClearData( | 
 |       remove_mask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |       filter_builder, std::move(storage_key_matcher), nullptr, false, | 
 |       delete_begin, delete_end, run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearData(content::StoragePartition* partition, base::RunLoop* run_loop) { | 
 |   base::Time time; | 
 |   partition->ClearData(StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE, | 
 |                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |                        blink::StorageKey(), time, time, | 
 |                        run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearDataForOrigin(uint32_t remove_mask, | 
 |                         content::StoragePartition* partition, | 
 |                         const GURL& origin, | 
 |                         base::RunLoop* run_loop) { | 
 |   partition->ClearDataForOrigin( | 
 |       remove_mask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, origin, | 
 |       run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearCodeCache(content::StoragePartition* partition, | 
 |                     base::Time begin_time, | 
 |                     base::Time end_time, | 
 |                     base::RepeatingCallback<bool(const GURL&)> url_predicate, | 
 |                     base::RunLoop* run_loop) { | 
 |   partition->ClearCodeCaches(begin_time, end_time, url_predicate, | 
 |                              run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | bool FilterURL(const GURL& filter_url, const GURL& url) { | 
 |   return url == filter_url; | 
 | } | 
 |  | 
 | void ClearInterestGroups(content::StoragePartition* partition, | 
 |                          const base::Time delete_begin, | 
 |                          const base::Time delete_end, | 
 |                          base::RunLoop* run_loop) { | 
 |   partition->ClearData(StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS, | 
 |                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |                        blink::StorageKey(), delete_begin, delete_end, | 
 |                        run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearInterestGroupsViewClick(content::StoragePartition* partition, | 
 |                                   const url::Origin& origin, | 
 |                                   bool user_action, | 
 |                                   base::RunLoop* run_loop) { | 
 |   partition->ClearData( | 
 |       StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS | | 
 |           (user_action | 
 |                ? StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS_USER_CLEAR | 
 |                : 0), | 
 |       StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |       blink::StorageKey::CreateFirstParty(origin), base::Time(), | 
 |       base::Time::Max(), run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearInterestGroupsViewClickOnRunLoop(content::StoragePartition* partition, | 
 |                                            const url::Origin& origin, | 
 |                                            bool user_action) { | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearInterestGroupsViewClick, partition, | 
 |                                 origin, user_action, &run_loop)); | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | void ClearInterestGroupsAndKAnon(content::StoragePartition* partition, | 
 |                                  const base::Time delete_begin, | 
 |                                  const base::Time delete_end, | 
 |                                  base::RunLoop* run_loop) { | 
 |   partition->ClearData( | 
 |       StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS | | 
 |           StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS_INTERNAL, | 
 |       StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, blink::StorageKey(), | 
 |       delete_begin, delete_end, run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | void ClearInterestGroupPermissionsCache(content::StoragePartition* partition, | 
 |                                         const base::Time delete_begin, | 
 |                                         const base::Time delete_end, | 
 |                                         base::RunLoop* run_loop) { | 
 |   partition->ClearData( | 
 |       StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUP_PERMISSIONS_CACHE, | 
 |       StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, blink::StorageKey(), | 
 |       delete_begin, delete_end, run_loop->QuitClosure()); | 
 | } | 
 |  | 
 | bool FilterMatchesCookie(const CookieDeletionFilterPtr& filter, | 
 |                          const net::CanonicalCookie& cookie) { | 
 |   return network::DeletionFilterToInfo(filter.Clone()) | 
 |       .Matches(cookie, net::CookieAccessParams{ | 
 |                            net::CookieAccessSemantics::NONLEGACY, | 
 |                            net::CookieScopeSemantics::UNKNOWN, false}); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | class StoragePartitionImplTest : public testing::Test { | 
 |  public: | 
 |   StoragePartitionImplTest() | 
 |       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP, | 
 |                           base::test::TaskEnvironment::TimeSource::MOCK_TIME), | 
 |         browser_context_(new TestBrowserContext()) { | 
 |     feature_list_.InitWithFeatures({network::features::kInterestGroupStorage, | 
 |                                     network::features::kSharedStorageAPI}, | 
 |                                    {}); | 
 |   } | 
 |  | 
 |   StoragePartitionImplTest(const StoragePartitionImplTest&) = delete; | 
 |   StoragePartitionImplTest& operator=(const StoragePartitionImplTest&) = delete; | 
 |  | 
 |   storage::MockQuotaManager* GetMockManager() { | 
 |     if (!quota_manager_.get()) { | 
 |       quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>( | 
 |           browser_context_->IsOffTheRecord(), browser_context_->GetPath(), | 
 |           GetIOThreadTaskRunner({}).get(), | 
 |           browser_context_->GetSpecialStoragePolicy()); | 
 |       mojo::PendingRemote<storage::mojom::QuotaClient> quota_client; | 
 |       mojo::MakeSelfOwnedReceiver( | 
 |           std::make_unique<storage::MockQuotaClient>( | 
 |               quota_manager_->proxy(), storage::QuotaClientType::kFileSystem), | 
 |           quota_client.InitWithNewPipeAndPassReceiver()); | 
 |       quota_manager_->proxy()->RegisterClient( | 
 |           std::move(quota_client), storage::QuotaClientType::kFileSystem); | 
 |     } | 
 |     return quota_manager_.get(); | 
 |   } | 
 |  | 
 |   TestBrowserContext* browser_context() { return browser_context_.get(); } | 
 |  | 
 |   content::BrowserTaskEnvironment* task_environment() { | 
 |     return &task_environment_; | 
 |   } | 
 |  | 
 |  private: | 
 |   base::test::ScopedCommandLine command_line_; | 
 |   base::test::ScopedFeatureList feature_list_; | 
 |   content::BrowserTaskEnvironment task_environment_; | 
 |   std::unique_ptr<TestBrowserContext> browser_context_; | 
 |   scoped_refptr<storage::MockQuotaManager> quota_manager_; | 
 | }; | 
 |  | 
 | class StoragePartitionShaderClearTest : public testing::Test { | 
 |  public: | 
 |   StoragePartitionShaderClearTest() | 
 |       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP), | 
 |         browser_context_(new TestBrowserContext()) { | 
 |     InitGpuDiskCacheFactorySingleton(); | 
 |  | 
 |     gpu::GpuDiskCacheType type = gpu::GpuDiskCacheType::kGlShaders; | 
 |     auto handle = GetGpuDiskCacheFactorySingleton()->GetCacheHandle( | 
 |         type, browser_context()->GetDefaultStoragePartition()->GetPath().Append( | 
 |                   gpu::GetGpuDiskCacheSubdir(type))); | 
 |     cache_ = | 
 |         GetGpuDiskCacheFactorySingleton()->Create(handle, base::DoNothing()); | 
 |   } | 
 |  | 
 |   ~StoragePartitionShaderClearTest() override { cache_ = nullptr; } | 
 |  | 
 |   void InitCache() { | 
 |     net::TestCompletionCallback available_cb; | 
 |     int rv = cache_->SetAvailableCallback(available_cb.callback()); | 
 |     ASSERT_EQ(net::OK, available_cb.GetResult(rv)); | 
 |     EXPECT_EQ(0, Size()); | 
 |  | 
 |     cache_->Cache(kCacheKey, kCacheValue); | 
 |  | 
 |     net::TestCompletionCallback complete_cb; | 
 |  | 
 |     rv = cache_->SetCacheCompleteCallback(complete_cb.callback()); | 
 |     ASSERT_EQ(net::OK, complete_cb.GetResult(rv)); | 
 |   } | 
 |  | 
 |   int32_t Size() { | 
 |     net::TestInt32CompletionCallback cb; | 
 |     return cb.GetResult(cache_->Size(cb.callback())); | 
 |   } | 
 |  | 
 |   TestBrowserContext* browser_context() { return browser_context_.get(); } | 
 |  | 
 |  private: | 
 |   content::BrowserTaskEnvironment task_environment_; | 
 |   std::unique_ptr<TestBrowserContext> browser_context_; | 
 |  | 
 |   scoped_refptr<gpu::GpuDiskCache> cache_; | 
 | }; | 
 |  | 
 | // Tests --------------------------------------------------------------------- | 
 |  | 
 | TEST_F(StoragePartitionShaderClearTest, ClearShaderCache) { | 
 |   InitCache(); | 
 |   EXPECT_EQ(1, Size()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearData, | 
 |                                 browser_context()->GetDefaultStoragePartition(), | 
 |                                 &run_loop)); | 
 |   run_loop.Run(); | 
 |   EXPECT_EQ(0, Size()); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, QuotaClientTypesGeneration) { | 
 |   EXPECT_THAT( | 
 |       StoragePartitionImpl::GenerateQuotaClientTypes( | 
 |           StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS), | 
 |       testing::UnorderedElementsAre(storage::QuotaClientType::kFileSystem)); | 
 |   EXPECT_THAT(StoragePartitionImpl::GenerateQuotaClientTypes( | 
 |                   StoragePartition::REMOVE_DATA_MASK_INDEXEDDB), | 
 |               testing::ElementsAre(storage::QuotaClientType::kIndexedDatabase)); | 
 |   EXPECT_THAT( | 
 |       StoragePartitionImpl::GenerateQuotaClientTypes(kAllQuotaRemoveMask), | 
 |       testing::UnorderedElementsAre( | 
 |           storage::QuotaClientType::kFileSystem, | 
 |           storage::QuotaClientType::kIndexedDatabase)); | 
 | } | 
 |  | 
 | storage::BucketInfo AddQuotaManagedBucket( | 
 |     storage::MockQuotaManager* manager, | 
 |     const blink::StorageKey& storage_key, | 
 |     const std::string& bucket_name, | 
 |     base::Time modified = base::Time::Now()) { | 
 |   storage::BucketInfo bucket = | 
 |       manager->CreateBucket({storage_key, bucket_name}); | 
 |   manager->AddBucket(bucket, {kClientFile}, modified); | 
 |   EXPECT_TRUE(manager->BucketHasData(bucket, kClientFile)); | 
 |   return bucket; | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForever) { | 
 |   const blink::StorageKey kStorageKey1 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host1:1/"); | 
 |   const blink::StorageKey kStorageKey2 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host2:1/"); | 
 |  | 
 |   AddQuotaManagedBucket(GetMockManager(), kStorageKey1, | 
 |                         storage::kDefaultBucketName); | 
 |   AddQuotaManagedBucket(GetMockManager(), kStorageKey2, | 
 |                         storage::kDefaultBucketName); | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideQuotaManagerForTesting(GetMockManager()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearQuotaData, partition, &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 0); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForeverNone) { | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 0); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideQuotaManagerForTesting(GetMockManager()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearQuotaData, partition, &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 0); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForeverSpecificOrigin) { | 
 |   const blink::StorageKey kStorageKey1 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host1:1/"); | 
 |   const blink::StorageKey kStorageKey2 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host2:1/"); | 
 |  | 
 |   storage::BucketInfo host1_bucket = AddQuotaManagedBucket( | 
 |       GetMockManager(), kStorageKey1, storage::kDefaultBucketName); | 
 |   storage::BucketInfo host2_bucket = AddQuotaManagedBucket( | 
 |       GetMockManager(), kStorageKey2, storage::kDefaultBucketName); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideQuotaManagerForTesting(GetMockManager()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearQuotaDataForOrigin, partition, | 
 |                      kStorageKey1.origin().GetURL(), base::Time(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1); | 
 |   EXPECT_FALSE(GetMockManager()->BucketHasData(host1_bucket, kClientFile)); | 
 |   EXPECT_TRUE(GetMockManager()->BucketHasData(host2_bucket, kClientFile)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForLastHour) { | 
 |   const blink::StorageKey kStorageKey1 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host1:1/"); | 
 |   const blink::StorageKey kStorageKey2 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host2:1/"); | 
 |   const blink::StorageKey kStorageKey3 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host3:1/"); | 
 |  | 
 |   // Buckets modified now. | 
 |   base::Time now = base::Time::Now(); | 
 |   storage::BucketInfo host1_bucket_now = | 
 |       AddQuotaManagedBucket(GetMockManager(), kStorageKey1, "bucket_now", now); | 
 |   storage::BucketInfo host2_bucket_now = | 
 |       AddQuotaManagedBucket(GetMockManager(), kStorageKey2, "bucket_now", now); | 
 |  | 
 |   // Buckets modified a day ago. | 
 |   base::Time yesterday = now - base::Days(1); | 
 |   storage::BucketInfo host1_bucket_yesterday = AddQuotaManagedBucket( | 
 |       GetMockManager(), kStorageKey1, "bucket_yesterday", yesterday); | 
 |   storage::BucketInfo host2_bucket_yesterday = AddQuotaManagedBucket( | 
 |       GetMockManager(), kStorageKey2, "bucket_yesterday", yesterday); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 4); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideQuotaManagerForTesting(GetMockManager()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearQuotaDataForOrigin, partition, GURL(), | 
 |                                 base::Time::Now() - base::Hours(1), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2); | 
 |   EXPECT_FALSE(GetMockManager()->BucketHasData(host1_bucket_now, kClientFile)); | 
 |   EXPECT_FALSE(GetMockManager()->BucketHasData(host2_bucket_now, kClientFile)); | 
 |   EXPECT_TRUE( | 
 |       GetMockManager()->BucketHasData(host1_bucket_yesterday, kClientFile)); | 
 |   EXPECT_TRUE( | 
 |       GetMockManager()->BucketHasData(host2_bucket_yesterday, kClientFile)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForLastWeek) { | 
 |   const blink::StorageKey kStorageKey = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host1:1/"); | 
 |  | 
 |   // Buckets modified yesterday. | 
 |   base::Time now = base::Time::Now(); | 
 |   base::Time yesterday = now - base::Days(1); | 
 |   storage::BucketInfo bucket_yesterday = AddQuotaManagedBucket( | 
 |       GetMockManager(), kStorageKey, "bucket_yesterday", yesterday); | 
 |  | 
 |   // Buckets modified 10 days ago. | 
 |   base::Time ten_days_ago = now - base::Days(10); | 
 |   storage::BucketInfo bucket_ten_days_ago = AddQuotaManagedBucket( | 
 |       GetMockManager(), kStorageKey, "bucket_ten_days_ago", ten_days_ago); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideQuotaManagerForTesting(GetMockManager()); | 
 |  | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearQuotaDataTime, partition, | 
 |                                 base::Time::Now() - base::Days(7), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1); | 
 |   EXPECT_FALSE(GetMockManager()->BucketHasData(bucket_yesterday, kClientFile)); | 
 |   EXPECT_TRUE( | 
 |       GetMockManager()->BucketHasData(bucket_ten_days_ago, kClientFile)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveQuotaManagedUnprotectedOrigins) { | 
 |   const blink::StorageKey kStorageKey1 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host1:1/"); | 
 |   const blink::StorageKey kStorageKey2 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host2:1/"); | 
 |  | 
 |   storage::BucketInfo host1_bucket = AddQuotaManagedBucket( | 
 |       GetMockManager(), kStorageKey1, storage::kDefaultBucketName); | 
 |   storage::BucketInfo host2_bucket = AddQuotaManagedBucket( | 
 |       GetMockManager(), kStorageKey2, storage::kDefaultBucketName); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2); | 
 |  | 
 |   // Protect kStorageKey1. | 
 |   auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>(); | 
 |   mock_policy->AddProtected(kStorageKey1.origin().GetURL()); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideQuotaManagerForTesting(GetMockManager()); | 
 |   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearQuotaDataWithOriginMatcher, partition, | 
 |                      base::BindRepeating(&DoesOriginMatchForUnprotectedWeb), | 
 |                      base::Time(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1); | 
 |   EXPECT_TRUE(GetMockManager()->BucketHasData(host1_bucket, kClientFile)); | 
 |   EXPECT_FALSE(GetMockManager()->BucketHasData(host2_bucket, kClientFile)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveQuotaManagedProtectedOrigins) { | 
 |   const blink::StorageKey kStorageKey1 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host1:1/"); | 
 |   const blink::StorageKey kStorageKey2 = | 
 |       blink::StorageKey::CreateFromStringForTesting("http://host2:1/"); | 
 |  | 
 |   AddQuotaManagedBucket(GetMockManager(), kStorageKey1, | 
 |                         storage::kDefaultBucketName); | 
 |   AddQuotaManagedBucket(GetMockManager(), kStorageKey2, | 
 |                         storage::kDefaultBucketName); | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2); | 
 |  | 
 |   // Protect kStorageKey1. | 
 |   auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>(); | 
 |   mock_policy->AddProtected(kStorageKey1.origin().GetURL()); | 
 |  | 
 |   // Try to remove kStorageKey1. Expect success. | 
 |   base::RunLoop run_loop; | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideQuotaManagerForTesting(GetMockManager()); | 
 |   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get()); | 
 |  | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearQuotaDataWithOriginMatcher, partition, | 
 |                      base::BindRepeating( | 
 |                          &DoesOriginMatchForBothProtectedAndUnprotectedWeb), | 
 |                      base::Time(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 0); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveQuotaManagedIgnoreDevTools) { | 
 |   const blink::StorageKey kStorageKey = | 
 |       blink::StorageKey::CreateFromStringForTesting( | 
 |           "devtools://abcdefghijklmnopqrstuvw/"); | 
 |  | 
 |   storage::BucketInfo bucket = AddQuotaManagedBucket( | 
 |       GetMockManager(), kStorageKey, storage::kDefaultBucketName, base::Time()); | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideQuotaManagerForTesting(GetMockManager()); | 
 |  | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearQuotaDataWithOriginMatcher, partition, | 
 |                                 base::BindRepeating(&DoesOriginMatchUnprotected, | 
 |                                                     kStorageKey.origin()), | 
 |                                 base::Time(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   // Check that devtools data isn't removed. | 
 |   EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1); | 
 |   EXPECT_TRUE(GetMockManager()->BucketHasData(bucket, kClientFile)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveCookieForever) { | 
 |   const url::Origin kOrigin = url::Origin::Create(GURL("http://host1:1/")); | 
 |  | 
 |   StoragePartition* partition = browser_context()->GetDefaultStoragePartition(); | 
 |  | 
 |   RemoveCookieTester tester(partition); | 
 |   tester.AddCookie(kOrigin); | 
 |   ASSERT_TRUE(tester.ContainsCookie(kOrigin)); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearCookies, partition, base::Time(), | 
 |                                 base::Time::Max(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_FALSE(tester.ContainsCookie(kOrigin)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveCookieLastHour) { | 
 |   const url::Origin kOrigin = url::Origin::Create(GURL("http://host1:1/")); | 
 |  | 
 |   StoragePartition* partition = browser_context()->GetDefaultStoragePartition(); | 
 |  | 
 |   RemoveCookieTester tester(partition); | 
 |   tester.AddCookie(kOrigin); | 
 |   ASSERT_TRUE(tester.ContainsCookie(kOrigin)); | 
 |  | 
 |   base::Time an_hour_ago = base::Time::Now() - base::Hours(1); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearCookies, partition, an_hour_ago, | 
 |                                 base::Time::Max(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_FALSE(tester.ContainsCookie(kOrigin)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveCookieWithDeleteInfo) { | 
 |   const url::Origin kOrigin = url::Origin::Create(GURL("http://host1:1/")); | 
 |  | 
 |   StoragePartition* partition = browser_context()->GetDefaultStoragePartition(); | 
 |  | 
 |   RemoveCookieTester tester(partition); | 
 |   tester.AddCookie(kOrigin); | 
 |   ASSERT_TRUE(tester.ContainsCookie(kOrigin)); | 
 |  | 
 |   base::RunLoop run_loop2; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearCookiesMatchingInfo, partition, | 
 |                                 CookieDeletionFilter::New(), &run_loop2)); | 
 |   run_loop2.RunUntilIdle(); | 
 |   EXPECT_FALSE(tester.ContainsCookie(kOrigin)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveInterestGroupForever) { | 
 |   const url::Origin kOrigin = url::Origin::Create(GURL("https://host1:1/")); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   RemoveInterestGroupTester tester(partition); | 
 |   tester.AddInterestGroup(kOrigin); | 
 |   ASSERT_TRUE(tester.ContainsInterestGroupOwner(kOrigin)); | 
 |  | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |         FROM_HERE, base::BindOnce(&ClearInterestGroups, partition, base::Time(), | 
 |                                   base::Time::Max(), &run_loop)); | 
 |     run_loop.Run(); | 
 |   } | 
 |   EXPECT_FALSE(tester.ContainsInterestGroupOwner(kOrigin)); | 
 |   EXPECT_TRUE(tester.ContainsInterestGroupKAnon(kOrigin)); | 
 |  | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |         FROM_HERE, base::BindOnce(&ClearInterestGroupsAndKAnon, partition, | 
 |                                   base::Time(), base::Time::Max(), &run_loop)); | 
 |     run_loop.Run(); | 
 |   } | 
 |   EXPECT_FALSE(tester.ContainsInterestGroupOwner(kOrigin)); | 
 |   EXPECT_FALSE(tester.ContainsInterestGroupKAnon(kOrigin)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveInterestGroupClicks) { | 
 |   const url::Origin kProvider1 = | 
 |       url::Origin::Create(GURL("https://provider1.test")); | 
 |   const url::Origin kProvider2 = | 
 |       url::Origin::Create(GURL("https://provider2.test")); | 
 |   const url::Origin kEligible1 = | 
 |       url::Origin::Create(GURL("https://elig1.test")); | 
 |   const url::Origin kEligible2 = | 
 |       url::Origin::Create(GURL("https://elig2.test")); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   RemoveInterestGroupTester tester(partition); | 
 |   tester.AddClick(kProvider1, kEligible1); | 
 |   tester.AddClick(kProvider2, kEligible2); | 
 |   EXPECT_EQ(true, tester.ClickInDb(kProvider1, kEligible1)); | 
 |   EXPECT_EQ(true, tester.ClickInDb(kProvider2, kEligible2)); | 
 |  | 
 |   // Deleting based on eligible origin doesn't match. | 
 |   ClearInterestGroupsViewClickOnRunLoop(partition, kEligible1, | 
 |                                         /*user_action=*/false); | 
 |   EXPECT_EQ(true, tester.ClickInDb(kProvider1, kEligible1)); | 
 |   EXPECT_EQ(true, tester.ClickInDb(kProvider2, kEligible2)); | 
 |  | 
 |   // Provider origin does. | 
 |   ClearInterestGroupsViewClickOnRunLoop(partition, kProvider2, | 
 |                                         /*user_action=*/false); | 
 |   EXPECT_EQ(true, tester.ClickInDb(kProvider1, kEligible1)); | 
 |   EXPECT_EQ(false, tester.ClickInDb(kProvider2, kEligible2)); | 
 |  | 
 |   ClearInterestGroupsViewClickOnRunLoop(partition, kProvider1, | 
 |                                         /*user_action=*/false); | 
 |   EXPECT_EQ(false, tester.ClickInDb(kProvider1, kEligible1)); | 
 |   EXPECT_EQ(false, tester.ClickInDb(kProvider2, kEligible2)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveInterestGroupClicksUserAction) { | 
 |   const url::Origin kProvider1 = | 
 |       url::Origin::Create(GURL("https://provider1.test")); | 
 |   const url::Origin kProvider2 = | 
 |       url::Origin::Create(GURL("https://provider2.test")); | 
 |   const url::Origin kEligible1 = | 
 |       url::Origin::Create(GURL("https://elig1.test")); | 
 |   const url::Origin kEligible2 = | 
 |       url::Origin::Create(GURL("https://elig2.test")); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   RemoveInterestGroupTester tester(partition); | 
 |   tester.AddClick(kProvider1, kEligible1); | 
 |   tester.AddClick(kProvider2, kEligible2); | 
 |   EXPECT_EQ(true, tester.ClickInDb(kProvider1, kEligible1)); | 
 |   EXPECT_EQ(true, tester.ClickInDb(kProvider2, kEligible2)); | 
 |  | 
 |   // If the delete is in response to a user request, it just clears everything. | 
 |   ClearInterestGroupsViewClickOnRunLoop(partition, kEligible1, | 
 |                                         /*user_action=*/true); | 
 |   EXPECT_EQ(false, tester.ClickInDb(kProvider1, kEligible1)); | 
 |   EXPECT_EQ(false, tester.ClickInDb(kProvider2, kEligible2)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveInterestGroupPermissionsCacheForever) { | 
 |   const url::Origin kFrameOrigin = | 
 |       url::Origin::Create(GURL("https://host1.test:1/")); | 
 |   const url::Origin kInterestGroupOrigin = | 
 |       url::Origin::Create(GURL("https://host2.test:2/")); | 
 |   const net::SchemefulSite kFrameSite = | 
 |       net::SchemefulSite(GURL("https://host1.test:1/")); | 
 |   const net::NetworkIsolationKey kNetworkIsolationKey(kFrameSite, kFrameSite); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   ASSERT_TRUE(partition->GetInterestGroupManager()); | 
 |  | 
 |   InterestGroupPermissionsCache& permissions_cache = | 
 |       static_cast<InterestGroupManagerImpl*>( | 
 |           partition->GetInterestGroupManager()) | 
 |           ->permissions_checker_for_testing() | 
 |           .cache_for_testing(); | 
 |  | 
 |   permissions_cache.CachePermissions(InterestGroupPermissionsCache::Permissions{ | 
 |                                          /*can_join=*/true, /*can_leave=*/true}, | 
 |                                      kFrameOrigin, kInterestGroupOrigin, | 
 |                                      kNetworkIsolationKey); | 
 |   EXPECT_TRUE(permissions_cache.GetPermissions( | 
 |       kFrameOrigin, kInterestGroupOrigin, kNetworkIsolationKey)); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, base::BindOnce(&ClearInterestGroupPermissionsCache, partition, | 
 |                                 base::Time(), base::Time::Max(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_FALSE(permissions_cache.GetPermissions( | 
 |       kFrameOrigin, kInterestGroupOrigin, kNetworkIsolationKey)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveUnprotectedLocalStorageForever) { | 
 |   const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/")); | 
 |   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/")); | 
 |   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/")); | 
 |  | 
 |   // Protect kOrigin1. | 
 |   auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>(); | 
 |   mock_policy->AddProtected(kOrigin1.GetURL()); | 
 |  | 
 |   RemoveLocalStorageTester tester(task_environment(), browser_context()); | 
 |  | 
 |   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce( | 
 |           &ClearStuff, StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE, | 
 |           partition, base::Time(), base::Time::Max(), | 
 |           /*filter_builder=*/nullptr, | 
 |           base::BindRepeating(&DoesOriginMatchForUnprotectedWeb), &run_loop)); | 
 |   run_loop.Run(); | 
 |   // ClearData only guarantees that tasks to delete data are scheduled when its | 
 |   // callback is invoked. It doesn't guarantee data has actually been cleared. | 
 |   // So run all scheduled tasks to make sure data is cleared. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |  | 
 |   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin1)); | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2)); | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin3)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveProtectedLocalStorageForever) { | 
 |   const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/")); | 
 |   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/")); | 
 |   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/")); | 
 |  | 
 |   // Protect kOrigin1. | 
 |   auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>(); | 
 |   mock_policy->AddProtected(kOrigin1.GetURL()); | 
 |  | 
 |   RemoveLocalStorageTester tester(task_environment(), browser_context()); | 
 |  | 
 |   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearStuff, | 
 |                      StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE, | 
 |                      partition, base::Time(), base::Time::Max(), | 
 |                      /*filter_builder=*/nullptr, | 
 |                      base::BindRepeating( | 
 |                          &DoesOriginMatchForBothProtectedAndUnprotectedWeb), | 
 |                      &run_loop)); | 
 |   run_loop.Run(); | 
 |   // ClearData only guarantees that tasks to delete data are scheduled when its | 
 |   // callback is invoked. It doesn't guarantee data has actually been cleared. | 
 |   // So run all scheduled tasks to make sure data is cleared. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |  | 
 |   // Even if kOrigin1 is protected, it will be deleted since we specify | 
 |   // ClearData to delete protected data. | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1)); | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2)); | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin3)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveLocalStorageForLastWeek) { | 
 |   const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/")); | 
 |   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/")); | 
 |   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/")); | 
 |  | 
 |   RemoveLocalStorageTester tester(task_environment(), browser_context()); | 
 |  | 
 |   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   base::Time a_week_ago = base::Time::Now() - base::Days(7); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearStuff, | 
 |                      StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE, | 
 |                      partition, a_week_ago, base::Time::Max(), | 
 |                      /*filter_builder=*/nullptr, | 
 |                      base::BindRepeating( | 
 |                          &DoesOriginMatchForBothProtectedAndUnprotectedWeb), | 
 |                      &run_loop)); | 
 |   run_loop.Run(); | 
 |   // ClearData only guarantees that tasks to delete data are scheduled when its | 
 |   // callback is invoked. It doesn't guarantee data has actually been cleared. | 
 |   // So run all scheduled tasks to make sure data is cleared. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |  | 
 |   // kOrigin1 and kOrigin2 do not have age more than a week. | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1)); | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2)); | 
 |   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin3)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveLocalStorageForOrigins) { | 
 |   const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/")); | 
 |   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/")); | 
 |   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/")); | 
 |  | 
 |   RemoveLocalStorageTester tester(task_environment(), browser_context()); | 
 |  | 
 |   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   auto filter_builder = BrowsingDataFilterBuilder::Create( | 
 |       BrowsingDataFilterBuilder::Mode::kDelete); | 
 |   filter_builder->AddOrigin(kOrigin1); | 
 |   filter_builder->AddOrigin(kOrigin2); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce( | 
 |           &ClearStuff, StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE, | 
 |           partition, base::Time::Min(), base::Time::Max(), filter_builder.get(), | 
 |           StoragePartition::StorageKeyPolicyMatcherFunction(), &run_loop)); | 
 |   run_loop.Run(); | 
 |   // ClearData only guarantees that tasks to delete data are scheduled when its | 
 |   // callback is invoked. It doesn't guarantee data has actually been cleared. | 
 |   // So run all scheduled tasks to make sure data is cleared. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |  | 
 |   // kOrigin3 is not filtered by the filter builder. | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1)); | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2)); | 
 |   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin3)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveLocalStorageForOneOrigin) { | 
 |   const GURL kUrl1 = GURL("http://host1:1/"); | 
 |   const url::Origin kOrigin1 = url::Origin::Create(kUrl1); | 
 |   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/")); | 
 |   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/")); | 
 |  | 
 |   RemoveLocalStorageTester tester(task_environment(), browser_context()); | 
 |  | 
 |   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearDataForOrigin, | 
 |                      StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE, | 
 |                      partition, kUrl1, &run_loop)); | 
 |   run_loop.Run(); | 
 |   // ClearData only guarantees that tasks to delete data are scheduled when its | 
 |   // callback is invoked. It doesn't guarantee data has actually been cleared. | 
 |   // So run all scheduled tasks to make sure data is cleared. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |  | 
 |   // kOrigin1 should be cleared. | 
 |   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1)); | 
 |   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin2)); | 
 |   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin3)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, ClearCodeCache) { | 
 |   const GURL kResourceURL("http://host4/script.js"); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   // Ensure code cache is initialized. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |   EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr); | 
 |  | 
 |   RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext()); | 
 |  | 
 |   GURL origin = GURL("http://host1:1/"); | 
 |   std::string data("SomeData"); | 
 |   tester.AddEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin, data); | 
 |   EXPECT_TRUE( | 
 |       tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin)); | 
 |   EXPECT_EQ(tester.received_data(), data); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearCodeCache, partition, base::Time(), base::Time(), | 
 |                      base::RepeatingCallback<bool(const GURL&)>(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin)); | 
 |  | 
 |   // Make sure there isn't a second invalid callback sitting in the queue. | 
 |   // (this used to be a bug). | 
 |   base::RunLoop().RunUntilIdle(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, ClearCodeCacheSpecificURL) { | 
 |   const GURL kResourceURL("http://host4/script.js"); | 
 |   const GURL kFilterResourceURLForCodeCache("http://host5/script.js"); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   // Ensure code cache is initialized. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |   EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr); | 
 |  | 
 |   RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext()); | 
 |  | 
 |   GURL origin = GURL("http://host1:1/"); | 
 |   std::string data("SomeData"); | 
 |   tester.AddEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin, data); | 
 |   tester.AddEntry(RemoveCodeCacheTester::kJs, kFilterResourceURLForCodeCache, | 
 |                   origin, data); | 
 |   EXPECT_TRUE( | 
 |       tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin)); | 
 |   EXPECT_TRUE(tester.ContainsEntry(RemoveCodeCacheTester::kJs, | 
 |                                    kFilterResourceURLForCodeCache, origin)); | 
 |   EXPECT_EQ(tester.received_data(), data); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce( | 
 |           &ClearCodeCache, partition, base::Time(), base::Time(), | 
 |           base::BindRepeating(&FilterURL, kFilterResourceURLForCodeCache), | 
 |           &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_TRUE( | 
 |       tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin)); | 
 |   EXPECT_FALSE(tester.ContainsEntry(RemoveCodeCacheTester::kJs, | 
 |                                     kFilterResourceURLForCodeCache, origin)); | 
 |  | 
 |   // Make sure there isn't a second invalid callback sitting in the queue. | 
 |   // (this used to be a bug). | 
 |   base::RunLoop().RunUntilIdle(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, ClearCodeCacheDateRange) { | 
 |   const GURL kResourceURL("http://host4/script.js"); | 
 |   const GURL kFilterResourceURLForCodeCache("http://host5/script.js"); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   // Ensure code cache is initialized. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |   EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr); | 
 |  | 
 |   RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext()); | 
 |  | 
 |   base::Time current_time = base::Time::NowFromSystemTime(); | 
 |   base::Time out_of_range_time = current_time - base::Hours(3); | 
 |   base::Time begin_time = current_time - base::Hours(2); | 
 |   base::Time in_range_time = current_time - base::Hours(1); | 
 |  | 
 |   GURL origin = GURL("http://host1:1/"); | 
 |   std::string data("SomeData"); | 
 |   tester.AddEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin, data); | 
 |   EXPECT_TRUE( | 
 |       tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin)); | 
 |   EXPECT_EQ(tester.received_data(), data); | 
 |   tester.SetLastUseTime(RemoveCodeCacheTester::kJs, kResourceURL, origin, | 
 |                         out_of_range_time); | 
 |  | 
 |   // Add a new entry. | 
 |   tester.AddEntry(RemoveCodeCacheTester::kJs, kFilterResourceURLForCodeCache, | 
 |                   origin, data); | 
 |   EXPECT_TRUE(tester.ContainsEntry(RemoveCodeCacheTester::kJs, | 
 |                                    kFilterResourceURLForCodeCache, origin)); | 
 |   tester.SetLastUseTime(RemoveCodeCacheTester::kJs, | 
 |                         kFilterResourceURLForCodeCache, origin, in_range_time); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce( | 
 |           &ClearCodeCache, partition, begin_time, current_time, | 
 |           base::BindRepeating(&FilterURL, kFilterResourceURLForCodeCache), | 
 |           &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_TRUE( | 
 |       tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin)); | 
 |   EXPECT_FALSE(tester.ContainsEntry(RemoveCodeCacheTester::kJs, | 
 |                                     kFilterResourceURLForCodeCache, origin)); | 
 |  | 
 |   // Make sure there isn't a second invalid callback sitting in the queue. | 
 |   // (this used to be a bug). | 
 |   base::RunLoop().RunUntilIdle(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, ClearWasmCodeCache) { | 
 |   const GURL kResourceURL("http://host4/script.js"); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   // Ensure code cache is initialized. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |   EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr); | 
 |  | 
 |   RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext()); | 
 |  | 
 |   GURL origin = GURL("http://host1:1/"); | 
 |   std::string data("SomeData.wasm"); | 
 |   tester.AddEntry(RemoveCodeCacheTester::kWebAssembly, kResourceURL, origin, | 
 |                   data); | 
 |   EXPECT_TRUE(tester.ContainsEntry(RemoveCodeCacheTester::kWebAssembly, | 
 |                                    kResourceURL, origin)); | 
 |   EXPECT_EQ(tester.received_data(), data); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearCodeCache, partition, base::Time(), base::Time(), | 
 |                      base::RepeatingCallback<bool(const GURL&)>(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_FALSE(tester.ContainsEntry(RemoveCodeCacheTester::kWebAssembly, | 
 |                                     kResourceURL, origin)); | 
 |  | 
 |   // Make sure there isn't a second invalid callback sitting in the queue. | 
 |   // (this used to be a bug). | 
 |   base::RunLoop().RunUntilIdle(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, ClearWebUICodeCache) { | 
 |   base::test::ScopedFeatureList features; | 
 |   features.InitAndEnableFeature(features::kWebUICodeCache); | 
 |  | 
 |   const GURL kResourceURL("chrome://host4/script.js"); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   // Ensure code cache is initialized. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |   EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr); | 
 |  | 
 |   RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext()); | 
 |  | 
 |   GURL origin = GURL("chrome://host1:1/"); | 
 |   std::string data("SomeData"); | 
 |   tester.AddEntry(RemoveCodeCacheTester::kWebUiJs, kResourceURL, origin, data); | 
 |   EXPECT_TRUE(tester.ContainsEntry(RemoveCodeCacheTester::kWebUiJs, | 
 |                                    kResourceURL, origin)); | 
 |   EXPECT_EQ(tester.received_data(), data); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearCodeCache, partition, base::Time(), base::Time(), | 
 |                      base::RepeatingCallback<bool(const GURL&)>(), &run_loop)); | 
 |   run_loop.Run(); | 
 |  | 
 |   EXPECT_FALSE(tester.ContainsEntry(RemoveCodeCacheTester::kWebUiJs, | 
 |                                     kResourceURL, origin)); | 
 |  | 
 |   // Make sure there isn't a second invalid callback sitting in the queue. | 
 |   // (this used to be a bug). | 
 |   base::RunLoop().RunUntilIdle(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, WebUICodeCacheDisabled) { | 
 |   base::test::ScopedFeatureList features; | 
 |   features.InitAndDisableFeature(features::kWebUICodeCache); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   // Ensure code cache is initialized. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |   EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr); | 
 |   base::RunLoop run_loop; | 
 |   auto* context = partition->GetGeneratedCodeCacheContext(); | 
 |   GeneratedCodeCacheContext::RunOrPostTask( | 
 |       context, FROM_HERE, base::BindLambdaForTesting([&]() { | 
 |         EXPECT_EQ(partition->GetGeneratedCodeCacheContext() | 
 |                       ->generated_webui_js_code_cache(), | 
 |                   nullptr); | 
 |         run_loop.Quit(); | 
 |       })); | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, ClearCodeCacheIncognito) { | 
 |   browser_context()->set_is_off_the_record(true); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   base::RunLoop().RunUntilIdle(); | 
 |   // We should not create GeneratedCodeCacheContext for off the record mode. | 
 |   EXPECT_EQ(nullptr, partition->GetGeneratedCodeCacheContext()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   // This shouldn't crash. | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearCodeCache, partition, base::Time(), base::Time(), | 
 |                      base::RepeatingCallback<bool(const GURL&)>(), &run_loop)); | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST(StoragePartitionImplStaticTest, CreatePredicateForHostCookies) { | 
 |   GURL url("http://www.example.com/"); | 
 |   GURL url2("https://www.example.com/"); | 
 |   GURL url3("https://www.google.com/"); | 
 |  | 
 |   std::optional<base::Time> server_time = std::nullopt; | 
 |   CookieDeletionFilterPtr deletion_filter = CookieDeletionFilter::New(); | 
 |   deletion_filter->host_name = url.host(); | 
 |  | 
 |   base::Time now = base::Time::Now(); | 
 |   std::vector<std::unique_ptr<CanonicalCookie>> valid_cookies; | 
 |   valid_cookies.push_back( | 
 |       CanonicalCookie::CreateForTesting(url, "A=B", now, server_time)); | 
 |   valid_cookies.push_back( | 
 |       CanonicalCookie::CreateForTesting(url, "C=F", now, server_time)); | 
 |   // We should match a different scheme with the same host. | 
 |   valid_cookies.push_back( | 
 |       CanonicalCookie::CreateForTesting(url2, "A=B", now, server_time)); | 
 |  | 
 |   std::vector<std::unique_ptr<CanonicalCookie>> invalid_cookies; | 
 |   // We don't match domain cookies. | 
 |   invalid_cookies.push_back(CanonicalCookie::CreateForTesting( | 
 |       url2, "A=B;domain=.example.com", now, server_time)); | 
 |   invalid_cookies.push_back( | 
 |       CanonicalCookie::CreateForTesting(url3, "A=B", now, server_time)); | 
 |  | 
 |   for (const auto& cookie : valid_cookies) { | 
 |     EXPECT_TRUE(FilterMatchesCookie(deletion_filter, *cookie)) | 
 |         << cookie->DebugString(); | 
 |   } | 
 |   for (const auto& cookie : invalid_cookies) { | 
 |     EXPECT_FALSE(FilterMatchesCookie(deletion_filter, *cookie)) | 
 |         << cookie->DebugString(); | 
 |   } | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, AttributionManagerCreatedInIncognito) { | 
 |   browser_context()->set_is_off_the_record(true); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   EXPECT_TRUE(partition->GetAttributionManager()); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, AttributionReportingClearData) { | 
 |   using ::testing::_; | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   const base::Time kDeleteBegin = base::Time::Now(); | 
 |   const base::Time kDeleteEnd = kDeleteBegin + base::Days(1); | 
 |  | 
 |   const auto kStorageKeyA = blink::StorageKey::CreateFirstParty( | 
 |       url::Origin::Create(GURL("https://a.test"))); | 
 |  | 
 |   const auto kStorageKeyB = blink::StorageKey::CreateFirstParty( | 
 |       url::Origin::Create(GURL("https://b.test"))); | 
 |  | 
 |   const struct { | 
 |     const char* name; | 
 |     uint32_t mask; | 
 |     bool expected_delete_rate_limit_data; | 
 |   } kTestCases[] = { | 
 |       { | 
 |           .name = "no_internal", | 
 |           .mask = 0, | 
 |           .expected_delete_rate_limit_data = false, | 
 |       }, | 
 |       { | 
 |           .name = "internal", | 
 |           .mask = | 
 |               StoragePartition::REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_INTERNAL, | 
 |           .expected_delete_rate_limit_data = true, | 
 |       }, | 
 |   }; | 
 |  | 
 |   for (const auto& test_case : kTestCases) { | 
 |     SCOPED_TRACE(test_case.name); | 
 |  | 
 |     auto attribution_manager = std::make_unique<MockAttributionManager>(); | 
 |  | 
 |     EXPECT_CALL(*attribution_manager, | 
 |                 ClearData(kDeleteBegin, kDeleteEnd, | 
 |                           /*filter=*/_, | 
 |                           /*filter_builder=*/_, | 
 |                           test_case.expected_delete_rate_limit_data, | 
 |                           /*done=*/_)) | 
 |         .WillOnce(::testing::DoAll( | 
 |             ::testing::WithArg<2>( | 
 |                 [&](StoragePartition::StorageKeyMatcherFunction f) { | 
 |                   EXPECT_TRUE(f.Run(kStorageKeyA)); | 
 |                   EXPECT_FALSE(f.Run(kStorageKeyB)); | 
 |                 }), | 
 |             base::test::RunOnceClosure<5>())); | 
 |  | 
 |     partition->OverrideAttributionManagerForTesting( | 
 |         std::move(attribution_manager)); | 
 |  | 
 |     base::RunLoop run_loop; | 
 |  | 
 |     partition->ClearData( | 
 |         StoragePartition::REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_SITE_CREATED | | 
 |             test_case.mask, | 
 |         /*quota_storage_remove_mask=*/0, kStorageKeyA, kDeleteBegin, kDeleteEnd, | 
 |         run_loop.QuitClosure()); | 
 |  | 
 |     run_loop.Run(); | 
 |   } | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, AttributionReportingClearDataWrongMask) { | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   auto attribution_manager = std::make_unique<MockAttributionManager>(); | 
 |   EXPECT_CALL(*attribution_manager, ClearData).Times(0); | 
 |  | 
 |   partition->OverrideAttributionManagerForTesting( | 
 |       std::move(attribution_manager)); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |  | 
 |   // Arbitrary irrelevant mask. | 
 |   partition->ClearData(StoragePartition::REMOVE_DATA_MASK_COOKIES, | 
 |                        /*quota_storage_remove_mask=*/0, blink::StorageKey(), | 
 |                        /*begin=*/base::Time::Min(), /*end=*/base::Time::Max(), | 
 |                        run_loop.QuitClosure()); | 
 |  | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, AttributionReportingClearDataForFilter) { | 
 |   using ::testing::_; | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   const auto kFilterBuilder = BrowsingDataFilterBuilder::Create( | 
 |       BrowsingDataFilterBuilder::Mode::kPreserve); | 
 |  | 
 |   auto attribution_manager = std::make_unique<MockAttributionManager>(); | 
 |  | 
 |   EXPECT_CALL(*attribution_manager, | 
 |               ClearData(/*delete_begin=*/_, | 
 |                         /*delete_end=*/_, | 
 |                         /*filter=*/_, | 
 |                         /*filter_builder=*/kFilterBuilder.get(), | 
 |                         /*delete_rate_limit_data=*/false, | 
 |                         /*done=*/_)) | 
 |       .WillOnce(base::test::RunOnceClosure<5>()); | 
 |  | 
 |   partition->OverrideAttributionManagerForTesting( | 
 |       std::move(attribution_manager)); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |  | 
 |   StoragePartition::StorageKeyPolicyMatcherFunction func = | 
 |       base::BindRepeating([](const blink::StorageKey&, | 
 |                              storage::SpecialStoragePolicy*) { return true; }); | 
 |  | 
 |   partition->ClearData( | 
 |       StoragePartition::REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_SITE_CREATED, | 
 |       /*quota_storage_remove_mask=*/0, kFilterBuilder.get(), func, | 
 |       /*cookie_deletion_filter=*/nullptr, /*perform_storage_cleanup=*/false, | 
 |       /*begin=*/base::Time::Min(), /*end=*/base::Time::Max(), | 
 |       run_loop.QuitClosure()); | 
 |  | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, DataRemovalObserver) { | 
 |   const uint32_t kTestClearMask = | 
 |       content::StoragePartition::REMOVE_DATA_MASK_INDEXEDDB; | 
 |   const uint32_t kTestQuotaClearMask = 0; | 
 |   const auto kTestOrigin = GURL("https://example.com"); | 
 |   const auto kBeginTime = base::Time() + base::Hours(1); | 
 |   const auto kEndTime = base::Time() + base::Hours(2); | 
 |   const auto storage_key_callback_valid = | 
 |       [&](content::StoragePartition::StorageKeyMatcherFunction callback) { | 
 |         return callback.Run(blink::StorageKey::CreateFirstParty( | 
 |             url::Origin::Create(kTestOrigin))); | 
 |       }; | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   MockDataRemovalObserver observer(partition); | 
 |  | 
 |   // Confirm that each of the StoragePartition interfaces for clearing origin | 
 |   // based data notify observers appropriately. | 
 |   EXPECT_CALL(observer, | 
 |               OnStorageKeyDataCleared( | 
 |                   kTestClearMask, testing::Truly(storage_key_callback_valid), | 
 |                   base::Time(), base::Time::Max())); | 
 |   base::RunLoop run_loop; | 
 |   partition->ClearDataForOrigin(kTestClearMask, kTestQuotaClearMask, | 
 |                                 kTestOrigin, run_loop.QuitClosure()); | 
 |   run_loop.Run(); | 
 |   testing::Mock::VerifyAndClearExpectations(&observer); | 
 |  | 
 |   EXPECT_CALL(observer, | 
 |               OnStorageKeyDataCleared( | 
 |                   kTestClearMask, testing::Truly(storage_key_callback_valid), | 
 |                   kBeginTime, kEndTime)); | 
 |   partition->ClearData( | 
 |       kTestClearMask, kTestQuotaClearMask, | 
 |       blink::StorageKey::CreateFirstParty(url::Origin::Create(kTestOrigin)), | 
 |       kBeginTime, kEndTime, base::DoNothing()); | 
 |   testing::Mock::VerifyAndClearExpectations(&observer); | 
 |  | 
 |   EXPECT_CALL(observer, | 
 |               OnStorageKeyDataCleared( | 
 |                   kTestClearMask, testing::Truly(storage_key_callback_valid), | 
 |                   kBeginTime, kEndTime)); | 
 |   partition->ClearData( | 
 |       kTestClearMask, kTestQuotaClearMask, | 
 |       /*filter_builder=*/nullptr, | 
 |       base::BindLambdaForTesting([&](const blink::StorageKey& storage_key, | 
 |                                      storage::SpecialStoragePolicy* policy) { | 
 |         return storage_key == blink::StorageKey::CreateFirstParty( | 
 |                                   url::Origin::Create(kTestOrigin)); | 
 |       }), | 
 |       /*cookie_deletion_filter=*/nullptr, /*perform_storage_cleanup=*/false, | 
 |       kBeginTime, kEndTime, base::DoNothing()); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemoveAggregationServiceData) { | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   auto aggregation_service = std::make_unique<MockAggregationService>(); | 
 |   auto* aggregation_service_ptr = aggregation_service.get(); | 
 |   partition->OverrideAggregationServiceForTesting( | 
 |       std::move(aggregation_service)); | 
 |  | 
 |   const uint32_t kTestClearMask = | 
 |       StoragePartition::REMOVE_DATA_MASK_AGGREGATION_SERVICE; | 
 |   const uint32_t kTestQuotaClearMask = | 
 |       StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL; | 
 |   const auto kTestOrigin = GURL("https://example.com"); | 
 |   const auto kOtherOrigin = GURL("https://example.net"); | 
 |   const auto kBeginTime = base::Time() + base::Hours(1); | 
 |   const auto kEndTime = base::Time() + base::Hours(2); | 
 |   const auto invoke_callback = | 
 |       [](base::Time delete_begin, base::Time delete_end, | 
 |          StoragePartition::StorageKeyMatcherFunction filter, | 
 |          base::OnceClosure done) { std::move(done).Run(); }; | 
 |   const auto is_test_origin_valid = | 
 |       [&kTestOrigin]( | 
 |           content::StoragePartition::StorageKeyMatcherFunction filter) { | 
 |         return filter.Run(blink::StorageKey::CreateFirstParty( | 
 |             url::Origin::Create(kTestOrigin))); | 
 |       }; | 
 |   const auto is_other_origin_valid = | 
 |       [&kOtherOrigin]( | 
 |           content::StoragePartition::StorageKeyMatcherFunction filter) { | 
 |         return filter.Run(blink::StorageKey::CreateFirstParty( | 
 |             url::Origin::Create(kOtherOrigin))); | 
 |       }; | 
 |   const auto is_filter_null = | 
 |       [&](content::StoragePartition::StorageKeyMatcherFunction filter) { | 
 |         return filter.is_null(); | 
 |       }; | 
 |  | 
 |   // Verify that each of the StoragePartition interfaces for clearing origin | 
 |   // based data calls aggregation service appropriately. | 
 |   EXPECT_CALL( | 
 |       *aggregation_service_ptr, | 
 |       ClearData( | 
 |           base::Time(), base::Time::Max(), | 
 |           testing::AllOf(testing::Truly(is_test_origin_valid), | 
 |                          testing::Not(testing::Truly(is_other_origin_valid))), | 
 |           testing::_)) | 
 |       .WillOnce(invoke_callback); | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     partition->ClearDataForOrigin(kTestClearMask, kTestQuotaClearMask, | 
 |                                   kTestOrigin, run_loop.QuitClosure()); | 
 |     run_loop.Run(); | 
 |     testing::Mock::VerifyAndClearExpectations(aggregation_service_ptr); | 
 |   } | 
 |  | 
 |   EXPECT_CALL( | 
 |       *aggregation_service_ptr, | 
 |       ClearData( | 
 |           kBeginTime, kEndTime, | 
 |           testing::AllOf(testing::Truly(is_test_origin_valid), | 
 |                          testing::Not(testing::Truly(is_other_origin_valid))), | 
 |           testing::_)) | 
 |       .WillOnce(testing::Invoke(invoke_callback)); | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     partition->ClearData( | 
 |         kTestClearMask, kTestQuotaClearMask, | 
 |         blink::StorageKey::CreateFirstParty(url::Origin::Create(kTestOrigin)), | 
 |         kBeginTime, kEndTime, run_loop.QuitClosure()); | 
 |     run_loop.Run(); | 
 |     testing::Mock::VerifyAndClearExpectations(aggregation_service_ptr); | 
 |   } | 
 |  | 
 |   EXPECT_CALL( | 
 |       *aggregation_service_ptr, | 
 |       ClearData( | 
 |           kBeginTime, kEndTime, | 
 |           testing::AllOf(testing::Truly(is_test_origin_valid), | 
 |                          testing::Not(testing::Truly(is_other_origin_valid))), | 
 |           testing::_)) | 
 |       .WillOnce(testing::Invoke(invoke_callback)); | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     partition->ClearData( | 
 |         kTestClearMask, kTestQuotaClearMask, | 
 |         /*filter_builder=*/nullptr, | 
 |         base::BindLambdaForTesting([&](const blink::StorageKey& storage_key, | 
 |                                        storage::SpecialStoragePolicy* policy) { | 
 |           return storage_key == blink::StorageKey::CreateFirstParty( | 
 |                                     url::Origin::Create(kTestOrigin)); | 
 |         }), | 
 |         /*cookie_deletion_filter=*/nullptr, | 
 |         /*perform_storage_cleanup=*/false, kBeginTime, kEndTime, | 
 |         run_loop.QuitClosure()); | 
 |     run_loop.Run(); | 
 |     testing::Mock::VerifyAndClearExpectations(aggregation_service_ptr); | 
 |   } | 
 |  | 
 |   EXPECT_CALL( | 
 |       *aggregation_service_ptr, | 
 |       ClearData( | 
 |           kBeginTime, kEndTime, | 
 |           testing::AllOf(testing::Truly(is_test_origin_valid), | 
 |                          testing::Not(testing::Truly(is_other_origin_valid))), | 
 |           testing::_)) | 
 |       .WillOnce(testing::Invoke(invoke_callback)); | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     auto filter_builder = BrowsingDataFilterBuilder::Create( | 
 |         BrowsingDataFilterBuilder::Mode::kDelete); | 
 |     filter_builder->AddOrigin(url::Origin::Create(kTestOrigin)); | 
 |     partition->ClearData(kTestClearMask, kTestQuotaClearMask, | 
 |                          filter_builder.get(), | 
 |                          StoragePartition::StorageKeyPolicyMatcherFunction(), | 
 |                          /*cookie_deletion_filter=*/nullptr, | 
 |                          /*perform_storage_cleanup=*/false, kBeginTime, | 
 |                          kEndTime, run_loop.QuitClosure()); | 
 |     run_loop.Run(); | 
 |     testing::Mock::VerifyAndClearExpectations(aggregation_service_ptr); | 
 |   } | 
 |  | 
 |   EXPECT_CALL(*aggregation_service_ptr, | 
 |               ClearData(kBeginTime, kEndTime, testing::Truly(is_filter_null), | 
 |                         testing::_)) | 
 |       .WillOnce(testing::Invoke(invoke_callback)); | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     partition->ClearData(kTestClearMask, kTestQuotaClearMask, | 
 |                          blink::StorageKey(), kBeginTime, kEndTime, | 
 |                          run_loop.QuitClosure()); | 
 |     run_loop.Run(); | 
 |   } | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, RemovePrivateAggregationData) { | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   auto private_aggregation_manager = | 
 |       std::make_unique<MockPrivateAggregationManagerImpl>(partition); | 
 |   auto* private_aggregation_manager_ptr = private_aggregation_manager.get(); | 
 |   partition->OverridePrivateAggregationManagerForTesting( | 
 |       std::move(private_aggregation_manager)); | 
 |  | 
 |   const uint32_t kTestClearMask = | 
 |       StoragePartition::REMOVE_DATA_MASK_PRIVATE_AGGREGATION_INTERNAL; | 
 |   const uint32_t kTestQuotaClearMask = | 
 |       StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL; | 
 |   const auto kTestOrigin = GURL("https://example.com"); | 
 |   const auto kOtherOrigin = GURL("https://example.net"); | 
 |   const auto kBeginTime = base::Time() + base::Hours(1); | 
 |   const auto kEndTime = base::Time() + base::Hours(2); | 
 |   const auto invoke_callback = | 
 |       [](base::Time delete_begin, base::Time delete_end, | 
 |          StoragePartition::StorageKeyMatcherFunction filter, | 
 |          base::OnceClosure done) { std::move(done).Run(); }; | 
 |   const auto is_test_origin_valid = | 
 |       [&kTestOrigin]( | 
 |           content::StoragePartition::StorageKeyMatcherFunction filter) { | 
 |         return filter.Run(blink::StorageKey::CreateFirstParty( | 
 |             url::Origin::Create(kTestOrigin))); | 
 |       }; | 
 |   const auto is_other_origin_valid = | 
 |       [&kOtherOrigin]( | 
 |           content::StoragePartition::StorageKeyMatcherFunction filter) { | 
 |         return filter.Run(blink::StorageKey::CreateFirstParty( | 
 |             url::Origin::Create(kOtherOrigin))); | 
 |       }; | 
 |   const auto is_filter_null = | 
 |       [&](content::StoragePartition::StorageKeyMatcherFunction filter) { | 
 |         return filter.is_null(); | 
 |       }; | 
 |  | 
 |   // Verify that each of the StoragePartition interfaces for clearing origin | 
 |   // based data calls aggregation service appropriately. | 
 |   EXPECT_CALL( | 
 |       *private_aggregation_manager_ptr, | 
 |       ClearBudgetData( | 
 |           base::Time(), base::Time::Max(), | 
 |           testing::AllOf(testing::Truly(is_test_origin_valid), | 
 |                          testing::Not(testing::Truly(is_other_origin_valid))), | 
 |           testing::_)) | 
 |       .WillOnce(invoke_callback); | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     partition->ClearDataForOrigin(kTestClearMask, kTestQuotaClearMask, | 
 |                                   kTestOrigin, run_loop.QuitClosure()); | 
 |     run_loop.Run(); | 
 |     testing::Mock::VerifyAndClearExpectations(private_aggregation_manager_ptr); | 
 |   } | 
 |  | 
 |   EXPECT_CALL( | 
 |       *private_aggregation_manager_ptr, | 
 |       ClearBudgetData( | 
 |           kBeginTime, kEndTime, | 
 |           testing::AllOf(testing::Truly(is_test_origin_valid), | 
 |                          testing::Not(testing::Truly(is_other_origin_valid))), | 
 |           testing::_)) | 
 |       .WillOnce(testing::Invoke(invoke_callback)); | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     partition->ClearData( | 
 |         kTestClearMask, kTestQuotaClearMask, | 
 |         blink::StorageKey::CreateFirstParty(url::Origin::Create(kTestOrigin)), | 
 |         kBeginTime, kEndTime, run_loop.QuitClosure()); | 
 |     run_loop.Run(); | 
 |     testing::Mock::VerifyAndClearExpectations(private_aggregation_manager_ptr); | 
 |   } | 
 |  | 
 |   EXPECT_CALL( | 
 |       *private_aggregation_manager_ptr, | 
 |       ClearBudgetData( | 
 |           kBeginTime, kEndTime, | 
 |           testing::AllOf(testing::Truly(is_test_origin_valid), | 
 |                          testing::Not(testing::Truly(is_other_origin_valid))), | 
 |           testing::_)) | 
 |       .WillOnce(testing::Invoke(invoke_callback)); | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     partition->ClearData( | 
 |         kTestClearMask, kTestQuotaClearMask, | 
 |         /*filter_builder=*/nullptr, | 
 |         base::BindLambdaForTesting([&](const blink::StorageKey& storage_key, | 
 |                                        storage::SpecialStoragePolicy* policy) { | 
 |           return storage_key == blink::StorageKey::CreateFirstParty( | 
 |                                     url::Origin::Create(kTestOrigin)); | 
 |         }), | 
 |         /*cookie_deletion_filter=*/nullptr, | 
 |         /*perform_storage_cleanup=*/false, kBeginTime, kEndTime, | 
 |         run_loop.QuitClosure()); | 
 |     run_loop.Run(); | 
 |     testing::Mock::VerifyAndClearExpectations(private_aggregation_manager_ptr); | 
 |   } | 
 |  | 
 |   EXPECT_CALL(*private_aggregation_manager_ptr, | 
 |               ClearBudgetData(kBeginTime, kEndTime, | 
 |                               testing::Truly(is_filter_null), testing::_)) | 
 |       .WillOnce(testing::Invoke(invoke_callback)); | 
 |   { | 
 |     base::RunLoop run_loop; | 
 |     partition->ClearData(kTestClearMask, kTestQuotaClearMask, | 
 |                          blink::StorageKey(), kBeginTime, kEndTime, | 
 |                          run_loop.QuitClosure()); | 
 |     run_loop.Run(); | 
 |   } | 
 | } | 
 |  | 
 | // https://crbug.com/1221382 | 
 | // Make sure StorageServiceImpl can be stored in a SequenceLocalStorageSlot and | 
 | // that it can be safely destroyed when the thread terminates. | 
 | TEST(StorageServiceImplOnSequenceLocalStorage, ThreadDestructionDoesNotFail) { | 
 |   mojo::Remote<storage::mojom::StorageService> remote_service; | 
 |   mojo::Remote<storage::mojom::LocalStorageControl> storage_control; | 
 |   // These remotes must outlive the thread, otherwise PartitionImpl cleanup will | 
 |   // not happen in the ~StorageServiceImpl but on the mojo error handler. | 
 |   { | 
 |     // When this variable gets out of scope the IO thread will be destroyed | 
 |     // along with all objects stored in a SequenceLocalStorageSlot. | 
 |     content::BrowserTaskEnvironment task_environment( | 
 |         content::BrowserTaskEnvironment::REAL_IO_THREAD); | 
 |  | 
 |     content::GetIOThreadTaskRunner({})->PostTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce( | 
 |             [](mojo::PendingReceiver<storage::mojom::StorageService> receiver) { | 
 |               DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 
 |               static base::SequenceLocalStorageSlot< | 
 |                   std::unique_ptr<storage::StorageServiceImpl>> | 
 |                   service_storage_slot; | 
 |               service_storage_slot.GetOrCreateValue() = | 
 |                   std::make_unique<storage::StorageServiceImpl>( | 
 |                       std::move(receiver), | 
 |                       /*io_task_runner=*/nullptr); | 
 |             }, | 
 |             remote_service.BindNewPipeAndPassReceiver())); | 
 |  | 
 |     // Make sure PartitionImpl gets to destroy a LocalStorageImpl object. | 
 |     base::ScopedTempDir temp_dir; | 
 |     CHECK(temp_dir.CreateUniqueTempDir()); | 
 |     remote_service->BindLocalStorageControl( | 
 |         temp_dir.GetPath(), storage::mojom::StorageLifecycle::kInitializing, | 
 |         storage_control.BindNewPipeAndPassReceiver()); | 
 |     storage_control.FlushForTesting(); | 
 |   } | 
 | } | 
 |  | 
 | #if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS) | 
 | TEST_F(StoragePartitionImplTest, RemoveDeviceBoundSessions) { | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   auto device_bound_session_manager = | 
 |       std::make_unique<network::MockDeviceBoundSessionManager>(); | 
 |   network::MockDeviceBoundSessionManager* device_bound_session_manager_raw = | 
 |       device_bound_session_manager.get(); | 
 |   partition->OverrideDeviceBoundSessionManagerForTesting( | 
 |       std::move(device_bound_session_manager)); | 
 |  | 
 |   base::Time created_before_time = base::Time::Now() - base::Days(1); | 
 |   base::Time created_after_time = base::Time::Now() - base::Days(3); | 
 |  | 
 |   EXPECT_CALL( | 
 |       *device_bound_session_manager_raw, | 
 |       DeleteAllSessions(Eq(net::device_bound_sessions::DeletionReason:: | 
 |                                kStoragePartitionCleared), | 
 |                         Eq(created_after_time), Eq(created_before_time), _, _)) | 
 |       .WillOnce(base::test::RunOnceClosure<4>()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   partition->ClearData(StoragePartition::REMOVE_DATA_MASK_DEVICE_BOUND_SESSIONS, | 
 |                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |                        blink::StorageKey(), created_after_time, | 
 |                        created_before_time, run_loop.QuitClosure()); | 
 |   run_loop.Run(); | 
 | } | 
 | #endif | 
 |  | 
 | class StoragePartitionImplSharedStorageTest : public StoragePartitionImplTest { | 
 |  public: | 
 |   StoragePartitionImplSharedStorageTest() | 
 |       : storage_partition_(browser_context()->GetDefaultStoragePartition()), | 
 |         shared_storage_manager_( | 
 |             static_cast<StoragePartitionImpl*>(storage_partition_) | 
 |                 ->GetSharedStorageManager()) { | 
 |     feature_list_.InitWithFeatures({network::features::kInterestGroupStorage, | 
 |                                     network::features::kSharedStorageAPI}, | 
 |                                    {}); | 
 |   } | 
 |  | 
 |   StoragePartitionImplSharedStorageTest( | 
 |       const StoragePartitionImplSharedStorageTest&) = delete; | 
 |   StoragePartitionImplSharedStorageTest& operator=( | 
 |       const StoragePartitionImplSharedStorageTest&) = delete; | 
 |  | 
 |   ~StoragePartitionImplSharedStorageTest() override { | 
 |     task_environment()->RunUntilIdle(); | 
 |   } | 
 |  | 
 |   scoped_refptr<storage::SpecialStoragePolicy> GetSpecialStoragePolicy() { | 
 |     return base::WrapRefCounted<storage::SpecialStoragePolicy>( | 
 |         static_cast<content::StoragePartitionImpl*>(storage_partition_) | 
 |             ->browser_context() | 
 |             ->GetSpecialStoragePolicy()); | 
 |   } | 
 |  | 
 |   // Returns true, if the given origin URL exists. | 
 |   bool SharedStorageExistsForOrigin(const url::Origin& origin) { | 
 |     for (const auto& info : GetSharedStorageUsage()) { | 
 |       if (origin == info->storage_key.origin()) | 
 |         return true; | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |   void AddSharedStorageTestData(const url::Origin& origin1, | 
 |                                 const url::Origin& origin2, | 
 |                                 const url::Origin& origin3) { | 
 |     base::FilePath path = | 
 |         storage_partition_->GetPath().Append(storage::kSharedStoragePath); | 
 |     std::unique_ptr<storage::AsyncSharedStorageDatabase> database = | 
 |         storage::AsyncSharedStorageDatabaseImpl::Create( | 
 |             path, | 
 |             base::ThreadPool::CreateSequencedTaskRunner( | 
 |                 {base::MayBlock(), base::WithBaseSyncPrimitives(), | 
 |                  base::TaskShutdownBehavior::BLOCK_SHUTDOWN}), | 
 |             GetSpecialStoragePolicy(), | 
 |             storage::SharedStorageOptions::Create()->GetDatabaseOptions()); | 
 |  | 
 |     // Add a key for origin1. | 
 |     { | 
 |       base::test::TestFuture<storage::SharedStorageDatabase::OperationResult> | 
 |           future; | 
 |       database->Set(origin1, u"key1", u"value1", future.GetCallback()); | 
 |       EXPECT_EQ(storage::SharedStorageDatabase::OperationResult::kSet, | 
 |                 future.Get()); | 
 |     } | 
 |     // Add a key for origin2. | 
 |     { | 
 |       base::test::TestFuture<storage::SharedStorageDatabase::OperationResult> | 
 |           future; | 
 |       database->Set(origin2, u"key1", u"value1", future.GetCallback()); | 
 |       EXPECT_EQ(storage::SharedStorageDatabase::OperationResult::kSet, | 
 |                 future.Get()); | 
 |     } | 
 |  | 
 |     task_environment()->AdvanceClock(base::Milliseconds(10)); | 
 |  | 
 |     // Add a key for origin3. | 
 |     { | 
 |       base::test::TestFuture<storage::SharedStorageDatabase::OperationResult> | 
 |           future; | 
 |       database->Set(origin3, u"key1", u"value1", future.GetCallback()); | 
 |       EXPECT_EQ(storage::SharedStorageDatabase::OperationResult::kSet, | 
 |                 future.Get()); | 
 |     } | 
 |  | 
 |     // Ensure that this database is fully closed before checking for existence. | 
 |     database.reset(); | 
 |     task_environment()->RunUntilIdle(); | 
 |  | 
 |     EXPECT_TRUE(SharedStorageExistsForOrigin(origin1)); | 
 |     EXPECT_TRUE(SharedStorageExistsForOrigin(origin2)); | 
 |     EXPECT_TRUE(SharedStorageExistsForOrigin(origin3)); | 
 |  | 
 |     task_environment()->RunUntilIdle(); | 
 |   } | 
 |  | 
 |  private: | 
 |   std::vector<storage::mojom::StorageUsageInfoPtr> GetSharedStorageUsage() { | 
 |     DCHECK(shared_storage_manager_); | 
 |  | 
 |     base::test::TestFuture<std::vector<storage::mojom::StorageUsageInfoPtr>> | 
 |         future; | 
 |     shared_storage_manager_->FetchOrigins(future.GetCallback()); | 
 |     return future.Take(); | 
 |   } | 
 |  | 
 |   base::test::ScopedFeatureList feature_list_; | 
 |  | 
 |   // We don't own these pointers. | 
 |   const raw_ptr<StoragePartition> storage_partition_; | 
 |   raw_ptr<storage::SharedStorageManager> shared_storage_manager_; | 
 | }; | 
 |  | 
 | TEST_F(StoragePartitionImplSharedStorageTest, | 
 |        RemoveUnprotectedSharedStorageForever) { | 
 |   const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/")); | 
 |   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/")); | 
 |   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/")); | 
 |  | 
 |   // Protect kOrigin1. | 
 |   auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>(); | 
 |   mock_policy->AddProtected(kOrigin1.GetURL()); | 
 |  | 
 |   AddSharedStorageTestData(kOrigin1, kOrigin2, kOrigin3); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->GetSharedStorageManager()->OverrideSpecialStoragePolicyForTesting( | 
 |       mock_policy.get()); | 
 |  | 
 |   base::RunLoop clear_run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearStuff, | 
 |                      StoragePartitionImpl::REMOVE_DATA_MASK_SHARED_STORAGE, | 
 |                      partition, base::Time(), base::Time::Max(), | 
 |                      /*filter_builder=*/nullptr, | 
 |                      base::BindRepeating(&DoesOriginMatchForUnprotectedWeb), | 
 |                      &clear_run_loop)); | 
 |   clear_run_loop.Run(); | 
 |  | 
 |   // ClearData only guarantees that tasks to delete data are scheduled when its | 
 |   // callback is invoked. It doesn't guarantee data has actually been cleared. | 
 |   // So run all scheduled tasks to make sure data is cleared. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |  | 
 |   EXPECT_TRUE(SharedStorageExistsForOrigin(kOrigin1)); | 
 |   EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin2)); | 
 |   EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin3)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplSharedStorageTest, | 
 |        RemoveProtectedSharedStorageForever) { | 
 |   const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/")); | 
 |   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/")); | 
 |   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/")); | 
 |  | 
 |   // Protect kOrigin1. | 
 |   auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>(); | 
 |   mock_policy->AddProtected(kOrigin1.GetURL()); | 
 |  | 
 |   AddSharedStorageTestData(kOrigin1, kOrigin2, kOrigin3); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   partition->GetSharedStorageManager()->OverrideSpecialStoragePolicyForTesting( | 
 |       mock_policy.get()); | 
 |  | 
 |   base::RunLoop clear_run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&ClearStuff, | 
 |                      StoragePartitionImpl::REMOVE_DATA_MASK_SHARED_STORAGE, | 
 |                      partition, base::Time(), base::Time::Max(), | 
 |                      /*filter_builder=*/nullptr, | 
 |                      base::BindRepeating( | 
 |                          &DoesOriginMatchForBothProtectedAndUnprotectedWeb), | 
 |                      &clear_run_loop)); | 
 |   clear_run_loop.Run(); | 
 |  | 
 |   // ClearData only guarantees that tasks to delete data are scheduled when its | 
 |   // callback is invoked. It doesn't guarantee data has actually been cleared. | 
 |   // So run all scheduled tasks to make sure data is cleared. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |  | 
 |   // Even if kOrigin1 is protected, it will be deleted since we specify | 
 |   // ClearData to delete protected data. | 
 |   EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin1)); | 
 |   EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin2)); | 
 |   EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin3)); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplSharedStorageTest, RemoveSharedStorageRecent) { | 
 |   const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/")); | 
 |   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/")); | 
 |   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/")); | 
 |  | 
 |   base::Time start = base::Time::Now(); | 
 |   AddSharedStorageTestData(kOrigin1, kOrigin2, kOrigin3); | 
 |  | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   DCHECK(partition); | 
 |  | 
 |   // Origins 1 and 2 wrote their keys at time start, origin 3 wrote its key | 
 |   // at time start+10. Delete from start+5 -> infinity. | 
 |   base::RunLoop clear_run_loop; | 
 |   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce( | 
 |           &ClearStuff, StoragePartitionImpl::REMOVE_DATA_MASK_SHARED_STORAGE, | 
 |           partition, start + base::Milliseconds(5), base::Time::Max(), | 
 |           /*filter_builder=*/nullptr, | 
 |           base::BindRepeating( | 
 |               &DoesOriginMatchForBothProtectedAndUnprotectedWeb), | 
 |           &clear_run_loop)); | 
 |   clear_run_loop.Run(); | 
 |  | 
 |   // ClearData only guarantees that tasks to delete data are scheduled when its | 
 |   // callback is invoked. It doesn't guarantee data has actually been cleared. | 
 |   // So run all scheduled tasks to make sure data is cleared. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |  | 
 |   // Only kOrigin3 should have been cleared. | 
 |   EXPECT_TRUE(SharedStorageExistsForOrigin(kOrigin1)); | 
 |   EXPECT_TRUE(SharedStorageExistsForOrigin(kOrigin2)); | 
 |   EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin3)); | 
 | } | 
 |  | 
 | // Local network access tests require there to be a (minimal) frame setup. | 
 | using StoragePartitionImplLocalNetworkAccessTest = RenderViewHostTestHarness; | 
 |  | 
 | // Tests triggering the Local Network Access permission check for a subresource | 
 | // request. | 
 | TEST_F(StoragePartitionImplLocalNetworkAccessTest, | 
 |        LocalNetworkAccessPermission_SubresourceContext) { | 
 |   base::test::ScopedFeatureList features( | 
 |       network::features::kLocalNetworkAccessChecks); | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   mojo::Remote<network::mojom::URLLoaderNetworkServiceObserver> observer( | 
 |       partition->CreateURLLoaderNetworkObserverForFrame( | 
 |           process()->GetDeprecatedID(), main_rfh()->GetRoutingID())); | 
 |  | 
 |   base::test::TestFuture<bool> grant_permission; | 
 |   observer->OnLocalNetworkAccessPermissionRequired( | 
 |       base::BindOnce(grant_permission.GetCallback())); | 
 |   EXPECT_FALSE(grant_permission.Get()); | 
 | } | 
 |  | 
 | // Tests triggering the Local Network Access permission check for a subframe | 
 | // navigation context. | 
 | TEST_F(StoragePartitionImplLocalNetworkAccessTest, | 
 |        LocalNetworkAccessPermission_SubframeNavigationContext) { | 
 |   base::test::ScopedFeatureList features( | 
 |       network::features::kLocalNetworkAccessChecks); | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   // Set up a frame tree with a subframe, start a navigation in the subframe, | 
 |   // and get the NavigationRequest for that navigation. | 
 |   NavigateAndCommit(GURL("https://foo.com")); | 
 |   content::RenderFrameHost* sub_frame = | 
 |       content::RenderFrameHostTester::For(main_rfh()) | 
 |           ->AppendChild(std::string("child")); | 
 |   std::unique_ptr<content::NavigationSimulator> simulator = | 
 |       content::NavigationSimulator::CreateRendererInitiated( | 
 |           GURL("http://test.local"), sub_frame); | 
 |   simulator->Start(); | 
 |   NavigationRequest* request = | 
 |       NavigationRequest::From(simulator->GetNavigationHandle()); | 
 |  | 
 |   mojo::Remote<network::mojom::URLLoaderNetworkServiceObserver> observer( | 
 |       partition->CreateURLLoaderNetworkObserverForNavigationRequest(*request)); | 
 |  | 
 |   base::test::TestFuture<bool> grant_permission; | 
 |   observer->OnLocalNetworkAccessPermissionRequired( | 
 |       base::BindOnce(grant_permission.GetCallback())); | 
 |   EXPECT_FALSE(grant_permission.Get()); | 
 | } | 
 |  | 
 | // Tests triggering the Local Network Access permission check for a worker | 
 | // request. | 
 | TEST_F(StoragePartitionImplLocalNetworkAccessTest, | 
 |        LocalNetworkAccessPermission_WorkerContext) { | 
 |   base::test::ScopedFeatureList features( | 
 |       network::features::kLocalNetworkAccessChecks); | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |  | 
 |   const url::Origin worker_origin = | 
 |       url::Origin::Create(GURL("https://foo.com")); | 
 |  | 
 |   mojo::Remote<network::mojom::URLLoaderNetworkServiceObserver> observer( | 
 |       partition->CreateURLLoaderNetworkObserverForServiceWorker( | 
 |           network::mojom::kBrowserProcessId, worker_origin)); | 
 |  | 
 |   base::test::TestFuture<bool> grant_permission; | 
 |   observer->OnLocalNetworkAccessPermissionRequired( | 
 |       base::BindOnce(grant_permission.GetCallback())); | 
 |   EXPECT_FALSE(grant_permission.Get()); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplTest, ClearDataStorageKeyDeletesPartitionedCookies) { | 
 |   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( | 
 |       browser_context()->GetDefaultStoragePartition()); | 
 |   RemoveCookieTester tester(partition); | 
 |  | 
 |   const auto kOrigin = url::Origin::Create(GURL("https://example.com")); | 
 |   const auto kPartitionKey = | 
 |       net::CookiePartitionKey::FromURLForTesting(GURL("https://a.com")); | 
 |   const auto kOtherPartitionKey = | 
 |       net::CookiePartitionKey::FromURLForTesting(GURL("https://b.com")); | 
 |  | 
 |   // Unpartitioned cookie. | 
 |   tester.AddCookie(kOrigin); | 
 |   // Partitioned cookie with two keys. | 
 |   tester.AddCookie(kOrigin, kPartitionKey); | 
 |   tester.AddCookie(kOrigin, kOtherPartitionKey); | 
 |  | 
 |   ASSERT_TRUE(tester.ContainsCookie(kOrigin)); | 
 |   ASSERT_TRUE(tester.ContainsCookie(kOrigin, kPartitionKey)); | 
 |   ASSERT_TRUE(tester.ContainsCookie(kOrigin, kOtherPartitionKey)); | 
 |  | 
 |   blink::StorageKey storage_key = blink::StorageKey::Create( | 
 |       kOrigin, net::SchemefulSite(GURL("https://a.com")), | 
 |       blink::mojom::AncestorChainBit::kCrossSite); | 
 |   ASSERT_EQ(storage_key.ToCookiePartitionKey(), kPartitionKey); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   partition->ClearData(StoragePartition::REMOVE_DATA_MASK_COOKIES, | 
 |                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |                        storage_key, base::Time(), base::Time::Max(), | 
 |                        run_loop.QuitClosure()); | 
 |   run_loop.Run(); | 
 |  | 
 |   // Should delete unpartitioned cookies and those in matching partition. | 
 |   EXPECT_FALSE(tester.ContainsCookie(kOrigin)); | 
 |   EXPECT_FALSE(tester.ContainsCookie(kOrigin, kPartitionKey)); | 
 |   // Should not delete cookies in other partitions. | 
 |   EXPECT_TRUE(tester.ContainsCookie(kOrigin, kOtherPartitionKey)); | 
 | } | 
 |  | 
 |  | 
 | class MockGpuDiskCacheFactory : public gpu::GpuDiskCacheFactory { | 
 |  public: | 
 |   MockGpuDiskCacheFactory() = default; | 
 |   ~MockGpuDiskCacheFactory() override = default; | 
 |  | 
 |   MOCK_METHOD(void, | 
 |               ClearByPath, | 
 |               (const base::FilePath&, base::Time, base::Time, base::OnceClosure), | 
 |               (override)); | 
 | }; | 
 |  | 
 | class StoragePartitionImplShaderCacheTest : public StoragePartitionImplTest { | 
 |  public: | 
 |   StoragePartitionImplShaderCacheTest() { | 
 |     InitGpuDiskCacheFactorySingleton(); | 
 |     SetGpuDiskCacheFactorySingletonForTesting(&mock_gpu_disk_cache_factory_); | 
 |   } | 
 |  | 
 |   ~StoragePartitionImplShaderCacheTest() override { | 
 |     SetGpuDiskCacheFactorySingletonForTesting(nullptr); | 
 |     DestroyGpuDiskCacheFactorySingletonForTesting(); | 
 |   } | 
 |  | 
 |  protected: | 
 |   StoragePartition* storage_partition() { | 
 |     return browser_context()->GetDefaultStoragePartition(); | 
 |   } | 
 |  | 
 |   base::test::ScopedFeatureList feature_list_; | 
 |   MockGpuDiskCacheFactory mock_gpu_disk_cache_factory_; | 
 | }; | 
 |  | 
 | TEST_F(StoragePartitionImplShaderCacheTest, | 
 |        ClearData_PartialCleanupDisabled_NoStorageCleanup) { | 
 |   feature_list_.InitAndEnableFeature( | 
 |       features::kDisablePartialStorageCleanupForGPUDiskCache); | 
 |  | 
 |   EXPECT_CALL(mock_gpu_disk_cache_factory_, ClearByPath(_, _, _, _)).Times(0); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   storage_partition()->ClearData( | 
 |       StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE, | 
 |       StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |       /*filter_builder=*/nullptr, | 
 |       /*storage_key_policy_matcher=*/{}, | 
 |       /*cookie_deletion_filter=*/nullptr, | 
 |       /*perform_storage_cleanup=*/false, base::Time(), base::Time::Max(), | 
 |       run_loop.QuitClosure()); | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplShaderCacheTest, | 
 |        ClearData_PartialCleanupEnabled_WithStorageCleanup) { | 
 |   feature_list_.InitAndDisableFeature( | 
 |       features::kDisablePartialStorageCleanupForGPUDiskCache); | 
 |  | 
 |   EXPECT_CALL(mock_gpu_disk_cache_factory_, ClearByPath(_, _, _, _)) | 
 |       .Times(gpu::kGpuDiskCacheTypes.size()) | 
 |       .WillRepeatedly(testing::Invoke( | 
 |           [](const base::FilePath&, base::Time, base::Time, | 
 |              base::OnceClosure callback) { std::move(callback).Run(); })); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   storage_partition()->ClearData( | 
 |       StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE, | 
 |       StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |       /*filter_builder=*/nullptr, | 
 |       /*storage_key_policy_matcher=*/{}, | 
 |       /*cookie_deletion_filter=*/nullptr, | 
 |       /*perform_storage_cleanup=*/true, base::Time(), base::Time::Max(), | 
 |       run_loop.QuitClosure()); | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST_F(StoragePartitionImplShaderCacheTest, | 
 |        ClearData_PartialCleanupDisabled_WithStorageCleanup) { | 
 |   feature_list_.InitAndEnableFeature( | 
 |       features::kDisablePartialStorageCleanupForGPUDiskCache); | 
 |  | 
 |   EXPECT_CALL(mock_gpu_disk_cache_factory_, ClearByPath(_, _, _, _)) | 
 |       .Times(gpu::kGpuDiskCacheTypes.size()) | 
 |       .WillRepeatedly(testing::Invoke( | 
 |           [](const base::FilePath&, base::Time, base::Time, | 
 |              base::OnceClosure callback) { std::move(callback).Run(); })); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   storage_partition()->ClearData( | 
 |       StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE, | 
 |       StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, | 
 |       /*filter_builder=*/nullptr, | 
 |       /*storage_key_policy_matcher=*/{}, | 
 |       /*cookie_deletion_filter=*/nullptr, | 
 |       /*perform_storage_cleanup=*/true, base::Time(), base::Time::Max(), | 
 |       run_loop.QuitClosure()); | 
 |   run_loop.Run(); | 
 | } | 
 | }  // namespace content | 
 |  |