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/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/synchronization/lock.h"
15 #include "base/threading/thread.h"
16 #include "base/values.h"
17 #include "chrome/test/chromedriver/chrome/status.h"
18 #include "chrome/test/chromedriver/chrome/stub_chrome.h"
19 #include "chrome/test/chromedriver/chrome/stub_web_view.h"
20 #include "chrome/test/chromedriver/chrome/web_view.h"
21 #include "chrome/test/chromedriver/command_listener_proxy.h"
22 #include "chrome/test/chromedriver/commands.h"
23 #include "chrome/test/chromedriver/element_commands.h"
24 #include "chrome/test/chromedriver/session.h"
25 #include "chrome/test/chromedriver/session_commands.h"
26 #include "chrome/test/chromedriver/window_commands.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "third_party/webdriver/atoms.h"
32 void OnGetStatus(const Status
& status
,
33 scoped_ptr
<base::Value
> value
,
34 const std::string
& session_id
) {
35 ASSERT_EQ(kOk
, status
.code());
36 base::DictionaryValue
* dict
;
37 ASSERT_TRUE(value
->GetAsDictionary(&dict
));
39 ASSERT_TRUE(dict
->Get("os.name", &unused
));
40 ASSERT_TRUE(dict
->Get("os.version", &unused
));
41 ASSERT_TRUE(dict
->Get("os.arch", &unused
));
42 ASSERT_TRUE(dict
->Get("build.version", &unused
));
47 TEST(CommandsTest
, GetStatus
) {
48 base::DictionaryValue params
;
49 ExecuteGetStatus(params
, std::string(), base::Bind(&OnGetStatus
));
54 void ExecuteStubGetSession(int* count
,
55 const base::DictionaryValue
& params
,
56 const std::string
& session_id
,
57 const CommandCallback
& callback
) {
59 EXPECT_STREQ("id", session_id
.c_str());
61 EXPECT_STREQ("id2", session_id
.c_str());
65 scoped_ptr
<base::DictionaryValue
> capabilities(new base::DictionaryValue());
67 capabilities
->Set("capability1", new base::StringValue("test1"));
68 capabilities
->Set("capability2", new base::StringValue("test2"));
70 callback
.Run(Status(kOk
), capabilities
.Pass(), session_id
);
73 void OnGetSessions(const Status
& status
,
74 scoped_ptr
<base::Value
> value
,
75 const std::string
& session_id
) {
76 ASSERT_EQ(kOk
, status
.code());
77 ASSERT_TRUE(value
.get());
78 base::ListValue
* sessions
;
79 ASSERT_TRUE(value
->GetAsList(&sessions
));
80 ASSERT_EQ(static_cast<size_t>(2), sessions
->GetSize());
82 base::DictionaryValue
* session1
;
83 base::DictionaryValue
* session2
;
84 ASSERT_TRUE(sessions
->GetDictionary(0, &session1
));
85 ASSERT_TRUE(sessions
->GetDictionary(1, &session2
));
87 ASSERT_EQ(static_cast<size_t>(2), session1
->size());
88 ASSERT_EQ(static_cast<size_t>(2), session2
->size());
90 std::string session1_id
;
91 std::string session2_id
;
92 base::DictionaryValue
* session1_capabilities
;
93 base::DictionaryValue
* session2_capabilities
;
95 ASSERT_TRUE(session1
->GetString("sessionId", &session1_id
));
96 ASSERT_TRUE(session2
->GetString("sessionId", &session2_id
));
97 ASSERT_TRUE(session1
->GetDictionary("capabilities", &session1_capabilities
));
98 ASSERT_TRUE(session2
->GetDictionary("capabilities", &session2_capabilities
));
100 ASSERT_EQ((size_t) 2, session1_capabilities
->size());
101 ASSERT_EQ((size_t) 2, session2_capabilities
->size());
102 ASSERT_EQ("id", session1_id
);
103 ASSERT_EQ("id2", session2_id
);
105 std::string session1_capability1
;
106 std::string session1_capability2
;
107 std::string session2_capability1
;
108 std::string session2_capability2
;
110 ASSERT_TRUE(session1_capabilities
->GetString("capability1",
111 &session1_capability1
));
112 ASSERT_TRUE(session1_capabilities
->GetString("capability2",
113 &session1_capability2
));
114 ASSERT_TRUE(session2_capabilities
->GetString("capability1",
115 &session2_capability1
));
116 ASSERT_TRUE(session2_capabilities
->GetString("capability2",
117 &session2_capability2
));
119 ASSERT_EQ("test1", session1_capability1
);
120 ASSERT_EQ("test2", session1_capability2
);
121 ASSERT_EQ("test1", session2_capability1
);
122 ASSERT_EQ("test2", session2_capability2
);
127 TEST(CommandsTest
, GetSessions
) {
128 SessionThreadMap map
;
129 Session
session("id");
130 Session
session2("id2");
131 map
[session
.id
] = make_linked_ptr(new base::Thread("1"));
132 map
[session2
.id
] = make_linked_ptr(new base::Thread("2"));
136 Command cmd
= base::Bind(&ExecuteStubGetSession
, &count
);
138 base::DictionaryValue params
;
139 base::MessageLoop loop
;
141 ExecuteGetSessions(cmd
, &map
, params
, std::string(),
142 base::Bind(&OnGetSessions
));
148 void ExecuteStubQuit(
150 const base::DictionaryValue
& params
,
151 const std::string
& session_id
,
152 const CommandCallback
& callback
) {
154 EXPECT_STREQ("id", session_id
.c_str());
156 EXPECT_STREQ("id2", session_id
.c_str());
159 callback
.Run(Status(kOk
), scoped_ptr
<base::Value
>(), session_id
);
162 void OnQuitAll(const Status
& status
,
163 scoped_ptr
<base::Value
> value
,
164 const std::string
& session_id
) {
165 ASSERT_EQ(kOk
, status
.code());
166 ASSERT_FALSE(value
.get());
171 TEST(CommandsTest
, QuitAll
) {
172 SessionThreadMap map
;
173 Session
session("id");
174 Session
session2("id2");
175 map
[session
.id
] = make_linked_ptr(new base::Thread("1"));
176 map
[session2
.id
] = make_linked_ptr(new base::Thread("2"));
179 Command cmd
= base::Bind(&ExecuteStubQuit
, &count
);
180 base::DictionaryValue params
;
181 base::MessageLoop loop
;
182 ExecuteQuitAll(cmd
, &map
, params
, std::string(), base::Bind(&OnQuitAll
));
188 Status
ExecuteSimpleCommand(
189 const std::string
& expected_id
,
190 base::DictionaryValue
* expected_params
,
193 const base::DictionaryValue
& params
,
194 scoped_ptr
<base::Value
>* return_value
) {
195 EXPECT_EQ(expected_id
, session
->id
);
196 EXPECT_TRUE(expected_params
->Equals(¶ms
));
197 return_value
->reset(value
->DeepCopy());
198 session
->quit
= true;
202 void OnSimpleCommand(base::RunLoop
* run_loop
,
203 const std::string
& expected_session_id
,
204 base::Value
* expected_value
,
205 const Status
& status
,
206 scoped_ptr
<base::Value
> value
,
207 const std::string
& session_id
) {
208 ASSERT_EQ(kOk
, status
.code());
209 ASSERT_TRUE(expected_value
->Equals(value
.get()));
210 ASSERT_EQ(expected_session_id
, session_id
);
216 TEST(CommandsTest
, ExecuteSessionCommand
) {
217 SessionThreadMap map
;
218 linked_ptr
<base::Thread
> thread(new base::Thread("1"));
219 ASSERT_TRUE(thread
->Start());
220 std::string
id("id");
221 thread
->message_loop()->PostTask(
223 base::Bind(&internal::CreateSessionOnSessionThreadForTesting
, id
));
226 base::DictionaryValue params
;
227 params
.SetInteger("param", 5);
228 base::FundamentalValue
expected_value(6);
229 SessionCommand cmd
= base::Bind(
230 &ExecuteSimpleCommand
, id
, ¶ms
, &expected_value
);
232 base::MessageLoop loop
;
233 base::RunLoop run_loop
;
234 ExecuteSessionCommand(
241 base::Bind(&OnSimpleCommand
, &run_loop
, id
, &expected_value
));
247 Status
ShouldNotBeCalled(
249 const base::DictionaryValue
& params
,
250 scoped_ptr
<base::Value
>* value
) {
255 void OnNoSuchSession(const Status
& status
,
256 scoped_ptr
<base::Value
> value
,
257 const std::string
& session_id
) {
258 EXPECT_EQ(kNoSuchSession
, status
.code());
259 EXPECT_FALSE(value
.get());
262 void OnNoSuchSessionIsOk(const Status
& status
,
263 scoped_ptr
<base::Value
> value
,
264 const std::string
& session_id
) {
265 EXPECT_EQ(kOk
, status
.code());
266 EXPECT_FALSE(value
.get());
271 TEST(CommandsTest
, ExecuteSessionCommandOnNoSuchSession
) {
272 SessionThreadMap map
;
273 base::DictionaryValue params
;
274 ExecuteSessionCommand(&map
,
276 base::Bind(&ShouldNotBeCalled
),
280 base::Bind(&OnNoSuchSession
));
283 TEST(CommandsTest
, ExecuteSessionCommandOnNoSuchSessionWhenItExpectsOk
) {
284 SessionThreadMap map
;
285 base::DictionaryValue params
;
286 ExecuteSessionCommand(&map
,
288 base::Bind(&ShouldNotBeCalled
),
292 base::Bind(&OnNoSuchSessionIsOk
));
297 void OnNoSuchSessionAndQuit(base::RunLoop
* run_loop
,
298 const Status
& status
,
299 scoped_ptr
<base::Value
> value
,
300 const std::string
& session_id
) {
302 EXPECT_EQ(kNoSuchSession
, status
.code());
303 EXPECT_FALSE(value
.get());
308 TEST(CommandsTest
, ExecuteSessionCommandOnJustDeletedSession
) {
309 SessionThreadMap map
;
310 linked_ptr
<base::Thread
> thread(new base::Thread("1"));
311 ASSERT_TRUE(thread
->Start());
312 std::string
id("id");
315 base::MessageLoop loop
;
316 base::RunLoop run_loop
;
317 ExecuteSessionCommand(&map
,
319 base::Bind(&ShouldNotBeCalled
),
321 base::DictionaryValue(),
323 base::Bind(&OnNoSuchSessionAndQuit
, &run_loop
));
330 kElementExistsQueryOnce
= 0,
331 kElementExistsQueryTwice
,
332 kElementNotExistsQueryOnce
,
333 kElementExistsTimeout
336 class FindElementWebView
: public StubWebView
{
338 FindElementWebView(bool only_one
, TestScenario scenario
)
339 : StubWebView("1"), only_one_(only_one
), scenario_(scenario
),
342 case kElementExistsQueryOnce
:
343 case kElementExistsQueryTwice
:
344 case kElementExistsTimeout
: {
346 base::DictionaryValue element
;
347 element
.SetString("ELEMENT", "1");
348 result_
.reset(element
.DeepCopy());
350 base::DictionaryValue element1
;
351 element1
.SetString("ELEMENT", "1");
352 base::DictionaryValue element2
;
353 element2
.SetString("ELEMENT", "2");
354 base::ListValue list
;
355 list
.Append(element1
.DeepCopy());
356 list
.Append(element2
.DeepCopy());
357 result_
.reset(list
.DeepCopy());
361 case kElementNotExistsQueryOnce
: {
363 result_
.reset(base::Value::CreateNullValue());
365 result_
.reset(new base::ListValue());
370 ~FindElementWebView() override
{}
372 void Verify(const std::string
& expected_frame
,
373 const base::ListValue
* expected_args
,
374 const base::Value
* actrual_result
) {
375 EXPECT_EQ(expected_frame
, frame_
);
376 std::string function
;
378 function
= webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENT
);
380 function
= webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENTS
);
381 EXPECT_EQ(function
, function_
);
382 ASSERT_TRUE(args_
.get());
383 EXPECT_TRUE(expected_args
->Equals(args_
.get()));
384 ASSERT_TRUE(actrual_result
);
385 EXPECT_TRUE(result_
->Equals(actrual_result
));
388 // Overridden from WebView:
389 Status
CallFunction(const std::string
& frame
,
390 const std::string
& function
,
391 const base::ListValue
& args
,
392 scoped_ptr
<base::Value
>* result
) override
{
394 if (scenario_
== kElementExistsTimeout
||
395 (scenario_
== kElementExistsQueryTwice
&& current_count_
== 1)) {
396 // Always return empty result when testing timeout.
398 result
->reset(base::Value::CreateNullValue());
400 result
->reset(new base::ListValue());
403 case kElementExistsQueryOnce
:
404 case kElementNotExistsQueryOnce
: {
405 EXPECT_EQ(1, current_count_
);
408 case kElementExistsQueryTwice
: {
409 EXPECT_EQ(2, current_count_
);
417 result
->reset(result_
->DeepCopy());
419 function_
= function
;
420 args_
.reset(args
.DeepCopy());
427 TestScenario scenario_
;
430 std::string function_
;
431 scoped_ptr
<base::ListValue
> args_
;
432 scoped_ptr
<base::Value
> result_
;
437 TEST(CommandsTest
, SuccessfulFindElement
) {
438 FindElementWebView
web_view(true, kElementExistsQueryTwice
);
439 Session
session("id");
440 session
.implicit_wait
= base::TimeDelta::FromSeconds(1);
441 session
.SwitchToSubFrame("frame_id1", std::string());
442 base::DictionaryValue params
;
443 params
.SetString("using", "id");
444 params
.SetString("value", "a");
445 scoped_ptr
<base::Value
> result
;
447 ExecuteFindElement(1, &session
, &web_view
, params
, &result
).code());
448 base::DictionaryValue param
;
449 param
.SetString("id", "a");
450 base::ListValue expected_args
;
451 expected_args
.Append(param
.DeepCopy());
452 web_view
.Verify("frame_id1", &expected_args
, result
.get());
455 TEST(CommandsTest
, FailedFindElement
) {
456 FindElementWebView
web_view(true, kElementNotExistsQueryOnce
);
457 Session
session("id");
458 base::DictionaryValue params
;
459 params
.SetString("using", "id");
460 params
.SetString("value", "a");
461 scoped_ptr
<base::Value
> result
;
462 ASSERT_EQ(kNoSuchElement
,
463 ExecuteFindElement(1, &session
, &web_view
, params
, &result
).code());
466 TEST(CommandsTest
, SuccessfulFindElements
) {
467 FindElementWebView
web_view(false, kElementExistsQueryTwice
);
468 Session
session("id");
469 session
.implicit_wait
= base::TimeDelta::FromSeconds(1);
470 session
.SwitchToSubFrame("frame_id2", std::string());
471 base::DictionaryValue params
;
472 params
.SetString("using", "name");
473 params
.SetString("value", "b");
474 scoped_ptr
<base::Value
> result
;
477 ExecuteFindElements(1, &session
, &web_view
, params
, &result
).code());
478 base::DictionaryValue param
;
479 param
.SetString("name", "b");
480 base::ListValue expected_args
;
481 expected_args
.Append(param
.DeepCopy());
482 web_view
.Verify("frame_id2", &expected_args
, result
.get());
485 TEST(CommandsTest
, FailedFindElements
) {
486 Session
session("id");
487 FindElementWebView
web_view(false, kElementNotExistsQueryOnce
);
488 base::DictionaryValue params
;
489 params
.SetString("using", "id");
490 params
.SetString("value", "a");
491 scoped_ptr
<base::Value
> result
;
494 ExecuteFindElements(1, &session
, &web_view
, params
, &result
).code());
495 base::ListValue
* list
;
496 ASSERT_TRUE(result
->GetAsList(&list
));
497 ASSERT_EQ(0U, list
->GetSize());
500 TEST(CommandsTest
, SuccessfulFindChildElement
) {
501 FindElementWebView
web_view(true, kElementExistsQueryTwice
);
502 Session
session("id");
503 session
.implicit_wait
= base::TimeDelta::FromSeconds(1);
504 session
.SwitchToSubFrame("frame_id3", std::string());
505 base::DictionaryValue params
;
506 params
.SetString("using", "tag name");
507 params
.SetString("value", "div");
508 std::string element_id
= "1";
509 scoped_ptr
<base::Value
> result
;
512 ExecuteFindChildElement(
513 1, &session
, &web_view
, element_id
, params
, &result
).code());
514 base::DictionaryValue locator_param
;
515 locator_param
.SetString("tag name", "div");
516 base::DictionaryValue root_element_param
;
517 root_element_param
.SetString("ELEMENT", element_id
);
518 base::ListValue expected_args
;
519 expected_args
.Append(locator_param
.DeepCopy());
520 expected_args
.Append(root_element_param
.DeepCopy());
521 web_view
.Verify("frame_id3", &expected_args
, result
.get());
524 TEST(CommandsTest
, FailedFindChildElement
) {
525 Session
session("id");
526 FindElementWebView
web_view(true, kElementNotExistsQueryOnce
);
527 base::DictionaryValue params
;
528 params
.SetString("using", "id");
529 params
.SetString("value", "a");
530 std::string element_id
= "1";
531 scoped_ptr
<base::Value
> result
;
534 ExecuteFindChildElement(
535 1, &session
, &web_view
, element_id
, params
, &result
).code());
538 TEST(CommandsTest
, SuccessfulFindChildElements
) {
539 FindElementWebView
web_view(false, kElementExistsQueryTwice
);
540 Session
session("id");
541 session
.implicit_wait
= base::TimeDelta::FromSeconds(1);
542 session
.SwitchToSubFrame("frame_id4", std::string());
543 base::DictionaryValue params
;
544 params
.SetString("using", "class name");
545 params
.SetString("value", "c");
546 std::string element_id
= "1";
547 scoped_ptr
<base::Value
> result
;
550 ExecuteFindChildElements(
551 1, &session
, &web_view
, element_id
, params
, &result
).code());
552 base::DictionaryValue locator_param
;
553 locator_param
.SetString("class name", "c");
554 base::DictionaryValue root_element_param
;
555 root_element_param
.SetString("ELEMENT", element_id
);
556 base::ListValue expected_args
;
557 expected_args
.Append(locator_param
.DeepCopy());
558 expected_args
.Append(root_element_param
.DeepCopy());
559 web_view
.Verify("frame_id4", &expected_args
, result
.get());
562 TEST(CommandsTest
, FailedFindChildElements
) {
563 Session
session("id");
564 FindElementWebView
web_view(false, kElementNotExistsQueryOnce
);
565 base::DictionaryValue params
;
566 params
.SetString("using", "id");
567 params
.SetString("value", "a");
568 std::string element_id
= "1";
569 scoped_ptr
<base::Value
> result
;
572 ExecuteFindChildElements(
573 1, &session
, &web_view
, element_id
, params
, &result
).code());
574 base::ListValue
* list
;
575 ASSERT_TRUE(result
->GetAsList(&list
));
576 ASSERT_EQ(0U, list
->GetSize());
579 TEST(CommandsTest
, TimeoutInFindElement
) {
580 Session
session("id");
581 FindElementWebView
web_view(true, kElementExistsTimeout
);
582 session
.implicit_wait
= base::TimeDelta::FromMilliseconds(2);
583 base::DictionaryValue params
;
584 params
.SetString("using", "id");
585 params
.SetString("value", "a");
586 params
.SetString("id", "1");
587 scoped_ptr
<base::Value
> result
;
588 ASSERT_EQ(kNoSuchElement
,
589 ExecuteFindElement(1, &session
, &web_view
, params
, &result
).code());
594 class ErrorCallFunctionWebView
: public StubWebView
{
596 explicit ErrorCallFunctionWebView(StatusCode code
)
597 : StubWebView("1"), code_(code
) {}
598 ~ErrorCallFunctionWebView() override
{}
600 // Overridden from WebView:
601 Status
CallFunction(const std::string
& frame
,
602 const std::string
& function
,
603 const base::ListValue
& args
,
604 scoped_ptr
<base::Value
>* result
) override
{
605 return Status(code_
);
614 TEST(CommandsTest
, ErrorFindElement
) {
615 Session
session("id");
616 ErrorCallFunctionWebView
web_view(kUnknownError
);
617 base::DictionaryValue params
;
618 params
.SetString("using", "id");
619 params
.SetString("value", "a");
620 scoped_ptr
<base::Value
> value
;
621 ASSERT_EQ(kUnknownError
,
622 ExecuteFindElement(1, &session
, &web_view
, params
, &value
).code());
623 ASSERT_EQ(kUnknownError
,
624 ExecuteFindElements(1, &session
, &web_view
, params
, &value
).code());
627 TEST(CommandsTest
, ErrorFindChildElement
) {
628 Session
session("id");
629 ErrorCallFunctionWebView
web_view(kStaleElementReference
);
630 base::DictionaryValue params
;
631 params
.SetString("using", "id");
632 params
.SetString("value", "a");
633 std::string element_id
= "1";
634 scoped_ptr
<base::Value
> result
;
636 kStaleElementReference
,
637 ExecuteFindChildElement(
638 1, &session
, &web_view
, element_id
, params
, &result
).code());
640 kStaleElementReference
,
641 ExecuteFindChildElements(
642 1, &session
, &web_view
, element_id
, params
, &result
).code());
647 class MockCommandListener
: public CommandListener
{
649 MockCommandListener() : called_(false) {}
650 ~MockCommandListener() override
{}
652 Status
BeforeCommand(const std::string
& command_name
) override
{
654 EXPECT_STREQ("cmd", command_name
.c_str());
658 void VerifyCalled() {
659 EXPECT_TRUE(called_
);
662 void VerifyNotCalled() {
663 EXPECT_FALSE(called_
);
670 Status
ExecuteAddListenerToSessionCommand(
671 CommandListener
* listener
,
673 const base::DictionaryValue
& params
,
674 scoped_ptr
<base::Value
>* return_value
) {
675 session
->command_listeners
.push_back(listener
);
679 Status
ExecuteQuitSessionCommand(
681 const base::DictionaryValue
& params
,
682 scoped_ptr
<base::Value
>* return_value
) {
683 session
->quit
= true;
687 void OnSessionCommand(
688 base::RunLoop
* run_loop
,
689 const Status
& status
,
690 scoped_ptr
<base::Value
> value
,
691 const std::string
& session_id
) {
692 ASSERT_EQ(kOk
, status
.code());
698 TEST(CommandsTest
, SuccessNotifyingCommandListeners
) {
699 SessionThreadMap map
;
700 linked_ptr
<base::Thread
> thread(new base::Thread("1"));
701 ASSERT_TRUE(thread
->Start());
702 std::string
id("id");
703 thread
->message_loop()->PostTask(
705 base::Bind(&internal::CreateSessionOnSessionThreadForTesting
, id
));
709 base::DictionaryValue params
;
710 scoped_ptr
<MockCommandListener
> listener(new MockCommandListener());
711 CommandListenerProxy
* proxy
= new CommandListenerProxy(listener
.get());
712 // We add |proxy| to the session instead of adding |listener| directly so that
713 // after the session is destroyed by ExecuteQuitSessionCommand, we can still
714 // verify the listener was called. The session owns and will destroy |proxy|.
715 SessionCommand cmd
= base::Bind(&ExecuteAddListenerToSessionCommand
, proxy
);
716 base::MessageLoop loop
;
717 base::RunLoop run_loop_addlistener
;
719 // |CommandListener|s are notified immediately before commands are run.
720 // Here, the command adds |listener| to the session, so |listener|
721 // should not be notified since it will not have been added yet.
722 ExecuteSessionCommand(
729 base::Bind(&OnSessionCommand
, &run_loop_addlistener
));
730 run_loop_addlistener
.Run();
732 listener
->VerifyNotCalled();
734 base::RunLoop run_loop_testlistener
;
735 cmd
= base::Bind(&ExecuteQuitSessionCommand
);
737 // |listener| was added to |session| by ExecuteAddListenerToSessionCommand
738 // and should be notified before the next command, ExecuteQuitSessionCommand.
739 ExecuteSessionCommand(
746 base::Bind(&OnSessionCommand
, &run_loop_testlistener
));
747 run_loop_testlistener
.Run();
749 listener
->VerifyCalled();
754 class FailingCommandListener
: public CommandListener
{
756 FailingCommandListener() {}
757 ~FailingCommandListener() override
{}
759 Status
BeforeCommand(const std::string
& command_name
) override
{
760 return Status(kUnknownError
);
764 void AddListenerToSessionIfSessionExists(CommandListener
* listener
) {
765 Session
* session
= GetThreadLocalSession();
767 session
->command_listeners
.push_back(listener
);
771 void OnFailBecauseErrorNotifyingListeners(
772 base::RunLoop
* run_loop
,
773 const Status
& status
,
774 scoped_ptr
<base::Value
> value
,
775 const std::string
& session_id
) {
776 EXPECT_EQ(kUnknownError
, status
.code());
777 EXPECT_FALSE(value
.get());
781 void VerifySessionWasDeleted() {
782 ASSERT_FALSE(GetThreadLocalSession());
787 TEST(CommandsTest
, ErrorNotifyingCommandListeners
) {
788 SessionThreadMap map
;
789 linked_ptr
<base::Thread
> thread(new base::Thread("1"));
790 ASSERT_TRUE(thread
->Start());
791 std::string
id("id");
792 thread
->message_loop()->PostTask(
794 base::Bind(&internal::CreateSessionOnSessionThreadForTesting
, id
));
797 // In SuccessNotifyingCommandListenersBeforeCommand, we verified BeforeCommand
798 // was called before (as opposed to after) command execution. We don't need to
799 // verify this again, so we can just add |listener| with PostTask.
800 CommandListener
* listener
= new FailingCommandListener();
801 thread
->message_loop()->PostTask(
803 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
->message_loop()->PostTask(
823 base::Bind(&VerifySessionWasDeleted
));