OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <list> | |
6 #include <string> | |
7 | |
8 #include "base/bind.h" | |
9 #include "base/compiler_specific.h" | |
10 #include "base/json/json_reader.h" | |
11 #include "base/json/json_writer.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/values.h" | |
14 #include "chrome/test/chromedriver/devtools_client_impl.h" | |
15 #include "chrome/test/chromedriver/devtools_event_listener.h" | |
16 #include "chrome/test/chromedriver/net/sync_websocket.h" | |
17 #include "chrome/test/chromedriver/net/sync_websocket_factory.h" | |
18 #include "chrome/test/chromedriver/status.h" | |
19 #include "googleurl/src/gurl.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 | |
22 namespace { | |
23 | |
24 Status CloserFunc() { | |
25 return Status(kOk); | |
26 } | |
27 | |
28 class MockSyncWebSocket : public SyncWebSocket { | |
29 public: | |
30 MockSyncWebSocket() : connected_(false), id_(-1), queued_messages_(1) {} | |
31 virtual ~MockSyncWebSocket() {} | |
32 | |
33 virtual bool IsConnected() OVERRIDE { | |
34 return connected_; | |
35 } | |
36 | |
37 virtual bool Connect(const GURL& url) OVERRIDE { | |
38 EXPECT_STREQ("http://url/", url.possibly_invalid_spec().c_str()); | |
39 connected_ = true; | |
40 return true; | |
41 } | |
42 | |
43 virtual bool Send(const std::string& message) OVERRIDE { | |
44 EXPECT_TRUE(connected_); | |
45 scoped_ptr<base::Value> value(base::JSONReader::Read(message)); | |
46 base::DictionaryValue* dict = NULL; | |
47 EXPECT_TRUE(value->GetAsDictionary(&dict)); | |
48 if (!dict) | |
49 return false; | |
50 EXPECT_TRUE(dict->GetInteger("id", &id_)); | |
51 std::string method; | |
52 EXPECT_TRUE(dict->GetString("method", &method)); | |
53 EXPECT_STREQ("method", method.c_str()); | |
54 base::DictionaryValue* params = NULL; | |
55 EXPECT_TRUE(dict->GetDictionary("params", ¶ms)); | |
56 if (!params) | |
57 return false; | |
58 int param = -1; | |
59 EXPECT_TRUE(params->GetInteger("param", ¶m)); | |
60 EXPECT_EQ(1, param); | |
61 return true; | |
62 } | |
63 | |
64 virtual bool ReceiveNextMessage(std::string* message) OVERRIDE { | |
65 base::DictionaryValue response; | |
66 response.SetInteger("id", id_); | |
67 base::DictionaryValue result; | |
68 result.SetInteger("param", 1); | |
69 response.Set("result", result.DeepCopy()); | |
70 base::JSONWriter::Write(&response, message); | |
71 --queued_messages_; | |
72 return true; | |
73 } | |
74 | |
75 virtual bool HasNextMessage() OVERRIDE { | |
76 return queued_messages_ > 0; | |
77 } | |
78 | |
79 protected: | |
80 bool connected_; | |
81 int id_; | |
82 int queued_messages_; | |
83 }; | |
84 | |
85 template <typename T> | |
86 scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket() { | |
87 return scoped_ptr<SyncWebSocket>(new T()); | |
88 } | |
89 | |
90 } // namespace | |
91 | |
92 TEST(DevToolsClientImpl, SendCommand) { | |
93 SyncWebSocketFactory factory = | |
94 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>); | |
95 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc)); | |
96 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
97 base::DictionaryValue params; | |
98 params.SetInteger("param", 1); | |
99 ASSERT_EQ(kOk, client.SendCommand("method", params).code()); | |
100 } | |
101 | |
102 TEST(DevToolsClientImpl, SendCommandAndGetResult) { | |
103 SyncWebSocketFactory factory = | |
104 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>); | |
105 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc)); | |
106 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
107 base::DictionaryValue params; | |
108 params.SetInteger("param", 1); | |
109 scoped_ptr<base::DictionaryValue> result; | |
110 Status status = client.SendCommandAndGetResult("method", params, &result); | |
111 ASSERT_EQ(kOk, status.code()); | |
112 std::string json; | |
113 base::JSONWriter::Write(result.get(), &json); | |
114 ASSERT_STREQ("{\"param\":1}", json.c_str()); | |
115 } | |
116 | |
117 namespace { | |
118 | |
119 class MockSyncWebSocket2 : public SyncWebSocket { | |
120 public: | |
121 MockSyncWebSocket2() {} | |
122 virtual ~MockSyncWebSocket2() {} | |
123 | |
124 virtual bool IsConnected() OVERRIDE { | |
125 return false; | |
126 } | |
127 | |
128 virtual bool Connect(const GURL& url) OVERRIDE { | |
129 return false; | |
130 } | |
131 | |
132 virtual bool Send(const std::string& message) OVERRIDE { | |
133 EXPECT_TRUE(false); | |
134 return false; | |
135 } | |
136 | |
137 virtual bool ReceiveNextMessage(std::string* message) OVERRIDE { | |
138 EXPECT_TRUE(false); | |
139 return false; | |
140 } | |
141 | |
142 virtual bool HasNextMessage() OVERRIDE { | |
143 return true; | |
144 } | |
145 }; | |
146 | |
147 } // namespace | |
148 | |
149 TEST(DevToolsClientImpl, ConnectIfNecessaryConnectFails) { | |
150 SyncWebSocketFactory factory = | |
151 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket2>); | |
152 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc)); | |
153 ASSERT_EQ(kDisconnected, client.ConnectIfNecessary().code()); | |
154 } | |
155 | |
156 namespace { | |
157 | |
158 class MockSyncWebSocket3 : public SyncWebSocket { | |
159 public: | |
160 MockSyncWebSocket3() : connected_(false) {} | |
161 virtual ~MockSyncWebSocket3() {} | |
162 | |
163 virtual bool IsConnected() OVERRIDE { | |
164 return connected_; | |
165 } | |
166 | |
167 virtual bool Connect(const GURL& url) OVERRIDE { | |
168 connected_ = true; | |
169 return true; | |
170 } | |
171 | |
172 virtual bool Send(const std::string& message) OVERRIDE { | |
173 return false; | |
174 } | |
175 | |
176 virtual bool ReceiveNextMessage(std::string* message) OVERRIDE { | |
177 EXPECT_TRUE(false); | |
178 return false; | |
179 } | |
180 | |
181 virtual bool HasNextMessage() OVERRIDE { | |
182 return true; | |
183 } | |
184 | |
185 private: | |
186 bool connected_; | |
187 }; | |
188 | |
189 } // namespace | |
190 | |
191 TEST(DevToolsClientImpl, SendCommandSendFails) { | |
192 SyncWebSocketFactory factory = | |
193 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket3>); | |
194 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc)); | |
195 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
196 base::DictionaryValue params; | |
197 ASSERT_TRUE(client.SendCommand("method", params).IsError()); | |
198 } | |
199 | |
200 namespace { | |
201 | |
202 class MockSyncWebSocket4 : public SyncWebSocket { | |
203 public: | |
204 MockSyncWebSocket4() : connected_(false) {} | |
205 virtual ~MockSyncWebSocket4() {} | |
206 | |
207 virtual bool IsConnected() OVERRIDE { | |
208 return connected_; | |
209 } | |
210 | |
211 virtual bool Connect(const GURL& url) OVERRIDE { | |
212 connected_ = true; | |
213 return true; | |
214 } | |
215 | |
216 virtual bool Send(const std::string& message) OVERRIDE { | |
217 return true; | |
218 } | |
219 | |
220 virtual bool ReceiveNextMessage(std::string* message) OVERRIDE { | |
221 return false; | |
222 } | |
223 | |
224 virtual bool HasNextMessage() OVERRIDE { | |
225 return true; | |
226 } | |
227 | |
228 private: | |
229 bool connected_; | |
230 }; | |
231 | |
232 } // namespace | |
233 | |
234 TEST(DevToolsClientImpl, SendCommandReceiveNextMessageFails) { | |
235 SyncWebSocketFactory factory = | |
236 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket4>); | |
237 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc)); | |
238 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
239 base::DictionaryValue params; | |
240 ASSERT_TRUE(client.SendCommand("method", params).IsError()); | |
241 } | |
242 | |
243 namespace { | |
244 | |
245 class FakeSyncWebSocket : public SyncWebSocket { | |
246 public: | |
247 FakeSyncWebSocket() : connected_(false) {} | |
248 virtual ~FakeSyncWebSocket() {} | |
249 | |
250 virtual bool IsConnected() OVERRIDE { | |
251 return connected_; | |
252 } | |
253 | |
254 virtual bool Connect(const GURL& url) OVERRIDE { | |
255 EXPECT_FALSE(connected_); | |
256 connected_ = true; | |
257 return true; | |
258 } | |
259 | |
260 virtual bool Send(const std::string& message) OVERRIDE { | |
261 return true; | |
262 } | |
263 | |
264 virtual bool ReceiveNextMessage(std::string* message) OVERRIDE { | |
265 return true; | |
266 } | |
267 | |
268 virtual bool HasNextMessage() OVERRIDE { | |
269 return true; | |
270 } | |
271 | |
272 private: | |
273 bool connected_; | |
274 }; | |
275 | |
276 bool ReturnCommand( | |
277 const std::string& message, | |
278 int expected_id, | |
279 internal::InspectorMessageType* type, | |
280 internal::InspectorEvent* event, | |
281 internal::InspectorCommandResponse* command_response) { | |
282 *type = internal::kCommandResponseMessageType; | |
283 command_response->id = expected_id; | |
284 command_response->result.reset(new base::DictionaryValue()); | |
285 return true; | |
286 } | |
287 | |
288 bool ReturnBadResponse( | |
289 const std::string& message, | |
290 int expected_id, | |
291 internal::InspectorMessageType* type, | |
292 internal::InspectorEvent* event, | |
293 internal::InspectorCommandResponse* command_response) { | |
294 *type = internal::kCommandResponseMessageType; | |
295 command_response->id = expected_id; | |
296 command_response->result.reset(new base::DictionaryValue()); | |
297 return false; | |
298 } | |
299 | |
300 bool ReturnCommandBadId( | |
301 const std::string& message, | |
302 int expected_id, | |
303 internal::InspectorMessageType* type, | |
304 internal::InspectorEvent* event, | |
305 internal::InspectorCommandResponse* command_response) { | |
306 *type = internal::kCommandResponseMessageType; | |
307 command_response->id = expected_id + 100; | |
308 command_response->result.reset(new base::DictionaryValue()); | |
309 return true; | |
310 } | |
311 | |
312 bool ReturnCommandError( | |
313 const std::string& message, | |
314 int expected_id, | |
315 internal::InspectorMessageType* type, | |
316 internal::InspectorEvent* event, | |
317 internal::InspectorCommandResponse* command_response) { | |
318 *type = internal::kCommandResponseMessageType; | |
319 command_response->id = expected_id; | |
320 command_response->error = "err"; | |
321 return true; | |
322 } | |
323 | |
324 class MockListener : public DevToolsEventListener { | |
325 public: | |
326 MockListener() : called_(false) {} | |
327 virtual ~MockListener() { | |
328 EXPECT_TRUE(called_); | |
329 } | |
330 | |
331 virtual Status OnConnected() OVERRIDE { | |
332 return Status(kOk); | |
333 } | |
334 | |
335 virtual void OnEvent(const std::string& method, | |
336 const base::DictionaryValue& params) OVERRIDE { | |
337 called_ = true; | |
338 EXPECT_STREQ("method", method.c_str()); | |
339 EXPECT_TRUE(params.HasKey("key")); | |
340 } | |
341 | |
342 private: | |
343 bool called_; | |
344 }; | |
345 | |
346 bool ReturnEventThenResponse( | |
347 bool* first, | |
348 const std::string& message, | |
349 int expected_id, | |
350 internal::InspectorMessageType* type, | |
351 internal::InspectorEvent* event, | |
352 internal::InspectorCommandResponse* command_response) { | |
353 if (*first) { | |
354 *type = internal::kEventMessageType; | |
355 event->method = "method"; | |
356 event->params.reset(new base::DictionaryValue()); | |
357 event->params->SetInteger("key", 1); | |
358 } else { | |
359 *type = internal::kCommandResponseMessageType; | |
360 command_response->id = expected_id; | |
361 base::DictionaryValue params; | |
362 command_response->result.reset(new base::DictionaryValue()); | |
363 command_response->result->SetInteger("key", 2); | |
364 } | |
365 *first = false; | |
366 return true; | |
367 } | |
368 | |
369 bool ReturnEvent( | |
370 const std::string& message, | |
371 int expected_id, | |
372 internal::InspectorMessageType* type, | |
373 internal::InspectorEvent* event, | |
374 internal::InspectorCommandResponse* command_response) { | |
375 *type = internal::kEventMessageType; | |
376 event->method = "method"; | |
377 event->params.reset(new base::DictionaryValue()); | |
378 event->params->SetInteger("key", 1); | |
379 return true; | |
380 } | |
381 | |
382 bool ReturnOutOfOrderResponses( | |
383 int* recurse_count, | |
384 DevToolsClient* client, | |
385 const std::string& message, | |
386 int expected_id, | |
387 internal::InspectorMessageType* type, | |
388 internal::InspectorEvent* event, | |
389 internal::InspectorCommandResponse* command_response) { | |
390 int key = 0; | |
391 base::DictionaryValue params; | |
392 params.SetInteger("param", 1); | |
393 switch ((*recurse_count)++) { | |
394 case 0: | |
395 client->SendCommand("method", params); | |
396 *type = internal::kEventMessageType; | |
397 event->method = "method"; | |
398 event->params.reset(new base::DictionaryValue()); | |
399 event->params->SetInteger("key", 1); | |
400 return true; | |
401 case 1: | |
402 command_response->id = expected_id - 1; | |
403 key = 2; | |
404 break; | |
405 case 2: | |
406 command_response->id = expected_id; | |
407 key = 3; | |
408 break; | |
409 } | |
410 *type = internal::kCommandResponseMessageType; | |
411 command_response->result.reset(new base::DictionaryValue()); | |
412 command_response->result->SetInteger("key", key); | |
413 return true; | |
414 } | |
415 | |
416 bool ReturnError( | |
417 const std::string& message, | |
418 int expected_id, | |
419 internal::InspectorMessageType* type, | |
420 internal::InspectorEvent* event, | |
421 internal::InspectorCommandResponse* command_response) { | |
422 return false; | |
423 } | |
424 | |
425 Status AlwaysTrue(bool* is_met) { | |
426 *is_met = true; | |
427 return Status(kOk); | |
428 } | |
429 | |
430 Status AlwaysError(bool* is_met) { | |
431 return Status(kUnknownError); | |
432 } | |
433 | |
434 } // namespace | |
435 | |
436 TEST(DevToolsClientImpl, SendCommandOnlyConnectsOnce) { | |
437 SyncWebSocketFactory factory = | |
438 base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>); | |
439 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc), | |
440 base::Bind(&ReturnCommand)); | |
441 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
442 base::DictionaryValue params; | |
443 ASSERT_TRUE(client.SendCommand("method", params).IsOk()); | |
444 ASSERT_TRUE(client.SendCommand("method", params).IsOk()); | |
445 } | |
446 | |
447 TEST(DevToolsClientImpl, SendCommandBadResponse) { | |
448 SyncWebSocketFactory factory = | |
449 base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>); | |
450 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc), | |
451 base::Bind(&ReturnBadResponse)); | |
452 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
453 base::DictionaryValue params; | |
454 ASSERT_TRUE(client.SendCommand("method", params).IsError()); | |
455 } | |
456 | |
457 TEST(DevToolsClientImpl, SendCommandBadId) { | |
458 SyncWebSocketFactory factory = | |
459 base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>); | |
460 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc), | |
461 base::Bind(&ReturnCommandBadId)); | |
462 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
463 base::DictionaryValue params; | |
464 ASSERT_TRUE(client.SendCommand("method", params).IsError()); | |
465 } | |
466 | |
467 TEST(DevToolsClientImpl, SendCommandResponseError) { | |
468 SyncWebSocketFactory factory = | |
469 base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>); | |
470 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc), | |
471 base::Bind(&ReturnCommandError)); | |
472 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
473 base::DictionaryValue params; | |
474 ASSERT_TRUE(client.SendCommand("method", params).IsError()); | |
475 } | |
476 | |
477 TEST(DevToolsClientImpl, SendCommandEventBeforeResponse) { | |
478 SyncWebSocketFactory factory = | |
479 base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>); | |
480 MockListener listener; | |
481 bool first = true; | |
482 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc), | |
483 base::Bind(&ReturnEventThenResponse, &first)); | |
484 client.AddListener(&listener); | |
485 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
486 base::DictionaryValue params; | |
487 scoped_ptr<base::DictionaryValue> result; | |
488 ASSERT_TRUE(client.SendCommandAndGetResult("method", params, &result).IsOk()); | |
489 ASSERT_TRUE(result); | |
490 int key; | |
491 ASSERT_TRUE(result->GetInteger("key", &key)); | |
492 ASSERT_EQ(2, key); | |
493 } | |
494 | |
495 TEST(ParseInspectorMessage, NonJson) { | |
496 internal::InspectorMessageType type; | |
497 internal::InspectorEvent event; | |
498 internal::InspectorCommandResponse response; | |
499 ASSERT_FALSE(internal::ParseInspectorMessage( | |
500 "hi", 0, &type, &event, &response)); | |
501 } | |
502 | |
503 TEST(ParseInspectorMessage, NeitherCommandNorEvent) { | |
504 internal::InspectorMessageType type; | |
505 internal::InspectorEvent event; | |
506 internal::InspectorCommandResponse response; | |
507 ASSERT_FALSE(internal::ParseInspectorMessage( | |
508 "{}", 0, &type, &event, &response)); | |
509 } | |
510 | |
511 TEST(ParseInspectorMessage, EventNoParams) { | |
512 internal::InspectorMessageType type; | |
513 internal::InspectorEvent event; | |
514 internal::InspectorCommandResponse response; | |
515 ASSERT_TRUE(internal::ParseInspectorMessage( | |
516 "{\"method\":\"method\"}", 0, &type, &event, &response)); | |
517 ASSERT_EQ(internal::kEventMessageType, type); | |
518 ASSERT_STREQ("method", event.method.c_str()); | |
519 ASSERT_TRUE(event.params->IsType(base::Value::TYPE_DICTIONARY)); | |
520 } | |
521 | |
522 TEST(ParseInspectorMessage, EventWithParams) { | |
523 internal::InspectorMessageType type; | |
524 internal::InspectorEvent event; | |
525 internal::InspectorCommandResponse response; | |
526 ASSERT_TRUE(internal::ParseInspectorMessage( | |
527 "{\"method\":\"method\",\"params\":{\"key\":100}}", | |
528 0, &type, &event, &response)); | |
529 ASSERT_EQ(internal::kEventMessageType, type); | |
530 ASSERT_STREQ("method", event.method.c_str()); | |
531 int key; | |
532 ASSERT_TRUE(event.params->GetInteger("key", &key)); | |
533 ASSERT_EQ(100, key); | |
534 } | |
535 | |
536 TEST(ParseInspectorMessage, CommandNoErrorOrResult) { | |
537 internal::InspectorMessageType type; | |
538 internal::InspectorEvent event; | |
539 internal::InspectorCommandResponse response; | |
540 ASSERT_FALSE(internal::ParseInspectorMessage( | |
541 "{\"id\":1}", 0, &type, &event, &response)); | |
542 } | |
543 | |
544 TEST(ParseInspectorMessage, CommandError) { | |
545 internal::InspectorMessageType type; | |
546 internal::InspectorEvent event; | |
547 internal::InspectorCommandResponse response; | |
548 ASSERT_TRUE(internal::ParseInspectorMessage( | |
549 "{\"id\":1,\"error\":{}}", 0, &type, &event, &response)); | |
550 ASSERT_EQ(internal::kCommandResponseMessageType, type); | |
551 ASSERT_EQ(1, response.id); | |
552 ASSERT_TRUE(response.error.length()); | |
553 ASSERT_FALSE(response.result); | |
554 } | |
555 | |
556 TEST(ParseInspectorMessage, Command) { | |
557 internal::InspectorMessageType type; | |
558 internal::InspectorEvent event; | |
559 internal::InspectorCommandResponse response; | |
560 ASSERT_TRUE(internal::ParseInspectorMessage( | |
561 "{\"id\":1,\"result\":{\"key\":1}}", 0, &type, &event, &response)); | |
562 ASSERT_EQ(internal::kCommandResponseMessageType, type); | |
563 ASSERT_EQ(1, response.id); | |
564 ASSERT_FALSE(response.error.length()); | |
565 int key; | |
566 ASSERT_TRUE(response.result->GetInteger("key", &key)); | |
567 ASSERT_EQ(1, key); | |
568 } | |
569 | |
570 TEST(DevToolsClientImpl, HandleEventsUntil) { | |
571 MockListener listener; | |
572 SyncWebSocketFactory factory = | |
573 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>); | |
574 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc), | |
575 base::Bind(&ReturnEvent)); | |
576 client.AddListener(&listener); | |
577 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
578 Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue)); | |
579 ASSERT_EQ(kOk, status.code()); | |
580 } | |
581 | |
582 TEST(DevToolsClientImpl, WaitForNextEventCommand) { | |
583 SyncWebSocketFactory factory = | |
584 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>); | |
585 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc), | |
586 base::Bind(&ReturnCommand)); | |
587 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
588 Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue)); | |
589 ASSERT_EQ(kUnknownError, status.code()); | |
590 } | |
591 | |
592 TEST(DevToolsClientImpl, WaitForNextEventError) { | |
593 SyncWebSocketFactory factory = | |
594 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>); | |
595 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc), | |
596 base::Bind(&ReturnError)); | |
597 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
598 Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue)); | |
599 ASSERT_EQ(kUnknownError, status.code()); | |
600 } | |
601 | |
602 TEST(DevToolsClientImpl, WaitForNextEventConditionalFuncReturnsError) { | |
603 SyncWebSocketFactory factory = | |
604 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>); | |
605 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc), | |
606 base::Bind(&ReturnEvent)); | |
607 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
608 Status status = client.HandleEventsUntil(base::Bind(&AlwaysError)); | |
609 ASSERT_EQ(kUnknownError, status.code()); | |
610 } | |
611 | |
612 TEST(DevToolsClientImpl, NestedCommandsWithOutOfOrderResults) { | |
613 SyncWebSocketFactory factory = | |
614 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>); | |
615 int recurse_count = 0; | |
616 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc)); | |
617 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
618 client.SetParserFuncForTesting( | |
619 base::Bind(&ReturnOutOfOrderResponses, &recurse_count, &client)); | |
620 base::DictionaryValue params; | |
621 params.SetInteger("param", 1); | |
622 scoped_ptr<base::DictionaryValue> result; | |
623 ASSERT_TRUE(client.SendCommandAndGetResult("method", params, &result).IsOk()); | |
624 ASSERT_TRUE(result); | |
625 int key; | |
626 ASSERT_TRUE(result->GetInteger("key", &key)); | |
627 ASSERT_EQ(2, key); | |
628 } | |
629 | |
630 namespace { | |
631 | |
632 class OnConnectedListener : public DevToolsEventListener { | |
633 public: | |
634 OnConnectedListener(const std::string& method, DevToolsClient* client) | |
635 : method_(method), | |
636 client_(client), | |
637 on_connected_called_(false), | |
638 on_event_called_(false) { | |
639 client_->AddListener(this); | |
640 } | |
641 virtual ~OnConnectedListener() {} | |
642 | |
643 void VerifyCalled() { | |
644 EXPECT_TRUE(on_connected_called_); | |
645 EXPECT_TRUE(on_event_called_); | |
646 } | |
647 | |
648 virtual Status OnConnected() OVERRIDE { | |
649 EXPECT_FALSE(on_connected_called_); | |
650 EXPECT_FALSE(on_event_called_); | |
651 on_connected_called_ = true; | |
652 base::DictionaryValue params; | |
653 return client_->SendCommand(method_, params); | |
654 } | |
655 | |
656 virtual void OnEvent(const std::string& method, | |
657 const base::DictionaryValue& params) OVERRIDE { | |
658 EXPECT_TRUE(on_connected_called_); | |
659 on_event_called_ = true; | |
660 } | |
661 | |
662 private: | |
663 std::string method_; | |
664 DevToolsClient* client_; | |
665 bool on_connected_called_; | |
666 bool on_event_called_; | |
667 }; | |
668 | |
669 class OnConnectedSyncWebSocket : public SyncWebSocket { | |
670 public: | |
671 OnConnectedSyncWebSocket() : connected_(false) {} | |
672 virtual ~OnConnectedSyncWebSocket() {} | |
673 | |
674 virtual bool IsConnected() OVERRIDE { | |
675 return connected_; | |
676 } | |
677 | |
678 virtual bool Connect(const GURL& url) OVERRIDE { | |
679 connected_ = true; | |
680 return true; | |
681 } | |
682 | |
683 virtual bool Send(const std::string& message) OVERRIDE { | |
684 EXPECT_TRUE(connected_); | |
685 scoped_ptr<base::Value> value(base::JSONReader::Read(message)); | |
686 base::DictionaryValue* dict = NULL; | |
687 EXPECT_TRUE(value->GetAsDictionary(&dict)); | |
688 if (!dict) | |
689 return false; | |
690 int id; | |
691 EXPECT_TRUE(dict->GetInteger("id", &id)); | |
692 std::string method; | |
693 EXPECT_TRUE(dict->GetString("method", &method)); | |
694 | |
695 base::DictionaryValue response; | |
696 response.SetInteger("id", id); | |
697 response.Set("result", new base::DictionaryValue()); | |
698 std::string json_response; | |
699 base::JSONWriter::Write(&response, &json_response); | |
700 queued_response_.push_back(json_response); | |
701 | |
702 // Push one event. | |
703 base::DictionaryValue event; | |
704 event.SetString("method", "updateEvent"); | |
705 event.Set("params", new base::DictionaryValue()); | |
706 std::string json_event; | |
707 base::JSONWriter::Write(&event, &json_event); | |
708 queued_response_.push_back(json_event); | |
709 | |
710 return true; | |
711 } | |
712 | |
713 virtual bool ReceiveNextMessage(std::string* message) OVERRIDE { | |
714 if (queued_response_.empty()) | |
715 return false; | |
716 *message = queued_response_.front(); | |
717 queued_response_.pop_front(); | |
718 return true; | |
719 } | |
720 | |
721 virtual bool HasNextMessage() OVERRIDE { | |
722 return !queued_response_.empty(); | |
723 } | |
724 | |
725 private: | |
726 bool connected_; | |
727 std::list<std::string> queued_response_; | |
728 }; | |
729 | |
730 } // namespace | |
731 | |
732 TEST(DevToolsClientImpl, ProcessOnConnectedFirstOnCommand) { | |
733 SyncWebSocketFactory factory = | |
734 base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>); | |
735 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc)); | |
736 OnConnectedListener listener1("DOM.getDocument", &client); | |
737 OnConnectedListener listener2("Runtime.enable", &client); | |
738 OnConnectedListener listener3("Page.enable", &client); | |
739 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
740 base::DictionaryValue params; | |
741 EXPECT_EQ(kOk, client.SendCommand("Runtime.execute", params).code()); | |
742 listener1.VerifyCalled(); | |
743 listener2.VerifyCalled(); | |
744 listener3.VerifyCalled(); | |
745 } | |
746 | |
747 TEST(DevToolsClientImpl, ProcessOnConnectedFirstOnHandleEventsUntil) { | |
748 SyncWebSocketFactory factory = | |
749 base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>); | |
750 DevToolsClientImpl client(factory, "http://url", base::Bind(&CloserFunc)); | |
751 OnConnectedListener listener1("DOM.getDocument", &client); | |
752 OnConnectedListener listener2("Runtime.enable", &client); | |
753 OnConnectedListener listener3("Page.enable", &client); | |
754 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
755 EXPECT_EQ(kOk, client.HandleReceivedEvents().code()); | |
756 listener1.VerifyCalled(); | |
757 listener2.VerifyCalled(); | |
758 listener3.VerifyCalled(); | |
759 } | |
760 | |
761 namespace { | |
762 | |
763 class DisconnectedSyncWebSocket : public MockSyncWebSocket { | |
764 public: | |
765 DisconnectedSyncWebSocket() : connection_count_(0), command_count_(0) {} | |
766 virtual ~DisconnectedSyncWebSocket() {} | |
767 | |
768 virtual bool Connect(const GURL& url) OVERRIDE { | |
769 connection_count_++; | |
770 connected_ = connection_count_ != 2; | |
771 return connected_; | |
772 } | |
773 | |
774 virtual bool Send(const std::string& message) OVERRIDE { | |
775 command_count_++; | |
776 if (command_count_ == 1) { | |
777 connected_ = false; | |
778 return false; | |
779 } | |
780 return MockSyncWebSocket::Send(message); | |
781 } | |
782 | |
783 private: | |
784 int connection_count_; | |
785 int command_count_; | |
786 }; | |
787 | |
788 Status CheckCloserFuncCalled(bool* is_called) { | |
789 *is_called = true; | |
790 return Status(kOk); | |
791 } | |
792 | |
793 } // namespace | |
794 | |
795 TEST(DevToolsClientImpl, Reconnect) { | |
796 SyncWebSocketFactory factory = | |
797 base::Bind(&CreateMockSyncWebSocket<DisconnectedSyncWebSocket>); | |
798 bool is_called = false; | |
799 DevToolsClientImpl client(factory, "http://url", | |
800 base::Bind(&CheckCloserFuncCalled, &is_called)); | |
801 ASSERT_FALSE(is_called); | |
802 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
803 ASSERT_FALSE(is_called); | |
804 base::DictionaryValue params; | |
805 params.SetInteger("param", 1); | |
806 is_called = false; | |
807 ASSERT_EQ(kDisconnected, client.SendCommand("method", params).code()); | |
808 ASSERT_FALSE(is_called); | |
809 ASSERT_EQ(kDisconnected, client.HandleReceivedEvents().code()); | |
810 ASSERT_FALSE(is_called); | |
811 ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); | |
812 ASSERT_TRUE(is_called); | |
813 is_called = false; | |
814 ASSERT_EQ(kOk, client.SendCommand("method", params).code()); | |
815 ASSERT_FALSE(is_called); | |
816 } | |
OLD | NEW |