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 "extensions/renderer/bindings/api_binding.h" | 10 #include "extensions/renderer/bindings/api_binding.h" |
11 #include "extensions/renderer/bindings/api_binding_hooks.h" | 11 #include "extensions/renderer/bindings/api_binding_hooks.h" |
12 #include "extensions/renderer/bindings/api_binding_hooks_test_delegate.h" | 12 #include "extensions/renderer/bindings/api_binding_hooks_test_delegate.h" |
13 #include "extensions/renderer/bindings/api_binding_test.h" | 13 #include "extensions/renderer/bindings/api_binding_test.h" |
14 #include "extensions/renderer/bindings/api_binding_test_util.h" | 14 #include "extensions/renderer/bindings/api_binding_test_util.h" |
15 #include "extensions/renderer/bindings/api_event_handler.h" | 15 #include "extensions/renderer/bindings/api_event_handler.h" |
16 #include "extensions/renderer/bindings/api_invocation_errors.h" | 16 #include "extensions/renderer/bindings/api_invocation_errors.h" |
17 #include "extensions/renderer/bindings/api_request_handler.h" | 17 #include "extensions/renderer/bindings/api_request_handler.h" |
18 #include "extensions/renderer/bindings/api_type_reference_map.h" | 18 #include "extensions/renderer/bindings/api_type_reference_map.h" |
19 #include "extensions/renderer/bindings/binding_access_checker.h" | 19 #include "extensions/renderer/bindings/binding_access_checker.h" |
20 #include "gin/arguments.h" | 20 #include "gin/arguments.h" |
21 #include "gin/converter.h" | 21 #include "gin/converter.h" |
22 #include "gin/public/context_holder.h" | 22 #include "gin/public/context_holder.h" |
| 23 #include "testing/gmock/include/gmock/gmock.h" |
23 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
24 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" | 25 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" |
25 #include "v8/include/v8.h" | 26 #include "v8/include/v8.h" |
26 | 27 |
27 namespace extensions { | 28 namespace extensions { |
28 | 29 |
29 using namespace api_errors; | 30 using namespace api_errors; |
30 | 31 |
31 namespace { | 32 namespace { |
32 | 33 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 bool AllowAllFeatures(v8::Local<v8::Context> context, const std::string& name) { | 74 bool AllowAllFeatures(v8::Local<v8::Context> context, const std::string& name) { |
74 return true; | 75 return true; |
75 } | 76 } |
76 | 77 |
77 void OnEventListenersChanged(const std::string& event_name, | 78 void OnEventListenersChanged(const std::string& event_name, |
78 binding::EventListenersChanged change, | 79 binding::EventListenersChanged change, |
79 const base::DictionaryValue* filter, | 80 const base::DictionaryValue* filter, |
80 bool was_manual, | 81 bool was_manual, |
81 v8::Local<v8::Context> context) {} | 82 v8::Local<v8::Context> context) {} |
82 | 83 |
| 84 void DoNothingWithSilentRequest( |
| 85 v8::Local<v8::Context> context, |
| 86 const std::string& call_name, |
| 87 const std::vector<v8::Local<v8::Value>>& arguments) {} |
| 88 |
83 } // namespace | 89 } // namespace |
84 | 90 |
85 class APIBindingUnittest : public APIBindingTest { | 91 class APIBindingUnittest : public APIBindingTest { |
86 public: | 92 public: |
87 void OnFunctionCall(std::unique_ptr<APIRequestHandler::Request> request, | 93 void OnFunctionCall(std::unique_ptr<APIRequestHandler::Request> request, |
88 v8::Local<v8::Context> context) { | 94 v8::Local<v8::Context> context) { |
89 last_request_ = std::move(request); | 95 last_request_ = std::move(request); |
90 } | 96 } |
91 | 97 |
92 protected: | 98 protected: |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 void SetHooksDelegate( | 149 void SetHooksDelegate( |
144 std::unique_ptr<APIBindingHooksDelegate> hooks_delegate) { | 150 std::unique_ptr<APIBindingHooksDelegate> hooks_delegate) { |
145 binding_hooks_delegate_ = std::move(hooks_delegate); | 151 binding_hooks_delegate_ = std::move(hooks_delegate); |
146 ASSERT_TRUE(binding_hooks_delegate_); | 152 ASSERT_TRUE(binding_hooks_delegate_); |
147 } | 153 } |
148 | 154 |
149 void SetCreateCustomType(const APIBinding::CreateCustomType& callback) { | 155 void SetCreateCustomType(const APIBinding::CreateCustomType& callback) { |
150 create_custom_type_ = callback; | 156 create_custom_type_ = callback; |
151 } | 157 } |
152 | 158 |
| 159 void SetOnSilentRequest(const APIBinding::OnSilentRequest& callback) { |
| 160 on_silent_request_ = callback; |
| 161 } |
| 162 |
153 void SetAvailabilityCallback( | 163 void SetAvailabilityCallback( |
154 const BindingAccessChecker::AvailabilityCallback& callback) { | 164 const BindingAccessChecker::AvailabilityCallback& callback) { |
155 availability_callback_ = callback; | 165 availability_callback_ = callback; |
156 } | 166 } |
157 | 167 |
158 void InitializeBinding() { | 168 void InitializeBinding() { |
159 if (!binding_hooks_) { | 169 if (!binding_hooks_) { |
160 binding_hooks_ = base::MakeUnique<APIBindingHooks>( | 170 binding_hooks_ = base::MakeUnique<APIBindingHooks>( |
161 kBindingName, binding::RunJSFunctionSync()); | 171 kBindingName, binding::RunJSFunctionSync()); |
162 } | 172 } |
163 if (binding_hooks_delegate_) | 173 if (binding_hooks_delegate_) |
164 binding_hooks_->SetDelegate(std::move(binding_hooks_delegate_)); | 174 binding_hooks_->SetDelegate(std::move(binding_hooks_delegate_)); |
| 175 if (!on_silent_request_) |
| 176 on_silent_request_ = base::Bind(&DoNothingWithSilentRequest); |
165 if (!availability_callback_) | 177 if (!availability_callback_) |
166 availability_callback_ = base::Bind(&AllowAllFeatures); | 178 availability_callback_ = base::Bind(&AllowAllFeatures); |
167 event_handler_ = base::MakeUnique<APIEventHandler>( | 179 event_handler_ = base::MakeUnique<APIEventHandler>( |
168 base::Bind(&RunFunctionOnGlobalAndIgnoreResult), | 180 base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
169 base::Bind(&RunFunctionOnGlobalAndReturnHandle), | 181 base::Bind(&RunFunctionOnGlobalAndReturnHandle), |
170 base::Bind(&OnEventListenersChanged)); | 182 base::Bind(&OnEventListenersChanged)); |
171 access_checker_ = | 183 access_checker_ = |
172 base::MakeUnique<BindingAccessChecker>(availability_callback_); | 184 base::MakeUnique<BindingAccessChecker>(availability_callback_); |
173 binding_ = base::MakeUnique<APIBinding>( | 185 binding_ = base::MakeUnique<APIBinding>( |
174 kBindingName, binding_functions_.get(), binding_types_.get(), | 186 kBindingName, binding_functions_.get(), binding_types_.get(), |
175 binding_events_.get(), binding_properties_.get(), create_custom_type_, | 187 binding_events_.get(), binding_properties_.get(), create_custom_type_, |
176 std::move(binding_hooks_), &type_refs_, request_handler_.get(), | 188 on_silent_request_, std::move(binding_hooks_), &type_refs_, |
177 event_handler_.get(), access_checker_.get()); | 189 request_handler_.get(), event_handler_.get(), access_checker_.get()); |
178 EXPECT_EQ(!binding_types_.get(), type_refs_.empty()); | 190 EXPECT_EQ(!binding_types_.get(), type_refs_.empty()); |
179 } | 191 } |
180 | 192 |
181 void ExpectPass(v8::Local<v8::Object> object, | 193 void ExpectPass(v8::Local<v8::Object> object, |
182 const std::string& script_source, | 194 const std::string& script_source, |
183 const std::string& expected_json_arguments_single_quotes, | 195 const std::string& expected_json_arguments_single_quotes, |
184 bool expect_callback) { | 196 bool expect_callback) { |
185 ExpectPass(MainContext(), object, script_source, | 197 ExpectPass(MainContext(), object, script_source, |
186 expected_json_arguments_single_quotes, expect_callback); | 198 expected_json_arguments_single_quotes, expect_callback); |
187 } | 199 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 std::unique_ptr<BindingAccessChecker> access_checker_; | 248 std::unique_ptr<BindingAccessChecker> access_checker_; |
237 APITypeReferenceMap type_refs_; | 249 APITypeReferenceMap type_refs_; |
238 | 250 |
239 std::unique_ptr<base::ListValue> binding_functions_; | 251 std::unique_ptr<base::ListValue> binding_functions_; |
240 std::unique_ptr<base::ListValue> binding_events_; | 252 std::unique_ptr<base::ListValue> binding_events_; |
241 std::unique_ptr<base::ListValue> binding_types_; | 253 std::unique_ptr<base::ListValue> binding_types_; |
242 std::unique_ptr<base::DictionaryValue> binding_properties_; | 254 std::unique_ptr<base::DictionaryValue> binding_properties_; |
243 std::unique_ptr<APIBindingHooks> binding_hooks_; | 255 std::unique_ptr<APIBindingHooks> binding_hooks_; |
244 std::unique_ptr<APIBindingHooksDelegate> binding_hooks_delegate_; | 256 std::unique_ptr<APIBindingHooksDelegate> binding_hooks_delegate_; |
245 APIBinding::CreateCustomType create_custom_type_; | 257 APIBinding::CreateCustomType create_custom_type_; |
| 258 APIBinding::OnSilentRequest on_silent_request_; |
246 BindingAccessChecker::AvailabilityCallback availability_callback_; | 259 BindingAccessChecker::AvailabilityCallback availability_callback_; |
247 | 260 |
248 DISALLOW_COPY_AND_ASSIGN(APIBindingUnittest); | 261 DISALLOW_COPY_AND_ASSIGN(APIBindingUnittest); |
249 }; | 262 }; |
250 | 263 |
251 void APIBindingUnittest::RunTest(v8::Local<v8::Context> context, | 264 void APIBindingUnittest::RunTest(v8::Local<v8::Context> context, |
252 v8::Local<v8::Object> object, | 265 v8::Local<v8::Object> object, |
253 const std::string& script_source, | 266 const std::string& script_source, |
254 bool should_pass, | 267 bool should_pass, |
255 const std::string& expected_json_arguments, | 268 const std::string& expected_json_arguments, |
(...skipping 1038 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1294 v8::Local<v8::Object> binding_object = binding()->CreateInstance(context); | 1307 v8::Local<v8::Object> binding_object = binding()->CreateInstance(context); |
1295 | 1308 |
1296 // The extra property should be present on the binding object. | 1309 // The extra property should be present on the binding object. |
1297 EXPECT_EQ("42", GetStringPropertyFromObject(binding_object, context, | 1310 EXPECT_EQ("42", GetStringPropertyFromObject(binding_object, context, |
1298 "hookedProperty")); | 1311 "hookedProperty")); |
1299 // Sanity check: other values should still be there. | 1312 // Sanity check: other values should still be there. |
1300 EXPECT_EQ("function", | 1313 EXPECT_EQ("function", |
1301 GetStringPropertyFromObject(binding_object, context, "oneString")); | 1314 GetStringPropertyFromObject(binding_object, context, "oneString")); |
1302 } | 1315 } |
1303 | 1316 |
| 1317 // Test that running hooks returning different results correctly sends requests |
| 1318 // or notifies of silent requests. |
| 1319 TEST_F(APIBindingUnittest, TestSendingRequestsAndSilentRequestsWithHooks) { |
| 1320 SetFunctions( |
| 1321 "[{" |
| 1322 " 'name': 'modifyArgs'," |
| 1323 " 'parameters': []" |
| 1324 "}, {" |
| 1325 " 'name': 'invalidInvocation'," |
| 1326 " 'parameters': []" |
| 1327 "}, {" |
| 1328 " 'name': 'throwException'," |
| 1329 " 'parameters': []" |
| 1330 "}, {" |
| 1331 " 'name': 'dontHandle'," |
| 1332 " 'parameters': []" |
| 1333 "}, {" |
| 1334 " 'name': 'handle'," |
| 1335 " 'parameters': []" |
| 1336 "}, {" |
| 1337 " 'name': 'handleAndSendRequest'," |
| 1338 " 'parameters': []" |
| 1339 "}, {" |
| 1340 " 'name': 'handleWithArgs'," |
| 1341 " 'parameters': [{" |
| 1342 " 'name': 'first'," |
| 1343 " 'type': 'string'" |
| 1344 " }, {" |
| 1345 " 'name': 'second'," |
| 1346 " 'type': 'integer'" |
| 1347 " }]" |
| 1348 "}]"); |
| 1349 |
| 1350 using RequestResult = APIBindingHooks::RequestResult; |
| 1351 |
| 1352 auto basic_handler = [](RequestResult::ResultCode code, const APISignature*, |
| 1353 v8::Local<v8::Context> context, |
| 1354 std::vector<v8::Local<v8::Value>>* arguments, |
| 1355 const APITypeReferenceMap& map) { |
| 1356 return RequestResult(code); |
| 1357 }; |
| 1358 |
| 1359 auto hooks = base::MakeUnique<APIBindingHooksTestDelegate>(); |
| 1360 hooks->AddHandler( |
| 1361 "test.modifyArgs", |
| 1362 base::Bind(basic_handler, RequestResult::ARGUMENTS_UPDATED)); |
| 1363 hooks->AddHandler( |
| 1364 "test.invalidInvocation", |
| 1365 base::Bind(basic_handler, RequestResult::INVALID_INVOCATION)); |
| 1366 hooks->AddHandler("test.dontHandle", |
| 1367 base::Bind(basic_handler, RequestResult::NOT_HANDLED)); |
| 1368 hooks->AddHandler("test.handle", |
| 1369 base::Bind(basic_handler, RequestResult::HANDLED)); |
| 1370 hooks->AddHandler( |
| 1371 "test.throwException", |
| 1372 base::Bind([](const APISignature*, v8::Local<v8::Context> context, |
| 1373 std::vector<v8::Local<v8::Value>>* arguments, |
| 1374 const APITypeReferenceMap& map) { |
| 1375 context->GetIsolate()->ThrowException( |
| 1376 gin::StringToV8(context->GetIsolate(), "some error")); |
| 1377 return RequestResult(RequestResult::THROWN); |
| 1378 })); |
| 1379 hooks->AddHandler( |
| 1380 "test.handleWithArgs", |
| 1381 base::Bind([](const APISignature*, v8::Local<v8::Context> context, |
| 1382 std::vector<v8::Local<v8::Value>>* arguments, |
| 1383 const APITypeReferenceMap& map) { |
| 1384 arguments->push_back(v8::Integer::New(context->GetIsolate(), 42)); |
| 1385 return RequestResult(RequestResult::HANDLED); |
| 1386 })); |
| 1387 |
| 1388 auto handle_and_send_request = |
| 1389 [](APIRequestHandler* handler, const APISignature*, |
| 1390 v8::Local<v8::Context> context, |
| 1391 std::vector<v8::Local<v8::Value>>* arguments, |
| 1392 const APITypeReferenceMap& map) { |
| 1393 handler->StartRequest( |
| 1394 context, "test.handleAndSendRequest", |
| 1395 base::MakeUnique<base::ListValue>(), v8::Local<v8::Function>(), |
| 1396 v8::Local<v8::Function>(), binding::RequestThread::UI); |
| 1397 return RequestResult(RequestResult::HANDLED); |
| 1398 }; |
| 1399 hooks->AddHandler("test.handleAndSendRequest", |
| 1400 base::Bind(handle_and_send_request, request_handler())); |
| 1401 |
| 1402 SetHooksDelegate(std::move(hooks)); |
| 1403 |
| 1404 auto on_silent_request = |
| 1405 [](base::Optional<std::string>* name_out, |
| 1406 base::Optional<std::vector<std::string>>* args_out, |
| 1407 v8::Local<v8::Context> context, const std::string& call_name, |
| 1408 const std::vector<v8::Local<v8::Value>>& arguments) { |
| 1409 *name_out = call_name; |
| 1410 *args_out = std::vector<std::string>(); |
| 1411 (*args_out)->reserve(arguments.size()); |
| 1412 for (const auto& arg : arguments) |
| 1413 (*args_out)->push_back(V8ToString(arg, context)); |
| 1414 }; |
| 1415 base::Optional<std::string> silent_request; |
| 1416 base::Optional<std::vector<std::string>> request_arguments; |
| 1417 SetOnSilentRequest( |
| 1418 base::Bind(on_silent_request, &silent_request, &request_arguments)); |
| 1419 |
| 1420 InitializeBinding(); |
| 1421 |
| 1422 v8::HandleScope handle_scope(isolate()); |
| 1423 v8::Local<v8::Context> context = MainContext(); |
| 1424 |
| 1425 v8::Local<v8::Object> binding_object = binding()->CreateInstance(context); |
| 1426 |
| 1427 auto call_api_method = [binding_object, context]( |
| 1428 base::StringPiece name, |
| 1429 base::StringPiece string_args) { |
| 1430 v8::Local<v8::Function> call = FunctionFromString( |
| 1431 context, base::StringPrintf("(function(binding) { binding.%s(%s); })", |
| 1432 name.data(), string_args.data())); |
| 1433 v8::Local<v8::Value> args[] = {binding_object}; |
| 1434 v8::TryCatch try_catch(context->GetIsolate()); |
| 1435 // The throwException call will throw an exception; ignore it. |
| 1436 ignore_result(call->Call(context, v8::Undefined(context->GetIsolate()), |
| 1437 arraysize(args), args)); |
| 1438 }; |
| 1439 |
| 1440 call_api_method("modifyArgs", ""); |
| 1441 ASSERT_TRUE(last_request()); |
| 1442 EXPECT_EQ("test.modifyArgs", last_request()->method_name); |
| 1443 EXPECT_FALSE(silent_request); |
| 1444 reset_last_request(); |
| 1445 silent_request.reset(); |
| 1446 request_arguments.reset(); |
| 1447 |
| 1448 call_api_method("invalidInvocation", ""); |
| 1449 EXPECT_FALSE(last_request()); |
| 1450 EXPECT_FALSE(silent_request); |
| 1451 reset_last_request(); |
| 1452 silent_request.reset(); |
| 1453 request_arguments.reset(); |
| 1454 |
| 1455 call_api_method("throwException", ""); |
| 1456 EXPECT_FALSE(last_request()); |
| 1457 EXPECT_FALSE(silent_request); |
| 1458 reset_last_request(); |
| 1459 silent_request.reset(); |
| 1460 request_arguments.reset(); |
| 1461 |
| 1462 call_api_method("dontHandle", ""); |
| 1463 ASSERT_TRUE(last_request()); |
| 1464 EXPECT_EQ("test.dontHandle", last_request()->method_name); |
| 1465 EXPECT_FALSE(silent_request); |
| 1466 reset_last_request(); |
| 1467 silent_request.reset(); |
| 1468 request_arguments.reset(); |
| 1469 |
| 1470 call_api_method("handle", ""); |
| 1471 EXPECT_FALSE(last_request()); |
| 1472 ASSERT_TRUE(silent_request); |
| 1473 EXPECT_EQ("test.handle", *silent_request); |
| 1474 ASSERT_TRUE(request_arguments); |
| 1475 EXPECT_TRUE(request_arguments->empty()); |
| 1476 reset_last_request(); |
| 1477 silent_request.reset(); |
| 1478 request_arguments.reset(); |
| 1479 |
| 1480 call_api_method("handleAndSendRequest", ""); |
| 1481 ASSERT_TRUE(last_request()); |
| 1482 EXPECT_EQ("test.handleAndSendRequest", last_request()->method_name); |
| 1483 EXPECT_FALSE(silent_request); |
| 1484 reset_last_request(); |
| 1485 silent_request.reset(); |
| 1486 request_arguments.reset(); |
| 1487 |
| 1488 call_api_method("handleWithArgs", "'str'"); |
| 1489 EXPECT_FALSE(last_request()); |
| 1490 ASSERT_TRUE(silent_request); |
| 1491 ASSERT_EQ("test.handleWithArgs", *silent_request); |
| 1492 ASSERT_TRUE(request_arguments); |
| 1493 EXPECT_THAT( |
| 1494 *request_arguments, |
| 1495 testing::ElementsAre("\"str\"", "42")); // 42 was added by the handler. |
| 1496 reset_last_request(); |
| 1497 silent_request.reset(); |
| 1498 request_arguments.reset(); |
| 1499 } |
| 1500 |
1304 } // namespace extensions | 1501 } // namespace extensions |
OLD | NEW |