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