Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_apitest.cc
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 "chrome/browser/extensions/extension_apitest.h"
6
7 #include "base/strings/string_split.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/unpacked_installer.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/extensions/application_launch.h"
15 #include "chrome/test/base/ui_test_utils.h"
16 #include "extensions/browser/api/test/test_api.h"
17 #include "extensions/browser/extension_system.h"
18 #include "extensions/common/extension.h"
19 #include "extensions/common/extension_set.h"
20 #include "extensions/test/result_catcher.h"
21 #include "net/base/escape.h"
22 #include "net/base/filename_util.h"
23 #include "net/test/embedded_test_server/embedded_test_server.h"
24 #include "net/test/embedded_test_server/http_request.h"
25 #include "net/test/embedded_test_server/http_response.h"
26 #include "net/test/spawned_test_server/spawned_test_server.h"
27
28 namespace {
29
30 const char kTestCustomArg[] = "customArg";
31 const char kTestServerPort[] = "testServer.port";
32 const char kTestDataDirectory[] = "testDataDirectory";
33 const char kTestWebSocketPort[] = "testWebSocketPort";
34 const char kFtpServerPort[] = "ftpServer.port";
35 const char kSpawnedTestServerPort[] = "spawnedTestServer.port";
36
37 scoped_ptr<net::test_server::HttpResponse> HandleServerRedirectRequest(
38     const net::test_server::HttpRequest& request) {
39   if (!StartsWithASCII(request.relative_url, "/server-redirect?", true))
40     return nullptr;
41
42   size_t query_string_pos = request.relative_url.find('?');
43   std::string redirect_target =
44       request.relative_url.substr(query_string_pos + 1);
45
46   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
47       new net::test_server::BasicHttpResponse);
48   http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
49   http_response->AddCustomHeader("Location", redirect_target);
50   return http_response.Pass();
51 }
52
53 scoped_ptr<net::test_server::HttpResponse> HandleEchoHeaderRequest(
54     const net::test_server::HttpRequest& request) {
55   if (!StartsWithASCII(request.relative_url, "/echoheader?", true))
56     return nullptr;
57
58   size_t query_string_pos = request.relative_url.find('?');
59   std::string header_name =
60       request.relative_url.substr(query_string_pos + 1);
61
62   std::string header_value;
63   std::map<std::string, std::string>::const_iterator it = request.headers.find(
64       header_name);
65   if (it != request.headers.end())
66     header_value = it->second;
67
68   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
69       new net::test_server::BasicHttpResponse);
70   http_response->set_code(net::HTTP_OK);
71   http_response->set_content(header_value);
72   return http_response.Pass();
73 }
74
75 scoped_ptr<net::test_server::HttpResponse> HandleSetCookieRequest(
76     const net::test_server::HttpRequest& request) {
77   if (!StartsWithASCII(request.relative_url, "/set-cookie?", true))
78     return nullptr;
79
80   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
81       new net::test_server::BasicHttpResponse);
82   http_response->set_code(net::HTTP_OK);
83
84   size_t query_string_pos = request.relative_url.find('?');
85   std::string cookie_value =
86       request.relative_url.substr(query_string_pos + 1);
87
88   std::vector<std::string> cookies;
89   base::SplitString(cookie_value, '&', &cookies);
90
91   for (size_t i = 0; i < cookies.size(); i++)
92     http_response->AddCustomHeader("Set-Cookie", cookies[i]);
93
94   return http_response.Pass();
95 }
96
97 scoped_ptr<net::test_server::HttpResponse> HandleSetHeaderRequest(
98     const net::test_server::HttpRequest& request) {
99   if (!StartsWithASCII(request.relative_url, "/set-header?", true))
100     return nullptr;
101
102   size_t query_string_pos = request.relative_url.find('?');
103   std::string escaped_header =
104       request.relative_url.substr(query_string_pos + 1);
105
106   std::string header =
107       net::UnescapeURLComponent(escaped_header,
108                                 net::UnescapeRule::NORMAL |
109                                 net::UnescapeRule::SPACES |
110                                 net::UnescapeRule::URL_SPECIAL_CHARS);
111
112   size_t colon_pos = header.find(':');
113   if (colon_pos == std::string::npos)
114     return scoped_ptr<net::test_server::HttpResponse>();
115
116   std::string header_name = header.substr(0, colon_pos);
117   // Skip space after colon.
118   std::string header_value = header.substr(colon_pos + 2);
119
120   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
121       new net::test_server::BasicHttpResponse);
122   http_response->set_code(net::HTTP_OK);
123   http_response->AddCustomHeader(header_name, header_value);
124   return http_response.Pass();
125 }
126
127 };  // namespace
128
129 ExtensionApiTest::ExtensionApiTest() {
130   embedded_test_server()->RegisterRequestHandler(
131       base::Bind(&HandleServerRedirectRequest));
132   embedded_test_server()->RegisterRequestHandler(
133       base::Bind(&HandleEchoHeaderRequest));
134   embedded_test_server()->RegisterRequestHandler(
135       base::Bind(&HandleSetCookieRequest));
136   embedded_test_server()->RegisterRequestHandler(
137       base::Bind(&HandleSetHeaderRequest));
138 }
139
140 ExtensionApiTest::~ExtensionApiTest() {}
141
142 void ExtensionApiTest::SetUpInProcessBrowserTestFixture() {
143   DCHECK(!test_config_.get()) << "Previous test did not clear config state.";
144   test_config_.reset(new base::DictionaryValue());
145   test_config_->SetString(kTestDataDirectory,
146                           net::FilePathToFileURL(test_data_dir_).spec());
147   test_config_->SetInteger(kTestWebSocketPort, 0);
148   extensions::TestGetConfigFunction::set_test_config_state(
149       test_config_.get());
150 }
151
152 void ExtensionApiTest::TearDownInProcessBrowserTestFixture() {
153   extensions::TestGetConfigFunction::set_test_config_state(NULL);
154   test_config_.reset(NULL);
155 }
156
157 bool ExtensionApiTest::RunExtensionTest(const std::string& extension_name) {
158   return RunExtensionTestImpl(
159       extension_name, std::string(), NULL, kFlagEnableFileAccess);
160 }
161
162 bool ExtensionApiTest::RunExtensionTestIncognito(
163     const std::string& extension_name) {
164   return RunExtensionTestImpl(extension_name,
165                               std::string(),
166                               NULL,
167                               kFlagEnableIncognito | kFlagEnableFileAccess);
168 }
169
170 bool ExtensionApiTest::RunExtensionTestIgnoreManifestWarnings(
171     const std::string& extension_name) {
172   return RunExtensionTestImpl(
173       extension_name, std::string(), NULL, kFlagIgnoreManifestWarnings);
174 }
175
176 bool ExtensionApiTest::RunExtensionTestAllowOldManifestVersion(
177     const std::string& extension_name) {
178   return RunExtensionTestImpl(
179       extension_name,
180       std::string(),
181       NULL,
182       kFlagEnableFileAccess | kFlagAllowOldManifestVersions);
183 }
184
185 bool ExtensionApiTest::RunComponentExtensionTest(
186     const std::string& extension_name) {
187   return RunExtensionTestImpl(extension_name,
188                               std::string(),
189                               NULL,
190                               kFlagEnableFileAccess | kFlagLoadAsComponent);
191 }
192
193 bool ExtensionApiTest::RunExtensionTestNoFileAccess(
194     const std::string& extension_name) {
195   return RunExtensionTestImpl(extension_name, std::string(), NULL, kFlagNone);
196 }
197
198 bool ExtensionApiTest::RunExtensionTestIncognitoNoFileAccess(
199     const std::string& extension_name) {
200   return RunExtensionTestImpl(
201       extension_name, std::string(), NULL, kFlagEnableIncognito);
202 }
203
204 bool ExtensionApiTest::RunExtensionSubtest(const std::string& extension_name,
205                                            const std::string& page_url) {
206   return RunExtensionSubtest(extension_name, page_url, kFlagEnableFileAccess);
207 }
208
209 bool ExtensionApiTest::RunExtensionSubtest(const std::string& extension_name,
210                                            const std::string& page_url,
211                                            int flags) {
212   DCHECK(!page_url.empty()) << "Argument page_url is required.";
213   // See http://crbug.com/177163 for details.
214 #if defined(OS_WIN) && !defined(NDEBUG)
215   LOG(WARNING) << "Workaround for 177163, prematurely returning";
216   return true;
217 #else
218   return RunExtensionTestImpl(extension_name, page_url, NULL, flags);
219 #endif
220 }
221
222
223 bool ExtensionApiTest::RunPageTest(const std::string& page_url) {
224   return RunExtensionSubtest(std::string(), page_url);
225 }
226
227 bool ExtensionApiTest::RunPageTest(const std::string& page_url,
228                                    int flags) {
229   return RunExtensionSubtest(std::string(), page_url, flags);
230 }
231
232 bool ExtensionApiTest::RunPlatformAppTest(const std::string& extension_name) {
233   return RunExtensionTestImpl(
234       extension_name, std::string(), NULL, kFlagLaunchPlatformApp);
235 }
236
237 bool ExtensionApiTest::RunPlatformAppTestWithArg(
238     const std::string& extension_name, const char* custom_arg) {
239   return RunExtensionTestImpl(
240       extension_name, std::string(), custom_arg, kFlagLaunchPlatformApp);
241 }
242
243 bool ExtensionApiTest::RunPlatformAppTestWithFlags(
244     const std::string& extension_name, int flags) {
245   return RunExtensionTestImpl(
246       extension_name, std::string(), NULL, flags | kFlagLaunchPlatformApp);
247 }
248
249 // Load |extension_name| extension and/or |page_url| and wait for
250 // PASSED or FAILED notification.
251 bool ExtensionApiTest::RunExtensionTestImpl(const std::string& extension_name,
252                                             const std::string& page_url,
253                                             const char* custom_arg,
254                                             int flags) {
255   bool load_as_component = (flags & kFlagLoadAsComponent) != 0;
256   bool launch_platform_app = (flags & kFlagLaunchPlatformApp) != 0;
257   bool use_incognito = (flags & kFlagUseIncognito) != 0;
258
259   if (custom_arg && custom_arg[0])
260     test_config_->SetString(kTestCustomArg, custom_arg);
261
262   extensions::ResultCatcher catcher;
263   DCHECK(!extension_name.empty() || !page_url.empty()) <<
264       "extension_name and page_url cannot both be empty";
265
266   const extensions::Extension* extension = NULL;
267   if (!extension_name.empty()) {
268     base::FilePath extension_path = test_data_dir_.AppendASCII(extension_name);
269     if (load_as_component) {
270       extension = LoadExtensionAsComponent(extension_path);
271     } else {
272       int browser_test_flags = ExtensionBrowserTest::kFlagNone;
273       if (flags & kFlagEnableIncognito)
274         browser_test_flags |= ExtensionBrowserTest::kFlagEnableIncognito;
275       if (flags & kFlagEnableFileAccess)
276         browser_test_flags |= ExtensionBrowserTest::kFlagEnableFileAccess;
277       if (flags & kFlagIgnoreManifestWarnings)
278         browser_test_flags |= ExtensionBrowserTest::kFlagIgnoreManifestWarnings;
279       if (flags & kFlagAllowOldManifestVersions) {
280         browser_test_flags |=
281             ExtensionBrowserTest::kFlagAllowOldManifestVersions;
282       }
283       extension = LoadExtensionWithFlags(extension_path, browser_test_flags);
284     }
285     if (!extension) {
286       message_ = "Failed to load extension.";
287       return false;
288     }
289   }
290
291   // If there is a page_url to load, navigate it.
292   if (!page_url.empty()) {
293     GURL url = GURL(page_url);
294
295     // Note: We use is_valid() here in the expectation that the provided url
296     // may lack a scheme & host and thus be a relative url within the loaded
297     // extension.
298     if (!url.is_valid()) {
299       DCHECK(!extension_name.empty()) <<
300           "Relative page_url given with no extension_name";
301
302       url = extension->GetResourceURL(page_url);
303     }
304
305     if (use_incognito)
306       ui_test_utils::OpenURLOffTheRecord(browser()->profile(), url);
307     else
308       ui_test_utils::NavigateToURL(browser(), url);
309   } else if (launch_platform_app) {
310     AppLaunchParams params(browser()->profile(),
311                            extension,
312                            extensions::LAUNCH_CONTAINER_NONE,
313                            NEW_WINDOW);
314     params.command_line = *CommandLine::ForCurrentProcess();
315     OpenApplication(params);
316   }
317
318   if (!catcher.GetNextResult()) {
319     message_ = catcher.message();
320     return false;
321   }
322
323   return true;
324 }
325
326 // Test that exactly one extension is loaded, and return it.
327 const extensions::Extension* ExtensionApiTest::GetSingleLoadedExtension() {
328   ExtensionService* service = extensions::ExtensionSystem::Get(
329       browser()->profile())->extension_service();
330
331   const extensions::Extension* extension = NULL;
332   for (extensions::ExtensionSet::const_iterator it =
333            service->extensions()->begin();
334        it != service->extensions()->end(); ++it) {
335     // Ignore any component extensions. They are automatically loaded into all
336     // profiles and aren't the extension we're looking for here.
337     if ((*it)->location() == extensions::Manifest::COMPONENT)
338       continue;
339
340     if (extension != NULL) {
341       // TODO(yoz): this is misleading; it counts component extensions.
342       message_ = base::StringPrintf(
343           "Expected only one extension to be present.  Found %u.",
344           static_cast<unsigned>(service->extensions()->size()));
345       return NULL;
346     }
347
348     extension = it->get();
349   }
350
351   if (!extension) {
352     message_ = "extension pointer is NULL.";
353     return NULL;
354   }
355   return extension;
356 }
357
358 bool ExtensionApiTest::StartEmbeddedTestServer() {
359   if (!embedded_test_server()->InitializeAndWaitUntilReady())
360     return false;
361
362   // Build a dictionary of values that tests can use to build URLs that
363   // access the test server and local file system.  Tests can see these values
364   // using the extension API function chrome.test.getConfig().
365   test_config_->SetInteger(kTestServerPort,
366                            embedded_test_server()->port());
367
368   return true;
369 }
370
371 bool ExtensionApiTest::StartWebSocketServer(
372     const base::FilePath& root_directory) {
373   websocket_server_.reset(new net::SpawnedTestServer(
374       net::SpawnedTestServer::TYPE_WS,
375       net::SpawnedTestServer::kLocalhost,
376       root_directory));
377
378   if (!websocket_server_->Start())
379     return false;
380
381   test_config_->SetInteger(kTestWebSocketPort,
382                            websocket_server_->host_port_pair().port());
383
384   return true;
385 }
386
387 bool ExtensionApiTest::StartFTPServer(const base::FilePath& root_directory) {
388   ftp_server_.reset(new net::SpawnedTestServer(
389       net::SpawnedTestServer::TYPE_FTP,
390       net::SpawnedTestServer::kLocalhost,
391       root_directory));
392
393   if (!ftp_server_->Start())
394     return false;
395
396   test_config_->SetInteger(kFtpServerPort,
397                            ftp_server_->host_port_pair().port());
398
399   return true;
400 }
401
402 bool ExtensionApiTest::StartSpawnedTestServer() {
403   if (!test_server()->Start())
404     return false;
405
406   // Build a dictionary of values that tests can use to build URLs that
407   // access the test server and local file system.  Tests can see these values
408   // using the extension API function chrome.test.getConfig().
409   test_config_->SetInteger(kSpawnedTestServerPort,
410                            test_server()->host_port_pair().port());
411
412   return true;
413 }
414
415 void ExtensionApiTest::SetUpCommandLine(CommandLine* command_line) {
416   ExtensionBrowserTest::SetUpCommandLine(command_line);
417   test_data_dir_ = test_data_dir_.AppendASCII("api_test");
418 }