EME test page application.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_apitest.cc
bloba8c397bae6573c7404a2f58ce318cb95ebe68e12
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.
5 #include "chrome/browser/extensions/extension_apitest.h"
7 #include "base/strings/string_split.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/unpacked_installer.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/extensions/application_launch.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "content/public/browser/notification_registrar.h"
18 #include "content/public/browser/notification_service.h"
19 #include "extensions/browser/api/test/test_api.h"
20 #include "extensions/browser/extension_system.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_set.h"
23 #include "net/base/escape.h"
24 #include "net/base/filename_util.h"
25 #include "net/test/embedded_test_server/embedded_test_server.h"
26 #include "net/test/embedded_test_server/http_request.h"
27 #include "net/test/embedded_test_server/http_response.h"
28 #include "net/test/spawned_test_server/spawned_test_server.h"
30 namespace {
32 const char kTestCustomArg[] = "customArg";
33 const char kTestServerPort[] = "testServer.port";
34 const char kTestDataDirectory[] = "testDataDirectory";
35 const char kTestWebSocketPort[] = "testWebSocketPort";
36 const char kFtpServerPort[] = "ftpServer.port";
37 const char kSpawnedTestServerPort[] = "spawnedTestServer.port";
39 scoped_ptr<net::test_server::HttpResponse> HandleServerRedirectRequest(
40 const net::test_server::HttpRequest& request) {
41 if (!StartsWithASCII(request.relative_url, "/server-redirect?", true))
42 return scoped_ptr<net::test_server::HttpResponse>();
44 size_t query_string_pos = request.relative_url.find('?');
45 std::string redirect_target =
46 request.relative_url.substr(query_string_pos + 1);
48 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
49 new net::test_server::BasicHttpResponse);
50 http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
51 http_response->AddCustomHeader("Location", redirect_target);
52 return http_response.PassAs<net::test_server::HttpResponse>();
55 scoped_ptr<net::test_server::HttpResponse> HandleEchoHeaderRequest(
56 const net::test_server::HttpRequest& request) {
57 if (!StartsWithASCII(request.relative_url, "/echoheader?", true))
58 return scoped_ptr<net::test_server::HttpResponse>();
60 size_t query_string_pos = request.relative_url.find('?');
61 std::string header_name =
62 request.relative_url.substr(query_string_pos + 1);
64 std::string header_value;
65 std::map<std::string, std::string>::const_iterator it = request.headers.find(
66 header_name);
67 if (it != request.headers.end())
68 header_value = it->second;
70 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
71 new net::test_server::BasicHttpResponse);
72 http_response->set_code(net::HTTP_OK);
73 http_response->set_content(header_value);
74 return http_response.PassAs<net::test_server::HttpResponse>();
77 scoped_ptr<net::test_server::HttpResponse> HandleSetCookieRequest(
78 const net::test_server::HttpRequest& request) {
79 if (!StartsWithASCII(request.relative_url, "/set-cookie?", true))
80 return scoped_ptr<net::test_server::HttpResponse>();
82 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
83 new net::test_server::BasicHttpResponse);
84 http_response->set_code(net::HTTP_OK);
86 size_t query_string_pos = request.relative_url.find('?');
87 std::string cookie_value =
88 request.relative_url.substr(query_string_pos + 1);
90 std::vector<std::string> cookies;
91 base::SplitString(cookie_value, '&', &cookies);
93 for (size_t i = 0; i < cookies.size(); i++)
94 http_response->AddCustomHeader("Set-Cookie", cookies[i]);
96 return http_response.PassAs<net::test_server::HttpResponse>();
99 scoped_ptr<net::test_server::HttpResponse> HandleSetHeaderRequest(
100 const net::test_server::HttpRequest& request) {
101 if (!StartsWithASCII(request.relative_url, "/set-header?", true))
102 return scoped_ptr<net::test_server::HttpResponse>();
104 size_t query_string_pos = request.relative_url.find('?');
105 std::string escaped_header =
106 request.relative_url.substr(query_string_pos + 1);
108 std::string header =
109 net::UnescapeURLComponent(escaped_header,
110 net::UnescapeRule::NORMAL |
111 net::UnescapeRule::SPACES |
112 net::UnescapeRule::URL_SPECIAL_CHARS);
114 size_t colon_pos = header.find(':');
115 if (colon_pos == std::string::npos)
116 return scoped_ptr<net::test_server::HttpResponse>();
118 std::string header_name = header.substr(0, colon_pos);
119 // Skip space after colon.
120 std::string header_value = header.substr(colon_pos + 2);
122 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
123 new net::test_server::BasicHttpResponse);
124 http_response->set_code(net::HTTP_OK);
125 http_response->AddCustomHeader(header_name, header_value);
126 return http_response.PassAs<net::test_server::HttpResponse>();
129 }; // namespace
131 ExtensionApiTest::ExtensionApiTest() {
132 embedded_test_server()->RegisterRequestHandler(
133 base::Bind(&HandleServerRedirectRequest));
134 embedded_test_server()->RegisterRequestHandler(
135 base::Bind(&HandleEchoHeaderRequest));
136 embedded_test_server()->RegisterRequestHandler(
137 base::Bind(&HandleSetCookieRequest));
138 embedded_test_server()->RegisterRequestHandler(
139 base::Bind(&HandleSetHeaderRequest));
142 ExtensionApiTest::~ExtensionApiTest() {}
144 ExtensionApiTest::ResultCatcher::ResultCatcher()
145 : profile_restriction_(NULL),
146 waiting_(false) {
147 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_TEST_PASSED,
148 content::NotificationService::AllSources());
149 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_TEST_FAILED,
150 content::NotificationService::AllSources());
153 ExtensionApiTest::ResultCatcher::~ResultCatcher() {
156 bool ExtensionApiTest::ResultCatcher::GetNextResult() {
157 // Depending on the tests, multiple results can come in from a single call
158 // to RunMessageLoop(), so we maintain a queue of results and just pull them
159 // off as the test calls this, going to the run loop only when the queue is
160 // empty.
161 if (results_.empty()) {
162 waiting_ = true;
163 content::RunMessageLoop();
164 waiting_ = false;
167 if (!results_.empty()) {
168 bool ret = results_.front();
169 results_.pop_front();
170 message_ = messages_.front();
171 messages_.pop_front();
172 return ret;
175 NOTREACHED();
176 return false;
179 void ExtensionApiTest::ResultCatcher::Observe(
180 int type, const content::NotificationSource& source,
181 const content::NotificationDetails& details) {
182 if (profile_restriction_ &&
183 content::Source<Profile>(source).ptr() != profile_restriction_) {
184 return;
187 switch (type) {
188 case chrome::NOTIFICATION_EXTENSION_TEST_PASSED:
189 VLOG(1) << "Got EXTENSION_TEST_PASSED notification.";
190 results_.push_back(true);
191 messages_.push_back(std::string());
192 if (waiting_)
193 base::MessageLoopForUI::current()->Quit();
194 break;
196 case chrome::NOTIFICATION_EXTENSION_TEST_FAILED:
197 VLOG(1) << "Got EXTENSION_TEST_FAILED notification.";
198 results_.push_back(false);
199 messages_.push_back(*(content::Details<std::string>(details).ptr()));
200 if (waiting_)
201 base::MessageLoopForUI::current()->Quit();
202 break;
204 default:
205 NOTREACHED();
209 void ExtensionApiTest::SetUpInProcessBrowserTestFixture() {
210 DCHECK(!test_config_.get()) << "Previous test did not clear config state.";
211 test_config_.reset(new base::DictionaryValue());
212 test_config_->SetString(kTestDataDirectory,
213 net::FilePathToFileURL(test_data_dir_).spec());
214 test_config_->SetInteger(kTestWebSocketPort, 0);
215 extensions::TestGetConfigFunction::set_test_config_state(
216 test_config_.get());
219 void ExtensionApiTest::TearDownInProcessBrowserTestFixture() {
220 extensions::TestGetConfigFunction::set_test_config_state(NULL);
221 test_config_.reset(NULL);
224 bool ExtensionApiTest::RunExtensionTest(const std::string& extension_name) {
225 return RunExtensionTestImpl(
226 extension_name, std::string(), NULL, kFlagEnableFileAccess);
229 bool ExtensionApiTest::RunExtensionTestIncognito(
230 const std::string& extension_name) {
231 return RunExtensionTestImpl(extension_name,
232 std::string(),
233 NULL,
234 kFlagEnableIncognito | kFlagEnableFileAccess);
237 bool ExtensionApiTest::RunExtensionTestIgnoreManifestWarnings(
238 const std::string& extension_name) {
239 return RunExtensionTestImpl(
240 extension_name, std::string(), NULL, kFlagIgnoreManifestWarnings);
243 bool ExtensionApiTest::RunExtensionTestAllowOldManifestVersion(
244 const std::string& extension_name) {
245 return RunExtensionTestImpl(
246 extension_name,
247 std::string(),
248 NULL,
249 kFlagEnableFileAccess | kFlagAllowOldManifestVersions);
252 bool ExtensionApiTest::RunComponentExtensionTest(
253 const std::string& extension_name) {
254 return RunExtensionTestImpl(extension_name,
255 std::string(),
256 NULL,
257 kFlagEnableFileAccess | kFlagLoadAsComponent);
260 bool ExtensionApiTest::RunExtensionTestNoFileAccess(
261 const std::string& extension_name) {
262 return RunExtensionTestImpl(extension_name, std::string(), NULL, kFlagNone);
265 bool ExtensionApiTest::RunExtensionTestIncognitoNoFileAccess(
266 const std::string& extension_name) {
267 return RunExtensionTestImpl(
268 extension_name, std::string(), NULL, kFlagEnableIncognito);
271 bool ExtensionApiTest::RunExtensionSubtest(const std::string& extension_name,
272 const std::string& page_url) {
273 return RunExtensionSubtest(extension_name, page_url, kFlagEnableFileAccess);
276 bool ExtensionApiTest::RunExtensionSubtest(const std::string& extension_name,
277 const std::string& page_url,
278 int flags) {
279 DCHECK(!page_url.empty()) << "Argument page_url is required.";
280 // See http://crbug.com/177163 for details.
281 #if defined(OS_WIN) && !defined(NDEBUG)
282 LOG(WARNING) << "Workaround for 177163, prematurely returning";
283 return true;
284 #else
285 return RunExtensionTestImpl(extension_name, page_url, NULL, flags);
286 #endif
290 bool ExtensionApiTest::RunPageTest(const std::string& page_url) {
291 return RunExtensionSubtest(std::string(), page_url);
294 bool ExtensionApiTest::RunPageTest(const std::string& page_url,
295 int flags) {
296 return RunExtensionSubtest(std::string(), page_url, flags);
299 bool ExtensionApiTest::RunPlatformAppTest(const std::string& extension_name) {
300 return RunExtensionTestImpl(
301 extension_name, std::string(), NULL, kFlagLaunchPlatformApp);
304 bool ExtensionApiTest::RunPlatformAppTestWithArg(
305 const std::string& extension_name, const char* custom_arg) {
306 return RunExtensionTestImpl(
307 extension_name, std::string(), custom_arg, kFlagLaunchPlatformApp);
310 bool ExtensionApiTest::RunPlatformAppTestWithFlags(
311 const std::string& extension_name, int flags) {
312 return RunExtensionTestImpl(
313 extension_name, std::string(), NULL, flags | kFlagLaunchPlatformApp);
316 // Load |extension_name| extension and/or |page_url| and wait for
317 // PASSED or FAILED notification.
318 bool ExtensionApiTest::RunExtensionTestImpl(const std::string& extension_name,
319 const std::string& page_url,
320 const char* custom_arg,
321 int flags) {
322 bool load_as_component = (flags & kFlagLoadAsComponent) != 0;
323 bool launch_platform_app = (flags & kFlagLaunchPlatformApp) != 0;
324 bool use_incognito = (flags & kFlagUseIncognito) != 0;
326 if (custom_arg && custom_arg[0])
327 test_config_->SetString(kTestCustomArg, custom_arg);
329 ResultCatcher catcher;
330 DCHECK(!extension_name.empty() || !page_url.empty()) <<
331 "extension_name and page_url cannot both be empty";
333 const extensions::Extension* extension = NULL;
334 if (!extension_name.empty()) {
335 base::FilePath extension_path = test_data_dir_.AppendASCII(extension_name);
336 if (load_as_component) {
337 extension = LoadExtensionAsComponent(extension_path);
338 } else {
339 int browser_test_flags = ExtensionBrowserTest::kFlagNone;
340 if (flags & kFlagEnableIncognito)
341 browser_test_flags |= ExtensionBrowserTest::kFlagEnableIncognito;
342 if (flags & kFlagEnableFileAccess)
343 browser_test_flags |= ExtensionBrowserTest::kFlagEnableFileAccess;
344 if (flags & kFlagIgnoreManifestWarnings)
345 browser_test_flags |= ExtensionBrowserTest::kFlagIgnoreManifestWarnings;
346 if (flags & kFlagAllowOldManifestVersions) {
347 browser_test_flags |=
348 ExtensionBrowserTest::kFlagAllowOldManifestVersions;
350 extension = LoadExtensionWithFlags(extension_path, browser_test_flags);
352 if (!extension) {
353 message_ = "Failed to load extension.";
354 return false;
358 // If there is a page_url to load, navigate it.
359 if (!page_url.empty()) {
360 GURL url = GURL(page_url);
362 // Note: We use is_valid() here in the expectation that the provided url
363 // may lack a scheme & host and thus be a relative url within the loaded
364 // extension.
365 if (!url.is_valid()) {
366 DCHECK(!extension_name.empty()) <<
367 "Relative page_url given with no extension_name";
369 url = extension->GetResourceURL(page_url);
372 if (use_incognito)
373 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), url);
374 else
375 ui_test_utils::NavigateToURL(browser(), url);
376 } else if (launch_platform_app) {
377 AppLaunchParams params(browser()->profile(),
378 extension,
379 extensions::LAUNCH_CONTAINER_NONE,
380 NEW_WINDOW);
381 params.command_line = *CommandLine::ForCurrentProcess();
382 OpenApplication(params);
385 if (!catcher.GetNextResult()) {
386 message_ = catcher.message();
387 return false;
390 return true;
393 // Test that exactly one extension is loaded, and return it.
394 const extensions::Extension* ExtensionApiTest::GetSingleLoadedExtension() {
395 ExtensionService* service = extensions::ExtensionSystem::Get(
396 browser()->profile())->extension_service();
398 const extensions::Extension* extension = NULL;
399 for (extensions::ExtensionSet::const_iterator it =
400 service->extensions()->begin();
401 it != service->extensions()->end(); ++it) {
402 // Ignore any component extensions. They are automatically loaded into all
403 // profiles and aren't the extension we're looking for here.
404 if ((*it)->location() == extensions::Manifest::COMPONENT)
405 continue;
407 if (extension != NULL) {
408 // TODO(yoz): this is misleading; it counts component extensions.
409 message_ = base::StringPrintf(
410 "Expected only one extension to be present. Found %u.",
411 static_cast<unsigned>(service->extensions()->size()));
412 return NULL;
415 extension = it->get();
418 if (!extension) {
419 message_ = "extension pointer is NULL.";
420 return NULL;
422 return extension;
425 bool ExtensionApiTest::StartEmbeddedTestServer() {
426 if (!embedded_test_server()->InitializeAndWaitUntilReady())
427 return false;
429 // Build a dictionary of values that tests can use to build URLs that
430 // access the test server and local file system. Tests can see these values
431 // using the extension API function chrome.test.getConfig().
432 test_config_->SetInteger(kTestServerPort,
433 embedded_test_server()->port());
435 return true;
438 bool ExtensionApiTest::StartWebSocketServer(
439 const base::FilePath& root_directory) {
440 websocket_server_.reset(new net::SpawnedTestServer(
441 net::SpawnedTestServer::TYPE_WS,
442 net::SpawnedTestServer::kLocalhost,
443 root_directory));
445 if (!websocket_server_->Start())
446 return false;
448 test_config_->SetInteger(kTestWebSocketPort,
449 websocket_server_->host_port_pair().port());
451 return true;
454 bool ExtensionApiTest::StartFTPServer(const base::FilePath& root_directory) {
455 ftp_server_.reset(new net::SpawnedTestServer(
456 net::SpawnedTestServer::TYPE_FTP,
457 net::SpawnedTestServer::kLocalhost,
458 root_directory));
460 if (!ftp_server_->Start())
461 return false;
463 test_config_->SetInteger(kFtpServerPort,
464 ftp_server_->host_port_pair().port());
466 return true;
469 bool ExtensionApiTest::StartSpawnedTestServer() {
470 if (!test_server()->Start())
471 return false;
473 // Build a dictionary of values that tests can use to build URLs that
474 // access the test server and local file system. Tests can see these values
475 // using the extension API function chrome.test.getConfig().
476 test_config_->SetInteger(kSpawnedTestServerPort,
477 test_server()->host_port_pair().port());
479 return true;
482 void ExtensionApiTest::SetUpCommandLine(CommandLine* command_line) {
483 ExtensionBrowserTest::SetUpCommandLine(command_line);
484 test_data_dir_ = test_data_dir_.AppendASCII("api_test");