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.
8 #include "base/callback.h"
9 #include "base/compiler_specific.h"
10 #include "base/files/file_path.h"
11 #include "base/location.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/synchronization/lock.h"
16 #include "base/threading/thread.h"
17 #include "base/values.h"
18 #include "chrome/test/chromedriver/chrome/status.h"
19 #include "chrome/test/chromedriver/chrome/stub_chrome.h"
20 #include "chrome/test/chromedriver/chrome/stub_web_view.h"
21 #include "chrome/test/chromedriver/chrome/web_view.h"
22 #include "chrome/test/chromedriver/command_listener_proxy.h"
23 #include "chrome/test/chromedriver/commands.h"
24 #include "chrome/test/chromedriver/element_commands.h"
25 #include "chrome/test/chromedriver/session.h"
26 #include "chrome/test/chromedriver/session_commands.h"
27 #include "chrome/test/chromedriver/window_commands.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 #include "third_party/webdriver/atoms.h"
33 void OnGetStatus(const Status
& status
,
34 scoped_ptr
<base::Value
> value
,
35 const std::string
& session_id
) {
36 ASSERT_EQ(kOk
, status
.code());
37 base::DictionaryValue
* dict
;
38 ASSERT_TRUE(value
->GetAsDictionary(&dict
));
40 ASSERT_TRUE(dict
->Get("os.name", &unused
));
41 ASSERT_TRUE(dict
->Get("os.version", &unused
));
42 ASSERT_TRUE(dict
->Get("os.arch", &unused
));
43 ASSERT_TRUE(dict
->Get("build.version", &unused
));
48 TEST(CommandsTest
, GetStatus
) {
49 base::DictionaryValue params
;
50 ExecuteGetStatus(params
, std::string(), base::Bind(&OnGetStatus
));
55 void ExecuteStubGetSession(int* count
,
56 const base::DictionaryValue
& params
,
57 const std::string
& session_id
,
58 const CommandCallback
& callback
) {
60 EXPECT_STREQ("id", session_id
.c_str());
62 EXPECT_STREQ("id2", session_id
.c_str());
66 scoped_ptr
<base::DictionaryValue
> capabilities(new base::DictionaryValue());
68 capabilities
->Set("capability1", new base::StringValue("test1"));
69 capabilities
->Set("capability2", new base::StringValue("test2"));
71 callback
.Run(Status(kOk
), capabilities
.Pass(), session_id
);
74 void OnGetSessions(const Status
& status
,
75 scoped_ptr
<base::Value
> value
,
76 const std::string
& session_id
) {
77 ASSERT_EQ(kOk
, status
.code());
78 ASSERT_TRUE(value
.get());
79 base::ListValue
* sessions
;
80 ASSERT_TRUE(value
->GetAsList(&sessions
));
81 ASSERT_EQ(static_cast<size_t>(2), sessions
->GetSize());
83 base::DictionaryValue
* session1
;
84 base::DictionaryValue
* session2
;
85 ASSERT_TRUE(sessions
->GetDictionary(0, &session1
));
86 ASSERT_TRUE(sessions
->GetDictionary(1, &session2
));
88 ASSERT_EQ(static_cast<size_t>(2), session1
->size());
89 ASSERT_EQ(static_cast<size_t>(2), session2
->size());
91 std::string session1_id
;
92 std::string session2_id
;
93 base::DictionaryValue
* session1_capabilities
;
94 base::DictionaryValue
* session2_capabilities
;
96 ASSERT_TRUE(session1
->GetString("sessionId", &session1_id
));
97 ASSERT_TRUE(session2
->GetString("sessionId", &session2_id
));
98 ASSERT_TRUE(session1
->GetDictionary("capabilities", &session1_capabilities
));
99 ASSERT_TRUE(session2
->GetDictionary("capabilities", &session2_capabilities
));
101 ASSERT_EQ((size_t) 2, session1_capabilities
->size());
102 ASSERT_EQ((size_t) 2, session2_capabilities
->size());
103 ASSERT_EQ("id", session1_id
);
104 ASSERT_EQ("id2", session2_id
);
106 std::string session1_capability1
;
107 std::string session1_capability2
;
108 std::string session2_capability1
;
109 std::string session2_capability2
;
111 ASSERT_TRUE(session1_capabilities
->GetString("capability1",
112 &session1_capability1
));
113 ASSERT_TRUE(session1_capabilities
->GetString("capability2",
114 &session1_capability2
));
115 ASSERT_TRUE(session2_capabilities
->GetString("capability1",
116 &session2_capability1
));
117 ASSERT_TRUE(session2_capabilities
->GetString("capability2",
118 &session2_capability2
));
120 ASSERT_EQ("test1", session1_capability1
);
121 ASSERT_EQ("test2", session1_capability2
);
122 ASSERT_EQ("test1", session2_capability1
);
123 ASSERT_EQ("test2", session2_capability2
);
128 TEST(CommandsTest
, GetSessions
) {
129 SessionThreadMap map
;
130 Session
session("id");
131 Session
session2("id2");
132 map
[session
.id
] = make_linked_ptr(new base::Thread("1"));
133 map
[session2
.id
] = make_linked_ptr(new base::Thread("2"));
137 Command cmd
= base::Bind(&ExecuteStubGetSession
, &count
);
139 base::DictionaryValue params
;
140 base::MessageLoop loop
;
142 ExecuteGetSessions(cmd
, &map
, params
, std::string(),
143 base::Bind(&OnGetSessions
));
149 void ExecuteStubQuit(
151 const base::DictionaryValue
& params
,
152 const std::string
& session_id
,
153 const CommandCallback
& callback
) {
155 EXPECT_STREQ("id", session_id
.c_str());
157 EXPECT_STREQ("id2", session_id
.c_str());
160 callback
.Run(Status(kOk
), scoped_ptr
<base::Value
>(), session_id
);
163 void OnQuitAll(const Status
& status
,
164 scoped_ptr
<base::Value
> value
,
165 const std::string
& session_id
) {
166 ASSERT_EQ(kOk
, status
.code());
167 ASSERT_FALSE(value
.get());
172 TEST(CommandsTest
, QuitAll
) {
173 SessionThreadMap map
;
174 Session
session("id");
175 Session
session2("id2");
176 map
[session
.id
] = make_linked_ptr(new base::Thread("1"));
177 map
[session2
.id
] = make_linked_ptr(new base::Thread("2"));
180 Command cmd
= base::Bind(&ExecuteStubQuit
, &count
);
181 base::DictionaryValue params
;
182 base::MessageLoop loop
;
183 ExecuteQuitAll(cmd
, &map
, params
, std::string(), base::Bind(&OnQuitAll
));
189 Status
ExecuteSimpleCommand(
190 const std::string
& expected_id
,
191 base::DictionaryValue
* expected_params
,
194 const base::DictionaryValue
& params
,
195 scoped_ptr
<base::Value
>* return_value
) {
196 EXPECT_EQ(expected_id
, session
->id
);
197 EXPECT_TRUE(expected_params
->Equals(¶ms
));
198 return_value
->reset(value
->DeepCopy());
199 session
->quit
= true;
203 void OnSimpleCommand(base::RunLoop
* run_loop
,
204 const std::string
& expected_session_id
,
205 base::Value
* expected_value
,
206 const Status
& status
,
207 scoped_ptr
<base::Value
> value
,
208 const std::string
& session_id
) {
209 ASSERT_EQ(kOk
, status
.code());
210 ASSERT_TRUE(expected_value
->Equals(value
.get()));
211 ASSERT_EQ(expected_session_id
, session_id
);
217 TEST(CommandsTest
, ExecuteSessionCommand
) {
218 SessionThreadMap map
;
219 linked_ptr
<base::Thread
> thread(new base::Thread("1"));
220 ASSERT_TRUE(thread
->Start());
221 std::string
id("id");
222 thread
->task_runner()->PostTask(
224 base::Bind(&internal::CreateSessionOnSessionThreadForTesting
, id
));
227 base::DictionaryValue params
;
228 params
.SetInteger("param", 5);
229 base::FundamentalValue
expected_value(6);
230 SessionCommand cmd
= base::Bind(
231 &ExecuteSimpleCommand
, id
, ¶ms
, &expected_value
);
233 base::MessageLoop loop
;
234 base::RunLoop run_loop
;
235 ExecuteSessionCommand(
242 base::Bind(&OnSimpleCommand
, &run_loop
, id
, &expected_value
));
248 Status
ShouldNotBeCalled(
250 const base::DictionaryValue
& params
,
251 scoped_ptr
<base::Value
>* value
) {
256 void OnNoSuchSession(const Status
& status
,
257 scoped_ptr
<base::Value
> value
,
258 const std::string
& session_id
) {
259 EXPECT_EQ(kNoSuchSession
, status
.code());
260 EXPECT_FALSE(value
.get());
263 void OnNoSuchSessionIsOk(const Status
& status
,
264 scoped_ptr
<base::Value
> value
,
265 const std::string
& session_id
) {
266 EXPECT_EQ(kOk
, status
.code());
267 EXPECT_FALSE(value
.get());
272 TEST(CommandsTest
, ExecuteSessionCommandOnNoSuchSession
) {
273 SessionThreadMap map
;
274 base::DictionaryValue params
;
275 ExecuteSessionCommand(&map
,
277 base::Bind(&ShouldNotBeCalled
),
281 base::Bind(&OnNoSuchSession
));
284 TEST(CommandsTest
, ExecuteSessionCommandOnNoSuchSessionWhenItExpectsOk
) {
285 SessionThreadMap map
;
286 base::DictionaryValue params
;
287 ExecuteSessionCommand(&map
,
289 base::Bind(&ShouldNotBeCalled
),
293 base::Bind(&OnNoSuchSessionIsOk
));
298 void OnNoSuchSessionAndQuit(base::RunLoop
* run_loop
,
299 const Status
& status
,
300 scoped_ptr
<base::Value
> value
,
301 const std::string
& session_id
) {
303 EXPECT_EQ(kNoSuchSession
, status
.code());
304 EXPECT_FALSE(value
.get());
309 TEST(CommandsTest
, ExecuteSessionCommandOnJustDeletedSession
) {
310 SessionThreadMap map
;
311 linked_ptr
<base::Thread
> thread(new base::Thread("1"));
312 ASSERT_TRUE(thread
->Start());
313 std::string
id("id");
316 base::MessageLoop loop
;
317 base::RunLoop run_loop
;
318 ExecuteSessionCommand(&map
,
320 base::Bind(&ShouldNotBeCalled
),
322 base::DictionaryValue(),
324 base::Bind(&OnNoSuchSessionAndQuit
, &run_loop
));
331 kElementExistsQueryOnce
= 0,
332 kElementExistsQueryTwice
,
333 kElementNotExistsQueryOnce
,
334 kElementExistsTimeout
337 class FindElementWebView
: public StubWebView
{
339 FindElementWebView(bool only_one
, TestScenario scenario
)
340 : StubWebView("1"), only_one_(only_one
), scenario_(scenario
),
343 case kElementExistsQueryOnce
:
344 case kElementExistsQueryTwice
:
345 case kElementExistsTimeout
: {
347 base::DictionaryValue element
;
348 element
.SetString("ELEMENT", "1");
349 result_
.reset(element
.DeepCopy());
351 base::DictionaryValue element1
;
352 element1
.SetString("ELEMENT", "1");
353 base::DictionaryValue element2
;
354 element2
.SetString("ELEMENT", "2");
355 base::ListValue list
;
356 list
.Append(element1
.DeepCopy());
357 list
.Append(element2
.DeepCopy());
358 result_
.reset(list
.DeepCopy());
362 case kElementNotExistsQueryOnce
: {
364 result_
= base::Value::CreateNullValue();
366 result_
.reset(new base::ListValue());
371 ~FindElementWebView() override
{}
373 void Verify(const std::string
& expected_frame
,
374 const base::ListValue
* expected_args
,
375 const base::Value
* actrual_result
) {
376 EXPECT_EQ(expected_frame
, frame_
);
377 std::string function
;
379 function
= webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENT
);
381 function
= webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENTS
);
382 EXPECT_EQ(function
, function_
);
383 ASSERT_TRUE(args_
.get());
384 EXPECT_TRUE(expected_args
->Equals(args_
.get()));
385 ASSERT_TRUE(actrual_result
);
386 EXPECT_TRUE(result_
->Equals(actrual_result
));
389 // Overridden from WebView:
390 Status
CallFunction(const std::string
& frame
,
391 const std::string
& function
,
392 const base::ListValue
& args
,
393 scoped_ptr
<base::Value
>* result
) override
{
395 if (scenario_
== kElementExistsTimeout
||
396 (scenario_
== kElementExistsQueryTwice
&& current_count_
== 1)) {
397 // Always return empty result when testing timeout.
399 *result
= base::Value::CreateNullValue();
401 result
->reset(new base::ListValue());
404 case kElementExistsQueryOnce
:
405 case kElementNotExistsQueryOnce
: {
406 EXPECT_EQ(1, current_count_
);
409 case kElementExistsQueryTwice
: {
410 EXPECT_EQ(2, current_count_
);
418 *result
= result_
->CreateDeepCopy();
420 function_
= function
;
421 args_
= args
.CreateDeepCopy();
428 TestScenario scenario_
;
431 std::string function_
;
432 scoped_ptr
<base::ListValue
> args_
;
433 scoped_ptr
<base::Value
> result_
;
438 TEST(CommandsTest
, SuccessfulFindElement
) {
439 FindElementWebView
web_view(true, kElementExistsQueryTwice
);
440 Session
session("id");
441 session
.implicit_wait
= base::TimeDelta::FromSeconds(1);
442 session
.SwitchToSubFrame("frame_id1", std::string());
443 base::DictionaryValue params
;
444 params
.SetString("using", "id");
445 params
.SetString("value", "a");
446 scoped_ptr
<base::Value
> result
;
448 ExecuteFindElement(1, &session
, &web_view
, params
, &result
).code());
449 base::DictionaryValue param
;
450 param
.SetString("id", "a");
451 base::ListValue expected_args
;
452 expected_args
.Append(param
.DeepCopy());
453 web_view
.Verify("frame_id1", &expected_args
, result
.get());
456 TEST(CommandsTest
, FailedFindElement
) {
457 FindElementWebView
web_view(true, kElementNotExistsQueryOnce
);
458 Session
session("id");
459 base::DictionaryValue params
;
460 params
.SetString("using", "id");
461 params
.SetString("value", "a");
462 scoped_ptr
<base::Value
> result
;
463 ASSERT_EQ(kNoSuchElement
,
464 ExecuteFindElement(1, &session
, &web_view
, params
, &result
).code());
467 TEST(CommandsTest
, SuccessfulFindElements
) {
468 FindElementWebView
web_view(false, kElementExistsQueryTwice
);
469 Session
session("id");
470 session
.implicit_wait
= base::TimeDelta::FromSeconds(1);
471 session
.SwitchToSubFrame("frame_id2", std::string());
472 base::DictionaryValue params
;
473 params
.SetString("using", "name");
474 params
.SetString("value", "b");
475 scoped_ptr
<base::Value
> result
;
478 ExecuteFindElements(1, &session
, &web_view
, params
, &result
).code());
479 base::DictionaryValue param
;
480 param
.SetString("name", "b");
481 base::ListValue expected_args
;
482 expected_args
.Append(param
.DeepCopy());
483 web_view
.Verify("frame_id2", &expected_args
, result
.get());
486 TEST(CommandsTest
, FailedFindElements
) {
487 Session
session("id");
488 FindElementWebView
web_view(false, kElementNotExistsQueryOnce
);
489 base::DictionaryValue params
;
490 params
.SetString("using", "id");
491 params
.SetString("value", "a");
492 scoped_ptr
<base::Value
> result
;
495 ExecuteFindElements(1, &session
, &web_view
, params
, &result
).code());
496 base::ListValue
* list
;
497 ASSERT_TRUE(result
->GetAsList(&list
));
498 ASSERT_EQ(0U, list
->GetSize());
501 TEST(CommandsTest
, SuccessfulFindChildElement
) {
502 FindElementWebView
web_view(true, kElementExistsQueryTwice
);
503 Session
session("id");
504 session
.implicit_wait
= base::TimeDelta::FromSeconds(1);
505 session
.SwitchToSubFrame("frame_id3", std::string());
506 base::DictionaryValue params
;
507 params
.SetString("using", "tag name");
508 params
.SetString("value", "div");
509 std::string element_id
= "1";
510 scoped_ptr
<base::Value
> result
;
513 ExecuteFindChildElement(
514 1, &session
, &web_view
, element_id
, params
, &result
).code());
515 base::DictionaryValue locator_param
;
516 locator_param
.SetString("tag name", "div");
517 base::DictionaryValue root_element_param
;
518 root_element_param
.SetString("ELEMENT", element_id
);
519 base::ListValue expected_args
;
520 expected_args
.Append(locator_param
.DeepCopy());
521 expected_args
.Append(root_element_param
.DeepCopy());
522 web_view
.Verify("frame_id3", &expected_args
, result
.get());
525 TEST(CommandsTest
, FailedFindChildElement
) {
526 Session
session("id");
527 FindElementWebView
web_view(true, kElementNotExistsQueryOnce
);
528 base::DictionaryValue params
;
529 params
.SetString("using", "id");
530 params
.SetString("value", "a");
531 std::string element_id
= "1";
532 scoped_ptr
<base::Value
> result
;
535 ExecuteFindChildElement(
536 1, &session
, &web_view
, element_id
, params
, &result
).code());
539 TEST(CommandsTest
, SuccessfulFindChildElements
) {
540 FindElementWebView
web_view(false, kElementExistsQueryTwice
);
541 Session
session("id");
542 session
.implicit_wait
= base::TimeDelta::FromSeconds(1);
543 session
.SwitchToSubFrame("frame_id4", std::string());
544 base::DictionaryValue params
;
545 params
.SetString("using", "class name");
546 params
.SetString("value", "c");
547 std::string element_id
= "1";
548 scoped_ptr
<base::Value
> result
;
551 ExecuteFindChildElements(
552 1, &session
, &web_view
, element_id
, params
, &result
).code());
553 base::DictionaryValue locator_param
;
554 locator_param
.SetString("class name", "c");
555 base::DictionaryValue root_element_param
;
556 root_element_param
.SetString("ELEMENT", element_id
);
557 base::ListValue expected_args
;
558 expected_args
.Append(locator_param
.DeepCopy());
559 expected_args
.Append(root_element_param
.DeepCopy());
560 web_view
.Verify("frame_id4", &expected_args
, result
.get());
563 TEST(CommandsTest
, FailedFindChildElements
) {
564 Session
session("id");
565 FindElementWebView
web_view(false, kElementNotExistsQueryOnce
);
566 base::DictionaryValue params
;
567 params
.SetString("using", "id");
568 params
.SetString("value", "a");
569 std::string element_id
= "1";
570 scoped_ptr
<base::Value
> result
;
573 ExecuteFindChildElements(
574 1, &session
, &web_view
, element_id
, params
, &result
).code());
575 base::ListValue
* list
;
576 ASSERT_TRUE(result
->GetAsList(&list
));
577 ASSERT_EQ(0U, list
->GetSize());
580 TEST(CommandsTest
, TimeoutInFindElement
) {
581 Session
session("id");
582 FindElementWebView
web_view(true, kElementExistsTimeout
);
583 session
.implicit_wait
= base::TimeDelta::FromMilliseconds(2);
584 base::DictionaryValue params
;
585 params
.SetString("using", "id");
586 params
.SetString("value", "a");
587 params
.SetString("id", "1");
588 scoped_ptr
<base::Value
> result
;
589 ASSERT_EQ(kNoSuchElement
,
590 ExecuteFindElement(1, &session
, &web_view
, params
, &result
).code());
595 class ErrorCallFunctionWebView
: public StubWebView
{
597 explicit ErrorCallFunctionWebView(StatusCode code
)
598 : StubWebView("1"), code_(code
) {}
599 ~ErrorCallFunctionWebView() override
{}
601 // Overridden from WebView:
602 Status
CallFunction(const std::string
& frame
,
603 const std::string
& function
,
604 const base::ListValue
& args
,
605 scoped_ptr
<base::Value
>* result
) override
{
606 return Status(code_
);
615 TEST(CommandsTest
, ErrorFindElement
) {
616 Session
session("id");
617 ErrorCallFunctionWebView
web_view(kUnknownError
);
618 base::DictionaryValue params
;
619 params
.SetString("using", "id");
620 params
.SetString("value", "a");
621 scoped_ptr
<base::Value
> value
;
622 ASSERT_EQ(kUnknownError
,
623 ExecuteFindElement(1, &session
, &web_view
, params
, &value
).code());
624 ASSERT_EQ(kUnknownError
,
625 ExecuteFindElements(1, &session
, &web_view
, params
, &value
).code());
628 TEST(CommandsTest
, ErrorFindChildElement
) {
629 Session
session("id");
630 ErrorCallFunctionWebView
web_view(kStaleElementReference
);
631 base::DictionaryValue params
;
632 params
.SetString("using", "id");
633 params
.SetString("value", "a");
634 std::string element_id
= "1";
635 scoped_ptr
<base::Value
> result
;
637 kStaleElementReference
,
638 ExecuteFindChildElement(
639 1, &session
, &web_view
, element_id
, params
, &result
).code());
641 kStaleElementReference
,
642 ExecuteFindChildElements(
643 1, &session
, &web_view
, element_id
, params
, &result
).code());
648 class MockCommandListener
: public CommandListener
{
650 MockCommandListener() : called_(false) {}
651 ~MockCommandListener() override
{}
653 Status
BeforeCommand(const std::string
& command_name
) override
{
655 EXPECT_STREQ("cmd", command_name
.c_str());
659 void VerifyCalled() {
660 EXPECT_TRUE(called_
);
663 void VerifyNotCalled() {
664 EXPECT_FALSE(called_
);
671 Status
ExecuteAddListenerToSessionCommand(
672 CommandListener
* listener
,
674 const base::DictionaryValue
& params
,
675 scoped_ptr
<base::Value
>* return_value
) {
676 session
->command_listeners
.push_back(listener
);
680 Status
ExecuteQuitSessionCommand(
682 const base::DictionaryValue
& params
,
683 scoped_ptr
<base::Value
>* return_value
) {
684 session
->quit
= true;
688 void OnSessionCommand(
689 base::RunLoop
* run_loop
,
690 const Status
& status
,
691 scoped_ptr
<base::Value
> value
,
692 const std::string
& session_id
) {
693 ASSERT_EQ(kOk
, status
.code());
699 TEST(CommandsTest
, SuccessNotifyingCommandListeners
) {
700 SessionThreadMap map
;
701 linked_ptr
<base::Thread
> thread(new base::Thread("1"));
702 ASSERT_TRUE(thread
->Start());
703 std::string
id("id");
704 thread
->task_runner()->PostTask(
706 base::Bind(&internal::CreateSessionOnSessionThreadForTesting
, id
));
710 base::DictionaryValue params
;
711 scoped_ptr
<MockCommandListener
> listener(new MockCommandListener());
712 CommandListenerProxy
* proxy
= new CommandListenerProxy(listener
.get());
713 // We add |proxy| to the session instead of adding |listener| directly so that
714 // after the session is destroyed by ExecuteQuitSessionCommand, we can still
715 // verify the listener was called. The session owns and will destroy |proxy|.
716 SessionCommand cmd
= base::Bind(&ExecuteAddListenerToSessionCommand
, proxy
);
717 base::MessageLoop loop
;
718 base::RunLoop run_loop_addlistener
;
720 // |CommandListener|s are notified immediately before commands are run.
721 // Here, the command adds |listener| to the session, so |listener|
722 // should not be notified since it will not have been added yet.
723 ExecuteSessionCommand(
730 base::Bind(&OnSessionCommand
, &run_loop_addlistener
));
731 run_loop_addlistener
.Run();
733 listener
->VerifyNotCalled();
735 base::RunLoop run_loop_testlistener
;
736 cmd
= base::Bind(&ExecuteQuitSessionCommand
);
738 // |listener| was added to |session| by ExecuteAddListenerToSessionCommand
739 // and should be notified before the next command, ExecuteQuitSessionCommand.
740 ExecuteSessionCommand(
747 base::Bind(&OnSessionCommand
, &run_loop_testlistener
));
748 run_loop_testlistener
.Run();
750 listener
->VerifyCalled();
755 class FailingCommandListener
: public CommandListener
{
757 FailingCommandListener() {}
758 ~FailingCommandListener() override
{}
760 Status
BeforeCommand(const std::string
& command_name
) override
{
761 return Status(kUnknownError
);
765 void AddListenerToSessionIfSessionExists(CommandListener
* listener
) {
766 Session
* session
= GetThreadLocalSession();
768 session
->command_listeners
.push_back(listener
);
772 void OnFailBecauseErrorNotifyingListeners(
773 base::RunLoop
* run_loop
,
774 const Status
& status
,
775 scoped_ptr
<base::Value
> value
,
776 const std::string
& session_id
) {
777 EXPECT_EQ(kUnknownError
, status
.code());
778 EXPECT_FALSE(value
.get());
782 void VerifySessionWasDeleted() {
783 ASSERT_FALSE(GetThreadLocalSession());
788 TEST(CommandsTest
, ErrorNotifyingCommandListeners
) {
789 SessionThreadMap map
;
790 linked_ptr
<base::Thread
> thread(new base::Thread("1"));
791 ASSERT_TRUE(thread
->Start());
792 std::string
id("id");
793 thread
->task_runner()->PostTask(
795 base::Bind(&internal::CreateSessionOnSessionThreadForTesting
, id
));
798 // In SuccessNotifyingCommandListenersBeforeCommand, we verified BeforeCommand
799 // was called before (as opposed to after) command execution. We don't need to
800 // verify this again, so we can just add |listener| with PostTask.
801 CommandListener
* listener
= new FailingCommandListener();
802 thread
->task_runner()->PostTask(
803 FROM_HERE
, base::Bind(&AddListenerToSessionIfSessionExists
, listener
));
805 base::DictionaryValue params
;
806 // The command should never be executed if BeforeCommand fails for a listener.
807 SessionCommand cmd
= base::Bind(&ShouldNotBeCalled
);
808 base::MessageLoop loop
;
809 base::RunLoop run_loop
;
811 ExecuteSessionCommand(
818 base::Bind(&OnFailBecauseErrorNotifyingListeners
, &run_loop
));
821 thread
->task_runner()->PostTask(FROM_HERE
,
822 base::Bind(&VerifySessionWasDeleted
));