Home | History | Annotate | Download | only in extensions
      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 
     22 ExtensionApiTest::ExtensionApiTest() {}
     23 
     24 ExtensionApiTest::~ExtensionApiTest() {}
     25 
     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 
     35 ExtensionApiTest::ResultCatcher::~ResultCatcher() {
     36 }
     37 
     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 
     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 
     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 
     97 void ExtensionApiTest::TearDownInProcessBrowserTestFixture() {
     98   ExtensionTestGetConfigFunction::set_test_config_state(NULL);
     99   test_config_.reset(NULL);
    100 }
    101 
    102 bool ExtensionApiTest::RunExtensionTest(const char* extension_name) {
    103   return RunExtensionTestImpl(extension_name, "", false, true, false);
    104 }
    105 
    106 bool ExtensionApiTest::RunExtensionTestIncognito(const char* extension_name) {
    107   return RunExtensionTestImpl(extension_name, "", true, true, false);
    108 }
    109 
    110 bool ExtensionApiTest::RunComponentExtensionTest(const char* extension_name) {
    111   return RunExtensionTestImpl(extension_name, "", false, true, true);
    112 }
    113 
    114 bool ExtensionApiTest::RunExtensionTestNoFileAccess(
    115     const char* extension_name) {
    116   return RunExtensionTestImpl(extension_name, "", false, false, false);
    117 }
    118 
    119 bool ExtensionApiTest::RunExtensionTestIncognitoNoFileAccess(
    120     const char* extension_name) {
    121   return RunExtensionTestImpl(extension_name, "", true, false, false);
    122 }
    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 
    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.
    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.
    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 
    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 
    240 void ExtensionApiTest::SetUpCommandLine(CommandLine* command_line) {
    241   ExtensionBrowserTest::SetUpCommandLine(command_line);
    242   test_data_dir_ = test_data_dir_.AppendASCII("api_test");
    243 }
    244