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 <memory>
6 #include <vector>
7
8 #include "base/callback_forward.h"
9 #include "base/callback_helpers.h"
10 #include "base/command_line.h"
11 #include "base/stl_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/profiles/profile_window.h"
16 #include "chrome/browser/task_manager/providers/task_provider_observer.h"
17 #include "chrome/browser/task_manager/providers/worker_task_provider.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_list.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "chrome/test/base/in_process_browser_test.h"
24 #include "chrome/test/base/testing_browser_process.h"
25 #include "chrome/test/base/ui_test_utils.h"
26 #include "content/public/browser/browser_context.h"
27 #include "content/public/browser/render_frame_host.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/service_worker_context.h"
30 #include "content/public/browser/storage_partition.h"
31 #include "content/public/test/browser_test.h"
32 #include "content/public/test/browser_test_utils.h"
33 #include "net/dns/mock_host_resolver.h"
34 #include "ui/base/l10n/l10n_util.h"
35
36 #if defined(OS_CHROMEOS)
37 #include "chromeos/constants/chromeos_switches.h"
38 #endif
39
40 namespace task_manager {
41
42 namespace {
43
OnUnblockOnProfileCreation(base::RunLoop * run_loop,Profile * profile,Profile::CreateStatus status)44 void OnUnblockOnProfileCreation(base::RunLoop* run_loop,
45 Profile* profile,
46 Profile::CreateStatus status) {
47 if (status == Profile::CREATE_STATUS_INITIALIZED)
48 run_loop->Quit();
49 }
50
ExpectedTaskTitle(const std::string & title)51 base::string16 ExpectedTaskTitle(const std::string& title) {
52 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_SERVICE_WORKER_PREFIX,
53 base::UTF8ToUTF16(title));
54 }
55
56 // Get the process id of the active WebContents for the passed |browser|.
GetChildProcessID(Browser * browser)57 int GetChildProcessID(Browser* browser) {
58 return browser->tab_strip_model()
59 ->GetActiveWebContents()
60 ->GetMainFrame()
61 ->GetProcess()
62 ->GetID();
63 }
64
65 } // namespace
66
67 class WorkerTaskProviderBrowserTest : public InProcessBrowserTest,
68 public TaskProviderObserver {
69 public:
70 WorkerTaskProviderBrowserTest() = default;
71
72 ~WorkerTaskProviderBrowserTest() override = default;
73
SetUpOnMainThread()74 void SetUpOnMainThread() override {
75 ASSERT_TRUE(embedded_test_server()->Start());
76 }
77
StartUpdating()78 void StartUpdating() {
79 task_provider_ = std::make_unique<WorkerTaskProvider>();
80 task_provider_->SetObserver(this);
81 }
82
StopUpdating()83 void StopUpdating() {
84 task_provider_->ClearObserver();
85 tasks_.clear();
86 task_provider_.reset();
87 }
88
CreateNewProfileAndSwitch()89 Browser* CreateNewProfileAndSwitch() {
90 ProfileManager* profile_manager = g_browser_process->profile_manager();
91
92 // Create an additional profile.
93 base::FilePath new_path =
94 profile_manager->GenerateNextProfileDirectoryPath();
95 base::RunLoop run_loop;
96 profile_manager->CreateProfileAsync(
97 new_path, base::BindRepeating(&OnUnblockOnProfileCreation, &run_loop),
98 base::string16(), std::string());
99 run_loop.Run();
100
101 profiles::SwitchToProfile(new_path, /* always_create = */ false,
102 base::DoNothing());
103 BrowserList* browser_list = BrowserList::GetInstance();
104 return *browser_list->begin_last_active();
105 }
106
GetServiceWorkerContext(Browser * browser)107 content::ServiceWorkerContext* GetServiceWorkerContext(Browser* browser) {
108 return content::BrowserContext::GetDefaultStoragePartition(
109 browser->profile())
110 ->GetServiceWorkerContext();
111 }
112
WaitUntilTaskCount(uint64_t count)113 void WaitUntilTaskCount(uint64_t count) {
114 if (tasks_.size() == count)
115 return;
116
117 expected_task_count_ = count;
118 base::RunLoop loop;
119 quit_closure_for_waiting_ = loop.QuitClosure();
120 loop.Run();
121 }
122
123 // task_manager::TaskProviderObserver:
TaskAdded(Task * task)124 void TaskAdded(Task* task) override {
125 DCHECK(task);
126 tasks_.push_back(task);
127
128 if (expected_task_count_ == tasks_.size())
129 StopWaiting();
130 }
131
TaskRemoved(Task * task)132 void TaskRemoved(Task* task) override {
133 DCHECK(task);
134 base::Erase(tasks_, task);
135
136 if (expected_task_count_ == tasks_.size())
137 StopWaiting();
138 }
139
tasks() const140 const std::vector<Task*>& tasks() const { return tasks_; }
task_provider() const141 TaskProvider* task_provider() const { return task_provider_.get(); }
142
143 protected:
SetUpCommandLine(base::CommandLine * command_line)144 void SetUpCommandLine(base::CommandLine* command_line) override {
145 #if defined(OS_CHROMEOS)
146 command_line->AppendSwitch(
147 chromeos::switches::kIgnoreUserProfileMappingForTests);
148 #endif
149 }
150
StopWaiting()151 void StopWaiting() {
152 if (quit_closure_for_waiting_)
153 std::move(quit_closure_for_waiting_).Run();
154 }
155
156 private:
157 std::unique_ptr<WorkerTaskProvider> task_provider_;
158
159 // Tasks created by |task_provider_|.
160 std::vector<Task*> tasks_;
161
162 base::OnceClosure quit_closure_for_waiting_;
163
164 uint64_t expected_task_count_ = 0;
165 };
166
167 // Make sure that the WorkerTaskProvider can create/delete a WorkerTask of type
168 // SERVICE_WORKER based on the actual service worker status, and the task
169 // representing the service worker has the expected properties.
IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest,CreateServiceWorkerTasksForSingleProfile)170 IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest,
171 CreateServiceWorkerTasksForSingleProfile) {
172 StartUpdating();
173
174 EXPECT_TRUE(tasks().empty());
175 ui_test_utils::NavigateToURL(
176 browser(), embedded_test_server()->GetURL(
177 "/service_worker/create_service_worker.html"));
178 EXPECT_EQ("DONE", EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
179 "register('respond_with_fetch_worker.js');"));
180 WaitUntilTaskCount(1);
181
182 const Task* task = tasks()[0];
183 EXPECT_EQ(task->GetChildProcessUniqueID(), GetChildProcessID(browser()));
184 EXPECT_EQ(Task::SERVICE_WORKER, task->GetType());
185 EXPECT_TRUE(base::StartsWith(
186 task->title(),
187 ExpectedTaskTitle(
188 embedded_test_server()
189 ->GetURL("/service_worker/respond_with_fetch_worker.js")
190 .spec()),
191 base::CompareCase::INSENSITIVE_ASCII));
192
193 GetServiceWorkerContext(browser())->StopAllServiceWorkersForOrigin(
194 url::Origin::Create(embedded_test_server()->base_url()));
195 WaitUntilTaskCount(0);
196
197 StopUpdating();
198 }
199
200 // If the profile is off the record, the WorkerTaskProvider can still grab the
201 // correct information and create/delete the task.
IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest,CreateServiceWorkerTasksForOffTheRecordProfile)202 IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest,
203 CreateServiceWorkerTasksForOffTheRecordProfile) {
204 StartUpdating();
205
206 EXPECT_TRUE(tasks().empty());
207 Browser* incognito = CreateIncognitoBrowser();
208
209 // Close the default browser.
210 CloseBrowserSynchronously(browser());
211
212 ui_test_utils::NavigateToURL(
213 incognito, embedded_test_server()->GetURL(
214 "/service_worker/create_service_worker.html"));
215 EXPECT_EQ("DONE", EvalJs(incognito->tab_strip_model()->GetActiveWebContents(),
216 "register('respond_with_fetch_worker.js');"));
217 WaitUntilTaskCount(1);
218
219 const Task* task = tasks()[0];
220 EXPECT_EQ(task->GetChildProcessUniqueID(), GetChildProcessID(incognito));
221 EXPECT_EQ(Task::SERVICE_WORKER, task->GetType());
222 EXPECT_TRUE(base::StartsWith(
223 task->title(),
224 ExpectedTaskTitle(
225 embedded_test_server()
226 ->GetURL("/service_worker/respond_with_fetch_worker.js")
227 .spec()),
228 base::CompareCase::INSENSITIVE_ASCII));
229
230 GetServiceWorkerContext(incognito)->StopAllServiceWorkersForOrigin(
231 url::Origin::Create(embedded_test_server()->base_url()));
232 WaitUntilTaskCount(0);
233
234 StopUpdating();
235 CloseBrowserSynchronously(incognito);
236 }
237
238 // If the profile are created dynamically and there is more than one profile
239 // simultaneously, the WorkerTaskProvider can still works.
IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest,CreateTasksForMultiProfiles)240 IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest,
241 CreateTasksForMultiProfiles) {
242 StartUpdating();
243
244 EXPECT_TRUE(tasks().empty());
245 Browser* browser_1 = CreateNewProfileAndSwitch();
246 ui_test_utils::NavigateToURL(
247 browser_1, embedded_test_server()->GetURL(
248 "/service_worker/create_service_worker.html"));
249 EXPECT_EQ("DONE", EvalJs(browser_1->tab_strip_model()->GetActiveWebContents(),
250 "register('respond_with_fetch_worker.js');"));
251 WaitUntilTaskCount(1);
252
253 Browser* browser_2 = CreateNewProfileAndSwitch();
254 ui_test_utils::NavigateToURL(
255 browser_2, embedded_test_server()->GetURL(
256 "/service_worker/create_service_worker.html"));
257 EXPECT_EQ("DONE", EvalJs(browser_2->tab_strip_model()->GetActiveWebContents(),
258 "register('respond_with_fetch_worker.js');"));
259 WaitUntilTaskCount(2);
260
261 const Task* task_1 = tasks()[0];
262 EXPECT_EQ(task_1->GetChildProcessUniqueID(), GetChildProcessID(browser_1));
263 EXPECT_EQ(Task::SERVICE_WORKER, task_1->GetType());
264 EXPECT_TRUE(base::StartsWith(
265 task_1->title(),
266 ExpectedTaskTitle(
267 embedded_test_server()
268 ->GetURL("/service_worker/respond_with_fetch_worker.js")
269 .spec()),
270 base::CompareCase::INSENSITIVE_ASCII));
271
272 const Task* task_2 = tasks()[1];
273 EXPECT_EQ(task_2->GetChildProcessUniqueID(), GetChildProcessID(browser_2));
274 EXPECT_EQ(Task::SERVICE_WORKER, task_2->GetType());
275 EXPECT_TRUE(base::StartsWith(
276 task_2->title(),
277 ExpectedTaskTitle(
278 embedded_test_server()
279 ->GetURL("/service_worker/respond_with_fetch_worker.js")
280 .spec()),
281 base::CompareCase::INSENSITIVE_ASCII));
282
283 GetServiceWorkerContext(browser_1)->StopAllServiceWorkersForOrigin(
284 url::Origin::Create(embedded_test_server()->base_url()));
285 WaitUntilTaskCount(1);
286 EXPECT_EQ(task_2, tasks()[0]);
287
288 GetServiceWorkerContext(browser_2)->StopAllServiceWorkersForOrigin(
289 url::Origin::Create(embedded_test_server()->base_url()));
290 WaitUntilTaskCount(0);
291
292 StopUpdating();
293 CloseBrowserSynchronously(browser_1);
294 CloseBrowserSynchronously(browser_2);
295 }
296
IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest,CreateExistingTasks)297 IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest, CreateExistingTasks) {
298 EXPECT_TRUE(tasks().empty());
299 ui_test_utils::NavigateToURL(
300 browser(), embedded_test_server()->GetURL(
301 "/service_worker/create_service_worker.html"));
302 EXPECT_EQ("DONE", EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
303 "register('respond_with_fetch_worker.js');"));
304
305 // No tasks yet as StartUpdating() wasn't called.
306 EXPECT_TRUE(tasks().empty());
307
308 StartUpdating();
309
310 ASSERT_EQ(tasks().size(), 1u);
311 const Task* task = tasks()[0];
312 EXPECT_EQ(task->GetChildProcessUniqueID(), GetChildProcessID(browser()));
313 EXPECT_EQ(Task::SERVICE_WORKER, task->GetType());
314 EXPECT_TRUE(base::StartsWith(
315 task->title(),
316 ExpectedTaskTitle(
317 embedded_test_server()
318 ->GetURL("/service_worker/respond_with_fetch_worker.js")
319 .spec()),
320 base::CompareCase::INSENSITIVE_ASCII));
321
322 GetServiceWorkerContext(browser())->StopAllServiceWorkersForOrigin(
323 url::Origin::Create(embedded_test_server()->base_url()));
324 WaitUntilTaskCount(0);
325
326 StopUpdating();
327 }
328
329 // Tests that destroying a profile while updating will correctly remove the
330 // existing tasks. An incognito browser is used because a regular profile is
331 // never truly destroyed until browser shutdown (See https://crbug.com/88586).
IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest,DestroyedProfile)332 IN_PROC_BROWSER_TEST_F(WorkerTaskProviderBrowserTest, DestroyedProfile) {
333 StartUpdating();
334
335 EXPECT_TRUE(tasks().empty());
336 Browser* browser = CreateIncognitoBrowser();
337
338 ui_test_utils::NavigateToURL(
339 browser, embedded_test_server()->GetURL(
340 "/service_worker/create_service_worker.html"));
341 EXPECT_EQ("DONE", EvalJs(browser->tab_strip_model()->GetActiveWebContents(),
342 "register('respond_with_fetch_worker.js');"));
343 WaitUntilTaskCount(1);
344
345 const Task* task_1 = tasks()[0];
346 EXPECT_EQ(task_1->GetChildProcessUniqueID(), GetChildProcessID(browser));
347 EXPECT_EQ(Task::SERVICE_WORKER, task_1->GetType());
348 EXPECT_TRUE(base::StartsWith(
349 task_1->title(),
350 ExpectedTaskTitle(
351 embedded_test_server()
352 ->GetURL("/service_worker/respond_with_fetch_worker.js")
353 .spec()),
354 base::CompareCase::INSENSITIVE_ASCII));
355
356 CloseBrowserSynchronously(browser);
357
358 WaitUntilTaskCount(0);
359
360 StopUpdating();
361 }
362
363 } // namespace task_manager
364