| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // 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 <memory> |
| #include <set> |
| #include <vector> |
| #include "base/metrics/field_trial_param_associator.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task/post_task.h" |
| #include "content/browser/background_sync/background_sync_manager.h" |
| #include "content/browser/storage_partition_impl.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/service_worker_context.h" |
| #include "content/public/test/background_sync_test_util.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "content/test/mock_background_sync_controller.h" |
| |
| namespace content { |
| |
| BackgroundSyncBaseBrowserTest::BackgroundSyncBaseBrowserTest() {} |
| BackgroundSyncBaseBrowserTest::~BackgroundSyncBaseBrowserTest() {} |
| |
| std::string BackgroundSyncBaseBrowserTest::BuildScriptString( |
| const std::string& function, |
| const std::string& argument) { |
| return base::StringPrintf("%s('%s');", function.c_str(), argument.c_str()); |
| } |
| |
| std::string BackgroundSyncBaseBrowserTest::BuildExpectedResult( |
| const std::string& tag, |
| const std::string& action) { |
| return base::StringPrintf("%s%s %s", kSuccessfulOperationPrefix, tag.c_str(), |
| action.c_str()); |
| } |
| |
| bool BackgroundSyncBaseBrowserTest::RegistrationPending( |
| const std::string& tag) { |
| bool is_pending; |
| base::RunLoop run_loop; |
| |
| StoragePartitionImpl* storage = GetStorage(); |
| BackgroundSyncContextImpl* sync_context = storage->GetBackgroundSyncContext(); |
| ServiceWorkerContextWrapper* service_worker_context = |
| static_cast<ServiceWorkerContextWrapper*>( |
| storage->GetServiceWorkerContext()); |
| |
| auto callback = base::BindOnce( |
| &BackgroundSyncBaseBrowserTest::RegistrationPendingCallback, |
| base::Unretained(this), run_loop.QuitClosure(), |
| base::ThreadTaskRunnerHandle::Get(), &is_pending); |
| |
| RunOrPostTaskOnThread( |
| FROM_HERE, ServiceWorkerContext::GetCoreThreadId(), |
| base::BindOnce( |
| &BackgroundSyncBaseBrowserTest::RegistrationPendingOnCoreThread, |
| base::Unretained(this), base::WrapRefCounted(sync_context), |
| base::WrapRefCounted(service_worker_context), tag, |
| https_server_->GetURL(kDefaultTestURL), std::move(callback))); |
| |
| run_loop.Run(); |
| |
| return is_pending; |
| } |
| |
| bool BackgroundSyncBaseBrowserTest::CompleteDelayedSyncEvent() { |
| std::string script_result; |
| EXPECT_TRUE(RunScript("completeDelayedSyncEvent()", &script_result)); |
| return script_result == BuildExpectedResult("delay", "completing"); |
| } |
| |
| void BackgroundSyncBaseBrowserTest::RegistrationPendingCallback( |
| base::OnceClosure quit, |
| const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| bool* result_out, |
| bool result) { |
| *result_out = result; |
| task_runner->PostTask(FROM_HERE, std::move(quit)); |
| } |
| |
| void BackgroundSyncBaseBrowserTest::RegistrationPendingDidGetSyncRegistration( |
| const std::string& tag, |
| base::OnceCallback<void(bool)> callback, |
| BackgroundSyncStatus error_type, |
| std::vector<std::unique_ptr<BackgroundSyncRegistration>> registrations) { |
| ASSERT_EQ(BACKGROUND_SYNC_STATUS_OK, error_type); |
| // Find the right registration in the list and check its status. |
| for (const auto& registration : registrations) { |
| if (registration->options()->tag == tag) { |
| std::move(callback).Run(registration->sync_state() == |
| blink::mojom::BackgroundSyncState::PENDING); |
| return; |
| } |
| } |
| ADD_FAILURE() << "Registration should exist"; |
| } |
| |
| void BackgroundSyncBaseBrowserTest::RegistrationPendingDidGetSWRegistration( |
| const scoped_refptr<BackgroundSyncContextImpl> sync_context, |
| const std::string& tag, |
| base::OnceCallback<void(bool)> callback, |
| blink::ServiceWorkerStatusCode status, |
| scoped_refptr<ServiceWorkerRegistration> registration) { |
| ASSERT_EQ(blink::ServiceWorkerStatusCode::kOk, status); |
| int64_t service_worker_id = registration->id(); |
| BackgroundSyncManager* sync_manager = sync_context->background_sync_manager(); |
| sync_manager->GetOneShotSyncRegistrations( |
| service_worker_id, |
| base::BindOnce(&BackgroundSyncBaseBrowserTest:: |
| RegistrationPendingDidGetSyncRegistration, |
| base::Unretained(this), tag, std::move(callback))); |
| } |
| |
| void BackgroundSyncBaseBrowserTest::RegistrationPendingOnCoreThread( |
| const scoped_refptr<BackgroundSyncContextImpl> sync_context, |
| const scoped_refptr<ServiceWorkerContextWrapper> sw_context, |
| const std::string& tag, |
| const GURL& url, |
| base::OnceCallback<void(bool)> callback) { |
| sw_context->FindReadyRegistrationForClientUrl( |
| url, base::BindOnce(&BackgroundSyncBaseBrowserTest:: |
| RegistrationPendingDidGetSWRegistration, |
| base::Unretained(this), sync_context, tag, |
| std::move(callback))); |
| } |
| |
| void BackgroundSyncBaseBrowserTest::SetTestClockOnCoreThread( |
| BackgroundSyncContextImpl* sync_context, |
| base::SimpleTestClock* clock) { |
| DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); |
| DCHECK(clock); |
| |
| BackgroundSyncManager* background_sync_manager = |
| sync_context->background_sync_manager(); |
| background_sync_manager->set_clock(clock); |
| } |
| |
| void BackgroundSyncBaseBrowserTest::SetUp() { |
| const char kTrialName[] = "BackgroundSync"; |
| const char kGroupName[] = "BackgroundSync"; |
| const char kFeatureName[] = "PeriodicBackgroundSync"; |
| scoped_refptr<base::FieldTrial> trial = |
| base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName); |
| std::map<std::string, std::string> params; |
| params["max_sync_attempts"] = "1"; |
| params["min_periodic_sync_events_interval_sec"] = "5"; |
| base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( |
| kTrialName, kGroupName, params); |
| std::unique_ptr<base::FeatureList> feature_list( |
| std::make_unique<base::FeatureList>()); |
| feature_list->RegisterFieldTrialOverride( |
| kFeatureName, base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get()); |
| scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); |
| |
| background_sync_test_util::SetIgnoreNetworkChanges(true); |
| ContentBrowserTest::SetUp(); |
| } |
| |
| void BackgroundSyncBaseBrowserTest::SetIncognitoMode(bool incognito) { |
| shell_ = incognito ? CreateOffTheRecordBrowser() : shell(); |
| // Let any async shell creation logic finish. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| StoragePartitionImpl* BackgroundSyncBaseBrowserTest::GetStorage() { |
| WebContents* web_contents = shell_->web_contents(); |
| return static_cast<StoragePartitionImpl*>(BrowserContext::GetStoragePartition( |
| web_contents->GetBrowserContext(), web_contents->GetSiteInstance())); |
| } |
| |
| WebContents* BackgroundSyncBaseBrowserTest::web_contents() { |
| return shell_->web_contents(); |
| } |
| |
| void BackgroundSyncBaseBrowserTest::SetUpOnMainThread() { |
| https_server_ = std::make_unique<net::EmbeddedTestServer>( |
| net::EmbeddedTestServer::TYPE_HTTPS); |
| https_server_->ServeFilesFromSourceDirectory(GetTestDataFilePath()); |
| ASSERT_TRUE(https_server_->Start()); |
| |
| SetIncognitoMode(false); |
| background_sync_test_util::SetOnline(web_contents(), true); |
| ASSERT_TRUE(LoadTestPage(kDefaultTestURL)); |
| |
| ContentBrowserTest::SetUpOnMainThread(); |
| } |
| |
| void BackgroundSyncBaseBrowserTest::TearDownOnMainThread() { |
| https_server_.reset(); |
| } |
| |
| bool BackgroundSyncBaseBrowserTest::LoadTestPage(const std::string& path) { |
| return NavigateToURL(shell_, https_server_->GetURL(path)); |
| } |
| |
| bool BackgroundSyncBaseBrowserTest::RunScript(const std::string& script, |
| std::string* result) { |
| return content::ExecuteScriptAndExtractString(web_contents(), script, result); |
| } |
| |
| void BackgroundSyncBaseBrowserTest::SetTestClock(base::SimpleTestClock* clock) { |
| StoragePartitionImpl* storage = GetStorage(); |
| BackgroundSyncContextImpl* sync_context = storage->GetBackgroundSyncContext(); |
| |
| // TODO(crbug.com/824858): Remove the else branch after the feature is |
| // enabled. Also, try to make a RunOrPostTaskOnThreadAndReply() function so |
| // the if/else isn't needed. |
| if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { |
| SetTestClockOnCoreThread(sync_context, clock); |
| } else { |
| base::RunLoop run_loop; |
| base::PostTaskAndReply( |
| FROM_HERE, ServiceWorkerContext::GetCoreThreadId(), |
| base::BindOnce(&BackgroundSyncBaseBrowserTest::SetTestClockOnCoreThread, |
| base::Unretained(this), base::Unretained(sync_context), |
| clock), |
| run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| } |
| |
| void BackgroundSyncBaseBrowserTest::ClearStoragePartitionData() { |
| // Clear data from the storage partition. Parameters are set to clear data |
| // for service workers, for all origins, for an unbounded time range. |
| StoragePartitionImpl* storage = GetStorage(); |
| |
| uint32_t storage_partition_mask = |
| StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS; |
| uint32_t quota_storage_mask = |
| StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL; |
| GURL delete_origin = GURL(); |
| const base::Time delete_begin = base::Time(); |
| base::Time delete_end = base::Time::Max(); |
| |
| base::RunLoop run_loop; |
| |
| storage->ClearData(storage_partition_mask, quota_storage_mask, delete_origin, |
| delete_begin, delete_end, run_loop.QuitClosure()); |
| |
| run_loop.Run(); |
| } |
| |
| std::string BackgroundSyncBaseBrowserTest::PopConsoleString() { |
| std::string script_result; |
| EXPECT_TRUE(RunScript("resultQueue.pop()", &script_result)); |
| return script_result; |
| } |
| |
| bool BackgroundSyncBaseBrowserTest::PopConsole( |
| const std::string& expected_msg) { |
| std::string script_result = PopConsoleString(); |
| return script_result == expected_msg; |
| } |
| |
| bool BackgroundSyncBaseBrowserTest::RegisterServiceWorker() { |
| std::string script_result; |
| EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result)); |
| return script_result == BuildExpectedResult("service worker", "registered"); |
| } |
| |
| } // namespace content |