blob: 198765bb8edb882fa744c55cc1d421968e71ee62 [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"
[email protected]f8d87d32013-06-06 02:51:2916#include "base/files/file_path.h"
thestig94712702014-09-10 07:46:5917#include "base/files/file_util.h"
[email protected]295890bd2013-06-15 10:52:4518#include "base/lazy_instance.h"
dchengf6f80662016-04-20 20:26:0419#include "base/memory/ptr_util.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 Cronin8cade482017-07-20 03:09:3125#include "extensions/common/feature_switch.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)
54 : ObjectBackedNativeHandler(context) {
55 DCHECK_EQ(FeatureSwitch::native_crx_bindings()->IsEnabled(),
56 !!bindings_system);
57
58 auto get_api = [](ScriptContext* context,
59 NativeExtensionBindingsSystem* bindings_system,
60 const v8::FunctionCallbackInfo<v8::Value>& args) {
61 CHECK_EQ(1, args.Length());
62 CHECK(args[0]->IsString());
63 std::string api_name = gin::V8ToString(args[0]);
64 v8::Local<v8::Object> api;
65 if (bindings_system) {
66 api = bindings_system->GetAPIObjectForTesting(context, api_name);
67 } else {
68 v8::Local<v8::Object> full_binding;
69 CHECK(
70 context->module_system()->Require(api_name).ToLocal(&full_binding))
71 << "Failed to get: " << api_name;
72 v8::Local<v8::Value> api_value;
73 CHECK(full_binding
74 ->Get(context->v8_context(),
75 gin::StringToSymbol(context->isolate(), "binding"))
76 .ToLocal(&api_value))
77 << "Failed to get: " << api_name;
78 CHECK(api_value->IsObject()) << "Failed to get: " << api_name;
79 api = api_value.As<v8::Object>();
80 }
81 args.GetReturnValue().Set(api);
82 };
83
84 RouteFunction("get", base::Bind(get_api, context, bindings_system));
85 }
86};
87
[email protected]295890bd2013-06-15 10:52:4588} // namespace
89
[email protected]1164b862012-05-09 22:38:3790// Native JS functions for doing asserts.
[email protected]d9f51dad2014-07-09 05:39:3891class ModuleSystemTestEnvironment::AssertNatives
92 : public ObjectBackedNativeHandler {
[email protected]1164b862012-05-09 22:38:3793 public:
[email protected]582f6e92014-07-16 23:39:1594 explicit AssertNatives(ScriptContext* context)
[email protected]4f1633f2013-03-09 14:26:2495 : ObjectBackedNativeHandler(context),
[email protected]2e0e0bc2013-02-04 10:30:3496 assertion_made_(false),
[email protected]1164b862012-05-09 22:38:3797 failed_(false) {
[email protected]582f6e92014-07-16 23:39:1598 RouteFunction(
99 "AssertTrue",
100 base::Bind(&AssertNatives::AssertTrue, base::Unretained(this)));
101 RouteFunction(
102 "AssertFalse",
103 base::Bind(&AssertNatives::AssertFalse, base::Unretained(this)));
[email protected]1164b862012-05-09 22:38:37104 }
105
106 bool assertion_made() { return assertion_made_; }
107 bool failed() { return failed_; }
108
[email protected]d8c5fbb2013-06-14 11:35:25109 void AssertTrue(const v8::FunctionCallbackInfo<v8::Value>& args) {
[email protected]1164b862012-05-09 22:38:37110 CHECK_EQ(1, args.Length());
111 assertion_made_ = true;
dcarney04cd9642014-11-21 13:58:11112 failed_ = failed_ || !args[0]->ToBoolean(args.GetIsolate())->Value();
[email protected]1164b862012-05-09 22:38:37113 }
114
[email protected]d8c5fbb2013-06-14 11:35:25115 void AssertFalse(const v8::FunctionCallbackInfo<v8::Value>& args) {
[email protected]1164b862012-05-09 22:38:37116 CHECK_EQ(1, args.Length());
117 assertion_made_ = true;
dcarney04cd9642014-11-21 13:58:11118 failed_ = failed_ || args[0]->ToBoolean(args.GetIsolate())->Value();
[email protected]1164b862012-05-09 22:38:37119 }
120
121 private:
122 bool assertion_made_;
123 bool failed_;
124};
125
Devlin Cronin8cade482017-07-20 03:09:31126ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(
127 v8::Isolate* isolate,
Devlin Cronin2db58e32017-08-15 21:29:29128 ScriptContextSet* context_set,
129 scoped_refptr<const Extension> extension)
[email protected]99ea16b2014-07-17 22:15:56130 : isolate_(isolate),
131 context_holder_(new gin::ContextHolder(isolate_)),
132 handle_scope_(isolate_),
Devlin Cronin2db58e32017-08-15 21:29:29133 extension_(extension),
Devlin Cronin8cade482017-07-20 03:09:31134 context_set_(context_set),
[email protected]d9f51dad2014-07-09 05:39:38135 source_map_(new StringSourceMap()) {
kalman33076cb2015-08-11 19:12:07136 context_holder_->SetContext(v8::Context::New(
rdevlin.cronin892cc672016-12-19 20:00:18137 isolate, TestV8ExtensionConfiguration::GetConfiguration()));
Devlin Cronin8cade482017-07-20 03:09:31138
139 {
Jeremy Roman16529d0e2017-08-24 18:13:47140 auto context = std::make_unique<ScriptContext>(
Devlin Cronin2db58e32017-08-15 21:29:29141 context_holder_->context(),
142 nullptr, // WebFrame
143 extension_.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension_.get(),
144 Feature::BLESSED_EXTENSION_CONTEXT);
Devlin Cronin8cade482017-07-20 03:09:31145 context_ = context.get();
146 context_set_->AddForTesting(std::move(context));
147 }
148
[email protected]9a598442013-06-04 16:39:12149 context_->v8_context()->Enter();
Devlin Cronin8cade482017-07-20 03:09:31150 assert_natives_ = new AssertNatives(context_);
151
152 if (FeatureSwitch::native_crx_bindings()->IsEnabled())
Jeremy Roman16529d0e2017-08-24 18:13:47153 bindings_system_ = std::make_unique<NativeExtensionBindingsSystem>(nullptr);
[email protected]2a356872014-02-21 23:18:52154
155 {
dchengf6f80662016-04-20 20:26:04156 std::unique_ptr<ModuleSystem> module_system(
Devlin Cronin8cade482017-07-20 03:09:31157 new ModuleSystem(context_, source_map_.get()));
dchenge59eca1602015-12-18 17:48:00158 context_->set_module_system(std::move(module_system));
[email protected]2a356872014-02-21 23:18:52159 }
160 ModuleSystem* module_system = context_->module_system();
[email protected]582f6e92014-07-16 23:39:15161 module_system->RegisterNativeHandler(
dchengf6f80662016-04-20 20:26:04162 "assert", std::unique_ptr<NativeHandler>(assert_natives_));
[email protected]582f6e92014-07-16 23:39:15163 module_system->RegisterNativeHandler(
164 "logging",
Devlin Cronin8cade482017-07-20 03:09:31165 std::unique_ptr<NativeHandler>(new LoggingNativeHandler(context_)));
[email protected]582f6e92014-07-16 23:39:15166 module_system->RegisterNativeHandler(
167 "utils",
Devlin Cronin8cade482017-07-20 03:09:31168 std::unique_ptr<NativeHandler>(new UtilsNativeHandler(context_)));
169 module_system->RegisterNativeHandler(
170 "apiGetter",
Jeremy Roman16529d0e2017-08-24 18:13:47171 std::make_unique<GetAPINatives>(context_, bindings_system_.get()));
[email protected]2a356872014-02-21 23:18:52172 module_system->SetExceptionHandlerForTest(
dchengf6f80662016-04-20 20:26:04173 std::unique_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));
Devlin Cronin8cade482017-07-20 03:09:31174
175 if (bindings_system_) {
176 bindings_system_->DidCreateScriptContext(context_);
177 bindings_system_->UpdateBindingsForContext(context_);
178 }
[email protected]1164b862012-05-09 22:38:37179}
180
[email protected]d9f51dad2014-07-09 05:39:38181ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() {
Devlin Cronin8cade482017-07-20 03:09:31182 if (context_)
kalmanb0c1c502015-04-15 00:25:06183 ShutdownModuleSystem();
[email protected]1164b862012-05-09 22:38:37184}
185
[email protected]d9f51dad2014-07-09 05:39:38186void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
187 const std::string& code) {
[email protected]1164b862012-05-09 22:38:37188 source_map_->RegisterModule(name, code);
189}
190
[email protected]d9f51dad2014-07-09 05:39:38191void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
192 int resource_id) {
[email protected]582f6e92014-07-16 23:39:15193 const std::string& code = ResourceBundle::GetSharedInstance()
194 .GetRawDataResource(resource_id)
195 .as_string();
[email protected]11844fa2012-05-10 00:35:59196 source_map_->RegisterModule(name, code);
197}
198
[email protected]d9f51dad2014-07-09 05:39:38199void ModuleSystemTestEnvironment::OverrideNativeHandler(
200 const std::string& name,
201 const std::string& code) {
[email protected]11844fa2012-05-10 00:35:59202 RegisterModule(name, code);
[email protected]2a356872014-02-21 23:18:52203 context_->module_system()->OverrideNativeHandlerForTest(name);
[email protected]11844fa2012-05-10 00:35:59204}
205
[email protected]d9f51dad2014-07-09 05:39:38206void ModuleSystemTestEnvironment::RegisterTestFile(
207 const std::string& module_name,
208 const std::string& file_name) {
[email protected]f8d87d32013-06-06 02:51:29209 base::FilePath test_js_file_path;
[email protected]582f6e92014-07-16 23:39:15210 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_js_file_path));
211 test_js_file_path = test_js_file_path.AppendASCII(file_name);
[email protected]f8d87d32013-06-06 02:51:29212 std::string test_js;
[email protected]82f84b92013-08-30 18:23:50213 ASSERT_TRUE(base::ReadFileToString(test_js_file_path, &test_js));
[email protected]f8d87d32013-06-06 02:51:29214 source_map_->RegisterModule(module_name, test_js);
215}
216
[email protected]d9f51dad2014-07-09 05:39:38217void ModuleSystemTestEnvironment::ShutdownGin() {
218 context_holder_.reset();
219}
220
221void ModuleSystemTestEnvironment::ShutdownModuleSystem() {
kalmanb0c1c502015-04-15 00:25:06222 CHECK(context_->is_valid());
[email protected]d9f51dad2014-07-09 05:39:38223 context_->v8_context()->Exit();
Devlin Cronin8cade482017-07-20 03:09:31224 context_set_->Remove(context_);
225 base::RunLoop().RunUntilIdle();
226 context_ = nullptr;
227 assert_natives_ = nullptr;
[email protected]d9f51dad2014-07-09 05:39:38228}
229
tfarinaf85316f2015-04-29 17:03:40230v8::Local<v8::Object> ModuleSystemTestEnvironment::CreateGlobal(
[email protected]d9f51dad2014-07-09 05:39:38231 const std::string& name) {
[email protected]99ea16b2014-07-17 22:15:56232 v8::EscapableHandleScope handle_scope(isolate_);
233 v8::Local<v8::Object> object = v8::Object::New(isolate_);
234 isolate_->GetCurrentContext()->Global()->Set(
235 v8::String::NewFromUtf8(isolate_, name.c_str()), object);
[email protected]d9f51dad2014-07-09 05:39:38236 return handle_scope.Escape(object);
237}
238
239ModuleSystemTest::ModuleSystemTest()
[email protected]99ea16b2014-07-17 22:15:56240 : isolate_(v8::Isolate::GetCurrent()),
Devlin Cronin8cade482017-07-20 03:09:31241 context_set_(&extension_ids_),
242 should_assertions_be_made_(true) {}
[email protected]d9f51dad2014-07-09 05:39:38243
244ModuleSystemTest::~ModuleSystemTest() {
245}
246
sammc32a6fc7d2014-09-15 02:47:31247void ModuleSystemTest::SetUp() {
Devlin Cronin2db58e32017-08-15 21:29:29248 extension_ = CreateExtension();
sammc32a6fc7d2014-09-15 02:47:31249 env_ = CreateEnvironment();
rdevlin.cronin585b1252016-04-19 23:29:26250 base::CommandLine::ForCurrentProcess()->AppendSwitch("test-type");
sammc32a6fc7d2014-09-15 02:47:31251}
252
[email protected]1164b862012-05-09 22:38:37253void ModuleSystemTest::TearDown() {
[email protected]1164b862012-05-09 22:38:37254 // All tests must assert at least once unless otherwise specified.
Devlin Cronin8cade482017-07-20 03:09:31255 if (env_->assert_natives()) { // The context may have already been shutdown.
256 EXPECT_EQ(should_assertions_be_made_,
257 env_->assert_natives()->assertion_made());
258 EXPECT_FALSE(env_->assert_natives()->failed());
259 } else {
260 EXPECT_FALSE(should_assertions_be_made_);
261 }
sammc32a6fc7d2014-09-15 02:47:31262 env_.reset();
263 v8::HeapStatistics stats;
264 isolate_->GetHeapStatistics(&stats);
265 size_t old_heap_size = 0;
266 // Run the GC until the heap size reaches a steady state to ensure that
267 // all the garbage is collected.
268 while (stats.used_heap_size() != old_heap_size) {
269 old_heap_size = stats.used_heap_size();
270 isolate_->RequestGarbageCollectionForTesting(
271 v8::Isolate::kFullGarbageCollection);
272 isolate_->GetHeapStatistics(&stats);
273 }
[email protected]d9f51dad2014-07-09 05:39:38274}
275
Devlin Cronin2db58e32017-08-15 21:29:29276scoped_refptr<const Extension> ModuleSystemTest::CreateExtension() {
277 std::unique_ptr<base::DictionaryValue> manifest =
278 DictionaryBuilder()
279 .Set("name", "test")
280 .Set("version", "1.0")
281 .Set("manifest_version", 2)
282 .Build();
283 return ExtensionBuilder().SetManifest(std::move(manifest)).Build();
284}
285
dchengf6f80662016-04-20 20:26:04286std::unique_ptr<ModuleSystemTestEnvironment>
287ModuleSystemTest::CreateEnvironment() {
Jeremy Roman16529d0e2017-08-24 18:13:47288 return std::make_unique<ModuleSystemTestEnvironment>(isolate_, &context_set_,
Devlin Cronin2db58e32017-08-15 21:29:29289 extension_);
[email protected]1164b862012-05-09 22:38:37290}
291
292void ModuleSystemTest::ExpectNoAssertionsMade() {
293 should_assertions_be_made_ = false;
294}
295
[email protected]d9f51dad2014-07-09 05:39:38296void ModuleSystemTest::RunResolvedPromises() {
dgozmanfdfd5d12016-03-11 07:50:47297 v8::MicrotasksScope::PerformCheckpoint(isolate_);
[email protected]1164b862012-05-09 22:38:37298}
[email protected]582f6e92014-07-16 23:39:15299
300} // namespace extensions