• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/string_util.h"
8 #include "base/stringprintf.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_test_api.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/test/ui_test_utils.h"
14 #include "content/common/notification_registrar.h"
15 
16 namespace {
17 
18 const char kTestServerPort[] = "testServer.port";
19 
20 };  // namespace
21 
ExtensionApiTest()22 ExtensionApiTest::ExtensionApiTest() {}
23 
~ExtensionApiTest()24 ExtensionApiTest::~ExtensionApiTest() {}
25 
ResultCatcher()26 ExtensionApiTest::ResultCatcher::ResultCatcher()
27     : profile_restriction_(NULL),
28       waiting_(false) {
29   registrar_.Add(this, NotificationType::EXTENSION_TEST_PASSED,
30                  NotificationService::AllSources());
31   registrar_.Add(this, NotificationType::EXTENSION_TEST_FAILED,
32                  NotificationService::AllSources());
33 }
34 
~ResultCatcher()35 ExtensionApiTest::ResultCatcher::~ResultCatcher() {
36 }
37 
GetNextResult()38 bool ExtensionApiTest::ResultCatcher::GetNextResult() {
39   // Depending on the tests, multiple results can come in from a single call
40   // to RunMessageLoop(), so we maintain a queue of results and just pull them
41   // off as the test calls this, going to the run loop only when the queue is
42   // empty.
43   if (results_.empty()) {
44     waiting_ = true;
45     ui_test_utils::RunMessageLoop();
46     waiting_ = false;
47   }
48 
49   if (!results_.empty()) {
50     bool ret = results_.front();
51     results_.pop_front();
52     message_ = messages_.front();
53     messages_.pop_front();
54     return ret;
55   }
56 
57   NOTREACHED();
58   return false;
59 }
60 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)61 void ExtensionApiTest::ResultCatcher::Observe(
62     NotificationType type, const NotificationSource& source,
63     const NotificationDetails& details) {
64   if (profile_restriction_ &&
65       Source<Profile>(source).ptr() != profile_restriction_) {
66     return;
67   }
68 
69   switch (type.value) {
70     case NotificationType::EXTENSION_TEST_PASSED:
71       VLOG(1) << "Got EXTENSION_TEST_PASSED notification.";
72       results_.push_back(true);
73       messages_.push_back("");
74       if (waiting_)
75         MessageLoopForUI::current()->Quit();
76       break;
77 
78     case NotificationType::EXTENSION_TEST_FAILED:
79       VLOG(1) << "Got EXTENSION_TEST_FAILED notification.";
80       results_.push_back(false);
81       messages_.push_back(*(Details<std::string>(details).ptr()));
82       if (waiting_)
83         MessageLoopForUI::current()->Quit();
84       break;
85 
86     default:
87       NOTREACHED();
88   }
89 }
90 
SetUpInProcessBrowserTestFixture()91 void ExtensionApiTest::SetUpInProcessBrowserTestFixture() {
92   DCHECK(!test_config_.get()) << "Previous test did not clear config state.";
93   test_config_.reset(new DictionaryValue());
94   ExtensionTestGetConfigFunction::set_test_config_state(test_config_.get());
95 }
96 
TearDownInProcessBrowserTestFixture()97 void ExtensionApiTest::TearDownInProcessBrowserTestFixture() {
98   ExtensionTestGetConfigFunction::set_test_config_state(NULL);
99   test_config_.reset(NULL);
100 }
101 
RunExtensionTest(const char * extension_name)102 bool ExtensionApiTest::RunExtensionTest(const char* extension_name) {
103   return RunExtensionTestImpl(extension_name, "", false, true, false);
104 }
105 
RunExtensionTestIncognito(const char * extension_name)106 bool ExtensionApiTest::RunExtensionTestIncognito(const char* extension_name) {
107   return RunExtensionTestImpl(extension_name, "", true, true, false);
108 }
109 
RunComponentExtensionTest(const char * extension_name)110 bool ExtensionApiTest::RunComponentExtensionTest(const char* extension_name) {
111   return RunExtensionTestImpl(extension_name, "", false, true, true);
112 }
113 
RunExtensionTestNoFileAccess(const char * extension_name)114 bool ExtensionApiTest::RunExtensionTestNoFileAccess(
115     const char* extension_name) {
116   return RunExtensionTestImpl(extension_name, "", false, false, false);
117 }
118 
RunExtensionTestIncognitoNoFileAccess(const char * extension_name)119 bool ExtensionApiTest::RunExtensionTestIncognitoNoFileAccess(
120     const char* extension_name) {
121   return RunExtensionTestImpl(extension_name, "", true, false, false);
122 }
RunExtensionSubtest(const char * extension_name,const std::string & page_url)123 bool ExtensionApiTest::RunExtensionSubtest(const char* extension_name,
124                                            const std::string& page_url) {
125   DCHECK(!page_url.empty()) << "Argument page_url is required.";
126   return RunExtensionTestImpl(extension_name, page_url, false, true, false);
127 }
128 
RunPageTest(const std::string & page_url)129 bool ExtensionApiTest::RunPageTest(const std::string& page_url) {
130   return RunExtensionSubtest("", page_url);
131 }
132 
133 // Load |extension_name| extension and/or |page_url| and wait for
134 // PASSED or FAILED notification.
RunExtensionTestImpl(const char * extension_name,const std::string & page_url,bool enable_incognito,bool enable_fileaccess,bool load_as_component)135 bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
136                                             const std::string& page_url,
137                                             bool enable_incognito,
138                                             bool enable_fileaccess,
139                                             bool load_as_component) {
140   ResultCatcher catcher;
141   DCHECK(!std::string(extension_name).empty() || !page_url.empty()) <<
142       "extension_name and page_url cannot both be empty";
143 
144   if (!std::string(extension_name).empty()) {
145     bool loaded = false;
146     if (load_as_component) {
147       loaded =
148           LoadExtensionAsComponent(test_data_dir_.AppendASCII(extension_name));
149     } else {
150       if (enable_incognito) {
151         loaded = enable_fileaccess ?
152           LoadExtensionIncognito(test_data_dir_.AppendASCII(extension_name)) :
153           LoadExtensionIncognitoNoFileAccess(
154               test_data_dir_.AppendASCII(extension_name));
155       } else {
156         loaded = enable_fileaccess ?
157           LoadExtension(test_data_dir_.AppendASCII(extension_name)) :
158           LoadExtensionNoFileAccess(test_data_dir_.AppendASCII(extension_name));
159       }
160     }
161     if (!loaded) {
162       message_ = "Failed to load extension.";
163       return false;
164     }
165   }
166 
167   // If there is a page_url to load, navigate it.
168   if (!page_url.empty()) {
169     GURL url = GURL(page_url);
170 
171     // Note: We use is_valid() here in the expectation that the provided url
172     // may lack a scheme & host and thus be a relative url within the loaded
173     // extension.
174     if (!url.is_valid()) {
175       DCHECK(!std::string(extension_name).empty()) <<
176           "Relative page_url given with no extension_name";
177 
178       ExtensionService* service = browser()->profile()->GetExtensionService();
179       const Extension* extension =
180           service->GetExtensionById(last_loaded_extension_id_, false);
181       if (!extension)
182         return false;
183 
184       url = extension->GetResourceURL(page_url);
185     }
186 
187     ui_test_utils::NavigateToURL(browser(), url);
188   }
189 
190   if (!catcher.GetNextResult()) {
191     message_ = catcher.message();
192     return false;
193   } else {
194     return true;
195   }
196 }
197 
198 // Test that exactly one extension loaded.
GetSingleLoadedExtension()199 const Extension* ExtensionApiTest::GetSingleLoadedExtension() {
200   ExtensionService* service = browser()->profile()->GetExtensionService();
201 
202   int found_extension_index = -1;
203   for (size_t i = 0; i < service->extensions()->size(); ++i) {
204     // Ignore any component extensions. They are automatically loaded into all
205     // profiles and aren't the extension we're looking for here.
206     if (service->extensions()->at(i)->location() == Extension::COMPONENT)
207       continue;
208 
209     if (found_extension_index != -1) {
210       message_ = base::StringPrintf(
211           "Expected only one extension to be present.  Found %u.",
212           static_cast<unsigned>(service->extensions()->size()));
213       return NULL;
214     }
215 
216     found_extension_index = static_cast<int>(i);
217   }
218 
219   const Extension* extension = service->extensions()->at(found_extension_index);
220   if (!extension) {
221     message_ = "extension pointer is NULL.";
222     return NULL;
223   }
224   return extension;
225 }
226 
StartTestServer()227 bool ExtensionApiTest::StartTestServer() {
228   if (!test_server()->Start())
229     return false;
230 
231   // Build a dictionary of values that tests can use to build URLs that
232   // access the test server.  Tests can see these values using the extension
233   // API function chrome.test.getConfig().
234   test_config_->SetInteger(kTestServerPort,
235                            test_server()->host_port_pair().port());
236 
237   return true;
238 }
239 
SetUpCommandLine(CommandLine * command_line)240 void ExtensionApiTest::SetUpCommandLine(CommandLine* command_line) {
241   ExtensionBrowserTest::SetUpCommandLine(command_line);
242   test_data_dir_ = test_data_dir_.AppendASCII("api_test");
243 }
244