OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/memory/ptr_util.h" | 6 #include "base/memory/ptr_util.h" |
7 #include "base/stl_util.h" | 7 #include "base/stl_util.h" |
8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
9 #include "base/values.h" | 9 #include "base/values.h" |
10 #include "content/public/child/v8_value_converter.h" | 10 #include "content/public/child/v8_value_converter.h" |
11 #include "extensions/renderer/api_binding.h" | 11 #include "extensions/renderer/api_binding.h" |
12 #include "extensions/renderer/api_binding_test_util.h" | 12 #include "extensions/renderer/api_binding_test_util.h" |
| 13 #include "extensions/renderer/api_event_handler.h" |
13 #include "extensions/renderer/api_request_handler.h" | 14 #include "extensions/renderer/api_request_handler.h" |
14 #include "gin/converter.h" | 15 #include "gin/converter.h" |
15 #include "gin/public/context_holder.h" | 16 #include "gin/public/context_holder.h" |
16 #include "gin/public/isolate_holder.h" | 17 #include "gin/public/isolate_holder.h" |
17 #include "gin/test/v8_test.h" | 18 #include "gin/test/v8_test.h" |
18 #include "gin/try_catch.h" | 19 #include "gin/try_catch.h" |
19 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
20 #include "v8/include/v8.h" | 21 #include "v8/include/v8.h" |
21 | 22 |
22 namespace extensions { | 23 namespace extensions { |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 v8::HandleScope handle_scope(instance_->isolate()); | 125 v8::HandleScope handle_scope(instance_->isolate()); |
125 holder_ = base::MakeUnique<gin::ContextHolder>(instance_->isolate()); | 126 holder_ = base::MakeUnique<gin::ContextHolder>(instance_->isolate()); |
126 holder_->SetContext( | 127 holder_->SetContext( |
127 v8::Local<v8::Context>::New(instance_->isolate(), context_)); | 128 v8::Local<v8::Context>::New(instance_->isolate(), context_)); |
128 request_handler_ = base::MakeUnique<APIRequestHandler>( | 129 request_handler_ = base::MakeUnique<APIRequestHandler>( |
129 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); | 130 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
130 } | 131 } |
131 | 132 |
132 void TearDown() override { | 133 void TearDown() override { |
133 request_handler_.reset(); | 134 request_handler_.reset(); |
| 135 |
| 136 v8::Global<v8::Context> weak_context(instance_->isolate(), context_); |
| 137 weak_context.SetWeak(); |
| 138 |
134 holder_.reset(); | 139 holder_.reset(); |
135 gin::V8Test::TearDown(); | 140 |
| 141 // NOTE: We explicitly do NOT call gin::V8Test::TearDown() here because we |
| 142 // do intermittent validation by doing a garbage collection after context |
| 143 // destruction and ensuring the context is fully released (which wouldn't |
| 144 // happen in cycles). |
| 145 // TODO(devlin): It might be time to move off V8Test if we're doing this. |
| 146 { |
| 147 v8::HandleScope handle_scope(instance_->isolate()); |
| 148 v8::Local<v8::Context>::New(instance_->isolate(), context_)->Exit(); |
| 149 context_.Reset(); |
| 150 } |
| 151 |
| 152 // Garbage collect everything so that we find any issues where we might be |
| 153 // double-freeing. |
| 154 // '5' is a magic number stolen from Blink; arbitrarily large enough to |
| 155 // hopefully clean up all the various paths. |
| 156 for (int i = 0; i < 5; i++) { |
| 157 instance_->isolate()->RequestGarbageCollectionForTesting( |
| 158 v8::Isolate::kFullGarbageCollection); |
| 159 } |
| 160 |
| 161 ASSERT_TRUE(weak_context.IsEmpty()); |
| 162 |
| 163 instance_->isolate()->Exit(); |
| 164 instance_.reset(); |
136 } | 165 } |
137 | 166 |
138 void ExpectPass(v8::Local<v8::Object> object, | 167 void ExpectPass(v8::Local<v8::Object> object, |
139 const std::string& script_source, | 168 const std::string& script_source, |
140 const std::string& expected_json_arguments_single_quotes) { | 169 const std::string& expected_json_arguments_single_quotes) { |
141 RunTest(object, script_source, true, | 170 RunTest(object, script_source, true, |
142 ReplaceSingleQuotes(expected_json_arguments_single_quotes), | 171 ReplaceSingleQuotes(expected_json_arguments_single_quotes), |
143 std::string()); | 172 std::string()); |
144 } | 173 } |
145 | 174 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 } | 224 } |
196 | 225 |
197 arguments_.reset(); | 226 arguments_.reset(); |
198 } | 227 } |
199 | 228 |
200 TEST_F(APIBindingTest, Test) { | 229 TEST_F(APIBindingTest, Test) { |
201 std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); | 230 std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); |
202 ASSERT_TRUE(functions); | 231 ASSERT_TRUE(functions); |
203 ArgumentSpec::RefMap refs; | 232 ArgumentSpec::RefMap refs; |
204 APIBinding binding( | 233 APIBinding binding( |
205 "test", *functions, nullptr, | 234 "test", *functions, nullptr, nullptr, |
206 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), | 235 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
207 &refs); | 236 &refs); |
208 EXPECT_TRUE(refs.empty()); | 237 EXPECT_TRUE(refs.empty()); |
209 | 238 |
210 v8::Isolate* isolate = instance_->isolate(); | 239 v8::Isolate* isolate = instance_->isolate(); |
211 | 240 |
212 v8::HandleScope handle_scope(isolate); | 241 v8::HandleScope handle_scope(isolate); |
213 v8::Local<v8::Context> context = | 242 v8::Local<v8::Context> context = |
214 v8::Local<v8::Context>::New(isolate, context_); | 243 v8::Local<v8::Context>::New(isolate, context_); |
215 | 244 |
| 245 APIEventHandler event_handler( |
| 246 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
216 v8::Local<v8::Object> binding_object = | 247 v8::Local<v8::Object> binding_object = |
217 binding.CreateInstance(context, isolate, base::Bind(&AllowAllAPIs)); | 248 binding.CreateInstance(context, isolate, &event_handler, |
| 249 base::Bind(&AllowAllAPIs)); |
218 | 250 |
219 ExpectPass(binding_object, "obj.oneString('foo');", "['foo']"); | 251 ExpectPass(binding_object, "obj.oneString('foo');", "['foo']"); |
220 ExpectPass(binding_object, "obj.oneString('');", "['']"); | 252 ExpectPass(binding_object, "obj.oneString('');", "['']"); |
221 ExpectFailure(binding_object, "obj.oneString(1);", kError); | 253 ExpectFailure(binding_object, "obj.oneString(1);", kError); |
222 ExpectFailure(binding_object, "obj.oneString();", kError); | 254 ExpectFailure(binding_object, "obj.oneString();", kError); |
223 ExpectFailure(binding_object, "obj.oneString({});", kError); | 255 ExpectFailure(binding_object, "obj.oneString({});", kError); |
224 ExpectFailure(binding_object, "obj.oneString('foo', 'bar');", kError); | 256 ExpectFailure(binding_object, "obj.oneString('foo', 'bar');", kError); |
225 | 257 |
226 ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]"); | 258 ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]"); |
227 ExpectPass(binding_object, "obj.stringAndInt('foo', -1);", "['foo',-1]"); | 259 ExpectPass(binding_object, "obj.stringAndInt('foo', -1);", "['foo',-1]"); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 " }]" | 329 " }]" |
298 "}]"; | 330 "}]"; |
299 | 331 |
300 std::unique_ptr<base::ListValue> functions = | 332 std::unique_ptr<base::ListValue> functions = |
301 ListValueFromString(kRefFunctions); | 333 ListValueFromString(kRefFunctions); |
302 ASSERT_TRUE(functions); | 334 ASSERT_TRUE(functions); |
303 std::unique_ptr<base::ListValue> types = ListValueFromString(kTypes); | 335 std::unique_ptr<base::ListValue> types = ListValueFromString(kTypes); |
304 ASSERT_TRUE(types); | 336 ASSERT_TRUE(types); |
305 ArgumentSpec::RefMap refs; | 337 ArgumentSpec::RefMap refs; |
306 APIBinding binding( | 338 APIBinding binding( |
307 "test", *functions, types.get(), | 339 "test", *functions, types.get(), nullptr, |
308 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), | 340 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
309 &refs); | 341 &refs); |
310 EXPECT_EQ(2u, refs.size()); | 342 EXPECT_EQ(2u, refs.size()); |
311 EXPECT_TRUE(base::ContainsKey(refs, "refObj")); | 343 EXPECT_TRUE(base::ContainsKey(refs, "refObj")); |
312 EXPECT_TRUE(base::ContainsKey(refs, "refEnum")); | 344 EXPECT_TRUE(base::ContainsKey(refs, "refEnum")); |
313 | 345 |
314 v8::Isolate* isolate = instance_->isolate(); | 346 v8::Isolate* isolate = instance_->isolate(); |
315 | 347 |
316 v8::HandleScope handle_scope(isolate); | 348 v8::HandleScope handle_scope(isolate); |
317 v8::Local<v8::Context> context = | 349 v8::Local<v8::Context> context = |
318 v8::Local<v8::Context>::New(isolate, context_); | 350 v8::Local<v8::Context>::New(isolate, context_); |
319 | 351 |
| 352 APIEventHandler event_handler( |
| 353 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
320 v8::Local<v8::Object> binding_object = | 354 v8::Local<v8::Object> binding_object = |
321 binding.CreateInstance(context, isolate, base::Bind(&AllowAllAPIs)); | 355 binding.CreateInstance(context, isolate, &event_handler, |
| 356 base::Bind(&AllowAllAPIs)); |
322 | 357 |
323 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo'})", | 358 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo'})", |
324 "[{'prop1':'foo'}]"); | 359 "[{'prop1':'foo'}]"); |
325 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 2})", | 360 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 2})", |
326 "[{'prop1':'foo','prop2':2}]"); | 361 "[{'prop1':'foo','prop2':2}]"); |
327 ExpectFailure(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 'a'})", | 362 ExpectFailure(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 'a'})", |
328 kError); | 363 kError); |
329 ExpectPass(binding_object, "obj.takesRefEnum('alpha')", "['alpha']"); | 364 ExpectPass(binding_object, "obj.takesRefEnum('alpha')", "['alpha']"); |
330 ExpectPass(binding_object, "obj.takesRefEnum('beta')", "['beta']"); | 365 ExpectPass(binding_object, "obj.takesRefEnum('beta')", "['beta']"); |
331 ExpectFailure(binding_object, "obj.takesRefEnum('gamma')", kError); | 366 ExpectFailure(binding_object, "obj.takesRefEnum('gamma')", kError); |
(...skipping 12 matching lines...) Expand all Loading... |
344 " 'parameters': []" | 379 " 'parameters': []" |
345 "}, {" | 380 "}, {" |
346 " 'name': 'restrictedTwo'," | 381 " 'name': 'restrictedTwo'," |
347 " 'parameters': []" | 382 " 'parameters': []" |
348 "}]"; | 383 "}]"; |
349 std::unique_ptr<base::ListValue> functions = | 384 std::unique_ptr<base::ListValue> functions = |
350 ListValueFromString(kRestrictedFunctions); | 385 ListValueFromString(kRestrictedFunctions); |
351 ASSERT_TRUE(functions); | 386 ASSERT_TRUE(functions); |
352 ArgumentSpec::RefMap refs; | 387 ArgumentSpec::RefMap refs; |
353 APIBinding binding( | 388 APIBinding binding( |
354 "test", *functions, nullptr, | 389 "test", *functions, nullptr, nullptr, |
355 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), | 390 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
356 &refs); | 391 &refs); |
357 | 392 |
358 v8::Isolate* isolate = instance_->isolate(); | 393 v8::Isolate* isolate = instance_->isolate(); |
359 v8::HandleScope handle_scope(isolate); | 394 v8::HandleScope handle_scope(isolate); |
360 v8::Local<v8::Context> context = | 395 v8::Local<v8::Context> context = |
361 v8::Local<v8::Context>::New(isolate, context_); | 396 v8::Local<v8::Context>::New(isolate, context_); |
362 | 397 |
363 auto is_available = [](const std::string& name) { | 398 auto is_available = [](const std::string& name) { |
364 std::set<std::string> functions = {"test.allowedOne", "test.allowedTwo", | 399 std::set<std::string> functions = {"test.allowedOne", "test.allowedTwo", |
365 "test.restrictedOne", | 400 "test.restrictedOne", |
366 "test.restrictedTwo"}; | 401 "test.restrictedTwo"}; |
367 EXPECT_TRUE(functions.count(name)); | 402 EXPECT_TRUE(functions.count(name)); |
368 return name == "test.allowedOne" || name == "test.allowedTwo"; | 403 return name == "test.allowedOne" || name == "test.allowedTwo"; |
369 }; | 404 }; |
370 | 405 |
| 406 APIEventHandler event_handler( |
| 407 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
371 v8::Local<v8::Object> binding_object = | 408 v8::Local<v8::Object> binding_object = |
372 binding.CreateInstance(context, isolate, base::Bind(is_available)); | 409 binding.CreateInstance(context, isolate, &event_handler, |
| 410 base::Bind(is_available)); |
373 | 411 |
374 auto is_defined = [&binding_object, context](const std::string& name) { | 412 auto is_defined = [&binding_object, context](const std::string& name) { |
375 v8::Local<v8::Value> val = | 413 v8::Local<v8::Value> val = |
376 GetPropertyFromObject(binding_object, context, name); | 414 GetPropertyFromObject(binding_object, context, name); |
377 EXPECT_FALSE(val.IsEmpty()); | 415 EXPECT_FALSE(val.IsEmpty()); |
378 return !val->IsUndefined() && !val->IsNull(); | 416 return !val->IsUndefined() && !val->IsNull(); |
379 }; | 417 }; |
380 | 418 |
381 EXPECT_TRUE(is_defined("allowedOne")); | 419 EXPECT_TRUE(is_defined("allowedOne")); |
382 EXPECT_TRUE(is_defined("allowedTwo")); | 420 EXPECT_TRUE(is_defined("allowedTwo")); |
383 EXPECT_FALSE(is_defined("restrictedOne")); | 421 EXPECT_FALSE(is_defined("restrictedOne")); |
384 EXPECT_FALSE(is_defined("restrictedTwo")); | 422 EXPECT_FALSE(is_defined("restrictedTwo")); |
385 } | 423 } |
386 | 424 |
| 425 // Tests that events specified in the API are created as properties of the API |
| 426 // object. |
| 427 TEST_F(APIBindingTest, TestEventCreation) { |
| 428 const char kEvents[] = "[{'name': 'onFoo'}, {'name': 'onBar'}]"; |
| 429 std::unique_ptr<base::ListValue> events = ListValueFromString(kEvents); |
| 430 ASSERT_TRUE(events); |
| 431 std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); |
| 432 ASSERT_TRUE(functions); |
| 433 ArgumentSpec::RefMap refs; |
| 434 APIBinding binding( |
| 435 "test", *functions, nullptr, events.get(), |
| 436 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
| 437 &refs); |
| 438 |
| 439 v8::Isolate* isolate = instance_->isolate(); |
| 440 v8::HandleScope handle_scope(isolate); |
| 441 v8::Local<v8::Context> context = |
| 442 v8::Local<v8::Context>::New(isolate, context_); |
| 443 |
| 444 APIEventHandler event_handler( |
| 445 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
| 446 v8::Local<v8::Object> binding_object = |
| 447 binding.CreateInstance(context, isolate, &event_handler, |
| 448 base::Bind(&AllowAllAPIs)); |
| 449 |
| 450 // Event behavior is tested in the APIEventHandler unittests as well as the |
| 451 // APIBindingsSystem tests, so we really only need to check that the events |
| 452 // are being initialized on the object. |
| 453 v8::Maybe<bool> has_on_foo = |
| 454 binding_object->Has(context, gin::StringToV8(isolate, "onFoo")); |
| 455 EXPECT_TRUE(has_on_foo.IsJust()); |
| 456 EXPECT_TRUE(has_on_foo.FromJust()); |
| 457 |
| 458 v8::Maybe<bool> has_on_bar = |
| 459 binding_object->Has(context, gin::StringToV8(isolate, "onBar")); |
| 460 EXPECT_TRUE(has_on_bar.IsJust()); |
| 461 EXPECT_TRUE(has_on_bar.FromJust()); |
| 462 |
| 463 v8::Maybe<bool> has_on_baz = |
| 464 binding_object->Has(context, gin::StringToV8(isolate, "onBaz")); |
| 465 EXPECT_TRUE(has_on_baz.IsJust()); |
| 466 EXPECT_FALSE(has_on_baz.FromJust()); |
| 467 } |
| 468 |
387 } // namespace extensions | 469 } // namespace extensions |
OLD | NEW |