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