| // 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_base_browsertest.h" |
| |
| #include "base/functional/bind.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "content/browser/background_sync/background_sync_manager.h" |
| #include "content/browser/background_sync/background_sync_network_observer.h" |
| #include "content/browser/service_worker/service_worker_context_wrapper.h" |
| #include "content/browser/storage_partition_impl.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/content_switches.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" |
| #include "content/public/test/content_browser_test.h" |
| #include "content/public/test/test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "net/base/network_change_notifier.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace content { |
| |
| class OneShotBackgroundSyncBrowserTest : public BackgroundSyncBaseBrowserTest { |
| public: |
| OneShotBackgroundSyncBrowserTest() = default; |
| |
| OneShotBackgroundSyncBrowserTest(const OneShotBackgroundSyncBrowserTest&) = |
| delete; |
| OneShotBackgroundSyncBrowserTest& operator=( |
| const OneShotBackgroundSyncBrowserTest&) = delete; |
| |
| ~OneShotBackgroundSyncBrowserTest() override = default; |
| |
| void Register(const std::string& tag); |
| void RegisterFromServiceWorker(const std::string& tag); |
| EvalJsResult RegisterFromCrossOriginFrame(const std::string& frame_url); |
| void WaitForTagRemoval(const std::string& tag, int64_t pauses_ms = 5); |
| bool HasTag(const std::string& tag); |
| bool HasTagFromServiceWorker(const std::string& tag); |
| bool MatchTags(const std::string& script_result, |
| const std::vector<std::string>& expected_tags); |
| bool GetTags(const std::vector<std::string>& expected_tags); |
| bool GetTagsFromServiceWorker(const std::vector<std::string>& expected_tags); |
| void RejectDelayedSyncEvent(); |
| }; |
| |
| void OneShotBackgroundSyncBrowserTest::Register(const std::string& tag) { |
| ASSERT_EQ( |
| BuildExpectedResult(tag, "registered"), |
| EvalJs(web_contents(), BuildScriptString("registerOneShotSync", tag))); |
| } |
| |
| void OneShotBackgroundSyncBrowserTest::RegisterFromServiceWorker( |
| const std::string& tag) { |
| ASSERT_EQ( |
| BuildExpectedResult(tag, "register sent to SW"), |
| EvalJs(web_contents(), |
| BuildScriptString("registerOneShotSyncFromServiceWorker", tag))); |
| } |
| |
| EvalJsResult OneShotBackgroundSyncBrowserTest::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("registerOneShotSyncFromCrossOriginFrame", url.spec())); |
| } |
| |
| void OneShotBackgroundSyncBrowserTest::WaitForTagRemoval(const std::string& tag, |
| int64_t pauses_ms) { |
| while (HasTag(tag)) { |
| base::RunLoop run_loop; |
| base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( |
| FROM_HERE, run_loop.QuitClosure(), base::Milliseconds(pauses_ms)); |
| run_loop.Run(); |
| } |
| } |
| |
| bool OneShotBackgroundSyncBrowserTest::HasTag(const std::string& tag) { |
| return EvalJs(web_contents(), BuildScriptString("hasOneShotSyncTag", tag)) == |
| BuildExpectedResult(tag, "found"); |
| } |
| |
| bool OneShotBackgroundSyncBrowserTest::HasTagFromServiceWorker( |
| const std::string& tag) { |
| EXPECT_EQ( |
| "ok - hasTag sent to SW", |
| EvalJs(web_contents(), |
| BuildScriptString("hasOneShotSyncTagFromServiceWorker", tag))); |
| |
| return PopConsoleString() == BuildExpectedResult(tag, "found"); |
| } |
| |
| bool OneShotBackgroundSyncBrowserTest::MatchTags( |
| const std::string& script_result, |
| const std::vector<std::string>& expected_tags) { |
| EXPECT_TRUE(base::StartsWith(script_result, kSuccessfulOperationPrefix, |
| base::CompareCase::INSENSITIVE_ASCII)); |
| std::string tag_string = |
| script_result.substr(strlen(kSuccessfulOperationPrefix)); |
| std::vector<std::string> result_tags = base::SplitString( |
| tag_string, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); |
| |
| return std::set<std::string>(expected_tags.begin(), expected_tags.end()) == |
| std::set<std::string>(result_tags.begin(), result_tags.end()); |
| } |
| |
| bool OneShotBackgroundSyncBrowserTest::GetTags( |
| const std::vector<std::string>& expected_tags) { |
| std::string script_result = |
| EvalJs(web_contents(), "getOneShotSyncTags()").ExtractString(); |
| |
| return MatchTags(script_result, expected_tags); |
| } |
| |
| bool OneShotBackgroundSyncBrowserTest::GetTagsFromServiceWorker( |
| const std::vector<std::string>& expected_tags) { |
| EXPECT_EQ("ok - getTags sent to SW", |
| EvalJs(web_contents(), "getOneShotSyncTagsFromServiceWorker()")); |
| |
| return MatchTags(PopConsoleString().ExtractString(), expected_tags); |
| } |
| |
| void OneShotBackgroundSyncBrowserTest::RejectDelayedSyncEvent() { |
| ASSERT_EQ(BuildExpectedResult("delay", "rejecting"), |
| EvalJs(web_contents(), "rejectDelayedSyncEvent()")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| RegisterFromControlledDocument) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| Register("foo"); |
| EXPECT_EQ("foo fired", PopConsoleString()); |
| WaitForTagRemoval("foo"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| RegisterFromUncontrolledDocument) { |
| RegisterServiceWorker(); |
| |
| Register("foo"); |
| EXPECT_EQ("foo fired", PopConsoleString()); |
| WaitForTagRemoval("foo"); |
| } |
| |
| // Verify that Register works in a service worker |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| RegisterFromServiceWorker) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| RegisterFromServiceWorker("foo_sw"); |
| EXPECT_EQ("ok - foo_sw registered in SW", PopConsoleString()); |
| EXPECT_EQ("foo_sw fired", PopConsoleString()); |
| WaitForTagRemoval("foo_sw"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| RegistrationDelaysForNetwork) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| // Prevent firing by going offline. |
| background_sync_test_util::SetOnline(web_contents(), false); |
| Register("foo"); |
| EXPECT_TRUE(HasTag("foo")); |
| EXPECT_TRUE(RegistrationPending("foo")); |
| |
| // Resume firing by going online. |
| background_sync_test_util::SetOnline(web_contents(), true); |
| EXPECT_EQ("foo fired", PopConsoleString()); |
| WaitForTagRemoval("foo"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, WaitUntil) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| background_sync_test_util::SetOnline(web_contents(), true); |
| Register("delay"); |
| |
| // Verify that it is firing. |
| EXPECT_TRUE(HasTag("delay")); |
| EXPECT_FALSE(RegistrationPending("delay")); |
| |
| // Complete the task. |
| CompleteDelayedSyncEvent(); |
| EXPECT_EQ("ok - delay completed", PopConsoleString()); |
| |
| // Verify that it finished firing. |
| WaitForTagRemoval("delay"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, WaitUntilReject) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| background_sync_test_util::SetOnline(web_contents(), true); |
| Register("delay"); |
| |
| // Verify that it is firing. |
| EXPECT_TRUE(HasTag("delay")); |
| EXPECT_FALSE(RegistrationPending("delay")); |
| |
| // Complete the task. |
| RejectDelayedSyncEvent(); |
| EXPECT_EQ("ok - delay rejected", PopConsoleString()); |
| WaitForTagRemoval("delay"); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, Incognito) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| background_sync_test_util::SetOnline(web_contents(), false); |
| Register("normal"); |
| EXPECT_TRUE(RegistrationPending("normal")); |
| |
| // Go incognito and verify that incognito doesn't see the registration. |
| SetIncognitoMode(true); |
| |
| // Tell the new network observer that we're offline (it initializes from |
| // NetworkChangeNotifier::GetCurrentConnectionType() which is not mocked out |
| // in this test). |
| background_sync_test_util::SetOnline(web_contents(), false); |
| |
| LoadTestPage(kDefaultTestURL); |
| RegisterServiceWorker(); |
| |
| EXPECT_FALSE(HasTag("normal")); |
| |
| Register("incognito"); |
| EXPECT_TRUE(RegistrationPending("incognito")); |
| |
| // Switch back and make sure the registration is still there. |
| SetIncognitoMode(false); |
| LoadTestPage(kDefaultTestURL); // Should be controlled. |
| |
| EXPECT_TRUE(HasTag("normal")); |
| EXPECT_FALSE(HasTag("incognito")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, GetTags) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| std::vector<std::string> registered_tags; |
| EXPECT_TRUE(GetTags(registered_tags)); |
| |
| background_sync_test_util::SetOnline(web_contents(), false); |
| registered_tags.push_back("foo"); |
| registered_tags.push_back("bar"); |
| |
| for (const std::string& tag : registered_tags) |
| Register(tag); |
| |
| EXPECT_TRUE(GetTags(registered_tags)); |
| } |
| |
| // Verify that GetOneShotSyncRegistrations works in a service worker |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| GetRegistrationsFromServiceWorker) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| std::vector<std::string> registered_tags; |
| EXPECT_TRUE(GetTags(registered_tags)); |
| |
| background_sync_test_util::SetOnline(web_contents(), false); |
| registered_tags.push_back("foo_sw"); |
| registered_tags.push_back("bar_sw"); |
| |
| for (const std::string& tag : registered_tags) { |
| RegisterFromServiceWorker(tag); |
| EXPECT_EQ(BuildExpectedResult(tag, "registered in SW"), PopConsoleString()); |
| } |
| |
| EXPECT_TRUE(GetTagsFromServiceWorker(registered_tags)); |
| } |
| |
| // Verify that GetOneShotSyncRegistration works in a service worker |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| HasTagFromServiceWorker) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| std::vector<std::string> registered_tags; |
| EXPECT_TRUE(GetTags(registered_tags)); |
| |
| background_sync_test_util::SetOnline(web_contents(), false); |
| |
| RegisterFromServiceWorker("foo_sw"); |
| EXPECT_EQ("ok - foo_sw registered in SW", PopConsoleString()); |
| EXPECT_TRUE(HasTagFromServiceWorker("foo_sw")); |
| } |
| |
| // Verify that a background sync registration is deleted when site data is |
| // cleared. |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| SyncRegistrationDeletedWhenClearingSiteData) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| // Prevent firing by going offline. |
| background_sync_test_util::SetOnline(web_contents(), false); |
| Register("foo"); |
| EXPECT_TRUE(HasTag("foo")); |
| EXPECT_TRUE(RegistrationPending("foo")); |
| |
| // Simulate a user clearing site data (including Service Workers, crucially), |
| // by clearing data from the storage partition. |
| ClearStoragePartitionData(); |
| |
| EXPECT_FALSE(HasTag("foo")); |
| } |
| |
| // Verify that a background sync registration, from a service worker, is deleted |
| // when site data is cleared. |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| SyncRegistrationFromSWDeletedWhenClearingSiteData) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| std::vector<std::string> registered_tags; |
| EXPECT_TRUE(GetTags(registered_tags)); |
| |
| background_sync_test_util::SetOnline(web_contents(), false); |
| |
| RegisterFromServiceWorker("foo_sw"); |
| EXPECT_EQ("ok - foo_sw registered in SW", PopConsoleString()); |
| EXPECT_TRUE(HasTagFromServiceWorker("foo_sw")); |
| |
| // Simulate a user clearing site data (including Service Workers, crucially), |
| // by clearing data from the storage partition. |
| ClearStoragePartitionData(); |
| |
| // Use HasTag() instead of HasTagServiceWorker() because clearing site data |
| // immediately terminates the service worker when removing it from the |
| // registration. |
| EXPECT_FALSE(HasTag("foo")); |
| } |
| |
| // Verify that multiple background sync registrations are deleted when site |
| // data is cleared. |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| SyncRegistrationsDeletedWhenClearingSiteData) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| std::vector<std::string> registered_tags; |
| EXPECT_TRUE(GetTags(registered_tags)); |
| |
| background_sync_test_util::SetOnline(web_contents(), false); |
| registered_tags.push_back("foo"); |
| registered_tags.push_back("bar"); |
| |
| for (const std::string& tag : registered_tags) |
| Register(tag); |
| |
| EXPECT_TRUE(GetTags(registered_tags)); |
| |
| for (const std::string& tag : registered_tags) |
| EXPECT_TRUE(RegistrationPending(tag)); |
| |
| // Simulate a user clearing site data (including Service Workers, crucially), |
| // by clearing data from the storage partition. |
| ClearStoragePartitionData(); |
| |
| for (const std::string& tag : registered_tags) |
| EXPECT_FALSE(HasTag(tag)); |
| } |
| |
| // Verify that a sync event that is currently firing is deleted when site |
| // data is cleared. |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| FiringSyncEventDeletedWhenClearingSiteData) { |
| RegisterServiceWorker(); |
| LoadTestPage(kDefaultTestURL); // Control the page. |
| |
| background_sync_test_util::SetOnline(web_contents(), true); |
| Register("delay"); |
| |
| // Verify that it is firing. |
| EXPECT_TRUE(HasTag("delay")); |
| EXPECT_FALSE(RegistrationPending("delay")); |
| |
| // Simulate a user clearing site data (including Service Workers, crucially), |
| // by clearing data from the storage partition. |
| ClearStoragePartitionData(); |
| |
| // Verify that it was deleted. |
| EXPECT_FALSE(HasTag("delay")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| RegisterFromIFrameWithMainFrameHost) { |
| GURL url = https_server()->GetURL(kEmptyURL); |
| EXPECT_EQ(BuildExpectedResult("iframe", "registered sync"), |
| EvalJs(web_contents(), |
| BuildScriptString("registerOneShotSyncFromLocalFrame", |
| url.spec()))); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| RegisterFromIFrameWithoutMainFrameHost) { |
| EXPECT_EQ(BuildExpectedResult("frame", "failed to register sync"), |
| RegisterFromCrossOriginFrame(kRegisterSyncFromIFrameURL)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(OneShotBackgroundSyncBrowserTest, |
| RegisterFromServiceWorkerWithoutMainFrameHost) { |
| EXPECT_EQ(BuildExpectedResult("frame", "failed to register sync"), |
| RegisterFromCrossOriginFrame(kRegisterSyncFromSWURL)); |
| } |
| |
| } // namespace content |