Home | History | Annotate | Download | only in renderer
      1 // Copyright 2014 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 "extensions/renderer/api_test_base.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/run_loop.h"
     10 #include "extensions/common/extension_urls.h"
     11 #include "extensions/renderer/dispatcher.h"
     12 #include "extensions/renderer/process_info_native_handler.h"
     13 #include "gin/converter.h"
     14 #include "gin/dictionary.h"
     15 #include "mojo/bindings/js/core.h"
     16 #include "mojo/bindings/js/handle.h"
     17 #include "mojo/bindings/js/support.h"
     18 #include "mojo/public/cpp/bindings/interface_request.h"
     19 #include "mojo/public/cpp/system/core.h"
     20 
     21 namespace extensions {
     22 namespace {
     23 
     24 // Natives for the implementation of the unit test version of chrome.test. Calls
     25 // the provided |quit_closure| when either notifyPass or notifyFail is called.
     26 class TestNatives : public gin::Wrappable<TestNatives> {
     27  public:
     28   static gin::Handle<TestNatives> Create(v8::Isolate* isolate,
     29                                          const base::Closure& quit_closure) {
     30     return gin::CreateHandle(isolate, new TestNatives(quit_closure));
     31   }
     32 
     33   virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
     34       v8::Isolate* isolate) OVERRIDE {
     35     return Wrappable<TestNatives>::GetObjectTemplateBuilder(isolate)
     36         .SetMethod("Log", &TestNatives::Log)
     37         .SetMethod("NotifyPass", &TestNatives::NotifyPass)
     38         .SetMethod("NotifyFail", &TestNatives::NotifyFail);
     39   }
     40 
     41   void Log(const std::string& value) { logs_ += value + "\n"; }
     42   void NotifyPass() { FinishTesting(); }
     43 
     44   void NotifyFail(const std::string& message) {
     45     FinishTesting();
     46     FAIL() << logs_ << message;
     47   }
     48 
     49   void FinishTesting() {
     50     base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_);
     51   }
     52 
     53   static gin::WrapperInfo kWrapperInfo;
     54 
     55  private:
     56   explicit TestNatives(const base::Closure& quit_closure)
     57       : quit_closure_(quit_closure) {}
     58 
     59   const base::Closure quit_closure_;
     60   std::string logs_;
     61 };
     62 
     63 gin::WrapperInfo TestNatives::kWrapperInfo = {gin::kEmbedderNativeGin};
     64 
     65 }  // namespace
     66 
     67 gin::WrapperInfo TestServiceProvider::kWrapperInfo = {gin::kEmbedderNativeGin};
     68 
     69 gin::Handle<TestServiceProvider> TestServiceProvider::Create(
     70     v8::Isolate* isolate) {
     71   return gin::CreateHandle(isolate, new TestServiceProvider());
     72 }
     73 
     74 TestServiceProvider::~TestServiceProvider() {
     75 }
     76 
     77 gin::ObjectTemplateBuilder TestServiceProvider::GetObjectTemplateBuilder(
     78     v8::Isolate* isolate) {
     79   return Wrappable<TestServiceProvider>::GetObjectTemplateBuilder(isolate)
     80       .SetMethod("connectToService", &TestServiceProvider::ConnectToService);
     81 }
     82 
     83 mojo::Handle TestServiceProvider::ConnectToService(
     84     const std::string& service_name) {
     85   EXPECT_EQ(1u, service_factories_.count(service_name))
     86       << "Unregistered service " << service_name << " requested.";
     87   mojo::MessagePipe pipe;
     88   std::map<std::string,
     89            base::Callback<void(mojo::ScopedMessagePipeHandle)> >::iterator it =
     90       service_factories_.find(service_name);
     91   if (it != service_factories_.end())
     92     it->second.Run(pipe.handle0.Pass());
     93   return pipe.handle1.release();
     94 }
     95 
     96 TestServiceProvider::TestServiceProvider() {
     97 }
     98 
     99 ApiTestBase::ApiTestBase() {
    100 }
    101 ApiTestBase::~ApiTestBase() {
    102 }
    103 
    104 void ApiTestBase::SetUp() {
    105   ModuleSystemTest::SetUp();
    106   InitializeEnvironment();
    107   RegisterModules();
    108 }
    109 
    110 void ApiTestBase::RegisterModules() {
    111   v8_schema_registry_.reset(new V8SchemaRegistry);
    112   const std::vector<std::pair<std::string, int> > resources =
    113       Dispatcher::GetJsResources();
    114   for (std::vector<std::pair<std::string, int> >::const_iterator resource =
    115            resources.begin();
    116        resource != resources.end();
    117        ++resource) {
    118     if (resource->first != "test_environment_specific_bindings")
    119       env()->RegisterModule(resource->first, resource->second);
    120   }
    121   Dispatcher::RegisterNativeHandlers(env()->module_system(),
    122                                      env()->context(),
    123                                      NULL,
    124                                      NULL,
    125                                      v8_schema_registry_.get());
    126   env()->module_system()->RegisterNativeHandler(
    127       "process",
    128       scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler(
    129           env()->context(),
    130           env()->context()->GetExtensionID(),
    131           env()->context()->GetContextTypeDescription(),
    132           false,
    133           2,
    134           false)));
    135   env()->RegisterTestFile("test_environment_specific_bindings",
    136                           "unit_test_environment_specific_bindings.js");
    137 
    138   env()->OverrideNativeHandler("activityLogger",
    139                                "exports.LogAPICall = function() {};");
    140   env()->OverrideNativeHandler(
    141       "apiDefinitions",
    142       "exports.GetExtensionAPIDefinitionsForTest = function() { return [] };");
    143   env()->OverrideNativeHandler(
    144       "event_natives",
    145       "exports.AttachEvent = function() {};"
    146       "exports.DetachEvent = function() {};"
    147       "exports.AttachFilteredEvent = function() {};"
    148       "exports.AttachFilteredEvent = function() {};"
    149       "exports.MatchAgainstEventFilter = function() { return [] };");
    150 
    151   gin::ModuleRegistry::From(env()->context()->v8_context())
    152       ->AddBuiltinModule(env()->isolate(),
    153                          mojo::js::Core::kModuleName,
    154                          mojo::js::Core::GetModule(env()->isolate()));
    155   gin::ModuleRegistry::From(env()->context()->v8_context())
    156       ->AddBuiltinModule(env()->isolate(),
    157                          mojo::js::Support::kModuleName,
    158                          mojo::js::Support::GetModule(env()->isolate()));
    159   gin::Handle<TestServiceProvider> service_provider =
    160       TestServiceProvider::Create(env()->isolate());
    161   service_provider_ = service_provider.get();
    162   gin::ModuleRegistry::From(env()->context()->v8_context())
    163       ->AddBuiltinModule(env()->isolate(),
    164                          "content/public/renderer/service_provider",
    165                          service_provider.ToV8());
    166 }
    167 
    168 void ApiTestBase::InitializeEnvironment() {
    169   gin::Dictionary global(env()->isolate(),
    170                          env()->context()->v8_context()->Global());
    171   gin::Dictionary navigator(gin::Dictionary::CreateEmpty(env()->isolate()));
    172   navigator.Set("appVersion", base::StringPiece(""));
    173   global.Set("navigator", navigator);
    174   gin::Dictionary chrome(gin::Dictionary::CreateEmpty(env()->isolate()));
    175   global.Set("chrome", chrome);
    176   gin::Dictionary extension(gin::Dictionary::CreateEmpty(env()->isolate()));
    177   chrome.Set("extension", extension);
    178   gin::Dictionary runtime(gin::Dictionary::CreateEmpty(env()->isolate()));
    179   chrome.Set("runtime", runtime);
    180 }
    181 
    182 void ApiTestBase::RunTest(const std::string& file_name,
    183                           const std::string& test_name) {
    184   env()->RegisterTestFile("testBody", file_name);
    185   ExpectNoAssertionsMade();
    186   base::RunLoop run_loop;
    187   gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule(
    188       env()->isolate(),
    189       "testNatives",
    190       TestNatives::Create(env()->isolate(), run_loop.QuitClosure()).ToV8());
    191   base::MessageLoop::current()->PostTask(FROM_HERE,
    192                                          base::Bind(&ApiTestBase::RunTestInner,
    193                                                     base::Unretained(this),
    194                                                     test_name,
    195                                                     run_loop.QuitClosure()));
    196   base::MessageLoop::current()->PostTask(
    197       FROM_HERE,
    198       base::Bind(&ApiTestBase::RunPromisesAgain, base::Unretained(this)));
    199   run_loop.Run();
    200 }
    201 
    202 void ApiTestBase::RunTestInner(const std::string& test_name,
    203                                const base::Closure& quit_closure) {
    204   v8::HandleScope scope(env()->isolate());
    205   ModuleSystem::NativesEnabledScope natives_enabled(env()->module_system());
    206   v8::Handle<v8::Value> result =
    207       env()->module_system()->CallModuleMethod("testBody", test_name);
    208   if (!result->IsTrue()) {
    209     base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure);
    210     FAIL() << "Failed to run test \"" << test_name << "\"";
    211   }
    212 }
    213 
    214 void ApiTestBase::RunPromisesAgain() {
    215   RunResolvedPromises();
    216   base::MessageLoop::current()->PostTask(
    217       FROM_HERE,
    218       base::Bind(&ApiTestBase::RunPromisesAgain, base::Unretained(this)));
    219 }
    220 
    221 }  // namespace extensions
    222