1 // Copyright (c) 2012 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 "base/bind.h" 6 #include "base/files/file_path.h" 7 #include "base/logging.h" 8 #include "base/path_service.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/stringprintf.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "base/sys_info.h" 13 #include "base/test/test_timeouts.h" 14 #include "content/browser/worker_host/worker_process_host.h" 15 #include "content/browser/worker_host/worker_service_impl.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "content/public/common/content_paths.h" 18 #include "content/public/test/browser_test_utils.h" 19 #include "content/public/test/test_utils.h" 20 #include "content/shell/shell.h" 21 #include "content/shell/shell_content_browser_client.h" 22 #include "content/shell/shell_resource_dispatcher_host_delegate.h" 23 #include "content/test/content_browser_test.h" 24 #include "content/test/content_browser_test_utils.h" 25 #include "net/base/test_data_directory.h" 26 #include "net/test/spawned_test_server/spawned_test_server.h" 27 #include "url/gurl.h" 28 29 namespace content { 30 31 class WorkerTest : public ContentBrowserTest { 32 public: 33 WorkerTest() {} 34 35 GURL GetTestURL(const std::string& test_case, const std::string& query) { 36 base::FilePath test_file_path = GetTestFilePath( 37 "workers", test_case.c_str()); 38 return GetFileUrlWithQuery(test_file_path, query); 39 } 40 41 void RunTest(Shell* window, 42 const std::string& test_case, 43 const std::string& query) { 44 GURL url = GetTestURL(test_case, query); 45 const string16 expected_title = ASCIIToUTF16("OK"); 46 TitleWatcher title_watcher(window->web_contents(), expected_title); 47 NavigateToURL(window, url); 48 string16 final_title = title_watcher.WaitAndGetTitle(); 49 EXPECT_EQ(expected_title, final_title); 50 } 51 52 void RunTest(const std::string& test_case, const std::string& query) { 53 RunTest(shell(), test_case, query); 54 } 55 56 static void CountWorkerProcesses(int *cur_process_count) { 57 *cur_process_count = 0; 58 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) 59 (*cur_process_count)++; 60 BrowserThread::PostTask( 61 BrowserThread::UI, FROM_HERE, base::MessageLoop::QuitClosure()); 62 } 63 64 bool WaitForWorkerProcessCount(int count) { 65 int cur_process_count; 66 for (int i = 0; i < 100; ++i) { 67 BrowserThread::PostTask( 68 BrowserThread::IO, FROM_HERE, 69 base::Bind(&CountWorkerProcesses, &cur_process_count)); 70 71 RunMessageLoop(); 72 if (cur_process_count == count) 73 return true; 74 75 // Sometimes the worker processes can take a while to shut down on the 76 // bots, so use a longer timeout period to avoid spurious failures. 77 base::PlatformThread::Sleep(TestTimeouts::action_max_timeout() / 100); 78 } 79 80 EXPECT_EQ(cur_process_count, count); 81 return false; 82 } 83 84 static void QuitUIMessageLoop(base::Callback<void()> callback) { 85 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); 86 } 87 88 void NavigateAndWaitForAuth(const GURL& url) { 89 ShellContentBrowserClient* browser_client = 90 ShellContentBrowserClient::Get(); 91 scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner(); 92 browser_client->resource_dispatcher_host_delegate()-> 93 set_login_request_callback( 94 base::Bind(&QuitUIMessageLoop, runner->QuitClosure())); 95 shell()->LoadURL(url); 96 runner->Run(); 97 } 98 }; 99 100 IN_PROC_BROWSER_TEST_F(WorkerTest, SingleWorker) { 101 RunTest("single_worker.html", std::string()); 102 } 103 104 IN_PROC_BROWSER_TEST_F(WorkerTest, MultipleWorkers) { 105 RunTest("multi_worker.html", std::string()); 106 } 107 108 IN_PROC_BROWSER_TEST_F(WorkerTest, SingleSharedWorker) { 109 RunTest("single_worker.html", "shared=true"); 110 } 111 112 // http://crbug.com/96435 113 IN_PROC_BROWSER_TEST_F(WorkerTest, MultipleSharedWorkers) { 114 RunTest("multi_worker.html", "shared=true"); 115 } 116 117 // Incognito windows should not share workers with non-incognito windows 118 // http://crbug.com/30021 119 IN_PROC_BROWSER_TEST_F(WorkerTest, IncognitoSharedWorkers) { 120 // Load a non-incognito tab and have it create a shared worker 121 RunTest("incognito_worker.html", std::string()); 122 123 // Incognito worker should not share with non-incognito 124 RunTest(CreateOffTheRecordBrowser(), "incognito_worker.html", std::string()); 125 } 126 127 // Make sure that auth dialog is displayed from worker context. 128 // http://crbug.com/33344 129 IN_PROC_BROWSER_TEST_F(WorkerTest, WorkerHttpAuth) { 130 ASSERT_TRUE(test_server()->Start()); 131 GURL url = test_server()->GetURL("files/workers/worker_auth.html"); 132 133 NavigateAndWaitForAuth(url); 134 } 135 136 // Make sure that auth dialog is displayed from shared worker context. 137 // http://crbug.com/33344 138 IN_PROC_BROWSER_TEST_F(WorkerTest, SharedWorkerHttpAuth) { 139 ASSERT_TRUE(test_server()->Start()); 140 GURL url = test_server()->GetURL("files/workers/shared_worker_auth.html"); 141 NavigateAndWaitForAuth(url); 142 } 143 144 #if defined(OS_LINUX) || defined(OS_CHROMEOS) 145 // This test is flaky inside the Linux SUID sandbox. 146 // http://crbug.com/130116 147 IN_PROC_BROWSER_TEST_F(WorkerTest, DISABLED_LimitPerPage) { 148 #else 149 IN_PROC_BROWSER_TEST_F(WorkerTest, LimitPerPage) { 150 #endif 151 int max_workers_per_tab = WorkerServiceImpl::kMaxWorkersPerTabWhenSeparate; 152 std::string query = base::StringPrintf("?count=%d", max_workers_per_tab + 1); 153 154 GURL url = GetTestURL("many_shared_workers.html", query); 155 NavigateToURL(shell(), url); 156 ASSERT_TRUE(WaitForWorkerProcessCount(max_workers_per_tab)); 157 } 158 159 #if defined(OS_LINUX) || defined(OS_CHROMEOS) 160 // This test is flaky inside the Linux SUID sandbox. 161 // http://crbug.com/130116 162 IN_PROC_BROWSER_TEST_F(WorkerTest, DISABLED_LimitTotal) { 163 #else 164 // http://crbug.com/36800 165 IN_PROC_BROWSER_TEST_F(WorkerTest, LimitTotal) { 166 #endif 167 if (base::SysInfo::AmountOfPhysicalMemoryMB() < 8192) { 168 LOG(INFO) << "WorkerTest.LimitTotal not running because it needs 8 GB RAM."; 169 return; 170 } 171 172 int max_workers_per_tab = WorkerServiceImpl::kMaxWorkersPerTabWhenSeparate; 173 int total_workers = WorkerServiceImpl::kMaxWorkersWhenSeparate; 174 175 std::string query = base::StringPrintf("?count=%d", max_workers_per_tab); 176 GURL url = GetTestURL("many_shared_workers.html", query); 177 NavigateToURL(shell(), 178 GURL(url.spec() + base::StringPrintf("&client_id=0"))); 179 180 // Adding 1 so that we cause some workers to be queued. 181 int tab_count = (total_workers / max_workers_per_tab) + 1; 182 for (int i = 1; i < tab_count; ++i) { 183 NavigateToURL( 184 CreateBrowser(), 185 GURL(url.spec() + base::StringPrintf("&client_id=%d", i))); 186 } 187 188 // Check that we didn't create more than the max number of workers. 189 ASSERT_TRUE(WaitForWorkerProcessCount(total_workers)); 190 191 // Now close a page and check that the queued workers were started. 192 url = GURL(GetTestUrl("google", "google.html")); 193 NavigateToURL(shell(), url); 194 195 ASSERT_TRUE(WaitForWorkerProcessCount(total_workers)); 196 } 197 198 // Flaky, http://crbug.com/59786. 199 IN_PROC_BROWSER_TEST_F(WorkerTest, WorkerClose) { 200 RunTest("worker_close.html", std::string()); 201 ASSERT_TRUE(WaitForWorkerProcessCount(0)); 202 } 203 204 // Flaky, http://crbug.com/70861. 205 // Times out regularly on Windows debug bots. See http://crbug.com/212339 . 206 #if defined(OS_WIN) && !defined(NDEBUG) 207 #define MAYBE_QueuedSharedWorkerShutdown DISABLED_QueuedSharedWorkerShutdown 208 #else 209 #define MAYBE_QueuedSharedWorkerShutdown QueuedSharedWorkerShutdown 210 #endif 211 IN_PROC_BROWSER_TEST_F(WorkerTest, MAYBE_QueuedSharedWorkerShutdown) { 212 // Tests to make sure that queued shared workers are started up when shared 213 // workers shut down. 214 int max_workers_per_tab = WorkerServiceImpl::kMaxWorkersPerTabWhenSeparate; 215 std::string query = base::StringPrintf("?count=%d", max_workers_per_tab); 216 RunTest("queued_shared_worker_shutdown.html", query); 217 ASSERT_TRUE(WaitForWorkerProcessCount(max_workers_per_tab)); 218 } 219 220 // Flaky, http://crbug.com/69881. 221 // Sometimes triggers 222 // Check failed: message_ports_[message_port_id].queued_messages.empty(). 223 IN_PROC_BROWSER_TEST_F(WorkerTest, DISABLED_MultipleTabsQueuedSharedWorker) { 224 // Tests to make sure that only one instance of queued shared workers are 225 // started up even when those instances are on multiple tabs. 226 int max_workers_per_tab = WorkerServiceImpl::kMaxWorkersPerTabWhenSeparate; 227 std::string query = base::StringPrintf("?count=%d", max_workers_per_tab + 1); 228 GURL url = GetTestURL("many_shared_workers.html", query); 229 NavigateToURL(shell(), url); 230 ASSERT_TRUE(WaitForWorkerProcessCount(max_workers_per_tab)); 231 232 // Create same set of workers in new tab (leaves one worker queued from this 233 // tab). 234 url = GetTestURL("many_shared_workers.html", query); 235 NavigateToURL(CreateBrowser(), url); 236 ASSERT_TRUE(WaitForWorkerProcessCount(max_workers_per_tab)); 237 238 // Now shutdown one of the shared workers - this will fire both queued 239 // workers, but only one instance should be started. 240 url = GetTestURL("shutdown_shared_worker.html", "?id=0"); 241 NavigateToURL(CreateBrowser(), url); 242 ASSERT_TRUE(WaitForWorkerProcessCount(max_workers_per_tab)); 243 } 244 245 // Flaky: http://crbug.com/48148 246 IN_PROC_BROWSER_TEST_F(WorkerTest, DISABLED_QueuedSharedWorkerStartedFromOtherTab) { 247 // Tests to make sure that queued shared workers are started up when 248 // an instance is launched from another tab. 249 int max_workers_per_tab = WorkerServiceImpl::kMaxWorkersPerTabWhenSeparate; 250 std::string query = base::StringPrintf("?count=%d", max_workers_per_tab + 1); 251 GURL url = GetTestURL("many_shared_workers.html", query); 252 NavigateToURL(shell(), url); 253 ASSERT_TRUE(WaitForWorkerProcessCount(max_workers_per_tab)); 254 255 // First window has hit its limit. Now launch second window which creates 256 // the same worker that was queued in the first window, to ensure it gets 257 // connected to the first window too. 258 query = base::StringPrintf("?id=%d", max_workers_per_tab); 259 url = GetTestURL("single_shared_worker.html", query); 260 NavigateToURL(CreateBrowser(), url); 261 262 ASSERT_TRUE(WaitForWorkerProcessCount(max_workers_per_tab + 1)); 263 } 264 265 IN_PROC_BROWSER_TEST_F(WorkerTest, WebSocketSharedWorker) { 266 // Launch WebSocket server. 267 net::SpawnedTestServer ws_server(net::SpawnedTestServer::TYPE_WS, 268 net::SpawnedTestServer::kLocalhost, 269 net::GetWebSocketTestDataDirectory()); 270 ASSERT_TRUE(ws_server.Start()); 271 272 // Generate test URL. 273 std::string scheme("http"); 274 GURL::Replacements replacements; 275 replacements.SetSchemeStr(scheme); 276 GURL url = ws_server.GetURL( 277 "websocket_shared_worker.html").ReplaceComponents(replacements); 278 279 // Run test. 280 Shell* window = shell(); 281 const string16 expected_title = ASCIIToUTF16("OK"); 282 TitleWatcher title_watcher(window->web_contents(), expected_title); 283 NavigateToURL(window, url); 284 string16 final_title = title_watcher.WaitAndGetTitle(); 285 EXPECT_EQ(expected_title, final_title); 286 } 287 288 } // namespace content 289