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 |