Chromium Code Reviews| 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 "extensions/renderer/bindings/api_request_handler.h" | |
| 6 | |
| 5 #include "base/bind.h" | 7 #include "base/bind.h" |
| 6 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 7 #include "base/optional.h" | 9 #include "base/optional.h" |
| 8 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 9 #include "base/values.h" | 11 #include "base/values.h" |
| 10 #include "extensions/renderer/bindings/api_binding_test.h" | 12 #include "extensions/renderer/bindings/api_binding_test.h" |
| 11 #include "extensions/renderer/bindings/api_binding_test_util.h" | 13 #include "extensions/renderer/bindings/api_binding_test_util.h" |
| 12 #include "extensions/renderer/bindings/api_request_handler.h" | 14 #include "extensions/renderer/bindings/exception_handler.h" |
| 13 #include "gin/converter.h" | 15 #include "gin/converter.h" |
| 14 #include "gin/function_template.h" | 16 #include "gin/function_template.h" |
| 15 #include "gin/public/context_holder.h" | 17 #include "gin/public/context_holder.h" |
| 16 #include "gin/public/isolate_holder.h" | 18 #include "gin/public/isolate_holder.h" |
| 17 #include "testing/gmock/include/gmock/gmock.h" | 19 #include "testing/gmock/include/gmock/gmock.h" |
| 18 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" | 20 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" |
| 19 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" | 21 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" |
| 20 | 22 |
| 21 namespace extensions { | 23 namespace extensions { |
| 22 | 24 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 40 public: | 42 public: |
| 41 // Runs the given |function|. | 43 // Runs the given |function|. |
| 42 void RunJS(v8::Local<v8::Function> function, | 44 void RunJS(v8::Local<v8::Function> function, |
| 43 v8::Local<v8::Context> context, | 45 v8::Local<v8::Context> context, |
| 44 int argc, | 46 int argc, |
| 45 v8::Local<v8::Value> argv[]) { | 47 v8::Local<v8::Value> argv[]) { |
| 46 RunFunctionOnGlobal(function, context, argc, argv); | 48 RunFunctionOnGlobal(function, context, argc, argv); |
| 47 did_run_js_ = true; | 49 did_run_js_ = true; |
| 48 } | 50 } |
| 49 | 51 |
| 52 std::unique_ptr<APIRequestHandler> CreateRequestHandler() { | |
| 53 return base::MakeUnique<APIRequestHandler>( | |
| 54 base::Bind(&DoNothingWithRequest), | |
| 55 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | |
| 56 APILastError(APILastError::GetParent(), binding::AddConsoleError()), | |
| 57 nullptr); | |
| 58 } | |
| 59 | |
| 50 protected: | 60 protected: |
| 51 APIRequestHandlerTest() {} | 61 APIRequestHandlerTest() {} |
| 52 ~APIRequestHandlerTest() override {} | 62 ~APIRequestHandlerTest() override {} |
| 53 | 63 |
| 54 bool did_run_js() const { return did_run_js_; } | 64 bool did_run_js() const { return did_run_js_; } |
| 55 | 65 |
| 56 private: | 66 private: |
| 57 bool did_run_js_ = false; | 67 bool did_run_js_ = false; |
| 58 | 68 |
| 59 DISALLOW_COPY_AND_ASSIGN(APIRequestHandlerTest); | 69 DISALLOW_COPY_AND_ASSIGN(APIRequestHandlerTest); |
| 60 }; | 70 }; |
| 61 | 71 |
| 62 // Tests adding a request to the request handler, and then triggering the | 72 // Tests adding a request to the request handler, and then triggering the |
| 63 // response. | 73 // response. |
| 64 TEST_F(APIRequestHandlerTest, AddRequestAndCompleteRequestTest) { | 74 TEST_F(APIRequestHandlerTest, AddRequestAndCompleteRequestTest) { |
| 65 v8::HandleScope handle_scope(isolate()); | 75 v8::HandleScope handle_scope(isolate()); |
| 66 v8::Local<v8::Context> context = MainContext(); | 76 v8::Local<v8::Context> context = MainContext(); |
| 67 | 77 |
| 68 APIRequestHandler request_handler( | 78 std::unique_ptr<APIRequestHandler> request_handler = CreateRequestHandler(); |
| 69 base::Bind(&DoNothingWithRequest), | |
| 70 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | |
| 71 APILastError(APILastError::GetParent(), APILastError::AddConsoleError())); | |
| 72 | 79 |
| 73 EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty()); | 80 EXPECT_TRUE(request_handler->GetPendingRequestIdsForTesting().empty()); |
| 74 | 81 |
| 75 v8::Local<v8::Function> function = FunctionFromString(context, kEchoArgs); | 82 v8::Local<v8::Function> function = FunctionFromString(context, kEchoArgs); |
| 76 ASSERT_FALSE(function.IsEmpty()); | 83 ASSERT_FALSE(function.IsEmpty()); |
| 77 | 84 |
| 78 int request_id = request_handler.StartRequest( | 85 int request_id = request_handler->StartRequest( |
| 79 context, kMethod, base::MakeUnique<base::ListValue>(), function, | 86 context, kMethod, base::MakeUnique<base::ListValue>(), function, |
| 80 v8::Local<v8::Function>(), binding::RequestThread::UI); | 87 v8::Local<v8::Function>(), binding::RequestThread::UI); |
| 81 EXPECT_THAT(request_handler.GetPendingRequestIdsForTesting(), | 88 EXPECT_THAT(request_handler->GetPendingRequestIdsForTesting(), |
| 82 testing::UnorderedElementsAre(request_id)); | 89 testing::UnorderedElementsAre(request_id)); |
| 83 | 90 |
| 84 const char kArguments[] = "['foo',1,{'prop1':'bar'}]"; | 91 const char kArguments[] = "['foo',1,{'prop1':'bar'}]"; |
| 85 std::unique_ptr<base::ListValue> response_arguments = | 92 std::unique_ptr<base::ListValue> response_arguments = |
| 86 ListValueFromString(kArguments); | 93 ListValueFromString(kArguments); |
| 87 ASSERT_TRUE(response_arguments); | 94 ASSERT_TRUE(response_arguments); |
| 88 request_handler.CompleteRequest(request_id, *response_arguments, | 95 request_handler->CompleteRequest(request_id, *response_arguments, |
| 89 std::string()); | 96 std::string()); |
| 90 | 97 |
| 91 EXPECT_TRUE(did_run_js()); | 98 EXPECT_TRUE(did_run_js()); |
| 92 EXPECT_EQ(ReplaceSingleQuotes(kArguments), | 99 EXPECT_EQ(ReplaceSingleQuotes(kArguments), |
| 93 GetStringPropertyFromObject(context->Global(), context, "result")); | 100 GetStringPropertyFromObject(context->Global(), context, "result")); |
| 94 | 101 |
| 95 EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty()); | 102 EXPECT_TRUE(request_handler->GetPendingRequestIdsForTesting().empty()); |
| 96 | 103 |
| 97 request_id = request_handler.StartRequest( | 104 request_id = request_handler->StartRequest( |
| 98 context, kMethod, base::MakeUnique<base::ListValue>(), | 105 context, kMethod, base::MakeUnique<base::ListValue>(), |
| 99 v8::Local<v8::Function>(), v8::Local<v8::Function>(), | 106 v8::Local<v8::Function>(), v8::Local<v8::Function>(), |
| 100 binding::RequestThread::UI); | 107 binding::RequestThread::UI); |
| 101 EXPECT_NE(-1, request_id); | 108 EXPECT_NE(-1, request_id); |
| 102 request_handler.CompleteRequest(request_id, base::ListValue(), std::string()); | 109 request_handler->CompleteRequest(request_id, base::ListValue(), |
| 110 std::string()); | |
| 103 } | 111 } |
| 104 | 112 |
| 105 // Tests that trying to run non-existent or invalided requests is a no-op. | 113 // Tests that trying to run non-existent or invalided requests is a no-op. |
| 106 TEST_F(APIRequestHandlerTest, InvalidRequestsTest) { | 114 TEST_F(APIRequestHandlerTest, InvalidRequestsTest) { |
| 107 v8::HandleScope handle_scope(isolate()); | 115 v8::HandleScope handle_scope(isolate()); |
| 108 v8::Local<v8::Context> context = MainContext(); | 116 v8::Local<v8::Context> context = MainContext(); |
| 109 | 117 |
| 110 APIRequestHandler request_handler( | 118 std::unique_ptr<APIRequestHandler> request_handler = CreateRequestHandler(); |
| 111 base::Bind(&DoNothingWithRequest), | |
| 112 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | |
| 113 APILastError(APILastError::GetParent(), APILastError::AddConsoleError())); | |
| 114 | 119 |
| 115 v8::Local<v8::Function> function = FunctionFromString(context, kEchoArgs); | 120 v8::Local<v8::Function> function = FunctionFromString(context, kEchoArgs); |
| 116 ASSERT_FALSE(function.IsEmpty()); | 121 ASSERT_FALSE(function.IsEmpty()); |
| 117 | 122 |
| 118 int request_id = request_handler.StartRequest( | 123 int request_id = request_handler->StartRequest( |
| 119 context, kMethod, base::MakeUnique<base::ListValue>(), function, | 124 context, kMethod, base::MakeUnique<base::ListValue>(), function, |
| 120 v8::Local<v8::Function>(), binding::RequestThread::UI); | 125 v8::Local<v8::Function>(), binding::RequestThread::UI); |
| 121 EXPECT_THAT(request_handler.GetPendingRequestIdsForTesting(), | 126 EXPECT_THAT(request_handler->GetPendingRequestIdsForTesting(), |
| 122 testing::UnorderedElementsAre(request_id)); | 127 testing::UnorderedElementsAre(request_id)); |
| 123 | 128 |
| 124 std::unique_ptr<base::ListValue> response_arguments = | 129 std::unique_ptr<base::ListValue> response_arguments = |
| 125 ListValueFromString("['foo']"); | 130 ListValueFromString("['foo']"); |
| 126 ASSERT_TRUE(response_arguments); | 131 ASSERT_TRUE(response_arguments); |
| 127 | 132 |
| 128 // Try running with a non-existent request id. | 133 // Try running with a non-existent request id. |
| 129 int fake_request_id = 42; | 134 int fake_request_id = 42; |
| 130 request_handler.CompleteRequest(fake_request_id, *response_arguments, | 135 request_handler->CompleteRequest(fake_request_id, *response_arguments, |
| 131 std::string()); | 136 std::string()); |
| 132 EXPECT_FALSE(did_run_js()); | 137 EXPECT_FALSE(did_run_js()); |
| 133 | 138 |
| 134 // Try running with a request from an invalidated context. | 139 // Try running with a request from an invalidated context. |
| 135 request_handler.InvalidateContext(context); | 140 request_handler->InvalidateContext(context); |
| 136 request_handler.CompleteRequest(request_id, *response_arguments, | 141 request_handler->CompleteRequest(request_id, *response_arguments, |
| 137 std::string()); | 142 std::string()); |
| 138 EXPECT_FALSE(did_run_js()); | 143 EXPECT_FALSE(did_run_js()); |
| 139 } | 144 } |
| 140 | 145 |
| 141 TEST_F(APIRequestHandlerTest, MultipleRequestsAndContexts) { | 146 TEST_F(APIRequestHandlerTest, MultipleRequestsAndContexts) { |
| 142 v8::HandleScope handle_scope(isolate()); | 147 v8::HandleScope handle_scope(isolate()); |
| 143 v8::Local<v8::Context> context_a = MainContext(); | 148 v8::Local<v8::Context> context_a = MainContext(); |
| 144 v8::Local<v8::Context> context_b = AddContext(); | 149 v8::Local<v8::Context> context_b = AddContext(); |
| 145 | 150 |
| 146 APIRequestHandler request_handler( | 151 std::unique_ptr<APIRequestHandler> request_handler = CreateRequestHandler(); |
| 147 base::Bind(&DoNothingWithRequest), | |
| 148 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | |
| 149 APILastError(APILastError::GetParent(), APILastError::AddConsoleError())); | |
| 150 | 152 |
| 151 // By having both different arguments and different behaviors in the | 153 // By having both different arguments and different behaviors in the |
| 152 // callbacks, we can easily verify that the right function is called in the | 154 // callbacks, we can easily verify that the right function is called in the |
| 153 // right context. | 155 // right context. |
| 154 v8::Local<v8::Function> function_a = FunctionFromString( | 156 v8::Local<v8::Function> function_a = FunctionFromString( |
| 155 context_a, "(function(res) { this.result = res + 'alpha'; })"); | 157 context_a, "(function(res) { this.result = res + 'alpha'; })"); |
| 156 v8::Local<v8::Function> function_b = FunctionFromString( | 158 v8::Local<v8::Function> function_b = FunctionFromString( |
| 157 context_b, "(function(res) { this.result = res + 'beta'; })"); | 159 context_b, "(function(res) { this.result = res + 'beta'; })"); |
| 158 | 160 |
| 159 int request_a = request_handler.StartRequest( | 161 int request_a = request_handler->StartRequest( |
| 160 context_a, kMethod, base::MakeUnique<base::ListValue>(), function_a, | 162 context_a, kMethod, base::MakeUnique<base::ListValue>(), function_a, |
| 161 v8::Local<v8::Function>(), binding::RequestThread::UI); | 163 v8::Local<v8::Function>(), binding::RequestThread::UI); |
| 162 int request_b = request_handler.StartRequest( | 164 int request_b = request_handler->StartRequest( |
| 163 context_b, kMethod, base::MakeUnique<base::ListValue>(), function_b, | 165 context_b, kMethod, base::MakeUnique<base::ListValue>(), function_b, |
| 164 v8::Local<v8::Function>(), binding::RequestThread::UI); | 166 v8::Local<v8::Function>(), binding::RequestThread::UI); |
| 165 | 167 |
| 166 EXPECT_THAT(request_handler.GetPendingRequestIdsForTesting(), | 168 EXPECT_THAT(request_handler->GetPendingRequestIdsForTesting(), |
| 167 testing::UnorderedElementsAre(request_a, request_b)); | 169 testing::UnorderedElementsAre(request_a, request_b)); |
| 168 | 170 |
| 169 std::unique_ptr<base::ListValue> response_a = | 171 std::unique_ptr<base::ListValue> response_a = |
| 170 ListValueFromString("['response_a:']"); | 172 ListValueFromString("['response_a:']"); |
| 171 ASSERT_TRUE(response_a); | 173 ASSERT_TRUE(response_a); |
| 172 | 174 |
| 173 request_handler.CompleteRequest(request_a, *response_a, std::string()); | 175 request_handler->CompleteRequest(request_a, *response_a, std::string()); |
| 174 EXPECT_TRUE(did_run_js()); | 176 EXPECT_TRUE(did_run_js()); |
| 175 EXPECT_THAT(request_handler.GetPendingRequestIdsForTesting(), | 177 EXPECT_THAT(request_handler->GetPendingRequestIdsForTesting(), |
| 176 testing::UnorderedElementsAre(request_b)); | 178 testing::UnorderedElementsAre(request_b)); |
| 177 | 179 |
| 178 EXPECT_EQ( | 180 EXPECT_EQ( |
| 179 ReplaceSingleQuotes("'response_a:alpha'"), | 181 ReplaceSingleQuotes("'response_a:alpha'"), |
| 180 GetStringPropertyFromObject(context_a->Global(), context_a, "result")); | 182 GetStringPropertyFromObject(context_a->Global(), context_a, "result")); |
| 181 | 183 |
| 182 std::unique_ptr<base::ListValue> response_b = | 184 std::unique_ptr<base::ListValue> response_b = |
| 183 ListValueFromString("['response_b:']"); | 185 ListValueFromString("['response_b:']"); |
| 184 ASSERT_TRUE(response_b); | 186 ASSERT_TRUE(response_b); |
| 185 | 187 |
| 186 request_handler.CompleteRequest(request_b, *response_b, std::string()); | 188 request_handler->CompleteRequest(request_b, *response_b, std::string()); |
| 187 EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty()); | 189 EXPECT_TRUE(request_handler->GetPendingRequestIdsForTesting().empty()); |
| 188 | 190 |
| 189 EXPECT_EQ( | 191 EXPECT_EQ( |
| 190 ReplaceSingleQuotes("'response_b:beta'"), | 192 ReplaceSingleQuotes("'response_b:beta'"), |
| 191 GetStringPropertyFromObject(context_b->Global(), context_b, "result")); | 193 GetStringPropertyFromObject(context_b->Global(), context_b, "result")); |
| 192 } | 194 } |
| 193 | 195 |
| 194 TEST_F(APIRequestHandlerTest, CustomCallbackArguments) { | 196 TEST_F(APIRequestHandlerTest, CustomCallbackArguments) { |
| 195 v8::HandleScope handle_scope(isolate()); | 197 v8::HandleScope handle_scope(isolate()); |
| 196 v8::Local<v8::Context> context = MainContext(); | 198 v8::Local<v8::Context> context = MainContext(); |
| 197 | 199 |
| 198 APIRequestHandler request_handler( | 200 std::unique_ptr<APIRequestHandler> request_handler = CreateRequestHandler(); |
| 199 base::Bind(&DoNothingWithRequest), | |
| 200 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | |
| 201 APILastError(APILastError::GetParent(), APILastError::AddConsoleError())); | |
| 202 | 201 |
| 203 v8::Local<v8::Function> custom_callback = | 202 v8::Local<v8::Function> custom_callback = |
| 204 FunctionFromString(context, kEchoArgs); | 203 FunctionFromString(context, kEchoArgs); |
| 205 v8::Local<v8::Function> callback = | 204 v8::Local<v8::Function> callback = |
| 206 FunctionFromString(context, "(function() {})"); | 205 FunctionFromString(context, "(function() {})"); |
| 207 ASSERT_FALSE(callback.IsEmpty()); | 206 ASSERT_FALSE(callback.IsEmpty()); |
| 208 ASSERT_FALSE(custom_callback.IsEmpty()); | 207 ASSERT_FALSE(custom_callback.IsEmpty()); |
| 209 | 208 |
| 210 int request_id = request_handler.StartRequest( | 209 int request_id = request_handler->StartRequest( |
| 211 context, "method", base::MakeUnique<base::ListValue>(), callback, | 210 context, "method", base::MakeUnique<base::ListValue>(), callback, |
| 212 custom_callback, binding::RequestThread::UI); | 211 custom_callback, binding::RequestThread::UI); |
| 213 EXPECT_THAT(request_handler.GetPendingRequestIdsForTesting(), | 212 EXPECT_THAT(request_handler->GetPendingRequestIdsForTesting(), |
| 214 testing::UnorderedElementsAre(request_id)); | 213 testing::UnorderedElementsAre(request_id)); |
| 215 | 214 |
| 216 std::unique_ptr<base::ListValue> response_arguments = | 215 std::unique_ptr<base::ListValue> response_arguments = |
| 217 ListValueFromString("['response', 'arguments']"); | 216 ListValueFromString("['response', 'arguments']"); |
| 218 ASSERT_TRUE(response_arguments); | 217 ASSERT_TRUE(response_arguments); |
| 219 request_handler.CompleteRequest(request_id, *response_arguments, | 218 request_handler->CompleteRequest(request_id, *response_arguments, |
| 220 std::string()); | 219 std::string()); |
| 221 | 220 |
| 222 EXPECT_TRUE(did_run_js()); | 221 EXPECT_TRUE(did_run_js()); |
| 223 v8::Local<v8::Value> result = | 222 v8::Local<v8::Value> result = |
| 224 GetPropertyFromObject(context->Global(), context, "result"); | 223 GetPropertyFromObject(context->Global(), context, "result"); |
| 225 ASSERT_FALSE(result.IsEmpty()); | 224 ASSERT_FALSE(result.IsEmpty()); |
| 226 ASSERT_TRUE(result->IsArray()); | 225 ASSERT_TRUE(result->IsArray()); |
| 227 ArgumentList args; | 226 ArgumentList args; |
| 228 ASSERT_TRUE(gin::Converter<ArgumentList>::FromV8(isolate(), result, &args)); | 227 ASSERT_TRUE(gin::Converter<ArgumentList>::FromV8(isolate(), result, &args)); |
| 229 ASSERT_EQ(5u, args.size()); | 228 ASSERT_EQ(5u, args.size()); |
| 230 EXPECT_EQ("\"method\"", V8ToString(args[0], context)); | 229 EXPECT_EQ("\"method\"", V8ToString(args[0], context)); |
| 231 EXPECT_EQ(base::StringPrintf("{\"id\":%d}", request_id), | 230 EXPECT_EQ(base::StringPrintf("{\"id\":%d}", request_id), |
| 232 V8ToString(args[1], context)); | 231 V8ToString(args[1], context)); |
| 233 EXPECT_EQ(callback, args[2]); | 232 EXPECT_EQ(callback, args[2]); |
| 234 EXPECT_EQ("\"response\"", V8ToString(args[3], context)); | 233 EXPECT_EQ("\"response\"", V8ToString(args[3], context)); |
| 235 EXPECT_EQ("\"arguments\"", V8ToString(args[4], context)); | 234 EXPECT_EQ("\"arguments\"", V8ToString(args[4], context)); |
| 236 | 235 |
| 237 EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty()); | 236 EXPECT_TRUE(request_handler->GetPendingRequestIdsForTesting().empty()); |
| 238 } | 237 } |
| 239 | 238 |
| 240 // Test that having a custom callback without an extension-provided callback | 239 // Test that having a custom callback without an extension-provided callback |
| 241 // doesn't crash. | 240 // doesn't crash. |
| 242 TEST_F(APIRequestHandlerTest, CustomCallbackArgumentsWithEmptyCallback) { | 241 TEST_F(APIRequestHandlerTest, CustomCallbackArgumentsWithEmptyCallback) { |
| 243 v8::HandleScope handle_scope(isolate()); | 242 v8::HandleScope handle_scope(isolate()); |
| 244 v8::Local<v8::Context> context = MainContext(); | 243 v8::Local<v8::Context> context = MainContext(); |
| 245 | 244 |
| 246 APIRequestHandler request_handler( | 245 std::unique_ptr<APIRequestHandler> request_handler = CreateRequestHandler(); |
| 247 base::Bind(&DoNothingWithRequest), | |
| 248 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | |
| 249 APILastError(APILastError::GetParent(), APILastError::AddConsoleError())); | |
| 250 | 246 |
| 251 v8::Local<v8::Function> custom_callback = | 247 v8::Local<v8::Function> custom_callback = |
| 252 FunctionFromString(context, kEchoArgs); | 248 FunctionFromString(context, kEchoArgs); |
| 253 ASSERT_FALSE(custom_callback.IsEmpty()); | 249 ASSERT_FALSE(custom_callback.IsEmpty()); |
| 254 | 250 |
| 255 v8::Local<v8::Function> empty_callback; | 251 v8::Local<v8::Function> empty_callback; |
| 256 int request_id = request_handler.StartRequest( | 252 int request_id = request_handler->StartRequest( |
| 257 context, "method", base::MakeUnique<base::ListValue>(), empty_callback, | 253 context, "method", base::MakeUnique<base::ListValue>(), empty_callback, |
| 258 custom_callback, binding::RequestThread::UI); | 254 custom_callback, binding::RequestThread::UI); |
| 259 EXPECT_THAT(request_handler.GetPendingRequestIdsForTesting(), | 255 EXPECT_THAT(request_handler->GetPendingRequestIdsForTesting(), |
| 260 testing::UnorderedElementsAre(request_id)); | 256 testing::UnorderedElementsAre(request_id)); |
| 261 | 257 |
| 262 request_handler.CompleteRequest(request_id, base::ListValue(), std::string()); | 258 request_handler->CompleteRequest(request_id, base::ListValue(), |
| 259 std::string()); | |
| 263 | 260 |
| 264 EXPECT_TRUE(did_run_js()); | 261 EXPECT_TRUE(did_run_js()); |
| 265 v8::Local<v8::Value> result = | 262 v8::Local<v8::Value> result = |
| 266 GetPropertyFromObject(context->Global(), context, "result"); | 263 GetPropertyFromObject(context->Global(), context, "result"); |
| 267 ASSERT_FALSE(result.IsEmpty()); | 264 ASSERT_FALSE(result.IsEmpty()); |
| 268 ASSERT_TRUE(result->IsArray()); | 265 ASSERT_TRUE(result->IsArray()); |
| 269 ArgumentList args; | 266 ArgumentList args; |
| 270 ASSERT_TRUE(gin::Converter<ArgumentList>::FromV8(isolate(), result, &args)); | 267 ASSERT_TRUE(gin::Converter<ArgumentList>::FromV8(isolate(), result, &args)); |
| 271 ASSERT_EQ(3u, args.size()); | 268 ASSERT_EQ(3u, args.size()); |
| 272 EXPECT_EQ("\"method\"", V8ToString(args[0], context)); | 269 EXPECT_EQ("\"method\"", V8ToString(args[0], context)); |
| 273 EXPECT_EQ(base::StringPrintf("{\"id\":%d}", request_id), | 270 EXPECT_EQ(base::StringPrintf("{\"id\":%d}", request_id), |
| 274 V8ToString(args[1], context)); | 271 V8ToString(args[1], context)); |
| 275 EXPECT_TRUE(args[2]->IsUndefined()); | 272 EXPECT_TRUE(args[2]->IsUndefined()); |
| 276 | 273 |
| 277 EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty()); | 274 EXPECT_TRUE(request_handler->GetPendingRequestIdsForTesting().empty()); |
| 278 } | 275 } |
| 279 | 276 |
| 280 // Test user gestures being curried around for API requests. | 277 // Test user gestures being curried around for API requests. |
| 281 TEST_F(APIRequestHandlerTest, UserGestureTest) { | 278 TEST_F(APIRequestHandlerTest, UserGestureTest) { |
| 282 v8::HandleScope handle_scope(isolate()); | 279 v8::HandleScope handle_scope(isolate()); |
| 283 v8::Local<v8::Context> context = MainContext(); | 280 v8::Local<v8::Context> context = MainContext(); |
| 284 | 281 |
| 285 APIRequestHandler request_handler( | 282 std::unique_ptr<APIRequestHandler> request_handler = CreateRequestHandler(); |
| 286 base::Bind(&DoNothingWithRequest), | |
| 287 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | |
| 288 APILastError(APILastError::GetParent(), APILastError::AddConsoleError())); | |
| 289 | 283 |
| 290 auto callback = [](base::Optional<bool>* ran_with_user_gesture) { | 284 auto callback = [](base::Optional<bool>* ran_with_user_gesture) { |
| 291 *ran_with_user_gesture = | 285 *ran_with_user_gesture = |
| 292 blink::WebUserGestureIndicator::IsProcessingUserGestureThreadSafe(); | 286 blink::WebUserGestureIndicator::IsProcessingUserGestureThreadSafe(); |
| 293 }; | 287 }; |
| 294 | 288 |
| 295 // Set up a callback to be used with the request so we can check if a user | 289 // Set up a callback to be used with the request so we can check if a user |
| 296 // gesture was active. | 290 // gesture was active. |
| 297 base::Optional<bool> ran_with_user_gesture; | 291 base::Optional<bool> ran_with_user_gesture; |
| 298 v8::Local<v8::FunctionTemplate> function_template = | 292 v8::Local<v8::FunctionTemplate> function_template = |
| 299 gin::CreateFunctionTemplate(isolate(), | 293 gin::CreateFunctionTemplate(isolate(), |
| 300 base::Bind(callback, &ran_with_user_gesture)); | 294 base::Bind(callback, &ran_with_user_gesture)); |
| 301 v8::Local<v8::Function> v8_callback = | 295 v8::Local<v8::Function> v8_callback = |
| 302 function_template->GetFunction(context).ToLocalChecked(); | 296 function_template->GetFunction(context).ToLocalChecked(); |
| 303 | 297 |
| 304 // Try first without a user gesture. | 298 // Try first without a user gesture. |
| 305 int request_id = request_handler.StartRequest( | 299 int request_id = request_handler->StartRequest( |
| 306 context, kMethod, base::MakeUnique<base::ListValue>(), v8_callback, | 300 context, kMethod, base::MakeUnique<base::ListValue>(), v8_callback, |
| 307 v8::Local<v8::Function>(), binding::RequestThread::UI); | 301 v8::Local<v8::Function>(), binding::RequestThread::UI); |
| 308 request_handler.CompleteRequest(request_id, *ListValueFromString("[]"), | 302 request_handler->CompleteRequest(request_id, *ListValueFromString("[]"), |
| 309 std::string()); | 303 std::string()); |
| 310 | 304 |
| 311 ASSERT_TRUE(ran_with_user_gesture); | 305 ASSERT_TRUE(ran_with_user_gesture); |
| 312 EXPECT_FALSE(*ran_with_user_gesture); | 306 EXPECT_FALSE(*ran_with_user_gesture); |
| 313 ran_with_user_gesture.reset(); | 307 ran_with_user_gesture.reset(); |
| 314 | 308 |
| 315 // Next try calling with a user gesture. Since a gesture will be active at the | 309 // Next try calling with a user gesture. Since a gesture will be active at the |
| 316 // time of the call, it should also be active during the callback. | 310 // time of the call, it should also be active during the callback. |
| 317 { | 311 { |
| 318 blink::WebScopedUserGesture user_gesture(nullptr); | 312 blink::WebScopedUserGesture user_gesture(nullptr); |
| 319 EXPECT_TRUE( | 313 EXPECT_TRUE( |
| 320 blink::WebUserGestureIndicator::IsProcessingUserGestureThreadSafe()); | 314 blink::WebUserGestureIndicator::IsProcessingUserGestureThreadSafe()); |
| 321 request_id = request_handler.StartRequest( | 315 request_id = request_handler->StartRequest( |
| 322 context, kMethod, base::MakeUnique<base::ListValue>(), v8_callback, | 316 context, kMethod, base::MakeUnique<base::ListValue>(), v8_callback, |
| 323 v8::Local<v8::Function>(), binding::RequestThread::UI); | 317 v8::Local<v8::Function>(), binding::RequestThread::UI); |
| 324 } | 318 } |
| 325 EXPECT_FALSE( | 319 EXPECT_FALSE( |
| 326 blink::WebUserGestureIndicator::IsProcessingUserGestureThreadSafe()); | 320 blink::WebUserGestureIndicator::IsProcessingUserGestureThreadSafe()); |
| 327 | 321 |
| 328 request_handler.CompleteRequest(request_id, *ListValueFromString("[]"), | 322 request_handler->CompleteRequest(request_id, *ListValueFromString("[]"), |
| 329 std::string()); | 323 std::string()); |
| 330 ASSERT_TRUE(ran_with_user_gesture); | 324 ASSERT_TRUE(ran_with_user_gesture); |
| 331 EXPECT_TRUE(*ran_with_user_gesture); | 325 EXPECT_TRUE(*ran_with_user_gesture); |
| 332 // Sanity check - after the callback ran, there shouldn't be an active | 326 // Sanity check - after the callback ran, there shouldn't be an active |
| 333 // gesture. | 327 // gesture. |
| 334 EXPECT_FALSE( | 328 EXPECT_FALSE( |
| 335 blink::WebUserGestureIndicator::IsProcessingUserGestureThreadSafe()); | 329 blink::WebUserGestureIndicator::IsProcessingUserGestureThreadSafe()); |
| 336 } | 330 } |
| 337 | 331 |
| 338 TEST_F(APIRequestHandlerTest, RequestThread) { | 332 TEST_F(APIRequestHandlerTest, RequestThread) { |
| 339 v8::HandleScope handle_scope(isolate()); | 333 v8::HandleScope handle_scope(isolate()); |
| 340 v8::Local<v8::Context> context = MainContext(); | 334 v8::Local<v8::Context> context = MainContext(); |
| 341 | 335 |
| 342 base::Optional<binding::RequestThread> thread; | 336 base::Optional<binding::RequestThread> thread; |
| 343 auto on_request = [](base::Optional<binding::RequestThread>* thread_out, | 337 auto on_request = [](base::Optional<binding::RequestThread>* thread_out, |
| 344 std::unique_ptr<APIRequestHandler::Request> request, | 338 std::unique_ptr<APIRequestHandler::Request> request, |
| 345 v8::Local<v8::Context> context) { | 339 v8::Local<v8::Context> context) { |
| 346 *thread_out = request->thread; | 340 *thread_out = request->thread; |
| 347 }; | 341 }; |
| 348 | 342 |
| 349 APIRequestHandler request_handler( | 343 APIRequestHandler request_handler( |
| 350 base::Bind(on_request, &thread), | 344 base::Bind(on_request, &thread), |
| 351 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | 345 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), |
| 352 APILastError(APILastError::GetParent(), APILastError::AddConsoleError())); | 346 APILastError(APILastError::GetParent(), binding::AddConsoleError()), |
| 347 nullptr); | |
| 353 | 348 |
| 354 request_handler.StartRequest( | 349 request_handler.StartRequest( |
| 355 context, kMethod, base::MakeUnique<base::ListValue>(), | 350 context, kMethod, base::MakeUnique<base::ListValue>(), |
| 356 v8::Local<v8::Function>(), v8::Local<v8::Function>(), | 351 v8::Local<v8::Function>(), v8::Local<v8::Function>(), |
| 357 binding::RequestThread::UI); | 352 binding::RequestThread::UI); |
| 358 ASSERT_TRUE(thread); | 353 ASSERT_TRUE(thread); |
| 359 EXPECT_EQ(binding::RequestThread::UI, *thread); | 354 EXPECT_EQ(binding::RequestThread::UI, *thread); |
| 360 thread.reset(); | 355 thread.reset(); |
| 361 | 356 |
| 362 request_handler.StartRequest( | 357 request_handler.StartRequest( |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 379 }; | 374 }; |
| 380 | 375 |
| 381 auto log_error = [](base::Optional<std::string>* logged_error, | 376 auto log_error = [](base::Optional<std::string>* logged_error, |
| 382 v8::Local<v8::Context> context, | 377 v8::Local<v8::Context> context, |
| 383 const std::string& error) { *logged_error = error; }; | 378 const std::string& error) { *logged_error = error; }; |
| 384 | 379 |
| 385 APIRequestHandler request_handler( | 380 APIRequestHandler request_handler( |
| 386 base::Bind(&DoNothingWithRequest), | 381 base::Bind(&DoNothingWithRequest), |
| 387 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | 382 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), |
| 388 APILastError(base::Bind(get_parent), | 383 APILastError(base::Bind(get_parent), |
| 389 base::Bind(log_error, &logged_error))); | 384 base::Bind(log_error, &logged_error)), |
| 385 nullptr); | |
| 390 | 386 |
| 391 const char kReportExposedLastError[] = | 387 const char kReportExposedLastError[] = |
| 392 "(function() {\n" | 388 "(function() {\n" |
| 393 " if (this.lastError)\n" | 389 " if (this.lastError)\n" |
| 394 " this.seenLastError = this.lastError.message;\n" | 390 " this.seenLastError = this.lastError.message;\n" |
| 395 "})"; | 391 "})"; |
| 396 auto get_exposed_error = [context]() { | 392 auto get_exposed_error = [context]() { |
| 397 return GetStringPropertyFromObject(context->Global(), context, | 393 return GetStringPropertyFromObject(context->Global(), context, |
| 398 "seenLastError"); | 394 "seenLastError"); |
| 399 }; | 395 }; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 452 bool dispatched_request = false; | 448 bool dispatched_request = false; |
| 453 auto handle_request = [](bool* dispatched_request, | 449 auto handle_request = [](bool* dispatched_request, |
| 454 std::unique_ptr<APIRequestHandler::Request> request, | 450 std::unique_ptr<APIRequestHandler::Request> request, |
| 455 v8::Local<v8::Context> context) { | 451 v8::Local<v8::Context> context) { |
| 456 *dispatched_request = true; | 452 *dispatched_request = true; |
| 457 }; | 453 }; |
| 458 | 454 |
| 459 APIRequestHandler request_handler( | 455 APIRequestHandler request_handler( |
| 460 base::Bind(handle_request, &dispatched_request), | 456 base::Bind(handle_request, &dispatched_request), |
| 461 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), | 457 base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)), |
| 462 APILastError(APILastError::GetParent(), APILastError::AddConsoleError())); | 458 APILastError(APILastError::GetParent(), binding::AddConsoleError()), |
| 459 nullptr); | |
| 463 | 460 |
| 464 EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty()); | 461 EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty()); |
| 465 v8::Local<v8::Function> function = FunctionFromString(context, kEchoArgs); | 462 v8::Local<v8::Function> function = FunctionFromString(context, kEchoArgs); |
| 466 ASSERT_FALSE(function.IsEmpty()); | 463 ASSERT_FALSE(function.IsEmpty()); |
| 467 | 464 |
| 468 int request_id = request_handler.AddPendingRequest(context, function); | 465 int request_id = request_handler.AddPendingRequest(context, function); |
| 469 EXPECT_THAT(request_handler.GetPendingRequestIdsForTesting(), | 466 EXPECT_THAT(request_handler.GetPendingRequestIdsForTesting(), |
| 470 testing::UnorderedElementsAre(request_id)); | 467 testing::UnorderedElementsAre(request_id)); |
| 471 // Even though we add a pending request, we shouldn't have dispatched anything | 468 // Even though we add a pending request, we shouldn't have dispatched anything |
| 472 // because AddPendingRequest() is intended for renderer-side implementations. | 469 // because AddPendingRequest() is intended for renderer-side implementations. |
| 473 EXPECT_FALSE(dispatched_request); | 470 EXPECT_FALSE(dispatched_request); |
| 474 | 471 |
| 475 const char kArguments[] = "['foo',1,{'prop1':'bar'}]"; | 472 const char kArguments[] = "['foo',1,{'prop1':'bar'}]"; |
| 476 std::unique_ptr<base::ListValue> response_arguments = | 473 std::unique_ptr<base::ListValue> response_arguments = |
| 477 ListValueFromString(kArguments); | 474 ListValueFromString(kArguments); |
| 478 ASSERT_TRUE(response_arguments); | 475 ASSERT_TRUE(response_arguments); |
| 479 request_handler.CompleteRequest(request_id, *response_arguments, | 476 request_handler.CompleteRequest(request_id, *response_arguments, |
| 480 std::string()); | 477 std::string()); |
| 481 | 478 |
| 482 EXPECT_EQ(ReplaceSingleQuotes(kArguments), | 479 EXPECT_EQ(ReplaceSingleQuotes(kArguments), |
| 483 GetStringPropertyFromObject(context->Global(), context, "result")); | 480 GetStringPropertyFromObject(context->Global(), context, "result")); |
| 484 | 481 |
| 485 EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty()); | 482 EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty()); |
| 486 EXPECT_FALSE(dispatched_request); | 483 EXPECT_FALSE(dispatched_request); |
| 487 } | 484 } |
| 488 | 485 |
| 486 // Tests that throwing an exception in a callback is properly handled. | |
| 487 TEST_F(APIRequestHandlerTest, ThrowExceptionInCallback) { | |
| 488 v8::HandleScope handle_scope(isolate()); | |
| 489 v8::Local<v8::Context> context = MainContext(); | |
| 490 | |
| 491 auto add_console_error = [](base::Optional<std::string>* error_out, | |
| 492 v8::Local<v8::Context> context, | |
| 493 const std::string& error) { *error_out = error; }; | |
| 494 | |
| 495 // RunFunction* from the test util assert no errors; provide a version that | |
| 496 // allows them. | |
| 497 auto run_function_and_allow_errors = | |
| 498 [](v8::Local<v8::Function> function, v8::Local<v8::Context> context, | |
| 499 int argc, v8::Local<v8::Value> argv[]) { | |
| 500 ignore_result(function->Call(context, context->Global(), argc, argv)); | |
| 501 }; | |
| 502 | |
| 503 base::Optional<std::string> logged_error; | |
| 504 ExceptionHandler exception_handler( | |
| 505 base::Bind(add_console_error, &logged_error), | |
| 506 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); | |
| 507 | |
| 508 APIRequestHandler request_handler( | |
| 509 base::Bind(&DoNothingWithRequest), | |
| 510 base::Bind(run_function_and_allow_errors), | |
| 511 APILastError(APILastError::GetParent(), binding::AddConsoleError()), | |
| 512 &exception_handler); | |
| 513 | |
| 514 v8::TryCatch try_catch(isolate()); | |
| 515 v8::Local<v8::Function> callback_throwing_error = | |
| 516 FunctionFromString(context, "(function() { throw new Error('hello'); })"); | |
| 517 int request_id = | |
| 518 request_handler.AddPendingRequest(context, callback_throwing_error); | |
| 519 request_handler.CompleteRequest(request_id, base::ListValue(), std::string()); | |
| 520 // The outer TryCatch should not be caught. This is important to not disrupt | |
|
lazyboy
2017/07/10 23:12:08
Add a bit more context about the try catch you're
Devlin
2017/07/11 17:33:35
Done.
| |
| 521 // our bindings code (or other running JS) when asynchronously returning from | |
| 522 // an API call. | |
| 523 EXPECT_FALSE(try_catch.HasCaught()); | |
| 524 ASSERT_TRUE(logged_error); | |
| 525 EXPECT_EQ("Error handling response: Uncaught Error: hello", *logged_error); | |
| 526 } | |
| 527 | |
| 489 } // namespace extensions | 528 } // namespace extensions |
| OLD | NEW |