1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/background_sync/background_sync_base_browsertest.h"
6 
7 #include <memory>
8 #include <set>
9 #include <vector>
10 #include "base/metrics/field_trial_param_associator.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/task/post_task.h"
13 #include "content/browser/background_sync/background_sync_manager.h"
14 #include "content/browser/storage_partition_impl.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/browser_task_traits.h"
17 #include "content/public/browser/service_worker_context.h"
18 #include "content/public/test/background_sync_test_util.h"
19 #include "content/public/test/content_browser_test_utils.h"
20 #include "content/shell/browser/shell.h"
21 #include "content/test/mock_background_sync_controller.h"
22 
23 namespace content {
24 
BackgroundSyncBaseBrowserTest()25 BackgroundSyncBaseBrowserTest::BackgroundSyncBaseBrowserTest() {}
~BackgroundSyncBaseBrowserTest()26 BackgroundSyncBaseBrowserTest::~BackgroundSyncBaseBrowserTest() {}
27 
BuildScriptString(const std::string & function,const std::string & argument)28 std::string BackgroundSyncBaseBrowserTest::BuildScriptString(
29     const std::string& function,
30     const std::string& argument) {
31   return base::StringPrintf("%s('%s');", function.c_str(), argument.c_str());
32 }
33 
BuildExpectedResult(const std::string & tag,const std::string & action)34 std::string BackgroundSyncBaseBrowserTest::BuildExpectedResult(
35     const std::string& tag,
36     const std::string& action) {
37   return base::StringPrintf("%s%s %s", kSuccessfulOperationPrefix, tag.c_str(),
38                             action.c_str());
39 }
40 
RegistrationPending(const std::string & tag)41 bool BackgroundSyncBaseBrowserTest::RegistrationPending(
42     const std::string& tag) {
43   bool is_pending;
44   base::RunLoop run_loop;
45 
46   StoragePartitionImpl* storage = GetStorage();
47   BackgroundSyncContextImpl* sync_context = storage->GetBackgroundSyncContext();
48   ServiceWorkerContextWrapper* service_worker_context =
49       static_cast<ServiceWorkerContextWrapper*>(
50           storage->GetServiceWorkerContext());
51 
52   auto callback = base::BindOnce(
53       &BackgroundSyncBaseBrowserTest::RegistrationPendingCallback,
54       base::Unretained(this), run_loop.QuitClosure(),
55       base::ThreadTaskRunnerHandle::Get(), &is_pending);
56 
57   RunOrPostTaskOnThread(
58       FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
59       base::BindOnce(
60           &BackgroundSyncBaseBrowserTest::RegistrationPendingOnCoreThread,
61           base::Unretained(this), base::WrapRefCounted(sync_context),
62           base::WrapRefCounted(service_worker_context), tag,
63           https_server_->GetURL(kDefaultTestURL), std::move(callback)));
64 
65   run_loop.Run();
66 
67   return is_pending;
68 }
69 
CompleteDelayedSyncEvent()70 bool BackgroundSyncBaseBrowserTest::CompleteDelayedSyncEvent() {
71   std::string script_result;
72   EXPECT_TRUE(RunScript("completeDelayedSyncEvent()", &script_result));
73   return script_result == BuildExpectedResult("delay", "completing");
74 }
75 
RegistrationPendingCallback(base::OnceClosure quit,const scoped_refptr<base::SingleThreadTaskRunner> & task_runner,bool * result_out,bool result)76 void BackgroundSyncBaseBrowserTest::RegistrationPendingCallback(
77     base::OnceClosure quit,
78     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
79     bool* result_out,
80     bool result) {
81   *result_out = result;
82   task_runner->PostTask(FROM_HERE, std::move(quit));
83 }
84 
RegistrationPendingDidGetSyncRegistration(const std::string & tag,base::OnceCallback<void (bool)> callback,BackgroundSyncStatus error_type,std::vector<std::unique_ptr<BackgroundSyncRegistration>> registrations)85 void BackgroundSyncBaseBrowserTest::RegistrationPendingDidGetSyncRegistration(
86     const std::string& tag,
87     base::OnceCallback<void(bool)> callback,
88     BackgroundSyncStatus error_type,
89     std::vector<std::unique_ptr<BackgroundSyncRegistration>> registrations) {
90   ASSERT_EQ(BACKGROUND_SYNC_STATUS_OK, error_type);
91   // Find the right registration in the list and check its status.
92   for (const auto& registration : registrations) {
93     if (registration->options()->tag == tag) {
94       std::move(callback).Run(registration->sync_state() ==
95                               blink::mojom::BackgroundSyncState::PENDING);
96       return;
97     }
98   }
99   ADD_FAILURE() << "Registration should exist";
100 }
101 
RegistrationPendingDidGetSWRegistration(const scoped_refptr<BackgroundSyncContextImpl> sync_context,const std::string & tag,base::OnceCallback<void (bool)> callback,blink::ServiceWorkerStatusCode status,scoped_refptr<ServiceWorkerRegistration> registration)102 void BackgroundSyncBaseBrowserTest::RegistrationPendingDidGetSWRegistration(
103     const scoped_refptr<BackgroundSyncContextImpl> sync_context,
104     const std::string& tag,
105     base::OnceCallback<void(bool)> callback,
106     blink::ServiceWorkerStatusCode status,
107     scoped_refptr<ServiceWorkerRegistration> registration) {
108   ASSERT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
109   int64_t service_worker_id = registration->id();
110   BackgroundSyncManager* sync_manager = sync_context->background_sync_manager();
111   sync_manager->GetOneShotSyncRegistrations(
112       service_worker_id,
113       base::BindOnce(&BackgroundSyncBaseBrowserTest::
114                          RegistrationPendingDidGetSyncRegistration,
115                      base::Unretained(this), tag, std::move(callback)));
116 }
117 
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)118 void BackgroundSyncBaseBrowserTest::RegistrationPendingOnCoreThread(
119     const scoped_refptr<BackgroundSyncContextImpl> sync_context,
120     const scoped_refptr<ServiceWorkerContextWrapper> sw_context,
121     const std::string& tag,
122     const GURL& url,
123     base::OnceCallback<void(bool)> callback) {
124   sw_context->FindReadyRegistrationForClientUrl(
125       url, base::BindOnce(&BackgroundSyncBaseBrowserTest::
126                               RegistrationPendingDidGetSWRegistration,
127                           base::Unretained(this), sync_context, tag,
128                           std::move(callback)));
129 }
130 
SetTestClockOnCoreThread(BackgroundSyncContextImpl * sync_context,base::SimpleTestClock * clock)131 void BackgroundSyncBaseBrowserTest::SetTestClockOnCoreThread(
132     BackgroundSyncContextImpl* sync_context,
133     base::SimpleTestClock* clock) {
134   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
135   DCHECK(clock);
136 
137   BackgroundSyncManager* background_sync_manager =
138       sync_context->background_sync_manager();
139   background_sync_manager->set_clock(clock);
140 }
141 
SetUp()142 void BackgroundSyncBaseBrowserTest::SetUp() {
143   const char kTrialName[] = "BackgroundSync";
144   const char kGroupName[] = "BackgroundSync";
145   const char kFeatureName[] = "PeriodicBackgroundSync";
146   scoped_refptr<base::FieldTrial> trial =
147       base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
148   std::map<std::string, std::string> params;
149   params["max_sync_attempts"] = "1";
150   params["min_periodic_sync_events_interval_sec"] = "5";
151   base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
152       kTrialName, kGroupName, params);
153   std::unique_ptr<base::FeatureList> feature_list(
154       std::make_unique<base::FeatureList>());
155   feature_list->RegisterFieldTrialOverride(
156       kFeatureName, base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
157   scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
158 
159   background_sync_test_util::SetIgnoreNetworkChanges(true);
160   ContentBrowserTest::SetUp();
161 }
162 
SetIncognitoMode(bool incognito)163 void BackgroundSyncBaseBrowserTest::SetIncognitoMode(bool incognito) {
164   shell_ = incognito ? CreateOffTheRecordBrowser() : shell();
165   // Let any async shell creation logic finish.
166   base::RunLoop().RunUntilIdle();
167 }
168 
GetStorage()169 StoragePartitionImpl* BackgroundSyncBaseBrowserTest::GetStorage() {
170   WebContents* web_contents = shell_->web_contents();
171   return static_cast<StoragePartitionImpl*>(BrowserContext::GetStoragePartition(
172       web_contents->GetBrowserContext(), web_contents->GetSiteInstance()));
173 }
174 
web_contents()175 WebContents* BackgroundSyncBaseBrowserTest::web_contents() {
176   return shell_->web_contents();
177 }
178 
SetUpOnMainThread()179 void BackgroundSyncBaseBrowserTest::SetUpOnMainThread() {
180   https_server_ = std::make_unique<net::EmbeddedTestServer>(
181       net::EmbeddedTestServer::TYPE_HTTPS);
182   https_server_->ServeFilesFromSourceDirectory(GetTestDataFilePath());
183   ASSERT_TRUE(https_server_->Start());
184 
185   SetIncognitoMode(false);
186   background_sync_test_util::SetOnline(web_contents(), true);
187   ASSERT_TRUE(LoadTestPage(kDefaultTestURL));
188 
189   ContentBrowserTest::SetUpOnMainThread();
190 }
191 
TearDownOnMainThread()192 void BackgroundSyncBaseBrowserTest::TearDownOnMainThread() {
193   https_server_.reset();
194 }
195 
LoadTestPage(const std::string & path)196 bool BackgroundSyncBaseBrowserTest::LoadTestPage(const std::string& path) {
197   return NavigateToURL(shell_, https_server_->GetURL(path));
198 }
199 
RunScript(const std::string & script,std::string * result)200 bool BackgroundSyncBaseBrowserTest::RunScript(const std::string& script,
201                                               std::string* result) {
202   return content::ExecuteScriptAndExtractString(web_contents(), script, result);
203 }
204 
SetTestClock(base::SimpleTestClock * clock)205 void BackgroundSyncBaseBrowserTest::SetTestClock(base::SimpleTestClock* clock) {
206   StoragePartitionImpl* storage = GetStorage();
207   BackgroundSyncContextImpl* sync_context = storage->GetBackgroundSyncContext();
208 
209   // TODO(crbug.com/824858): Remove the else branch after the feature is
210   // enabled. Also, try to make a RunOrPostTaskOnThreadAndReply() function so
211   // the if/else isn't needed.
212   if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
213     SetTestClockOnCoreThread(sync_context, clock);
214   } else {
215     base::RunLoop run_loop;
216     base::PostTaskAndReply(
217         FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
218         base::BindOnce(&BackgroundSyncBaseBrowserTest::SetTestClockOnCoreThread,
219                        base::Unretained(this), base::Unretained(sync_context),
220                        clock),
221         run_loop.QuitClosure());
222     run_loop.Run();
223   }
224 }
225 
ClearStoragePartitionData()226 void BackgroundSyncBaseBrowserTest::ClearStoragePartitionData() {
227   // Clear data from the storage partition.  Parameters are set to clear data
228   // for service workers, for all origins, for an unbounded time range.
229   StoragePartitionImpl* storage = GetStorage();
230 
231   uint32_t storage_partition_mask =
232       StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS;
233   uint32_t quota_storage_mask =
234       StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
235   GURL delete_origin = GURL();
236   const base::Time delete_begin = base::Time();
237   base::Time delete_end = base::Time::Max();
238 
239   base::RunLoop run_loop;
240 
241   storage->ClearData(storage_partition_mask, quota_storage_mask, delete_origin,
242                      delete_begin, delete_end, run_loop.QuitClosure());
243 
244   run_loop.Run();
245 }
246 
PopConsoleString()247 std::string BackgroundSyncBaseBrowserTest::PopConsoleString() {
248   std::string script_result;
249   EXPECT_TRUE(RunScript("resultQueue.pop()", &script_result));
250   return script_result;
251 }
252 
PopConsole(const std::string & expected_msg)253 bool BackgroundSyncBaseBrowserTest::PopConsole(
254     const std::string& expected_msg) {
255   std::string script_result = PopConsoleString();
256   return script_result == expected_msg;
257 }
258 
RegisterServiceWorker()259 bool BackgroundSyncBaseBrowserTest::RegisterServiceWorker() {
260   std::string script_result;
261   EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result));
262   return script_result == BuildExpectedResult("service worker", "registered");
263 }
264 
265 }  // namespace content
266