| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/background_sync/background_sync_launcher.h" |
| |
| #include <map> |
| #include <vector> |
| |
| #include "base/functional/bind.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/test/bind.h" |
| #include "base/test/task_environment.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "content/browser/storage_partition_impl.h" |
| #include "content/common/content_export.h" |
| #include "content/public/browser/background_sync_context.h" |
| #include "content/public/browser/content_browser_client.h" |
| #include "content/public/common/content_client.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "content/public/test/test_browser_context.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| #if BUILDFLAG(IS_ANDROID) |
| #include "base/run_loop.h" |
| #endif |
| |
| namespace content { |
| |
| namespace { |
| |
| const char kUrl_1[] = "https://example.com"; |
| const char kUrl_2[] = "https://whereswaldo.com"; |
| |
| class TestBrowserClient : public ContentBrowserClient { |
| public: |
| TestBrowserClient() = default; |
| ~TestBrowserClient() override = default; |
| |
| StoragePartitionConfig GetStoragePartitionConfigForSite( |
| BrowserContext* browser_context, |
| const GURL& site) override { |
| DCHECK(browser_context); |
| auto partition_num = base::NumberToString(++partition_count_); |
| return StoragePartitionConfig::Create( |
| browser_context, std::string("PartitionDomain") + partition_num, |
| std::string("Partition") + partition_num, false /* in_memory */); |
| } |
| |
| private: |
| int partition_count_ = 0; |
| }; |
| |
| } // namespace |
| |
| class BackgroundSyncLauncherTest : public testing::Test { |
| public: |
| BackgroundSyncLauncherTest() |
| : task_environment_(BrowserTaskEnvironment::MainThreadType::UI) {} |
| |
| void SetUpBrowserContext(const std::vector<GURL>& urls, |
| blink::mojom::BackgroundSyncType sync_type, |
| const std::map<GURL, int>& wakeup_deltas = {}) { |
| DCHECK(!urls.empty()); |
| |
| for (const auto& url : urls) { |
| auto* storage_partition = |
| test_browser_context_.GetStoragePartitionForUrl(url); |
| |
| auto iter = wakeup_deltas.find(url); |
| if (iter == wakeup_deltas.end()) |
| continue; |
| |
| static_cast<StoragePartitionImpl*>(storage_partition) |
| ->GetBackgroundSyncContext() |
| ->set_wakeup_delta_for_testing(sync_type, |
| base::Milliseconds(iter->second)); |
| } |
| } |
| |
| void SetUp() override { |
| original_client_ = SetBrowserClientForTesting(&browser_client_); |
| } |
| |
| void TearDown() override { SetBrowserClientForTesting(original_client_); } |
| |
| base::TimeDelta GetSoonestWakeupDelta( |
| blink::mojom::BackgroundSyncType sync_type) { |
| return BackgroundSyncLauncher::GetSoonestWakeupDelta( |
| sync_type, &test_browser_context_); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| void FireBackgroundSyncEventsForAllPartitions() { |
| num_invocations_fire_background_sync_events_ = 0; |
| |
| auto done_closure = base::BindLambdaForTesting( |
| [&]() { num_invocations_fire_background_sync_events_++; }); |
| |
| test_browser_context_.ForEachLoadedStoragePartition( |
| [&](StoragePartition* storage_partition) { |
| BackgroundSyncContext* sync_context = |
| storage_partition->GetBackgroundSyncContext(); |
| sync_context->FireBackgroundSyncEvents( |
| blink::mojom::BackgroundSyncType::ONE_SHOT, done_closure); |
| }); |
| |
| task_environment_.RunUntilIdle(); |
| } |
| |
| int NumInvocationsOfFireBackgroundSyncEvents() { |
| return num_invocations_fire_background_sync_events_; |
| } |
| #endif |
| |
| protected: |
| void DidFireBackgroundSyncEvents() { |
| num_invocations_fire_background_sync_events_++; |
| } |
| |
| BrowserTaskEnvironment task_environment_; |
| TestBrowserClient browser_client_; |
| raw_ptr<ContentBrowserClient> original_client_; |
| TestBrowserContext test_browser_context_; |
| int num_invocations_fire_background_sync_events_ = 0; |
| }; |
| |
| // Tests that we pick the correct wake up delta for the one-shot Background |
| // Sync wake up task, across all storage partitions. |
| TEST_F(BackgroundSyncLauncherTest, CorrectSoonestWakeupDeltaIsPicked) { |
| std::vector<GURL> urls = {GURL(kUrl_1), GURL(kUrl_2)}; |
| |
| // Add two storage partitions. Verify that we set the soonest wake up delta |
| // to base::TimeDelta::Max(). This will cause cancellation of the wakeup |
| // task. |
| SetUpBrowserContext(urls, blink::mojom::BackgroundSyncType::ONE_SHOT); |
| EXPECT_TRUE(GetSoonestWakeupDelta(blink::mojom::BackgroundSyncType::ONE_SHOT) |
| .is_max()); |
| |
| // Add two more storage partitions, this time with wakeup_deltas. |
| // Verify that we pick the smaller of the two. |
| int delta_ms = 0; |
| std::map<GURL, int> wakeup_deltas; |
| for (const auto& url : urls) |
| wakeup_deltas[url] = delta_ms += 1000; |
| SetUpBrowserContext(urls, blink::mojom::BackgroundSyncType::ONE_SHOT, |
| wakeup_deltas); |
| |
| EXPECT_EQ(GetSoonestWakeupDelta(blink::mojom::BackgroundSyncType::ONE_SHOT) |
| .InMilliseconds(), |
| 1000); |
| } |
| |
| // Tests that we pick the correct wake up delta for the correct Background Sync |
| // wake up task, across all storage partitions. |
| TEST_F(BackgroundSyncLauncherTest, SoonestWakeupDeltaIsPickedForTheRightTask) { |
| std::vector<GURL> urls = {GURL(kUrl_1), GURL(kUrl_2)}; |
| |
| // Add two storage partitions with wakeup_deltas, both of the same sync type. |
| // Verify that we pick the smaller of the two. |
| int delta_ms = 0; |
| std::map<GURL, int> wakeup_deltas; |
| for (const auto& url : urls) |
| wakeup_deltas[url] = delta_ms += 1000; |
| SetUpBrowserContext(urls, blink::mojom::BackgroundSyncType::ONE_SHOT, |
| wakeup_deltas); |
| |
| EXPECT_EQ(GetSoonestWakeupDelta(blink::mojom::BackgroundSyncType::ONE_SHOT) |
| .InMilliseconds(), |
| 1000); |
| EXPECT_TRUE(GetSoonestWakeupDelta(blink::mojom::BackgroundSyncType::PERIODIC) |
| .is_max()); |
| |
| // Add some more wakeup_deltas now for Periodic Background Sync. |
| wakeup_deltas.clear(); |
| wakeup_deltas[GURL(kUrl_1)] = 500; |
| SetUpBrowserContext(urls, blink::mojom::BackgroundSyncType::PERIODIC, |
| wakeup_deltas); |
| EXPECT_EQ(GetSoonestWakeupDelta(blink::mojom::BackgroundSyncType::ONE_SHOT) |
| .InMilliseconds(), |
| 1000); |
| EXPECT_EQ(GetSoonestWakeupDelta(blink::mojom::BackgroundSyncType::PERIODIC) |
| .InMilliseconds(), |
| 500); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| TEST_F(BackgroundSyncLauncherTest, FireBackgroundSyncEvents) { |
| std::vector<GURL> urls = {GURL(kUrl_1), GURL(kUrl_2)}; |
| SetUpBrowserContext(urls, blink::mojom::BackgroundSyncType::ONE_SHOT); |
| |
| ASSERT_NO_FATAL_FAILURE(FireBackgroundSyncEventsForAllPartitions()); |
| EXPECT_EQ(NumInvocationsOfFireBackgroundSyncEvents(), 2); |
| } |
| #endif |
| |
| } // namespace content |