blob: 13d50d9832f893d09b93a54a0e5ad4d7bd2c30b7 [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"
[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"
[email protected]582f6e92014-07-16 23:39:1524#include "extensions/common/extension_paths.h"
Devlin Cronin2db58e32017-08-15 21:29:2925#include "extensions/common/value_builder.h"
Devlin Cronin8cade482017-07-20 03:09:3126#include "extensions/renderer/ipc_message_sender.h"
[email protected]701a94e2014-04-17 04:37:3727#include "extensions/renderer/logging_native_handler.h"
Devlin Cronin8cade482017-07-20 03:09:3128#include "extensions/renderer/native_extension_bindings_system.h"
[email protected]f55c90ee62014-04-12 00:50:0329#include "extensions/renderer/object_backed_native_handler.h"
kalman33076cb2015-08-11 19:12:0730#include "extensions/renderer/safe_builtins.h"
Devlin Cronin8cade482017-07-20 03:09:3131#include "extensions/renderer/script_context_set.h"
rdevlin.cronin892cc672016-12-19 20:00:1832#include "extensions/renderer/string_source_map.h"
33#include "extensions/renderer/test_v8_extension_configuration.h"
[email protected]701a94e2014-04-17 04:37:3734#include "extensions/renderer/utils_native_handler.h"
Devlin Cronin8cade482017-07-20 03:09:3135#include "gin/converter.h"
[email protected]11844fa2012-05-10 00:35:5936#include "ui/base/resource/resource_bundle.h"
[email protected]1164b862012-05-09 22:38:3737
[email protected]582f6e92014-07-16 23:39:1538namespace extensions {
[email protected]295890bd2013-06-15 10:52:4539namespace {
40
41class FailsOnException : public ModuleSystem::ExceptionHandler {
42 public:
bashi6a4854f2015-06-19 00:51:5143 FailsOnException() : ModuleSystem::ExceptionHandler(nullptr) {}
dcheng9168b2f2014-10-21 12:38:2444 void HandleUncaughtException(const v8::TryCatch& try_catch) override {
[email protected]295890bd2013-06-15 10:52:4545 FAIL() << "Uncaught exception: " << CreateExceptionString(try_catch);
46 }
47};
48
Devlin Cronin8cade482017-07-20 03:09:3149class GetAPINatives : public ObjectBackedNativeHandler {
50 public:
51 GetAPINatives(ScriptContext* context,
52 NativeExtensionBindingsSystem* bindings_system)
Devlin Cronind9ea8342018-01-27 06:00:0453 : ObjectBackedNativeHandler(context), bindings_system_(bindings_system) {
Devlin Cronin242d19d22019-03-12 18:08:4854 DCHECK(bindings_system_);
Devlin Cronind9ea8342018-01-27 06:00:0455 }
56 ~GetAPINatives() override {}
Devlin Cronin8cade482017-07-20 03:09:3157
Devlin Cronind9ea8342018-01-27 06:00:0458 // ObjectBackedNativeHandler:
59 void AddRoutes() override {
Devlin Cronin8cade482017-07-20 03:09:3160 auto get_api = [](ScriptContext* context,
61 NativeExtensionBindingsSystem* bindings_system,
62 const v8::FunctionCallbackInfo<v8::Value>& args) {
63 CHECK_EQ(1, args.Length());
64 CHECK(args[0]->IsString());
Dan Elphick38a508052018-07-23 22:19:5365 std::string api_name = gin::V8ToString(context->isolate(), args[0]);
Devlin Cronin8cade482017-07-20 03:09:3166 v8::Local<v8::Object> api;
67 if (bindings_system) {
68 api = bindings_system->GetAPIObjectForTesting(context, api_name);
69 } else {
70 v8::Local<v8::Object> full_binding;
71 CHECK(
72 context->module_system()->Require(api_name).ToLocal(&full_binding))
73 << "Failed to get: " << api_name;
74 v8::Local<v8::Value> api_value;
75 CHECK(full_binding
76 ->Get(context->v8_context(),
77 gin::StringToSymbol(context->isolate(), "binding"))
78 .ToLocal(&api_value))
79 << "Failed to get: " << api_name;
80 CHECK(api_value->IsObject()) << "Failed to get: " << api_name;
81 api = api_value.As<v8::Object>();
82 }
83 args.GetReturnValue().Set(api);
84 };
85
Devlin Cronincc02a0c2019-01-03 22:15:0786 RouteHandlerFunction(
87 "get", base::BindRepeating(get_api, context(), bindings_system_));
Devlin Cronin8cade482017-07-20 03:09:3188 }
Devlin Cronind9ea8342018-01-27 06:00:0489
90 private:
91 NativeExtensionBindingsSystem* bindings_system_ = nullptr;
92
93 DISALLOW_COPY_AND_ASSIGN(GetAPINatives);
Devlin Cronin8cade482017-07-20 03:09:3194};
95
[email protected]295890bd2013-06-15 10:52:4596} // namespace
97
[email protected]1164b862012-05-09 22:38:3798// Native JS functions for doing asserts.
[email protected]d9f51dad2014-07-09 05:39:3899class ModuleSystemTestEnvironment::AssertNatives
100 : public ObjectBackedNativeHandler {
[email protected]1164b862012-05-09 22:38:37101 public:
[email protected]582f6e92014-07-16 23:39:15102 explicit AssertNatives(ScriptContext* context)
[email protected]4f1633f2013-03-09 14:26:24103 : ObjectBackedNativeHandler(context),
[email protected]2e0e0bc2013-02-04 10:30:34104 assertion_made_(false),
Devlin Cronind9ea8342018-01-27 06:00:04105 failed_(false) {}
106
107 // ObjectBackedNativeHandler:
108 void AddRoutes() override {
Devlin Cronincc02a0c2019-01-03 22:15:07109 RouteHandlerFunction("AssertTrue",
110 base::BindRepeating(&AssertNatives::AssertTrue,
111 base::Unretained(this)));
112 RouteHandlerFunction("AssertFalse",
113 base::BindRepeating(&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 Cronin242d19d22019-03-12 18:08:48163 bindings_system_ = std::make_unique<NativeExtensionBindingsSystem>(nullptr);
[email protected]2a356872014-02-21 23:18:52164
165 {
dchengf6f80662016-04-20 20:26:04166 std::unique_ptr<ModuleSystem> module_system(
Devlin Cronin8cade482017-07-20 03:09:31167 new ModuleSystem(context_, source_map_.get()));
Devlin Cronind9ea8342018-01-27 06:00:04168 context_->SetModuleSystem(std::move(module_system));
[email protected]2a356872014-02-21 23:18:52169 }
170 ModuleSystem* module_system = context_->module_system();
[email protected]582f6e92014-07-16 23:39:15171 module_system->RegisterNativeHandler(
dchengf6f80662016-04-20 20:26:04172 "assert", std::unique_ptr<NativeHandler>(assert_natives_));
[email protected]582f6e92014-07-16 23:39:15173 module_system->RegisterNativeHandler(
174 "logging",
Devlin Cronin8cade482017-07-20 03:09:31175 std::unique_ptr<NativeHandler>(new LoggingNativeHandler(context_)));
[email protected]582f6e92014-07-16 23:39:15176 module_system->RegisterNativeHandler(
177 "utils",
Devlin Cronin8cade482017-07-20 03:09:31178 std::unique_ptr<NativeHandler>(new UtilsNativeHandler(context_)));
179 module_system->RegisterNativeHandler(
180 "apiGetter",
Jeremy Roman16529d0e2017-08-24 18:13:47181 std::make_unique<GetAPINatives>(context_, bindings_system_.get()));
[email protected]2a356872014-02-21 23:18:52182 module_system->SetExceptionHandlerForTest(
dchengf6f80662016-04-20 20:26:04183 std::unique_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));
Devlin Cronin8cade482017-07-20 03:09:31184
Devlin Cronin242d19d22019-03-12 18:08:48185 bindings_system_->DidCreateScriptContext(context_);
186 bindings_system_->UpdateBindingsForContext(context_);
[email protected]1164b862012-05-09 22:38:37187}
188
[email protected]d9f51dad2014-07-09 05:39:38189ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() {
Devlin Cronin8cade482017-07-20 03:09:31190 if (context_)
kalmanb0c1c502015-04-15 00:25:06191 ShutdownModuleSystem();
[email protected]1164b862012-05-09 22:38:37192}
193
[email protected]d9f51dad2014-07-09 05:39:38194void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
195 const std::string& code) {
[email protected]1164b862012-05-09 22:38:37196 source_map_->RegisterModule(name, code);
197}
198
[email protected]d9f51dad2014-07-09 05:39:38199void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
Yuzhu Shenbcd734d2017-11-15 20:40:58200 int resource_id,
201 bool gzipped) {
Lei Zhangcf30efc2017-10-04 21:31:24202 const std::string& code = ui::ResourceBundle::GetSharedInstance()
[email protected]582f6e92014-07-16 23:39:15203 .GetRawDataResource(resource_id)
204 .as_string();
Yuzhu Shenbcd734d2017-11-15 20:40:58205 source_map_->RegisterModule(name, code, gzipped);
[email protected]11844fa2012-05-10 00:35:59206}
207
[email protected]d9f51dad2014-07-09 05:39:38208void ModuleSystemTestEnvironment::OverrideNativeHandler(
209 const std::string& name,
210 const std::string& code) {
[email protected]11844fa2012-05-10 00:35:59211 RegisterModule(name, code);
[email protected]2a356872014-02-21 23:18:52212 context_->module_system()->OverrideNativeHandlerForTest(name);
[email protected]11844fa2012-05-10 00:35:59213}
214
[email protected]d9f51dad2014-07-09 05:39:38215void ModuleSystemTestEnvironment::RegisterTestFile(
216 const std::string& module_name,
217 const std::string& file_name) {
[email protected]f8d87d32013-06-06 02:51:29218 base::FilePath test_js_file_path;
Avi Drissman210441b72018-05-01 15:51:00219 ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_js_file_path));
[email protected]582f6e92014-07-16 23:39:15220 test_js_file_path = test_js_file_path.AppendASCII(file_name);
[email protected]f8d87d32013-06-06 02:51:29221 std::string test_js;
[email protected]82f84b92013-08-30 18:23:50222 ASSERT_TRUE(base::ReadFileToString(test_js_file_path, &test_js));
[email protected]f8d87d32013-06-06 02:51:29223 source_map_->RegisterModule(module_name, test_js);
224}
225
[email protected]d9f51dad2014-07-09 05:39:38226void ModuleSystemTestEnvironment::ShutdownGin() {
227 context_holder_.reset();
228}
229
230void ModuleSystemTestEnvironment::ShutdownModuleSystem() {
kalmanb0c1c502015-04-15 00:25:06231 CHECK(context_->is_valid());
[email protected]d9f51dad2014-07-09 05:39:38232 context_->v8_context()->Exit();
Devlin Cronin8cade482017-07-20 03:09:31233 context_set_->Remove(context_);
234 base::RunLoop().RunUntilIdle();
235 context_ = nullptr;
236 assert_natives_ = nullptr;
[email protected]d9f51dad2014-07-09 05:39:38237}
238
tfarinaf85316f2015-04-29 17:03:40239v8::Local<v8::Object> ModuleSystemTestEnvironment::CreateGlobal(
[email protected]d9f51dad2014-07-09 05:39:38240 const std::string& name) {
[email protected]99ea16b2014-07-17 22:15:56241 v8::EscapableHandleScope handle_scope(isolate_);
242 v8::Local<v8::Object> object = v8::Object::New(isolate_);
Dan Elphick19cdae82018-12-11 16:03:51243 isolate_->GetCurrentContext()
244 ->Global()
245 ->Set(context_->v8_context(),
246 v8::String::NewFromUtf8(isolate_, name.c_str(),
247 v8::NewStringType::kInternalized)
248 .ToLocalChecked(),
249 object)
250 .ToChecked();
[email protected]d9f51dad2014-07-09 05:39:38251 return handle_scope.Escape(object);
252}
253
254ModuleSystemTest::ModuleSystemTest()
[email protected]99ea16b2014-07-17 22:15:56255 : isolate_(v8::Isolate::GetCurrent()),
Devlin Cronin8cade482017-07-20 03:09:31256 context_set_(&extension_ids_),
257 should_assertions_be_made_(true) {}
[email protected]d9f51dad2014-07-09 05:39:38258
259ModuleSystemTest::~ModuleSystemTest() {
260}
261
sammc32a6fc7d2014-09-15 02:47:31262void ModuleSystemTest::SetUp() {
Devlin Cronin2db58e32017-08-15 21:29:29263 extension_ = CreateExtension();
sammc32a6fc7d2014-09-15 02:47:31264 env_ = CreateEnvironment();
rdevlin.cronin585b1252016-04-19 23:29:26265 base::CommandLine::ForCurrentProcess()->AppendSwitch("test-type");
sammc32a6fc7d2014-09-15 02:47:31266}
267
[email protected]1164b862012-05-09 22:38:37268void ModuleSystemTest::TearDown() {
[email protected]1164b862012-05-09 22:38:37269 // All tests must assert at least once unless otherwise specified.
Devlin Cronin8cade482017-07-20 03:09:31270 if (env_->assert_natives()) { // The context may have already been shutdown.
271 EXPECT_EQ(should_assertions_be_made_,
272 env_->assert_natives()->assertion_made());
273 EXPECT_FALSE(env_->assert_natives()->failed());
274 } else {
275 EXPECT_FALSE(should_assertions_be_made_);
276 }
sammc32a6fc7d2014-09-15 02:47:31277 env_.reset();
278 v8::HeapStatistics stats;
279 isolate_->GetHeapStatistics(&stats);
280 size_t old_heap_size = 0;
281 // Run the GC until the heap size reaches a steady state to ensure that
282 // all the garbage is collected.
283 while (stats.used_heap_size() != old_heap_size) {
284 old_heap_size = stats.used_heap_size();
285 isolate_->RequestGarbageCollectionForTesting(
286 v8::Isolate::kFullGarbageCollection);
287 isolate_->GetHeapStatistics(&stats);
288 }
[email protected]d9f51dad2014-07-09 05:39:38289}
290
Devlin Cronin2db58e32017-08-15 21:29:29291scoped_refptr<const Extension> ModuleSystemTest::CreateExtension() {
292 std::unique_ptr<base::DictionaryValue> manifest =
293 DictionaryBuilder()
294 .Set("name", "test")
295 .Set("version", "1.0")
296 .Set("manifest_version", 2)
297 .Build();
298 return ExtensionBuilder().SetManifest(std::move(manifest)).Build();
299}
300
dchengf6f80662016-04-20 20:26:04301std::unique_ptr<ModuleSystemTestEnvironment>
302ModuleSystemTest::CreateEnvironment() {
Jeremy Roman16529d0e2017-08-24 18:13:47303 return std::make_unique<ModuleSystemTestEnvironment>(isolate_, &context_set_,
Devlin Cronin2db58e32017-08-15 21:29:29304 extension_);
[email protected]1164b862012-05-09 22:38:37305}
306
307void ModuleSystemTest::ExpectNoAssertionsMade() {
308 should_assertions_be_made_ = false;
309}
310
[email protected]d9f51dad2014-07-09 05:39:38311void ModuleSystemTest::RunResolvedPromises() {
dgozmanfdfd5d12016-03-11 07:50:47312 v8::MicrotasksScope::PerformCheckpoint(isolate_);
[email protected]1164b862012-05-09 22:38:37313}
[email protected]582f6e92014-07-16 23:39:15314
315} // namespace extensions