blob: 95551cff23cd39fc850e68ead75c9f9f860a3eda [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
Devlin Cronincc02a0c2019-01-03 22:15:0714#include "base/bind.h"
[email protected]1164b862012-05-09 22:38:3715#include "base/callback.h"
rdevlin.cronin585b1252016-04-19 23:29:2616#include "base/command_line.h"
Findit59c7f1e2019-03-12 07:00:5617#include "base/feature_list.h"
[email protected]f8d87d32013-06-06 02:51:2918#include "base/files/file_path.h"
thestig94712702014-09-10 07:46:5919#include "base/files/file_util.h"
[email protected]295890bd2013-06-15 10:52:4520#include "base/lazy_instance.h"
[email protected]f8d87d32013-06-06 02:51:2921#include "base/path_service.h"
Gabriel Charette078e3662017-08-28 22:59:0422#include "base/run_loop.h"
[email protected]4570a252013-03-31 00:35:4323#include "base/strings/string_piece.h"
Devlin Cronin2db58e32017-08-15 21:29:2924#include "extensions/common/extension_builder.h"
Findit59c7f1e2019-03-12 07:00:5625#include "extensions/common/extension_features.h"
[email protected]582f6e92014-07-16 23:39:1526#include "extensions/common/extension_paths.h"
Devlin Cronin2db58e32017-08-15 21:29:2927#include "extensions/common/value_builder.h"
Devlin Cronin8cade482017-07-20 03:09:3128#include "extensions/renderer/ipc_message_sender.h"
[email protected]701a94e2014-04-17 04:37:3729#include "extensions/renderer/logging_native_handler.h"
Devlin Cronin8cade482017-07-20 03:09:3130#include "extensions/renderer/native_extension_bindings_system.h"
[email protected]f55c90ee62014-04-12 00:50:0331#include "extensions/renderer/object_backed_native_handler.h"
kalman33076cb2015-08-11 19:12:0732#include "extensions/renderer/safe_builtins.h"
Devlin Cronin8cade482017-07-20 03:09:3133#include "extensions/renderer/script_context_set.h"
rdevlin.cronin892cc672016-12-19 20:00:1834#include "extensions/renderer/string_source_map.h"
35#include "extensions/renderer/test_v8_extension_configuration.h"
[email protected]701a94e2014-04-17 04:37:3736#include "extensions/renderer/utils_native_handler.h"
Devlin Cronin8cade482017-07-20 03:09:3137#include "gin/converter.h"
[email protected]11844fa2012-05-10 00:35:5938#include "ui/base/resource/resource_bundle.h"
[email protected]1164b862012-05-09 22:38:3739
[email protected]582f6e92014-07-16 23:39:1540namespace extensions {
[email protected]295890bd2013-06-15 10:52:4541namespace {
42
43class FailsOnException : public ModuleSystem::ExceptionHandler {
44 public:
bashi6a4854f2015-06-19 00:51:5145 FailsOnException() : ModuleSystem::ExceptionHandler(nullptr) {}
dcheng9168b2f2014-10-21 12:38:2446 void HandleUncaughtException(const v8::TryCatch& try_catch) override {
[email protected]295890bd2013-06-15 10:52:4547 FAIL() << "Uncaught exception: " << CreateExceptionString(try_catch);
48 }
49};
50
Devlin Cronin8cade482017-07-20 03:09:3151class GetAPINatives : public ObjectBackedNativeHandler {
52 public:
53 GetAPINatives(ScriptContext* context,
54 NativeExtensionBindingsSystem* bindings_system)
Devlin Cronind9ea8342018-01-27 06:00:0455 : ObjectBackedNativeHandler(context), bindings_system_(bindings_system) {
Findit59c7f1e2019-03-12 07:00:5656 DCHECK_EQ(
57 base::FeatureList::IsEnabled(extensions_features::kNativeCrxBindings),
58 !!bindings_system);
Devlin Cronind9ea8342018-01-27 06:00:0459 }
60 ~GetAPINatives() override {}
Devlin Cronin8cade482017-07-20 03:09:3161
Devlin Cronind9ea8342018-01-27 06:00:0462 // ObjectBackedNativeHandler:
63 void AddRoutes() override {
Devlin Cronin8cade482017-07-20 03:09:3164 auto get_api = [](ScriptContext* context,
65 NativeExtensionBindingsSystem* bindings_system,
66 const v8::FunctionCallbackInfo<v8::Value>& args) {
67 CHECK_EQ(1, args.Length());
68 CHECK(args[0]->IsString());
Dan Elphick38a508052018-07-23 22:19:5369 std::string api_name = gin::V8ToString(context->isolate(), args[0]);
Devlin Cronin8cade482017-07-20 03:09:3170 v8::Local<v8::Object> api;
71 if (bindings_system) {
72 api = bindings_system->GetAPIObjectForTesting(context, api_name);
73 } else {
74 v8::Local<v8::Object> full_binding;
75 CHECK(
76 context->module_system()->Require(api_name).ToLocal(&full_binding))
77 << "Failed to get: " << api_name;
78 v8::Local<v8::Value> api_value;
79 CHECK(full_binding
80 ->Get(context->v8_context(),
81 gin::StringToSymbol(context->isolate(), "binding"))
82 .ToLocal(&api_value))
83 << "Failed to get: " << api_name;
84 CHECK(api_value->IsObject()) << "Failed to get: " << api_name;
85 api = api_value.As<v8::Object>();
86 }
87 args.GetReturnValue().Set(api);
88 };
89
Devlin Cronincc02a0c2019-01-03 22:15:0790 RouteHandlerFunction(
91 "get", base::BindRepeating(get_api, context(), bindings_system_));
Devlin Cronin8cade482017-07-20 03:09:3192 }
Devlin Cronind9ea8342018-01-27 06:00:0493
94 private:
95 NativeExtensionBindingsSystem* bindings_system_ = nullptr;
96
97 DISALLOW_COPY_AND_ASSIGN(GetAPINatives);
Devlin Cronin8cade482017-07-20 03:09:3198};
99
[email protected]295890bd2013-06-15 10:52:45100} // namespace
101
[email protected]1164b862012-05-09 22:38:37102// Native JS functions for doing asserts.
[email protected]d9f51dad2014-07-09 05:39:38103class ModuleSystemTestEnvironment::AssertNatives
104 : public ObjectBackedNativeHandler {
[email protected]1164b862012-05-09 22:38:37105 public:
[email protected]582f6e92014-07-16 23:39:15106 explicit AssertNatives(ScriptContext* context)
[email protected]4f1633f2013-03-09 14:26:24107 : ObjectBackedNativeHandler(context),
[email protected]2e0e0bc2013-02-04 10:30:34108 assertion_made_(false),
Devlin Cronind9ea8342018-01-27 06:00:04109 failed_(false) {}
110
111 // ObjectBackedNativeHandler:
112 void AddRoutes() override {
Devlin Cronincc02a0c2019-01-03 22:15:07113 RouteHandlerFunction("AssertTrue",
114 base::BindRepeating(&AssertNatives::AssertTrue,
115 base::Unretained(this)));
116 RouteHandlerFunction("AssertFalse",
117 base::BindRepeating(&AssertNatives::AssertFalse,
118 base::Unretained(this)));
[email protected]1164b862012-05-09 22:38:37119 }
120
121 bool assertion_made() { return assertion_made_; }
122 bool failed() { return failed_; }
123
[email protected]d8c5fbb2013-06-14 11:35:25124 void AssertTrue(const v8::FunctionCallbackInfo<v8::Value>& args) {
[email protected]1164b862012-05-09 22:38:37125 CHECK_EQ(1, args.Length());
126 assertion_made_ = true;
dcarney04cd9642014-11-21 13:58:11127 failed_ = failed_ || !args[0]->ToBoolean(args.GetIsolate())->Value();
[email protected]1164b862012-05-09 22:38:37128 }
129
[email protected]d8c5fbb2013-06-14 11:35:25130 void AssertFalse(const v8::FunctionCallbackInfo<v8::Value>& args) {
[email protected]1164b862012-05-09 22:38:37131 CHECK_EQ(1, args.Length());
132 assertion_made_ = true;
dcarney04cd9642014-11-21 13:58:11133 failed_ = failed_ || args[0]->ToBoolean(args.GetIsolate())->Value();
[email protected]1164b862012-05-09 22:38:37134 }
135
136 private:
137 bool assertion_made_;
138 bool failed_;
139};
140
Devlin Cronin8cade482017-07-20 03:09:31141ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(
142 v8::Isolate* isolate,
Devlin Cronin2db58e32017-08-15 21:29:29143 ScriptContextSet* context_set,
144 scoped_refptr<const Extension> extension)
[email protected]99ea16b2014-07-17 22:15:56145 : isolate_(isolate),
146 context_holder_(new gin::ContextHolder(isolate_)),
147 handle_scope_(isolate_),
Devlin Cronin2db58e32017-08-15 21:29:29148 extension_(extension),
Devlin Cronin8cade482017-07-20 03:09:31149 context_set_(context_set),
[email protected]d9f51dad2014-07-09 05:39:38150 source_map_(new StringSourceMap()) {
kalman33076cb2015-08-11 19:12:07151 context_holder_->SetContext(v8::Context::New(
rdevlin.cronin892cc672016-12-19 20:00:18152 isolate, TestV8ExtensionConfiguration::GetConfiguration()));
Devlin Cronin8cade482017-07-20 03:09:31153
154 {
Jeremy Roman16529d0e2017-08-24 18:13:47155 auto context = std::make_unique<ScriptContext>(
Devlin Cronin2db58e32017-08-15 21:29:29156 context_holder_->context(),
157 nullptr, // WebFrame
158 extension_.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension_.get(),
159 Feature::BLESSED_EXTENSION_CONTEXT);
Devlin Cronin8cade482017-07-20 03:09:31160 context_ = context.get();
161 context_set_->AddForTesting(std::move(context));
162 }
163
[email protected]9a598442013-06-04 16:39:12164 context_->v8_context()->Enter();
Devlin Cronin8cade482017-07-20 03:09:31165 assert_natives_ = new AssertNatives(context_);
166
Findit59c7f1e2019-03-12 07:00:56167 if (base::FeatureList::IsEnabled(extensions_features::kNativeCrxBindings))
168 bindings_system_ = std::make_unique<NativeExtensionBindingsSystem>(nullptr);
[email protected]2a356872014-02-21 23:18:52169
170 {
dchengf6f80662016-04-20 20:26:04171 std::unique_ptr<ModuleSystem> module_system(
Devlin Cronin8cade482017-07-20 03:09:31172 new ModuleSystem(context_, source_map_.get()));
Devlin Cronind9ea8342018-01-27 06:00:04173 context_->SetModuleSystem(std::move(module_system));
[email protected]2a356872014-02-21 23:18:52174 }
175 ModuleSystem* module_system = context_->module_system();
[email protected]582f6e92014-07-16 23:39:15176 module_system->RegisterNativeHandler(
dchengf6f80662016-04-20 20:26:04177 "assert", std::unique_ptr<NativeHandler>(assert_natives_));
[email protected]582f6e92014-07-16 23:39:15178 module_system->RegisterNativeHandler(
179 "logging",
Devlin Cronin8cade482017-07-20 03:09:31180 std::unique_ptr<NativeHandler>(new LoggingNativeHandler(context_)));
[email protected]582f6e92014-07-16 23:39:15181 module_system->RegisterNativeHandler(
182 "utils",
Devlin Cronin8cade482017-07-20 03:09:31183 std::unique_ptr<NativeHandler>(new UtilsNativeHandler(context_)));
184 module_system->RegisterNativeHandler(
185 "apiGetter",
Jeremy Roman16529d0e2017-08-24 18:13:47186 std::make_unique<GetAPINatives>(context_, bindings_system_.get()));
[email protected]2a356872014-02-21 23:18:52187 module_system->SetExceptionHandlerForTest(
dchengf6f80662016-04-20 20:26:04188 std::unique_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));
Devlin Cronin8cade482017-07-20 03:09:31189
Findit59c7f1e2019-03-12 07:00:56190 if (bindings_system_) {
191 bindings_system_->DidCreateScriptContext(context_);
192 bindings_system_->UpdateBindingsForContext(context_);
193 }
[email protected]1164b862012-05-09 22:38:37194}
195
[email protected]d9f51dad2014-07-09 05:39:38196ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() {
Devlin Cronin8cade482017-07-20 03:09:31197 if (context_)
kalmanb0c1c502015-04-15 00:25:06198 ShutdownModuleSystem();
[email protected]1164b862012-05-09 22:38:37199}
200
[email protected]d9f51dad2014-07-09 05:39:38201void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
202 const std::string& code) {
[email protected]1164b862012-05-09 22:38:37203 source_map_->RegisterModule(name, code);
204}
205
[email protected]d9f51dad2014-07-09 05:39:38206void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
Yuzhu Shenbcd734d2017-11-15 20:40:58207 int resource_id,
208 bool gzipped) {
Lei Zhangcf30efc2017-10-04 21:31:24209 const std::string& code = ui::ResourceBundle::GetSharedInstance()
[email protected]582f6e92014-07-16 23:39:15210 .GetRawDataResource(resource_id)
211 .as_string();
Yuzhu Shenbcd734d2017-11-15 20:40:58212 source_map_->RegisterModule(name, code, gzipped);
[email protected]11844fa2012-05-10 00:35:59213}
214
[email protected]d9f51dad2014-07-09 05:39:38215void ModuleSystemTestEnvironment::OverrideNativeHandler(
216 const std::string& name,
217 const std::string& code) {
[email protected]11844fa2012-05-10 00:35:59218 RegisterModule(name, code);
[email protected]2a356872014-02-21 23:18:52219 context_->module_system()->OverrideNativeHandlerForTest(name);
[email protected]11844fa2012-05-10 00:35:59220}
221
[email protected]d9f51dad2014-07-09 05:39:38222void ModuleSystemTestEnvironment::RegisterTestFile(
223 const std::string& module_name,
224 const std::string& file_name) {
[email protected]f8d87d32013-06-06 02:51:29225 base::FilePath test_js_file_path;
Avi Drissman210441b72018-05-01 15:51:00226 ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_js_file_path));
[email protected]582f6e92014-07-16 23:39:15227 test_js_file_path = test_js_file_path.AppendASCII(file_name);
[email protected]f8d87d32013-06-06 02:51:29228 std::string test_js;
[email protected]82f84b92013-08-30 18:23:50229 ASSERT_TRUE(base::ReadFileToString(test_js_file_path, &test_js));
[email protected]f8d87d32013-06-06 02:51:29230 source_map_->RegisterModule(module_name, test_js);
231}
232
[email protected]d9f51dad2014-07-09 05:39:38233void ModuleSystemTestEnvironment::ShutdownGin() {
234 context_holder_.reset();
235}
236
237void ModuleSystemTestEnvironment::ShutdownModuleSystem() {
kalmanb0c1c502015-04-15 00:25:06238 CHECK(context_->is_valid());
[email protected]d9f51dad2014-07-09 05:39:38239 context_->v8_context()->Exit();
Devlin Cronin8cade482017-07-20 03:09:31240 context_set_->Remove(context_);
241 base::RunLoop().RunUntilIdle();
242 context_ = nullptr;
243 assert_natives_ = nullptr;
[email protected]d9f51dad2014-07-09 05:39:38244}
245
tfarinaf85316f2015-04-29 17:03:40246v8::Local<v8::Object> ModuleSystemTestEnvironment::CreateGlobal(
[email protected]d9f51dad2014-07-09 05:39:38247 const std::string& name) {
[email protected]99ea16b2014-07-17 22:15:56248 v8::EscapableHandleScope handle_scope(isolate_);
249 v8::Local<v8::Object> object = v8::Object::New(isolate_);
Dan Elphick19cdae82018-12-11 16:03:51250 isolate_->GetCurrentContext()
251 ->Global()
252 ->Set(context_->v8_context(),
253 v8::String::NewFromUtf8(isolate_, name.c_str(),
254 v8::NewStringType::kInternalized)
255 .ToLocalChecked(),
256 object)
257 .ToChecked();
[email protected]d9f51dad2014-07-09 05:39:38258 return handle_scope.Escape(object);
259}
260
261ModuleSystemTest::ModuleSystemTest()
[email protected]99ea16b2014-07-17 22:15:56262 : isolate_(v8::Isolate::GetCurrent()),
Devlin Cronin8cade482017-07-20 03:09:31263 context_set_(&extension_ids_),
264 should_assertions_be_made_(true) {}
[email protected]d9f51dad2014-07-09 05:39:38265
266ModuleSystemTest::~ModuleSystemTest() {
267}
268
sammc32a6fc7d2014-09-15 02:47:31269void ModuleSystemTest::SetUp() {
Devlin Cronin2db58e32017-08-15 21:29:29270 extension_ = CreateExtension();
sammc32a6fc7d2014-09-15 02:47:31271 env_ = CreateEnvironment();
rdevlin.cronin585b1252016-04-19 23:29:26272 base::CommandLine::ForCurrentProcess()->AppendSwitch("test-type");
sammc32a6fc7d2014-09-15 02:47:31273}
274
[email protected]1164b862012-05-09 22:38:37275void ModuleSystemTest::TearDown() {
[email protected]1164b862012-05-09 22:38:37276 // All tests must assert at least once unless otherwise specified.
Devlin Cronin8cade482017-07-20 03:09:31277 if (env_->assert_natives()) { // The context may have already been shutdown.
278 EXPECT_EQ(should_assertions_be_made_,
279 env_->assert_natives()->assertion_made());
280 EXPECT_FALSE(env_->assert_natives()->failed());
281 } else {
282 EXPECT_FALSE(should_assertions_be_made_);
283 }
sammc32a6fc7d2014-09-15 02:47:31284 env_.reset();
285 v8::HeapStatistics stats;
286 isolate_->GetHeapStatistics(&stats);
287 size_t old_heap_size = 0;
288 // Run the GC until the heap size reaches a steady state to ensure that
289 // all the garbage is collected.
290 while (stats.used_heap_size() != old_heap_size) {
291 old_heap_size = stats.used_heap_size();
292 isolate_->RequestGarbageCollectionForTesting(
293 v8::Isolate::kFullGarbageCollection);
294 isolate_->GetHeapStatistics(&stats);
295 }
[email protected]d9f51dad2014-07-09 05:39:38296}
297
Devlin Cronin2db58e32017-08-15 21:29:29298scoped_refptr<const Extension> ModuleSystemTest::CreateExtension() {
299 std::unique_ptr<base::DictionaryValue> manifest =
300 DictionaryBuilder()
301 .Set("name", "test")
302 .Set("version", "1.0")
303 .Set("manifest_version", 2)
304 .Build();
305 return ExtensionBuilder().SetManifest(std::move(manifest)).Build();
306}
307
dchengf6f80662016-04-20 20:26:04308std::unique_ptr<ModuleSystemTestEnvironment>
309ModuleSystemTest::CreateEnvironment() {
Jeremy Roman16529d0e2017-08-24 18:13:47310 return std::make_unique<ModuleSystemTestEnvironment>(isolate_, &context_set_,
Devlin Cronin2db58e32017-08-15 21:29:29311 extension_);
[email protected]1164b862012-05-09 22:38:37312}
313
314void ModuleSystemTest::ExpectNoAssertionsMade() {
315 should_assertions_be_made_ = false;
316}
317
[email protected]d9f51dad2014-07-09 05:39:38318void ModuleSystemTest::RunResolvedPromises() {
dgozmanfdfd5d12016-03-11 07:50:47319 v8::MicrotasksScope::PerformCheckpoint(isolate_);
[email protected]1164b862012-05-09 22:38:37320}
[email protected]582f6e92014-07-16 23:39:15321
322} // namespace extensions