Move StartsWith[ASCII] to base namespace.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_apitest.cc
blobfebd0962f3ceae7eb9619620b741ebe8f391ed95
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/base_switches.h"
8 #include "base/strings/string_split.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.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/app_launch_params.h"
16 #include "chrome/browser/ui/extensions/application_launch.h"
17 #include "chrome/test/base/ui_test_utils.h"
18 #include "content/public/common/content_switches.h"
19 #include "extensions/browser/api/test/test_api.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/common/constants.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_set.h"
25 #include "extensions/test/result_catcher.h"
26 #include "net/base/escape.h"
27 #include "net/base/filename_util.h"
28 #include "net/test/embedded_test_server/embedded_test_server.h"
29 #include "net/test/embedded_test_server/http_request.h"
30 #include "net/test/embedded_test_server/http_response.h"
31 #include "net/test/spawned_test_server/spawned_test_server.h"
33 namespace {
35 const char kTestCustomArg[] = "customArg";
36 const char kTestServerPort[] = "testServer.port";
37 const char kTestDataDirectory[] = "testDataDirectory";
38 const char kTestWebSocketPort[] = "testWebSocketPort";
39 const char kFtpServerPort[] = "ftpServer.port";
40 const char kSpawnedTestServerPort[] = "spawnedTestServer.port";
42 scoped_ptr<net::test_server::HttpResponse> HandleServerRedirectRequest(
43 const net::test_server::HttpRequest& request) {
44 if (!base::StartsWithASCII(request.relative_url, "/server-redirect?", true))
45 return nullptr;
47 size_t query_string_pos = request.relative_url.find('?');
48 std::string redirect_target =
49 request.relative_url.substr(query_string_pos + 1);
51 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
52 new net::test_server::BasicHttpResponse);
53 http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
54 http_response->AddCustomHeader("Location", redirect_target);
55 return http_response.Pass();
58 scoped_ptr<net::test_server::HttpResponse> HandleEchoHeaderRequest(
59 const net::test_server::HttpRequest& request) {
60 if (!base::StartsWithASCII(request.relative_url, "/echoheader?", true))
61 return nullptr;
63 size_t query_string_pos = request.relative_url.find('?');
64 std::string header_name =
65 request.relative_url.substr(query_string_pos + 1);
67 std::string header_value;
68 std::map<std::string, std::string>::const_iterator it = request.headers.find(
69 header_name);
70 if (it != request.headers.end())
71 header_value = it->second;
73 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
74 new net::test_server::BasicHttpResponse);
75 http_response->set_code(net::HTTP_OK);
76 http_response->set_content(header_value);
77 return http_response.Pass();
80 scoped_ptr<net::test_server::HttpResponse> HandleSetCookieRequest(
81 const net::test_server::HttpRequest& request) {
82 if (!base::StartsWithASCII(request.relative_url, "/set-cookie?", true))
83 return nullptr;
85 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
86 new net::test_server::BasicHttpResponse);
87 http_response->set_code(net::HTTP_OK);
89 size_t query_string_pos = request.relative_url.find('?');
90 std::string cookie_value =
91 request.relative_url.substr(query_string_pos + 1);
93 std::vector<std::string> cookies;
94 base::SplitString(cookie_value, '&', &cookies);
96 for (size_t i = 0; i < cookies.size(); i++)
97 http_response->AddCustomHeader("Set-Cookie", cookies[i]);
99 return http_response.Pass();
102 scoped_ptr<net::test_server::HttpResponse> HandleSetHeaderRequest(
103 const net::test_server::HttpRequest& request) {
104 if (!base::StartsWithASCII(request.relative_url, "/set-header?", true))
105 return nullptr;
107 size_t query_string_pos = request.relative_url.find('?');
108 std::string escaped_header =
109 request.relative_url.substr(query_string_pos + 1);
111 std::string header =
112 net::UnescapeURLComponent(escaped_header,
113 net::UnescapeRule::NORMAL |
114 net::UnescapeRule::SPACES |
115 net::UnescapeRule::URL_SPECIAL_CHARS);
117 size_t colon_pos = header.find(':');
118 if (colon_pos == std::string::npos)
119 return scoped_ptr<net::test_server::HttpResponse>();
121 std::string header_name = header.substr(0, colon_pos);
122 // Skip space after colon.
123 std::string header_value = header.substr(colon_pos + 2);
125 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
126 new net::test_server::BasicHttpResponse);
127 http_response->set_code(net::HTTP_OK);
128 http_response->AddCustomHeader(header_name, header_value);
129 return http_response.Pass();
132 }; // namespace
134 ExtensionApiTest::ExtensionApiTest() {
135 embedded_test_server()->RegisterRequestHandler(
136 base::Bind(&HandleServerRedirectRequest));
137 embedded_test_server()->RegisterRequestHandler(
138 base::Bind(&HandleEchoHeaderRequest));
139 embedded_test_server()->RegisterRequestHandler(
140 base::Bind(&HandleSetCookieRequest));
141 embedded_test_server()->RegisterRequestHandler(
142 base::Bind(&HandleSetHeaderRequest));
145 ExtensionApiTest::~ExtensionApiTest() {}
147 void ExtensionApiTest::SetUpInProcessBrowserTestFixture() {
148 DCHECK(!test_config_.get()) << "Previous test did not clear config state.";
149 test_config_.reset(new base::DictionaryValue());
150 test_config_->SetString(kTestDataDirectory,
151 net::FilePathToFileURL(test_data_dir_).spec());
152 test_config_->SetInteger(kTestWebSocketPort, 0);
153 extensions::TestGetConfigFunction::set_test_config_state(
154 test_config_.get());
157 void ExtensionApiTest::TearDownInProcessBrowserTestFixture() {
158 extensions::TestGetConfigFunction::set_test_config_state(NULL);
159 test_config_.reset(NULL);
162 bool ExtensionApiTest::RunExtensionTest(const std::string& extension_name) {
163 return RunExtensionTestImpl(
164 extension_name, std::string(), NULL, kFlagEnableFileAccess);
167 bool ExtensionApiTest::RunExtensionTestIncognito(
168 const std::string& extension_name) {
169 return RunExtensionTestImpl(extension_name,
170 std::string(),
171 NULL,
172 kFlagEnableIncognito | kFlagEnableFileAccess);
175 bool ExtensionApiTest::RunExtensionTestIgnoreManifestWarnings(
176 const std::string& extension_name) {
177 return RunExtensionTestImpl(
178 extension_name, std::string(), NULL, kFlagIgnoreManifestWarnings);
181 bool ExtensionApiTest::RunExtensionTestAllowOldManifestVersion(
182 const std::string& extension_name) {
183 return RunExtensionTestImpl(
184 extension_name,
185 std::string(),
186 NULL,
187 kFlagEnableFileAccess | kFlagAllowOldManifestVersions);
190 bool ExtensionApiTest::RunComponentExtensionTest(
191 const std::string& extension_name) {
192 return RunExtensionTestImpl(extension_name,
193 std::string(),
194 NULL,
195 kFlagEnableFileAccess | kFlagLoadAsComponent);
198 bool ExtensionApiTest::RunExtensionTestNoFileAccess(
199 const std::string& extension_name) {
200 return RunExtensionTestImpl(extension_name, std::string(), NULL, kFlagNone);
203 bool ExtensionApiTest::RunExtensionTestIncognitoNoFileAccess(
204 const std::string& extension_name) {
205 return RunExtensionTestImpl(
206 extension_name, std::string(), NULL, kFlagEnableIncognito);
209 bool ExtensionApiTest::ExtensionSubtestsAreSkipped() {
210 // See http://crbug.com/177163 for details.
211 #if defined(OS_WIN) && !defined(NDEBUG)
212 LOG(WARNING) << "Workaround for 177163, prematurely returning";
213 return true;
214 #else
215 return false;
216 #endif
219 bool ExtensionApiTest::RunExtensionSubtest(const std::string& extension_name,
220 const std::string& page_url) {
221 return RunExtensionSubtest(extension_name, page_url, kFlagEnableFileAccess);
224 bool ExtensionApiTest::RunExtensionSubtest(const std::string& extension_name,
225 const std::string& page_url,
226 int flags) {
227 DCHECK(!page_url.empty()) << "Argument page_url is required.";
228 if (ExtensionSubtestsAreSkipped())
229 return true;
230 return RunExtensionTestImpl(extension_name, page_url, NULL, flags);
233 bool ExtensionApiTest::RunPageTest(const std::string& page_url) {
234 return RunExtensionSubtest(std::string(), page_url);
237 bool ExtensionApiTest::RunPageTest(const std::string& page_url,
238 int flags) {
239 return RunExtensionSubtest(std::string(), page_url, flags);
242 bool ExtensionApiTest::RunPlatformAppTest(const std::string& extension_name) {
243 return RunExtensionTestImpl(
244 extension_name, std::string(), NULL, kFlagLaunchPlatformApp);
247 bool ExtensionApiTest::RunPlatformAppTestWithArg(
248 const std::string& extension_name, const char* custom_arg) {
249 return RunExtensionTestImpl(
250 extension_name, std::string(), custom_arg, kFlagLaunchPlatformApp);
253 bool ExtensionApiTest::RunPlatformAppTestWithFlags(
254 const std::string& extension_name, int flags) {
255 return RunExtensionTestImpl(
256 extension_name, std::string(), NULL, flags | kFlagLaunchPlatformApp);
259 // Load |extension_name| extension and/or |page_url| and wait for
260 // PASSED or FAILED notification.
261 bool ExtensionApiTest::RunExtensionTestImpl(const std::string& extension_name,
262 const std::string& page_url,
263 const char* custom_arg,
264 int flags) {
265 bool load_as_component = (flags & kFlagLoadAsComponent) != 0;
266 bool launch_platform_app = (flags & kFlagLaunchPlatformApp) != 0;
267 bool use_incognito = (flags & kFlagUseIncognito) != 0;
269 if (custom_arg && custom_arg[0])
270 test_config_->SetString(kTestCustomArg, custom_arg);
272 extensions::ResultCatcher catcher;
273 DCHECK(!extension_name.empty() || !page_url.empty()) <<
274 "extension_name and page_url cannot both be empty";
276 const extensions::Extension* extension = NULL;
277 if (!extension_name.empty()) {
278 base::FilePath extension_path = test_data_dir_.AppendASCII(extension_name);
279 if (load_as_component) {
280 extension = LoadExtensionAsComponent(extension_path);
281 } else {
282 int browser_test_flags = ExtensionBrowserTest::kFlagNone;
283 if (flags & kFlagEnableIncognito)
284 browser_test_flags |= ExtensionBrowserTest::kFlagEnableIncognito;
285 if (flags & kFlagEnableFileAccess)
286 browser_test_flags |= ExtensionBrowserTest::kFlagEnableFileAccess;
287 if (flags & kFlagIgnoreManifestWarnings)
288 browser_test_flags |= ExtensionBrowserTest::kFlagIgnoreManifestWarnings;
289 if (flags & kFlagAllowOldManifestVersions) {
290 browser_test_flags |=
291 ExtensionBrowserTest::kFlagAllowOldManifestVersions;
293 extension = LoadExtensionWithFlags(extension_path, browser_test_flags);
295 if (!extension) {
296 message_ = "Failed to load extension.";
297 return false;
301 // If there is a page_url to load, navigate it.
302 if (!page_url.empty()) {
303 GURL url = GURL(page_url);
305 // Note: We use is_valid() here in the expectation that the provided url
306 // may lack a scheme & host and thus be a relative url within the loaded
307 // extension.
308 if (!url.is_valid()) {
309 DCHECK(!extension_name.empty()) <<
310 "Relative page_url given with no extension_name";
312 url = extension->GetResourceURL(page_url);
315 if (use_incognito)
316 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), url);
317 else
318 ui_test_utils::NavigateToURL(browser(), url);
319 } else if (launch_platform_app) {
320 AppLaunchParams params(browser()->profile(), extension,
321 extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW,
322 extensions::SOURCE_TEST);
323 params.command_line = *base::CommandLine::ForCurrentProcess();
324 OpenApplication(params);
327 if (!catcher.GetNextResult()) {
328 message_ = catcher.message();
329 return false;
332 return true;
335 // Test that exactly one extension is loaded, and return it.
336 const extensions::Extension* ExtensionApiTest::GetSingleLoadedExtension() {
337 extensions::ExtensionRegistry* registry =
338 extensions::ExtensionRegistry::Get(browser()->profile());
340 const extensions::Extension* result = NULL;
341 for (const scoped_refptr<const extensions::Extension>& extension :
342 registry->enabled_extensions()) {
343 // Ignore any component extensions. They are automatically loaded into all
344 // profiles and aren't the extension we're looking for here.
345 if (extension->location() == extensions::Manifest::COMPONENT)
346 continue;
348 if (result != NULL) {
349 // TODO(yoz): this is misleading; it counts component extensions.
350 message_ = base::StringPrintf(
351 "Expected only one extension to be present. Found %u.",
352 static_cast<unsigned>(registry->enabled_extensions().size()));
353 return NULL;
356 result = extension.get();
359 if (!result) {
360 message_ = "extension pointer is NULL.";
361 return NULL;
363 return result;
366 bool ExtensionApiTest::StartEmbeddedTestServer() {
367 if (!embedded_test_server()->InitializeAndWaitUntilReady())
368 return false;
370 // Build a dictionary of values that tests can use to build URLs that
371 // access the test server and local file system. Tests can see these values
372 // using the extension API function chrome.test.getConfig().
373 test_config_->SetInteger(kTestServerPort,
374 embedded_test_server()->port());
376 return true;
379 bool ExtensionApiTest::StartWebSocketServer(
380 const base::FilePath& root_directory) {
381 websocket_server_.reset(new net::SpawnedTestServer(
382 net::SpawnedTestServer::TYPE_WS,
383 net::SpawnedTestServer::kLocalhost,
384 root_directory));
386 if (!websocket_server_->Start())
387 return false;
389 test_config_->SetInteger(kTestWebSocketPort,
390 websocket_server_->host_port_pair().port());
392 return true;
395 bool ExtensionApiTest::StartFTPServer(const base::FilePath& root_directory) {
396 ftp_server_.reset(new net::SpawnedTestServer(
397 net::SpawnedTestServer::TYPE_FTP,
398 net::SpawnedTestServer::kLocalhost,
399 root_directory));
401 if (!ftp_server_->Start())
402 return false;
404 test_config_->SetInteger(kFtpServerPort,
405 ftp_server_->host_port_pair().port());
407 return true;
410 bool ExtensionApiTest::StartSpawnedTestServer() {
411 if (!test_server()->Start())
412 return false;
414 // Build a dictionary of values that tests can use to build URLs that
415 // access the test server and local file system. Tests can see these values
416 // using the extension API function chrome.test.getConfig().
417 test_config_->SetInteger(kSpawnedTestServerPort,
418 test_server()->host_port_pair().port());
420 return true;
423 void ExtensionApiTest::SetUpCommandLine(base::CommandLine* command_line) {
424 ExtensionBrowserTest::SetUpCommandLine(command_line);
425 test_data_dir_ = test_data_dir_.AppendASCII("api_test");
426 // Backgrounded renderer processes run at a lower priority, causing the
427 // tests to take more time to complete. Disable backgrounding so that the
428 // tests don't time out.
429 command_line->AppendSwitch(switches::kDisableRendererBackgrounding);