blob: 06ffcadc4bbec7632e6ef98a46b937542d21f8bc [file] [log] [blame]
[email protected]582f6e92014-07-16 23:39:151// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]1164b862012-05-09 22:38:372// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]582f6e92014-07-16 23:39:155#include "extensions/renderer/module_system_test.h"
6
avi2d124c02015-12-23 06:36:427#include <stddef.h>
8
[email protected]582f6e92014-07-16 23:39:159#include <map>
dchengf6f80662016-04-20 20:26:0410#include <memory>
[email protected]582f6e92014-07-16 23:39:1511#include <string>
dchenge59eca1602015-12-18 17:48:0012#include <utility>
[email protected]1164b862012-05-09 22:38:3713
14#include "base/callback.h"
rdevlin.cronin585b1252016-04-19 23:29:2615#include "base/command_line.h"
Devlin Cronina3fe3d602017-11-22 04:47:4316#include "base/feature_list.h"
[email protected]f8d87d32013-06-06 02:51:2917#include "base/files/file_path.h"
thestig94712702014-09-10 07:46:5918#include "base/files/file_util.h"
[email protected]295890bd2013-06-15 10:52:4519#include "base/lazy_instance.h"
[email protected]f8d87d32013-06-06 02:51:2920#include "base/path_service.h"
Gabriel Charette078e3662017-08-28 22:59:0421#include "base/run_loop.h"
[email protected]4570a252013-03-31 00:35:4322#include "base/strings/string_piece.h"
Devlin Cronin2db58e32017-08-15 21:29:2923#include "extensions/common/extension_builder.h"
Devlin Cronina3fe3d602017-11-22 04:47:4324#include "extensions/common/extension_features.h"
[email protected]582f6e92014-07-16 23:39:1525#include "extensions/common/extension_paths.h"
Devlin Cronin2db58e32017-08-15 21:29:2926#include "extensions/common/value_builder.h"
Devlin Cronin8cade482017-07-20 03:09:3127#include "extensions/renderer/ipc_message_sender.h"
[email protected]701a94e2014-04-17 04:37:3728#include "extensions/renderer/logging_native_handler.h"
Devlin Cronin8cade482017-07-20 03:09:3129#include "extensions/renderer/native_extension_bindings_system.h"
[email protected]f55c90ee62014-04-12 00:50:0330#include "extensions/renderer/object_backed_native_handler.h"
kalman33076cb2015-08-11 19:12:0731#include "extensions/renderer/safe_builtins.h"
Devlin Cronin8cade482017-07-20 03:09:3132#include "extensions/renderer/script_context_set.h"
rdevlin.cronin892cc672016-12-19 20:00:1833#include "extensions/renderer/string_source_map.h"
34#include "extensions/renderer/test_v8_extension_configuration.h"
[email protected]701a94e2014-04-17 04:37:3735#include "extensions/renderer/utils_native_handler.h"
Devlin Cronin8cade482017-07-20 03:09:3136#include "gin/converter.h"
[email protected]11844fa2012-05-10 00:35:5937#include "ui/base/resource/resource_bundle.h"
[email protected]1164b862012-05-09 22:38:3738
[email protected]582f6e92014-07-16 23:39:1539namespace extensions {
[email protected]295890bd2013-06-15 10:52:4540namespace {
41
42class FailsOnException : public ModuleSystem::ExceptionHandler {
43 public:
bashi6a4854f2015-06-19 00:51:5144 FailsOnException() : ModuleSystem::ExceptionHandler(nullptr) {}
dcheng9168b2f2014-10-21 12:38:2445 void HandleUncaughtException(const v8::TryCatch& try_catch) override {
[email protected]295890bd2013-06-15 10:52:4546 FAIL() << "Uncaught exception: " << CreateExceptionString(try_catch);
47 }
48};
49
Devlin Cronin8cade482017-07-20 03:09:3150class GetAPINatives : public ObjectBackedNativeHandler {
51 public:
52 GetAPINatives(ScriptContext* context,
53 NativeExtensionBindingsSystem* bindings_system)
Devlin Cronind9ea8342018-01-27 06:00:0454 : ObjectBackedNativeHandler(context), bindings_system_(bindings_system) {
Devlin Cronina3fe3d602017-11-22 04:47:4355 DCHECK_EQ(base::FeatureList::IsEnabled(features::kNativeCrxBindings),
Devlin Cronin8cade482017-07-20 03:09:3156 !!bindings_system);
Devlin Cronind9ea8342018-01-27 06:00:0457 }
58 ~GetAPINatives() override {}
Devlin Cronin8cade482017-07-20 03:09:3159
Devlin Cronind9ea8342018-01-27 06:00:0460 // ObjectBackedNativeHandler:
61 void AddRoutes() override {
Devlin Cronin8cade482017-07-20 03:09:3162 auto get_api = [](ScriptContext* context,
63 NativeExtensionBindingsSystem* bindings_system,
64 const v8::FunctionCallbackInfo<v8::Value>& args) {
65 CHECK_EQ(1, args.Length());
66 CHECK(args[0]->IsString());
Dan Elphick38a508052018-07-23 22:19:5367 std::string api_name = gin::V8ToString(context->isolate(), args[0]);
Devlin Cronin8cade482017-07-20 03:09:3168 v8::Local<v8::Object> api;
69 if (bindings_system) {
70 api = bindings_system->GetAPIObjectForTesting(context, api_name);
71 } else {
72 v8::Local<v8::Object> full_binding;
73 CHECK(
74 context->module_system()->Require(api_name).ToLocal(&full_binding))
75 << "Failed to get: " << api_name;
76 v8::Local<v8::Value> api_value;
77 CHECK(full_binding
78 ->Get(context->v8_context(),
79 gin::StringToSymbol(context->isolate(), "binding"))
80 .ToLocal(&api_value))
81 << "Failed to get: " << api_name;
82 CHECK(api_value->IsObject()) << "Failed to get: " << api_name;
83 api = api_value.As<v8::Object>();
84 }
85 args.GetReturnValue().Set(api);
86 };
87
Devlin Cronind9ea8342018-01-27 06:00:0488 RouteHandlerFunction("get",
89 base::Bind(get_api, context(), bindings_system_));
Devlin Cronin8cade482017-07-20 03:09:3190 }
Devlin Cronind9ea8342018-01-27 06:00:0491
92 private:
93 NativeExtensionBindingsSystem* bindings_system_ = nullptr;
94
95 DISALLOW_COPY_AND_ASSIGN(GetAPINatives);
Devlin Cronin8cade482017-07-20 03:09:3196};
97
[email protected]295890bd2013-06-15 10:52:4598} // namespace
99
[email protected]1164b862012-05-09 22:38:37100// Native JS functions for doing asserts.
[email protected]d9f51dad2014-07-09 05:39:38101class ModuleSystemTestEnvironment::AssertNatives
102 : public ObjectBackedNativeHandler {
[email protected]1164b862012-05-09 22:38:37103 public:
[email protected]582f6e92014-07-16 23:39:15104 explicit AssertNatives(ScriptContext* context)
[email protected]4f1633f2013-03-09 14:26:24105 : ObjectBackedNativeHandler(context),
[email protected]2e0e0bc2013-02-04 10:30:34106 assertion_made_(false),
Devlin Cronind9ea8342018-01-27 06:00:04107 failed_(false) {}
108
109 // ObjectBackedNativeHandler:
110 void AddRoutes() override {
111 RouteHandlerFunction("AssertTrue", base::Bind(&AssertNatives::AssertTrue,
112 base::Unretained(this)));
113 RouteHandlerFunction("AssertFalse", base::Bind(&AssertNatives::AssertFalse,
114 base::Unretained(this)));
[email protected]1164b862012-05-09 22:38:37115 }
116
117 bool assertion_made() { return assertion_made_; }
118 bool failed() { return failed_; }
119
[email protected]d8c5fbb2013-06-14 11:35:25120 void AssertTrue(const v8::FunctionCallbackInfo<v8::Value>& args) {
[email protected]1164b862012-05-09 22:38:37121 CHECK_EQ(1, args.Length());
122 assertion_made_ = true;
dcarney04cd9642014-11-21 13:58:11123 failed_ = failed_ || !args[0]->ToBoolean(args.GetIsolate())->Value();
[email protected]1164b862012-05-09 22:38:37124 }
125
[email protected]d8c5fbb2013-06-14 11:35:25126 void AssertFalse(const v8::FunctionCallbackInfo<v8::Value>& args) {
[email protected]1164b862012-05-09 22:38:37127 CHECK_EQ(1, args.Length());
128 assertion_made_ = true;
dcarney04cd9642014-11-21 13:58:11129 failed_ = failed_ || args[0]->ToBoolean(args.GetIsolate())->Value();
[email protected]1164b862012-05-09 22:38:37130 }
131
132 private:
133 bool assertion_made_;
134 bool failed_;
135};
136
Devlin Cronin8cade482017-07-20 03:09:31137ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(
138 v8::Isolate* isolate,
Devlin Cronin2db58e32017-08-15 21:29:29139 ScriptContextSet* context_set,
140 scoped_refptr<const Extension> extension)
[email protected]99ea16b2014-07-17 22:15:56141 : isolate_(isolate),
142 context_holder_(new gin::ContextHolder(isolate_)),
143 handle_scope_(isolate_),
Devlin Cronin2db58e32017-08-15 21:29:29144 extension_(extension),
Devlin Cronin8cade482017-07-20 03:09:31145 context_set_(context_set),
[email protected]d9f51dad2014-07-09 05:39:38146 source_map_(new StringSourceMap()) {
kalman33076cb2015-08-11 19:12:07147 context_holder_->SetContext(v8::Context::New(
rdevlin.cronin892cc672016-12-19 20:00:18148 isolate, TestV8ExtensionConfiguration::GetConfiguration()));
Devlin Cronin8cade482017-07-20 03:09:31149
150 {
Jeremy Roman16529d0e2017-08-24 18:13:47151 auto context = std::make_unique<ScriptContext>(
Devlin Cronin2db58e32017-08-15 21:29:29152 context_holder_->context(),
153 nullptr, // WebFrame
154 extension_.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension_.get(),
155 Feature::BLESSED_EXTENSION_CONTEXT);
Devlin Cronin8cade482017-07-20 03:09:31156 context_ = context.get();
157 context_set_->AddForTesting(std::move(context));
158 }
159
[email protected]9a598442013-06-04 16:39:12160 context_->v8_context()->Enter();
Devlin Cronin8cade482017-07-20 03:09:31161 assert_natives_ = new AssertNatives(context_);
162
Devlin Cronina3fe3d602017-11-22 04:47:43163 if (base::FeatureList::IsEnabled(features::kNativeCrxBindings))
Jeremy Roman16529d0e2017-08-24 18:13:47164 bindings_system_ = std::make_unique<NativeExtensionBindingsSystem>(nullptr);
[email protected]2a356872014-02-21 23:18:52165
166 {
dchengf6f80662016-04-20 20:26:04167 std::unique_ptr<ModuleSystem> module_system(
Devlin Cronin8cade482017-07-20 03:09:31168 new ModuleSystem(context_, source_map_.get()));
Devlin Cronind9ea8342018-01-27 06:00:04169 context_->SetModuleSystem(std::move(module_system));
[email protected]2a356872014-02-21 23:18:52170 }
171 ModuleSystem* module_system = context_->module_system();
[email protected]582f6e92014-07-16 23:39:15172 module_system->RegisterNativeHandler(
dchengf6f80662016-04-20 20:26:04173 "assert", std::unique_ptr<NativeHandler>(assert_natives_));
[email protected]582f6e92014-07-16 23:39:15174 module_system->RegisterNativeHandler(
175 "logging",
Devlin Cronin8cade482017-07-20 03:09:31176 std::unique_ptr<NativeHandler>(new LoggingNativeHandler(context_)));
[email protected]582f6e92014-07-16 23:39:15177 module_system->RegisterNativeHandler(
178 "utils",
Devlin Cronin8cade482017-07-20 03:09:31179 std::unique_ptr<NativeHandler>(new UtilsNativeHandler(context_)));
180 module_system->RegisterNativeHandler(
181 "apiGetter",
Jeremy Roman16529d0e2017-08-24 18:13:47182 std::make_unique<GetAPINatives>(context_, bindings_system_.get()));
[email protected]2a356872014-02-21 23:18:52183 module_system->SetExceptionHandlerForTest(
dchengf6f80662016-04-20 20:26:04184 std::unique_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));
Devlin Cronin8cade482017-07-20 03:09:31185
186 if (bindings_system_) {
187 bindings_system_->DidCreateScriptContext(context_);
188 bindings_system_->UpdateBindingsForContext(context_);
189 }
[email protected]1164b862012-05-09 22:38:37190}
191
[email protected]d9f51dad2014-07-09 05:39:38192ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() {
Devlin Cronin8cade482017-07-20 03:09:31193 if (context_)
kalmanb0c1c502015-04-15 00:25:06194 ShutdownModuleSystem();
[email protected]1164b862012-05-09 22:38:37195}
196
[email protected]d9f51dad2014-07-09 05:39:38197void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
198 const std::string& code) {
[email protected]1164b862012-05-09 22:38:37199 source_map_->RegisterModule(name, code);
200}
201
[email protected]d9f51dad2014-07-09 05:39:38202void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
Yuzhu Shenbcd734d2017-11-15 20:40:58203 int resource_id,
204 bool gzipped) {
Lei Zhangcf30efc2017-10-04 21:31:24205 const std::string& code = ui::ResourceBundle::GetSharedInstance()
[email protected]582f6e92014-07-16 23:39:15206 .GetRawDataResource(resource_id)
207 .as_string();
Yuzhu Shenbcd734d2017-11-15 20:40:58208 source_map_->RegisterModule(name, code, gzipped);
[email protected]11844fa2012-05-10 00:35:59209}
210
[email protected]d9f51dad2014-07-09 05:39:38211void ModuleSystemTestEnvironment::OverrideNativeHandler(
212 const std::string& name,
213 const std::string& code) {
[email protected]11844fa2012-05-10 00:35:59214 RegisterModule(name, code);
[email protected]2a356872014-02-21 23:18:52215 context_->module_system()->OverrideNativeHandlerForTest(name);
[email protected]11844fa2012-05-10 00:35:59216}
217
[email protected]d9f51dad2014-07-09 05:39:38218void ModuleSystemTestEnvironment::RegisterTestFile(
219 const std::string& module_name,
220 const std::string& file_name) {
[email protected]f8d87d32013-06-06 02:51:29221 base::FilePath test_js_file_path;
Avi Drissman210441b72018-05-01 15:51:00222 ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_js_file_path));
[email protected]582f6e92014-07-16 23:39:15223 test_js_file_path = test_js_file_path.AppendASCII(file_name);
[email protected]f8d87d32013-06-06 02:51:29224 std::string test_js;
[email protected]82f84b92013-08-30 18:23:50225 ASSERT_TRUE(base::ReadFileToString(test_js_file_path, &test_js));
[email protected]f8d87d32013-06-06 02:51:29226 source_map_->RegisterModule(module_name, test_js);
227}
228
[email protected]d9f51dad2014-07-09 05:39:38229void ModuleSystemTestEnvironment::ShutdownGin() {
230 context_holder_.reset();
231}
232
233void ModuleSystemTestEnvironment::ShutdownModuleSystem() {
kalmanb0c1c502015-04-15 00:25:06234 CHECK(context_->is_valid());
[email protected]d9f51dad2014-07-09 05:39:38235 context_->v8_context()->Exit();
Devlin Cronin8cade482017-07-20 03:09:31236 context_set_->Remove(context_);
237 base::RunLoop().RunUntilIdle();
238 context_ = nullptr;
239 assert_natives_ = nullptr;
[email protected]d9f51dad2014-07-09 05:39:38240}
241
tfarinaf85316f2015-04-29 17:03:40242v8::Local<v8::Object> ModuleSystemTestEnvironment::CreateGlobal(
[email protected]d9f51dad2014-07-09 05:39:38243 const std::string& name) {
[email protected]99ea16b2014-07-17 22:15:56244 v8::EscapableHandleScope handle_scope(isolate_);
245 v8::Local<v8::Object> object = v8::Object::New(isolate_);
246 isolate_->GetCurrentContext()->Global()->Set(
247 v8::String::NewFromUtf8(isolate_, name.c_str()), object);
[email protected]d9f51dad2014-07-09 05:39:38248 return handle_scope.Escape(object);
249}
250
251ModuleSystemTest::ModuleSystemTest()
[email protected]99ea16b2014-07-17 22:15:56252 : isolate_(v8::Isolate::GetCurrent()),
Devlin Cronin8cade482017-07-20 03:09:31253 context_set_(&extension_ids_),
254 should_assertions_be_made_(true) {}
[email protected]d9f51dad2014-07-09 05:39:38255
256ModuleSystemTest::~ModuleSystemTest() {
257}
258
sammc32a6fc7d2014-09-15 02:47:31259void ModuleSystemTest::SetUp() {
Devlin Cronin2db58e32017-08-15 21:29:29260 extension_ = CreateExtension();
sammc32a6fc7d2014-09-15 02:47:31261 env_ = CreateEnvironment();
rdevlin.cronin585b1252016-04-19 23:29:26262 base::CommandLine::ForCurrentProcess()->AppendSwitch("test-type");
sammc32a6fc7d2014-09-15 02:47:31263}
264
[email protected]1164b862012-05-09 22:38:37265void ModuleSystemTest::TearDown() {
[email protected]1164b862012-05-09 22:38:37266 // All tests must assert at least once unless otherwise specified.
Devlin Cronin8cade482017-07-20 03:09:31267 if (env_->assert_natives()) { // The context may have already been shutdown.
268 EXPECT_EQ(should_assertions_be_made_,
269 env_->assert_natives()->assertion_made());
270 EXPECT_FALSE(env_->assert_natives()->failed());
271 } else {
272 EXPECT_FALSE(should_assertions_be_made_);
273 }
sammc32a6fc7d2014-09-15 02:47:31274 env_.reset();
275 v8::HeapStatistics stats;
276 isolate_->GetHeapStatistics(&stats);
277 size_t old_heap_size = 0;
278 // Run the GC until the heap size reaches a steady state to ensure that
279 // all the garbage is collected.
280 while (stats.used_heap_size() != old_heap_size) {
281 old_heap_size = stats.used_heap_size();
282 isolate_->RequestGarbageCollectionForTesting(
283 v8::Isolate::kFullGarbageCollection);
284 isolate_->GetHeapStatistics(&stats);
285 }
[email protected]d9f51dad2014-07-09 05:39:38286}
287
Devlin Cronin2db58e32017-08-15 21:29:29288scoped_refptr<const Extension> ModuleSystemTest::CreateExtension() {
289 std::unique_ptr<base::DictionaryValue> manifest =
290 DictionaryBuilder()
291 .Set("name", "test")
292 .Set("version", "1.0")
293 .Set("manifest_version", 2)
294 .Build();
295 return ExtensionBuilder().SetManifest(std::move(manifest)).Build();
296}
297
dchengf6f80662016-04-20 20:26:04298std::unique_ptr<ModuleSystemTestEnvironment>
299ModuleSystemTest::CreateEnvironment() {
Jeremy Roman16529d0e2017-08-24 18:13:47300 return std::make_unique<ModuleSystemTestEnvironment>(isolate_, &context_set_,
Devlin Cronin2db58e32017-08-15 21:29:29301 extension_);
[email protected]1164b862012-05-09 22:38:37302}
303
304void ModuleSystemTest::ExpectNoAssertionsMade() {
305 should_assertions_be_made_ = false;
306}
307
[email protected]d9f51dad2014-07-09 05:39:38308void ModuleSystemTest::RunResolvedPromises() {
dgozmanfdfd5d12016-03-11 07:50:47309 v8::MicrotasksScope::PerformCheckpoint(isolate_);
[email protected]1164b862012-05-09 22:38:37310}
[email protected]582f6e92014-07-16 23:39:15311
312} // namespace extensions