module_system_test.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "extensions/renderer/module_system_test.h"
  5. #include <stddef.h>
  6. #include <map>
  7. #include <memory>
  8. #include <string>
  9. #include <utility>
  10. #include "base/bind.h"
  11. #include "base/callback.h"
  12. #include "base/command_line.h"
  13. #include "base/files/file_path.h"
  14. #include "base/files/file_util.h"
  15. #include "base/lazy_instance.h"
  16. #include "base/path_service.h"
  17. #include "base/run_loop.h"
  18. #include "base/strings/string_piece.h"
  19. #include "extensions/common/extension_builder.h"
  20. #include "extensions/common/extension_paths.h"
  21. #include "extensions/common/value_builder.h"
  22. #include "extensions/renderer/ipc_message_sender.h"
  23. #include "extensions/renderer/logging_native_handler.h"
  24. #include "extensions/renderer/native_extension_bindings_system.h"
  25. #include "extensions/renderer/object_backed_native_handler.h"
  26. #include "extensions/renderer/safe_builtins.h"
  27. #include "extensions/renderer/script_context_set.h"
  28. #include "extensions/renderer/string_source_map.h"
  29. #include "extensions/renderer/test_v8_extension_configuration.h"
  30. #include "extensions/renderer/utils_native_handler.h"
  31. #include "gin/converter.h"
  32. #include "ui/base/resource/resource_bundle.h"
  33. #include "v8/include/v8-context.h"
  34. #include "v8/include/v8-function-callback.h"
  35. #include "v8/include/v8-isolate.h"
  36. #include "v8/include/v8-microtask-queue.h"
  37. #include "v8/include/v8-object.h"
  38. #include "v8/include/v8-primitive.h"
  39. #include "v8/include/v8-statistics.h"
  40. namespace extensions {
  41. namespace {
  42. class FailsOnException : public ModuleSystem::ExceptionHandler {
  43. public:
  44. FailsOnException() : ModuleSystem::ExceptionHandler(nullptr) {}
  45. void HandleUncaughtException(const v8::TryCatch& try_catch) override {
  46. FAIL() << "Uncaught exception: " << CreateExceptionString(try_catch);
  47. }
  48. };
  49. class GetAPINatives : public ObjectBackedNativeHandler {
  50. public:
  51. GetAPINatives(ScriptContext* context,
  52. NativeExtensionBindingsSystem* bindings_system)
  53. : ObjectBackedNativeHandler(context), bindings_system_(bindings_system) {
  54. DCHECK(bindings_system_);
  55. }
  56. GetAPINatives(const GetAPINatives&) = delete;
  57. GetAPINatives& operator=(const GetAPINatives&) = delete;
  58. ~GetAPINatives() override {}
  59. // ObjectBackedNativeHandler:
  60. void AddRoutes() override {
  61. auto get_api = [](ScriptContext* context,
  62. NativeExtensionBindingsSystem* bindings_system,
  63. const v8::FunctionCallbackInfo<v8::Value>& args) {
  64. CHECK_EQ(1, args.Length());
  65. CHECK(args[0]->IsString());
  66. std::string api_name = gin::V8ToString(context->isolate(), args[0]);
  67. v8::Local<v8::Object> api;
  68. if (bindings_system) {
  69. api = bindings_system->GetAPIObjectForTesting(context, api_name);
  70. } else {
  71. v8::Local<v8::Object> full_binding;
  72. CHECK(
  73. context->module_system()->Require(api_name).ToLocal(&full_binding))
  74. << "Failed to get: " << api_name;
  75. v8::Local<v8::Value> api_value;
  76. CHECK(full_binding
  77. ->Get(context->v8_context(),
  78. gin::StringToSymbol(context->isolate(), "binding"))
  79. .ToLocal(&api_value))
  80. << "Failed to get: " << api_name;
  81. CHECK(api_value->IsObject()) << "Failed to get: " << api_name;
  82. api = api_value.As<v8::Object>();
  83. }
  84. args.GetReturnValue().Set(api);
  85. };
  86. RouteHandlerFunction(
  87. "get", base::BindRepeating(get_api, context(), bindings_system_));
  88. }
  89. private:
  90. NativeExtensionBindingsSystem* bindings_system_ = nullptr;
  91. };
  92. } // namespace
  93. // Native JS functions for doing asserts.
  94. class ModuleSystemTestEnvironment::AssertNatives
  95. : public ObjectBackedNativeHandler {
  96. public:
  97. explicit AssertNatives(ScriptContext* context)
  98. : ObjectBackedNativeHandler(context),
  99. assertion_made_(false),
  100. failed_(false) {}
  101. // ObjectBackedNativeHandler:
  102. void AddRoutes() override {
  103. RouteHandlerFunction("AssertTrue",
  104. base::BindRepeating(&AssertNatives::AssertTrue,
  105. base::Unretained(this)));
  106. RouteHandlerFunction("AssertFalse",
  107. base::BindRepeating(&AssertNatives::AssertFalse,
  108. base::Unretained(this)));
  109. }
  110. bool assertion_made() { return assertion_made_; }
  111. bool failed() { return failed_; }
  112. void AssertTrue(const v8::FunctionCallbackInfo<v8::Value>& args) {
  113. CHECK_EQ(1, args.Length());
  114. assertion_made_ = true;
  115. failed_ = failed_ || !args[0]->ToBoolean(args.GetIsolate())->Value();
  116. }
  117. void AssertFalse(const v8::FunctionCallbackInfo<v8::Value>& args) {
  118. CHECK_EQ(1, args.Length());
  119. assertion_made_ = true;
  120. failed_ = failed_ || args[0]->ToBoolean(args.GetIsolate())->Value();
  121. }
  122. private:
  123. bool assertion_made_;
  124. bool failed_;
  125. };
  126. ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(
  127. v8::Isolate* isolate,
  128. ScriptContextSet* context_set,
  129. scoped_refptr<const Extension> extension)
  130. : isolate_(isolate),
  131. context_holder_(new gin::ContextHolder(isolate_)),
  132. handle_scope_(isolate_),
  133. extension_(extension),
  134. context_set_(context_set),
  135. source_map_(new StringSourceMap()) {
  136. context_holder_->SetContext(v8::Context::New(
  137. isolate, TestV8ExtensionConfiguration::GetConfiguration()));
  138. {
  139. auto context = std::make_unique<ScriptContext>(
  140. context_holder_->context(),
  141. nullptr, // WebFrame
  142. extension_.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension_.get(),
  143. Feature::BLESSED_EXTENSION_CONTEXT);
  144. context_ = context.get();
  145. context_set_->AddForTesting(std::move(context));
  146. }
  147. context_->v8_context()->Enter();
  148. assert_natives_ = new AssertNatives(context_);
  149. bindings_system_ = std::make_unique<NativeExtensionBindingsSystem>(nullptr);
  150. {
  151. std::unique_ptr<ModuleSystem> module_system(
  152. new ModuleSystem(context_, source_map_.get()));
  153. context_->SetModuleSystem(std::move(module_system));
  154. }
  155. ModuleSystem* module_system = context_->module_system();
  156. module_system->RegisterNativeHandler(
  157. "assert", std::unique_ptr<NativeHandler>(assert_natives_));
  158. module_system->RegisterNativeHandler(
  159. "logging",
  160. std::unique_ptr<NativeHandler>(new LoggingNativeHandler(context_)));
  161. module_system->RegisterNativeHandler(
  162. "utils",
  163. std::unique_ptr<NativeHandler>(new UtilsNativeHandler(context_)));
  164. module_system->RegisterNativeHandler(
  165. "apiGetter",
  166. std::make_unique<GetAPINatives>(context_, bindings_system_.get()));
  167. module_system->SetExceptionHandlerForTest(
  168. std::unique_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));
  169. bindings_system_->DidCreateScriptContext(context_);
  170. bindings_system_->UpdateBindingsForContext(context_);
  171. }
  172. ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() {
  173. if (context_)
  174. ShutdownModuleSystem();
  175. }
  176. void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
  177. const std::string& code) {
  178. source_map_->RegisterModule(name, code);
  179. }
  180. void ModuleSystemTestEnvironment::RegisterModule(const std::string& name,
  181. int resource_id,
  182. bool gzipped) {
  183. std::string code =
  184. ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
  185. resource_id);
  186. source_map_->RegisterModule(name, code, gzipped);
  187. }
  188. void ModuleSystemTestEnvironment::OverrideNativeHandler(
  189. const std::string& name,
  190. const std::string& code) {
  191. RegisterModule(name, code);
  192. context_->module_system()->OverrideNativeHandlerForTest(name);
  193. }
  194. void ModuleSystemTestEnvironment::RegisterTestFile(
  195. const std::string& module_name,
  196. const std::string& file_name) {
  197. base::FilePath test_js_file_path;
  198. ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_js_file_path));
  199. test_js_file_path = test_js_file_path.AppendASCII(file_name);
  200. std::string test_js;
  201. ASSERT_TRUE(base::ReadFileToString(test_js_file_path, &test_js));
  202. source_map_->RegisterModule(module_name, test_js);
  203. }
  204. void ModuleSystemTestEnvironment::ShutdownGin() {
  205. context_holder_.reset();
  206. }
  207. void ModuleSystemTestEnvironment::ShutdownModuleSystem() {
  208. CHECK(context_->is_valid());
  209. context_->v8_context()->Exit();
  210. context_set_->Remove(context_);
  211. base::RunLoop().RunUntilIdle();
  212. context_ = nullptr;
  213. assert_natives_ = nullptr;
  214. }
  215. v8::Local<v8::Object> ModuleSystemTestEnvironment::CreateGlobal(
  216. const std::string& name) {
  217. v8::EscapableHandleScope handle_scope(isolate_);
  218. v8::MicrotasksScope microtasks(isolate_,
  219. v8::MicrotasksScope::kDoNotRunMicrotasks);
  220. v8::Local<v8::Object> object = v8::Object::New(isolate_);
  221. isolate_->GetCurrentContext()
  222. ->Global()
  223. ->Set(context_->v8_context(),
  224. v8::String::NewFromUtf8(isolate_, name.c_str(),
  225. v8::NewStringType::kInternalized)
  226. .ToLocalChecked(),
  227. object)
  228. .ToChecked();
  229. return handle_scope.Escape(object);
  230. }
  231. void ModuleSystemTestEnvironment::SetLazyField(
  232. v8::Local<v8::Object> object,
  233. const std::string& field,
  234. const std::string& module_name,
  235. const std::string& module_field) {
  236. module_system()->SetLazyField(object, field, module_name, module_field);
  237. }
  238. ModuleSystemTest::ModuleSystemTest()
  239. : isolate_holder_(task_environment_.GetMainThreadTaskRunner(),
  240. gin::IsolateHolder::IsolateType::kTest),
  241. isolate_(isolate_holder_.isolate()),
  242. context_set_(&extension_ids_),
  243. should_assertions_be_made_(true) {}
  244. ModuleSystemTest::~ModuleSystemTest() {
  245. }
  246. void ModuleSystemTest::SetUp() {
  247. isolate_->Enter();
  248. extension_ = CreateExtension();
  249. env_ = CreateEnvironment();
  250. base::CommandLine::ForCurrentProcess()->AppendSwitch("test-type");
  251. }
  252. void ModuleSystemTest::TearDown() {
  253. // All tests must assert at least once unless otherwise specified.
  254. 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. }
  261. 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. }
  273. isolate_->Exit();
  274. }
  275. scoped_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. std::unique_ptr<ModuleSystemTestEnvironment>
  285. ModuleSystemTest::CreateEnvironment() {
  286. return std::make_unique<ModuleSystemTestEnvironment>(isolate_, &context_set_,
  287. extension_);
  288. }
  289. void ModuleSystemTest::ExpectNoAssertionsMade() {
  290. should_assertions_be_made_ = false;
  291. }
  292. void ModuleSystemTest::RunResolvedPromises() {
  293. v8::MicrotasksScope::PerformCheckpoint(isolate_);
  294. }
  295. } // namespace extensions