blob: 588341489a0a414bd12fd325f26b201b6bd7f69d [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"
[email protected]4570a252013-03-31 00:35:4321#include "base/strings/string_piece.h"
Devlin Cronin2db58e32017-08-15 21:29:2922#include "extensions/common/extension_builder.h"
[email protected]582f6e92014-07-16 23:39:1523#include "extensions/common/extension_paths.h"
Devlin Cronin8cade482017-07-20 03:09:3124#include "extensions/common/feature_switch.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)
53 : ObjectBackedNativeHandler(context) {
54 DCHECK_EQ(FeatureSwitch::native_crx_bindings()->IsEnabled(),
55 !!bindings_system);
56
57 auto get_api = [](ScriptContext* context,
58 NativeExtensionBindingsSystem* bindings_system,
59 const v8::FunctionCallbackInfo<v8::Value>& args) {
60 CHECK_EQ(1, args.Length());
61 CHECK(args[0]->IsString());
62 std::string api_name = gin::V8ToString(args[0]);
63 v8::Local<v8::Object> api;
64 if (bindings_system) {
65 api = bindings_system->GetAPIObjectForTesting(context, api_name);
66 } else {
67 v8::Local<v8::Object> full_binding;
68 CHECK(
69 context->module_system()->Require(api_name).ToLocal(&full_binding))
70 << "Failed to get: " << api_name;
71 v8::Local<v8::Value> api_value;
72 CHECK(full_binding
73 ->Get(context->v8_context(),
74 gin::StringToSymbol(context->isolate(), "binding"))
75 .ToLocal(&api_value))
76 << "Failed to get: " << api_name;
77 CHECK(api_value->IsObject()) << "Failed to get: " << api_name;
78 api = api_value.As<v8::Object>();
79 }
80 args.GetReturnValue().Set(api);
81 };
82
83 RouteFunction("get", base::Bind(get_api, context, bindings_system));
84 }
85};
86
[email protected]295890bd2013-06-15 10:52:4587} // namespace
88
[email protected]1164b862012-05-09 22:38:3789// Native JS functions for doing asserts.
[email protected]d9f51dad2014-07-09 05:39:3890class ModuleSystemTestEnvironment::AssertNatives
91 : public ObjectBackedNativeHandler {
[email protected]1164b862012-05-09 22:38:3792 public:
[email protected]582f6e92014-07-16 23:39:1593 explicit AssertNatives(ScriptContext* context)
[email protected]4f1633f2013-03-09 14:26:2494 : ObjectBackedNativeHandler(context),
[email protected]2e0e0bc2013-02-04 10:30:3495 assertion_made_(false),
[email protected]1164b862012-05-09 22:38:3796 failed_(false) {
[email protected]582f6e92014-07-16 23:39:1597 RouteFunction(
98 "AssertTrue",
99 base::Bind(&AssertNatives::AssertTrue, base::Unretained(this)));
100 RouteFunction(
101 "AssertFalse",
102 base::Bind(&AssertNatives::AssertFalse, base::Unretained(this)));
[email protected]1164b862012-05-09 22:38:37103 }
104
105 bool assertion_made() { return assertion_made_; }
106 bool failed() { return failed_; }
107
[email protected]d8c5fbb2013-06-14 11:35:25108 void AssertTrue(const v8::FunctionCallbackInfo<v8::Value>& args) {
[email protected]1164b862012-05-09 22:38:37109 CHECK_EQ(1, args.Length());
110 assertion_made_ = true;
dcarney04cd9642014-11-21 13:58:11111 failed_ = failed_ || !args[0]->ToBoolean(args.GetIsolate())->Value();
[email protected]1164b862012-05-09 22:38:37112 }
113
[email protected]d8c5fbb2013-06-14 11:35:25114 void AssertFalse(const v8::FunctionCallbackInfo<v8::Value>& args) {
[email protected]1164b862012-05-09 22:38:37115 CHECK_EQ(1, args.Length());
116 assertion_made_ = true;
dcarney04cd9642014-11-21 13:58:11117 failed_ = failed_ || args[0]->ToBoolean(args.GetIsolate())->Value();
[email protected]1164b862012-05-09 22:38:37118 }
119
120 private:
121 bool assertion_made_;
122 bool failed_;
123};
124
Devlin Cronin8cade482017-07-20 03:09:31125ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(
126 v8::Isolate* isolate,
Devlin Cronin2db58e32017-08-15 21:29:29127 ScriptContextSet* context_set,
128 scoped_refptr<const Extension> extension)
[email protected]99ea16b2014-07-17 22:15:56129 : isolate_(isolate),
130 context_holder_(new gin::ContextHolder(isolate_)),
131 handle_scope_(isolate_),
Devlin Cronin2db58e32017-08-15 21:29:29132 extension_(extension),
Devlin Cronin8cade482017-07-20 03:09:31133 context_set_(context_set),
[email protected]d9f51dad2014-07-09 05:39:38134 source_map_(new StringSourceMap()) {
kalman33076cb2015-08-11 19:12:07135 context_holder_->SetContext(v8::Context::New(
rdevlin.cronin892cc672016-12-19 20:00:18136 isolate, TestV8ExtensionConfiguration::GetConfiguration()));
Devlin Cronin8cade482017-07-20 03:09:31137
138 {
Devlin Cronin2db58e32017-08-15 21:29:29139 auto context = base::MakeUnique<ScriptContext>(
140 context_holder_->context(),
141 nullptr, // WebFrame
142 extension_.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension_.get(),
143 Feature::BLESSED_EXTENSION_CONTEXT);
Devlin Cronin8cade482017-07-20 03:09:31144 context_ = context.get();
145 context_set_->AddForTesting(std::move(context));
146 }
147
[email protected]9a598442013-06-04 16:39:12148 context_->v8_context()->Enter();
Devlin Cronin8cade482017-07-20 03:09:31149 assert_natives_ = new AssertNatives(context_);
150
151 if (FeatureSwitch::native_crx_bindings()->IsEnabled())
152 bindings_system_ = base::MakeUnique<NativeExtensionBindingsSystem>(nullptr);
[email protected]2a356872014-02-21 23:18:52153
154 {
dchengf6f80662016-04-20 20:26:04155 std::unique_ptr<ModuleSystem> module_system(
Devlin Cronin8cade482017-07-20 03:09:31156 new ModuleSystem(context_, source_map_.get()));
dchenge59eca1602015-12-18 17:48:00157 context_->set_module_system(std::move(module_system));
[email protected]2a356872014-02-21 23:18:52158 }
159 ModuleSystem* module_system = context_->module_system();
[email protected]582f6e92014-07-16 23:39:15160 module_system->RegisterNativeHandler(
dchengf6f80662016-04-20 20:26:04161 "assert", std::unique_ptr<NativeHandler>(assert_natives_));
[email protected]582f6e92014-07-16 23:39:15162 module_system->RegisterNativeHandler(
163 "logging",
Devlin Cronin8cade482017-07-20 03:09:31164 std::unique_ptr<NativeHandler>(new LoggingNativeHandler(context_)));
[email protected]582f6e92014-07-16 23:39:15165 module_system->RegisterNativeHandler(
166 "utils",
Devlin Cronin8cade482017-07-20 03:09:31167 std::unique_ptr<NativeHandler>(new UtilsNativeHandler(context_)));
168 module_system->RegisterNativeHandler(
169 "apiGetter",
170 base::MakeUnique<GetAPINatives>(context_, bindings_system_.get()));
[email protected]2a356872014-02-21 23:18:52171 module_system->SetExceptionHandlerForTest(
dchengf6f80662016-04-20 20:26:04172 std::unique_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));
Devlin Cronin8cade482017-07-20 03:09:31173
174 if (bindings_system_) {
175 bindings_system_->DidCreateScriptContext(context_);
176 bindings_system_->UpdateBindingsForContext(context_);
177 }
[email protected]1164b862012-05-09 22:38:37178}
179
[email protected]d9f51dad2014-07-09 05:39:38180ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() {
Devlin Cronin8cade482017-07-20 03:09:31181 if (context_)
kalmanb0c1c502015-04-15 00:25:06182 ShutdownModuleSystem();
[email protected]1164b862012-05-09 22:38:37183}
184
[email protected]d9f51dad2014-07-09 05:39:38185void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
186 const std::string& code) {
[email protected]1164b862012-05-09 22:38:37187 source_map_->RegisterModule(name, code);
188}
189
[email protected]d9f51dad2014-07-09 05:39:38190void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
191 int resource_id) {
[email protected]582f6e92014-07-16 23:39:15192 const std::string& code = ResourceBundle::GetSharedInstance()
193 .GetRawDataResource(resource_id)
194 .as_string();
[email protected]11844fa2012-05-10 00:35:59195 source_map_->RegisterModule(name, code);
196}
197
[email protected]d9f51dad2014-07-09 05:39:38198void ModuleSystemTestEnvironment::OverrideNativeHandler(
199 const std::string& name,
200 const std::string& code) {
[email protected]11844fa2012-05-10 00:35:59201 RegisterModule(name, code);
[email protected]2a356872014-02-21 23:18:52202 context_->module_system()->OverrideNativeHandlerForTest(name);
[email protected]11844fa2012-05-10 00:35:59203}
204
[email protected]d9f51dad2014-07-09 05:39:38205void ModuleSystemTestEnvironment::RegisterTestFile(
206 const std::string& module_name,
207 const std::string& file_name) {
[email protected]f8d87d32013-06-06 02:51:29208 base::FilePath test_js_file_path;
[email protected]582f6e92014-07-16 23:39:15209 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_js_file_path));
210 test_js_file_path = test_js_file_path.AppendASCII(file_name);
[email protected]f8d87d32013-06-06 02:51:29211 std::string test_js;
[email protected]82f84b92013-08-30 18:23:50212 ASSERT_TRUE(base::ReadFileToString(test_js_file_path, &test_js));
[email protected]f8d87d32013-06-06 02:51:29213 source_map_->RegisterModule(module_name, test_js);
214}
215
[email protected]d9f51dad2014-07-09 05:39:38216void ModuleSystemTestEnvironment::ShutdownGin() {
217 context_holder_.reset();
218}
219
220void ModuleSystemTestEnvironment::ShutdownModuleSystem() {
kalmanb0c1c502015-04-15 00:25:06221 CHECK(context_->is_valid());
[email protected]d9f51dad2014-07-09 05:39:38222 context_->v8_context()->Exit();
Devlin Cronin8cade482017-07-20 03:09:31223 context_set_->Remove(context_);
224 base::RunLoop().RunUntilIdle();
225 context_ = nullptr;
226 assert_natives_ = nullptr;
[email protected]d9f51dad2014-07-09 05:39:38227}
228
tfarinaf85316f2015-04-29 17:03:40229v8::Local<v8::Object> ModuleSystemTestEnvironment::CreateGlobal(
[email protected]d9f51dad2014-07-09 05:39:38230 const std::string& name) {
[email protected]99ea16b2014-07-17 22:15:56231 v8::EscapableHandleScope handle_scope(isolate_);
232 v8::Local<v8::Object> object = v8::Object::New(isolate_);
233 isolate_->GetCurrentContext()->Global()->Set(
234 v8::String::NewFromUtf8(isolate_, name.c_str()), object);
[email protected]d9f51dad2014-07-09 05:39:38235 return handle_scope.Escape(object);
236}
237
238ModuleSystemTest::ModuleSystemTest()
[email protected]99ea16b2014-07-17 22:15:56239 : isolate_(v8::Isolate::GetCurrent()),
Devlin Cronin8cade482017-07-20 03:09:31240 context_set_(&extension_ids_),
241 should_assertions_be_made_(true) {}
[email protected]d9f51dad2014-07-09 05:39:38242
243ModuleSystemTest::~ModuleSystemTest() {
244}
245
sammc32a6fc7d2014-09-15 02:47:31246void ModuleSystemTest::SetUp() {
Devlin Cronin2db58e32017-08-15 21:29:29247 extension_ = CreateExtension();
sammc32a6fc7d2014-09-15 02:47:31248 env_ = CreateEnvironment();
rdevlin.cronin585b1252016-04-19 23:29:26249 base::CommandLine::ForCurrentProcess()->AppendSwitch("test-type");
sammc32a6fc7d2014-09-15 02:47:31250}
251
[email protected]1164b862012-05-09 22:38:37252void ModuleSystemTest::TearDown() {
[email protected]1164b862012-05-09 22:38:37253 // All tests must assert at least once unless otherwise specified.
Devlin Cronin8cade482017-07-20 03:09:31254 if (env_->assert_natives()) { // The context may have already been shutdown.
255 EXPECT_EQ(should_assertions_be_made_,
256 env_->assert_natives()->assertion_made());
257 EXPECT_FALSE(env_->assert_natives()->failed());
258 } else {
259 EXPECT_FALSE(should_assertions_be_made_);
260 }
sammc32a6fc7d2014-09-15 02:47:31261 env_.reset();
262 v8::HeapStatistics stats;
263 isolate_->GetHeapStatistics(&stats);
264 size_t old_heap_size = 0;
265 // Run the GC until the heap size reaches a steady state to ensure that
266 // all the garbage is collected.
267 while (stats.used_heap_size() != old_heap_size) {
268 old_heap_size = stats.used_heap_size();
269 isolate_->RequestGarbageCollectionForTesting(
270 v8::Isolate::kFullGarbageCollection);
271 isolate_->GetHeapStatistics(&stats);
272 }
[email protected]d9f51dad2014-07-09 05:39:38273}
274
Devlin Cronin2db58e32017-08-15 21:29:29275scoped_refptr<const Extension> ModuleSystemTest::CreateExtension() {
276 std::unique_ptr<base::DictionaryValue> manifest =
277 DictionaryBuilder()
278 .Set("name", "test")
279 .Set("version", "1.0")
280 .Set("manifest_version", 2)
281 .Build();
282 return ExtensionBuilder().SetManifest(std::move(manifest)).Build();
283}
284
dchengf6f80662016-04-20 20:26:04285std::unique_ptr<ModuleSystemTestEnvironment>
286ModuleSystemTest::CreateEnvironment() {
Devlin Cronin2db58e32017-08-15 21:29:29287 return base::MakeUnique<ModuleSystemTestEnvironment>(isolate_, &context_set_,
288 extension_);
[email protected]1164b862012-05-09 22:38:37289}
290
291void ModuleSystemTest::ExpectNoAssertionsMade() {
292 should_assertions_be_made_ = false;
293}
294
[email protected]d9f51dad2014-07-09 05:39:38295void ModuleSystemTest::RunResolvedPromises() {
dgozmanfdfd5d12016-03-11 07:50:47296 v8::MicrotasksScope::PerformCheckpoint(isolate_);
[email protected]1164b862012-05-09 22:38:37297}
[email protected]582f6e92014-07-16 23:39:15298
299} // namespace extensions