blob: 4b8e10362ed9b751eb35d456f85c844a8043e19a [file] [log] [blame]
// 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