| // 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 "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/test/simple_test_clock.h" |
| #include "base/time/time.h" |
| #include "content/browser/background_sync/background_sync_base_browsertest.h" |
| #include "content/browser/background_sync/background_sync_manager.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/test/background_sync_test_util.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| |
| namespace { |
| |
| constexpr base::TimeDelta kMinGapBetweenPeriodicSyncEvents = base::Seconds(5); |
| |
| } // namespace |
| |
| namespace content { |
| |
| class PeriodicBackgroundSyncBrowserTest : public BackgroundSyncBaseBrowserTest { |
| public: |
| PeriodicBackgroundSyncBrowserTest() = default; |
| |
| PeriodicBackgroundSyncBrowserTest(const PeriodicBackgroundSyncBrowserTest&) = |
| delete; |
| PeriodicBackgroundSyncBrowserTest& operator=( |
| const PeriodicBackgroundSyncBrowserTest&) = delete; |
| |
| ~PeriodicBackgroundSyncBrowserTest() override = default; |
| |
| void Register(const std::string& tag, int min_interval_ms); |
| void RegisterNoMinInterval(const std::string& tag); |
| void RegisterFromServiceWorker(const std::string& tag, int min_interval_ms); |
| EvalJsResult RegisterFromCrossOriginFrame(const std::string& frame_url); |
| void RegisterFromServiceWorkerNoMinInterval(const std::string& tag); |
| bool HasTag(const std::string& tag); |
| bool HasTagFromServiceWorker(const std::string& tag); |
| void Unregister(const std::string& tag); |
| void UnregisterFromServiceWorker(const std::string& tag); |
| int GetNumPeriodicSyncEvents(); |
| |
| protected: |
| base::SimpleTestClock clock_; |
| }; |
| |
| void PeriodicBackgroundSyncBrowserTest::Register(const std::string& tag, |
| int min_interval_ms) { |
| ASSERT_EQ(BuildExpectedResult(tag, "registered"), |
| EvalJs(web_contents(), |
| base::StringPrintf("%s('%s', %d);", "registerPeriodicSync", |
| tag.c_str(), min_interval_ms))); |
| } |
| |
| EvalJsResult PeriodicBackgroundSyncBrowserTest::RegisterFromCrossOriginFrame( |
| const std::string& frame_url) { |
| // Start a second https server to use as a second origin. |
| net::EmbeddedTestServer alt_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| alt_server.ServeFilesFromSourceDirectory(GetTestDataFilePath()); |
| EXPECT_TRUE(alt_server.Start()); |
| |
| GURL url = alt_server.GetURL(frame_url); |
| return EvalJs(web_contents(), |
| BuildScriptString("registerPeriodicSyncFromCrossOriginFrame", |
| url.spec())); |
| } |
| |
| void PeriodicBackgroundSyncBrowserTest::RegisterNoMinInterval( |
| const std::string& tag) { |
| ASSERT_EQ(BuildExpectedResult(tag, "registered"), |
| EvalJs(web_contents(), |
| base::StringPrintf("%s('%s');", "registerPeriodicSync", |
| tag.c_str()))); |
| } |
| |
| void PeriodicBackgroundSyncBrowserTest::RegisterFromServiceWorker( |
| const std::string& tag, |
| int min_interval_ms) { |
| ASSERT_EQ(BuildExpectedResult(tag, "register sent to SW"), |
| EvalJs(web_contents(), |
| base::StringPrintf("%s('%s', %d);", |
| "registerPeriodicSyncFromServiceWorker", |
| tag.c_str(), min_interval_ms))); |
| } |
| |
| void PeriodicBackgroundSyncBrowserTest::RegisterFromServiceWorkerNoMinInterval( |
| const std::string& tag) { |
| ASSERT_EQ( |
| BuildExpectedResult(tag, "register sent to SW"), |
| EvalJs(web_contents(), |
| BuildScriptString("registerPeriodicSyncFromServiceWorker", tag))); |
| } |
| |
| bool PeriodicBackgroundSyncBrowserTest::HasTag(const std::string& tag) { |
| return EvalJs(web_contents(), BuildScriptString("hasPeriodicSyncTag", tag)) == |
| BuildExpectedResult(tag, "found"); |
| } |
| |
| bool PeriodicBackgroundSyncBrowserTest::HasTagFromServiceWorker( |
| const std::string& tag) { |
| return EvalJs(web_contents(), |
| BuildScriptString("hasPeriodicSyncTagFromServiceWorker", |
| tag)) == "ok - hasTag sent to SW"; |
| } |
| |
| void PeriodicBackgroundSyncBrowserTest::Unregister(const std::string& tag) { |
| ASSERT_EQ(BuildExpectedResult(tag, "unregistered"), |
| EvalJs(web_contents(), BuildScriptString("unregister", tag))); |
| } |
| |
| void PeriodicBackgroundSyncBrowserTest::UnregisterFromServiceWorker( |
| const std::string& tag) { |
| ASSERT_EQ(BuildExpectedResult(tag, "unregister sent to SW"), |
| EvalJs(web_contents(), |
| BuildScriptString("unregisterFromServiceWorker", tag))); |
| } |
| |
| int PeriodicBackgroundSyncBrowserTest::GetNumPeriodicSyncEvents() { |
| EXPECT_TRUE(ExecJs(web_contents(), "getNumPeriodicSyncEvents()")); |
| int num_periodic_sync_events = -1; |
| bool converted = base::StringToInt(PopConsoleString().ExtractString(), |
| &num_periodic_sync_events); |
| DCHECK(converted); |
| return num_periodic_sync_events; |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| RegisterFromControlledDocument) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| Register("foo", /* min_interval_ms= */ 1000); |
| Unregister("foo"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| RegisterNoMinInterval) { |
| RegisterServiceWorker(); |
| |
| RegisterNoMinInterval("foo"); |
| Unregister("foo"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| RegisterFromIFrameWithTopLevelFrameForOrigin) { |
| GURL url = https_server()->GetURL(kEmptyURL); |
| |
| // This succeeds because there's a top level frame for the origin. |
| EXPECT_EQ(EvalJs(web_contents(), |
| BuildScriptString("registerPeriodicSyncFromLocalFrame", |
| url.spec())), |
| BuildExpectedResult("iframe", "registered periodicSync")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| RegisterFromIFrameWithoutTopLevelFrameForOrigin) { |
| // This fails because there's no top level frame open for the origin. |
| EXPECT_EQ(BuildExpectedResult("frame", "failed to register periodicSync"), |
| RegisterFromCrossOriginFrame(kRegisterPeriodicSyncFromIFrameURL)); |
| } |
| |
| // Verify that Register works in a service worker |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| RegisterFromServiceWorker) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); |
| |
| RegisterFromServiceWorker("foo_sw", /* min_interval_ms= */ 10); |
| EXPECT_EQ("ok - foo_sw registered in SW", PopConsoleString()); |
| Unregister("foo"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| RegisterFromServiceWorkerNoMinInterval) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); |
| |
| RegisterFromServiceWorkerNoMinInterval("foo_sw"); |
| EXPECT_EQ("ok - foo_sw registered in SW", PopConsoleString()); |
| Unregister("foo"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, FindATag) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| Register("foo", /* min_interval_ms= */ 1000); |
| EXPECT_TRUE(HasTag("foo")); |
| Unregister("foo"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| FindATagFromServiceWorker) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| Register("foo", /* min_interval_ms= */ 1000); |
| EXPECT_TRUE(HasTagFromServiceWorker("foo")); |
| EXPECT_EQ("ok - foo found in SW", PopConsoleString()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| UnregisterFromServiceWorker) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); |
| |
| RegisterNoMinInterval("foo"); |
| EXPECT_TRUE(HasTag("foo")); |
| UnregisterFromServiceWorker("foo"); |
| EXPECT_EQ("ok - foo unregistered in SW", PopConsoleString()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| FirePeriodicSyncOnConnectivity) { |
| SetTestClock(&clock_); |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); |
| |
| // Prevent firing by going offline. |
| background_sync_test_util::SetOnline(web_contents(), false); |
| Register("foo", /* min_interval_ms= */ 10); |
| EXPECT_TRUE(HasTag("foo")); |
| |
| int initial_periodic_sync_events = GetNumPeriodicSyncEvents(); |
| ASSERT_EQ(initial_periodic_sync_events, 0); |
| |
| clock_.Advance(kMinGapBetweenPeriodicSyncEvents); |
| |
| EXPECT_EQ(GetNumPeriodicSyncEvents(), initial_periodic_sync_events); |
| |
| // Resume firing by going online. |
| background_sync_test_util::SetOnline(web_contents(), true); |
| EXPECT_EQ("foo fired", PopConsoleString()); |
| EXPECT_EQ(GetNumPeriodicSyncEvents(), initial_periodic_sync_events + 1); |
| EXPECT_TRUE(HasTag("foo")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, MultipleEventsFired) { |
| SetTestClock(&clock_); |
| |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); |
| |
| Register("foo", /* min_interval_ms= */ 10); |
| |
| clock_.Advance(kMinGapBetweenPeriodicSyncEvents); |
| EXPECT_EQ("foo fired", PopConsoleString()); |
| EXPECT_TRUE(HasTag("foo")); |
| |
| clock_.Advance(kMinGapBetweenPeriodicSyncEvents); |
| EXPECT_EQ("foo fired", PopConsoleString()); |
| EXPECT_TRUE(HasTag("foo")); |
| Unregister("foo"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, |
| MultipleMinIntervalsAndTags) { |
| SetTestClock(&clock_); |
| |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); |
| |
| Register("foo", /* min_interval_ms= */ 10); |
| Register("foo", /* min_interval_ms= */ 200); |
| EXPECT_TRUE(HasTag("foo")); |
| |
| Register("bar", /* min_interval_ms= */ 50); |
| EXPECT_TRUE(HasTag("bar")); |
| |
| clock_.Advance(kMinGapBetweenPeriodicSyncEvents); |
| |
| // Ordering is important here. |
| EXPECT_EQ("bar fired", PopConsoleString()); |
| EXPECT_EQ("foo fired", PopConsoleString()); |
| |
| Unregister("foo"); |
| EXPECT_FALSE(HasTag("foo")); |
| EXPECT_TRUE(HasTag("bar")); |
| |
| clock_.Advance(kMinGapBetweenPeriodicSyncEvents); |
| EXPECT_EQ("bar fired", PopConsoleString()); |
| Unregister("bar"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PeriodicBackgroundSyncBrowserTest, WaitUntil) { |
| SetTestClock(&clock_); |
| |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); |
| |
| background_sync_test_util::SetOnline(web_contents(), false); |
| |
| Register("delay", /* min_interval_ms= */ 10); |
| ASSERT_TRUE(HasTag("delay")); |
| |
| clock_.Advance(kMinGapBetweenPeriodicSyncEvents); |
| background_sync_test_util::SetOnline(web_contents(), true); |
| base::RunLoop().RunUntilIdle(); |
| |
| int num_periodicsync_events_fired = GetNumPeriodicSyncEvents(); |
| |
| // Complete the task. |
| CompleteDelayedSyncEvent(); |
| EXPECT_EQ("ok - delay completed", PopConsoleString()); |
| EXPECT_EQ(GetNumPeriodicSyncEvents(), num_periodicsync_events_fired + 1); |
| |
| EXPECT_TRUE(HasTag("delay")); |
| Unregister("delay"); |
| } |
| |
| } // namespace content |