1 // Copyright 2015 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/location.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/run_loop.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/test/test_timeouts.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "content/browser/presentation/presentation_service_impl.h"
15 #include "content/public/browser/presentation_service_delegate.h"
16 #include "content/public/browser/presentation_session.h"
17 #include "content/public/common/presentation_constants.h"
18 #include "content/test/test_render_frame_host.h"
19 #include "content/test/test_render_view_host.h"
20 #include "content/test/test_web_contents.h"
21 #include "mojo/public/cpp/bindings/interface_ptr.h"
22 #include "mojo/public/cpp/bindings/string.h"
23 #include "testing/gmock/include/gmock/gmock.h"
27 using ::testing::InvokeWithoutArgs
;
28 using ::testing::Mock
;
29 using ::testing::Return
;
30 using ::testing::SaveArg
;
36 // Matches mojo structs.
37 MATCHER_P(Equals
, expected
, "") {
38 return expected
.Equals(arg
);
41 const char *const kPresentationId
= "presentationId";
42 const char *const kPresentationUrl
= "http://foo.com/index.html";
44 bool ArePresentationSessionsEqual(
45 const presentation::PresentationSessionInfo
& expected
,
46 const presentation::PresentationSessionInfo
& actual
) {
47 return expected
.url
== actual
.url
&& expected
.id
== actual
.id
;
50 bool ArePresentationSessionMessagesEqual(
51 const presentation::SessionMessage
* expected
,
52 const presentation::SessionMessage
* actual
) {
53 return expected
->type
== actual
->type
&&
54 expected
->message
== actual
->message
&&
55 expected
->data
.Equals(actual
->data
);
59 presentation::PresentationSessionInfoPtr info
,
60 presentation::PresentationErrorPtr error
) {
65 class MockPresentationServiceDelegate
: public PresentationServiceDelegate
{
67 MOCK_METHOD3(AddObserver
,
68 void(int render_process_id
,
70 PresentationServiceDelegate::Observer
* observer
));
71 MOCK_METHOD2(RemoveObserver
,
72 void(int render_process_id
, int render_frame_id
));
73 MOCK_METHOD3(AddScreenAvailabilityListener
,
75 int render_process_id
,
77 PresentationScreenAvailabilityListener
* listener
));
78 MOCK_METHOD3(RemoveScreenAvailabilityListener
,
80 int render_process_id
,
82 PresentationScreenAvailabilityListener
* listener
));
85 int render_process_id
,
87 MOCK_METHOD3(SetDefaultPresentationUrl
,
89 int render_process_id
,
91 const std::string
& default_presentation_url
));
92 MOCK_METHOD5(StartSession
,
94 int render_process_id
,
96 const std::string
& presentation_url
,
97 const PresentationSessionSuccessCallback
& success_cb
,
98 const PresentationSessionErrorCallback
& error_cb
));
99 MOCK_METHOD6(JoinSession
,
101 int render_process_id
,
103 const std::string
& presentation_url
,
104 const std::string
& presentation_id
,
105 const PresentationSessionSuccessCallback
& success_cb
,
106 const PresentationSessionErrorCallback
& error_cb
));
107 MOCK_METHOD3(CloseSession
,
108 void(int render_process_id
,
110 const std::string
& presentation_id
));
111 MOCK_METHOD4(ListenForSessionMessages
,
112 void(int render_process_id
,
114 const content::PresentationSessionInfo
& session
,
115 const PresentationSessionMessageCallback
& message_cb
));
116 MOCK_METHOD5(SendMessageRawPtr
,
117 void(int render_process_id
,
119 const content::PresentationSessionInfo
& session
,
120 PresentationSessionMessage
* message_request
,
121 const SendMessageCallback
& send_message_cb
));
122 void SendMessage(int render_process_id
,
124 const content::PresentationSessionInfo
& session
,
125 scoped_ptr
<PresentationSessionMessage
> message_request
,
126 const SendMessageCallback
& send_message_cb
) override
{
127 SendMessageRawPtr(render_process_id
, render_frame_id
, session
,
128 message_request
.release(), send_message_cb
);
131 ListenForSessionStateChange
,
132 void(int render_process_id
,
134 const content::SessionStateChangedCallback
& state_changed_cb
));
137 class MockPresentationServiceClient
:
138 public presentation::PresentationServiceClient
{
140 MOCK_METHOD2(OnScreenAvailabilityUpdated
,
141 void(const mojo::String
& url
, bool available
));
142 void OnSessionStateChanged(
143 presentation::PresentationSessionInfoPtr session_info
,
144 presentation::PresentationSessionState new_state
) override
{
145 OnSessionStateChanged(*session_info
, new_state
);
147 MOCK_METHOD2(OnSessionStateChanged
,
148 void(const presentation::PresentationSessionInfo
& session_info
,
149 presentation::PresentationSessionState new_state
));
150 void OnScreenAvailabilityNotSupported(const mojo::String
& url
) override
{
154 void OnSessionMessagesReceived(
155 presentation::PresentationSessionInfoPtr session_info
,
156 mojo::Array
<presentation::SessionMessagePtr
> messages
) override
{
157 messages_received_
= messages
.Pass();
160 MOCK_METHOD0(MessagesReceived
, void());
162 mojo::Array
<presentation::SessionMessagePtr
> messages_received_
;
165 class PresentationServiceImplTest
: public RenderViewHostImplTestHarness
{
167 PresentationServiceImplTest() : default_session_started_count_(0) {}
169 void SetUp() override
{
170 RenderViewHostImplTestHarness::SetUp();
172 auto request
= mojo::GetProxy(&service_ptr_
);
173 EXPECT_CALL(mock_delegate_
, AddObserver(_
, _
, _
)).Times(1);
174 service_impl_
.reset(new PresentationServiceImpl(
175 contents()->GetMainFrame(), contents(), &mock_delegate_
));
176 service_impl_
->Bind(request
.Pass());
178 presentation::PresentationServiceClientPtr client_ptr
;
179 client_binding_
.reset(
180 new mojo::Binding
<presentation::PresentationServiceClient
>(
181 &mock_client_
, mojo::GetProxy(&client_ptr
)));
182 service_impl_
->SetClient(client_ptr
.Pass());
185 void TearDown() override
{
186 service_ptr_
.reset();
187 if (service_impl_
.get()) {
188 EXPECT_CALL(mock_delegate_
, RemoveObserver(_
, _
)).Times(1);
189 service_impl_
.reset();
191 RenderViewHostImplTestHarness::TearDown();
194 void ListenForScreenAvailabilityAndWait(
195 const mojo::String
& url
, bool delegate_success
) {
196 base::RunLoop run_loop
;
197 // This will call to |service_impl_| via mojo. Process the message
199 // The callback shouldn't be invoked since there is no availability
201 EXPECT_CALL(mock_delegate_
, AddScreenAvailabilityListener(_
, _
, _
))
203 InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
204 Return(delegate_success
)));
205 service_ptr_
->ListenForScreenAvailability(url
);
208 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_
));
211 void RunLoopFor(base::TimeDelta duration
) {
212 base::RunLoop run_loop
;
213 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
214 FROM_HERE
, run_loop
.QuitClosure(), duration
);
218 void SaveQuitClosureAndRunLoop() {
219 base::RunLoop run_loop
;
220 run_loop_quit_closure_
= run_loop
.QuitClosure();
222 run_loop_quit_closure_
.Reset();
225 void SimulateScreenAvailabilityChangeAndWait(
226 const std::string
& url
, bool available
) {
227 auto listener_it
= service_impl_
->screen_availability_listeners_
.find(url
);
228 ASSERT_TRUE(listener_it
->second
);
230 base::RunLoop run_loop
;
231 EXPECT_CALL(mock_client_
,
232 OnScreenAvailabilityUpdated(mojo::String(url
), available
))
233 .WillOnce(InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
));
234 listener_it
->second
->OnScreenAvailabilityChanged(available
);
239 EXPECT_CALL(mock_delegate_
, Reset(_
, _
)).Times(1);
242 void ExpectCleanState() {
243 EXPECT_TRUE(service_impl_
->default_presentation_url_
.empty());
245 service_impl_
->screen_availability_listeners_
.find(kPresentationUrl
),
246 service_impl_
->screen_availability_listeners_
.end());
247 EXPECT_FALSE(service_impl_
->default_session_start_context_
.get());
248 EXPECT_FALSE(service_impl_
->on_session_messages_callback_
.get());
251 void ExpectNewSessionMojoCallbackSuccess(
252 presentation::PresentationSessionInfoPtr info
,
253 presentation::PresentationErrorPtr error
) {
254 EXPECT_FALSE(info
.is_null());
255 EXPECT_TRUE(error
.is_null());
256 if (!run_loop_quit_closure_
.is_null())
257 run_loop_quit_closure_
.Run();
260 void ExpectNewSessionMojoCallbackError(
261 presentation::PresentationSessionInfoPtr info
,
262 presentation::PresentationErrorPtr error
) {
263 EXPECT_TRUE(info
.is_null());
264 EXPECT_FALSE(error
.is_null());
265 if (!run_loop_quit_closure_
.is_null())
266 run_loop_quit_closure_
.Run();
269 void ExpectDefaultSessionStarted(
270 const presentation::PresentationSessionInfo
& expected_session
,
271 presentation::PresentationSessionInfoPtr actual_session
) {
272 ASSERT_TRUE(!actual_session
.is_null());
273 EXPECT_TRUE(ArePresentationSessionsEqual(
274 expected_session
, *actual_session
));
275 ++default_session_started_count_
;
276 if (!run_loop_quit_closure_
.is_null())
277 run_loop_quit_closure_
.Run();
280 void ExpectDefaultSessionNull(
281 presentation::PresentationSessionInfoPtr actual_session
) {
282 EXPECT_TRUE(actual_session
.is_null());
283 ++default_session_started_count_
;
284 if (!run_loop_quit_closure_
.is_null())
285 run_loop_quit_closure_
.Run();
288 void ExpectSessionMessages(
289 const mojo::Array
<presentation::SessionMessagePtr
>& expected_msgs
,
290 const mojo::Array
<presentation::SessionMessagePtr
>& actual_msgs
) {
291 EXPECT_EQ(expected_msgs
.size(), actual_msgs
.size());
292 for (size_t i
= 0; i
< actual_msgs
.size(); ++i
) {
293 EXPECT_TRUE(ArePresentationSessionMessagesEqual(expected_msgs
[i
].get(),
294 actual_msgs
[i
].get()));
298 void ExpectSendMessageMojoCallback(bool success
) {
299 EXPECT_TRUE(success
);
300 EXPECT_FALSE(service_impl_
->send_message_callback_
);
301 if (!run_loop_quit_closure_
.is_null())
302 run_loop_quit_closure_
.Run();
305 void RunListenForSessionMessages(const std::string
& text_msg
,
306 const std::vector
<uint8_t>& binary_data
,
307 bool pass_ownership
) {
308 mojo::Array
<presentation::SessionMessagePtr
> expected_msgs(2);
309 expected_msgs
[0] = presentation::SessionMessage::New();
310 expected_msgs
[0]->type
=
311 presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_TEXT
;
312 expected_msgs
[0]->message
= text_msg
;
313 expected_msgs
[1] = presentation::SessionMessage::New();
314 expected_msgs
[1]->type
= presentation::PresentationMessageType::
315 PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER
;
316 expected_msgs
[1]->data
= mojo::Array
<uint8_t>::From(binary_data
);
318 presentation::PresentationSessionInfoPtr
session(
319 presentation::PresentationSessionInfo::New());
320 session
->url
= kPresentationUrl
;
321 session
->id
= kPresentationId
;
323 PresentationSessionMessageCallback message_cb
;
325 base::RunLoop run_loop
;
326 EXPECT_CALL(mock_delegate_
, ListenForSessionMessages(_
, _
, _
, _
))
327 .WillOnce(DoAll(InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
328 SaveArg
<3>(&message_cb
)));
329 service_ptr_
->ListenForSessionMessages(session
.Clone());
333 ScopedVector
<PresentationSessionMessage
> messages
;
334 scoped_ptr
<content::PresentationSessionMessage
> message
;
336 new content::PresentationSessionMessage(PresentationMessageType::TEXT
));
337 message
->message
= text_msg
;
338 messages
.push_back(message
.Pass());
339 message
.reset(new content::PresentationSessionMessage(
340 PresentationMessageType::ARRAY_BUFFER
));
341 message
->data
.reset(new std::vector
<uint8_t>(binary_data
));
342 messages
.push_back(message
.Pass());
344 std::vector
<presentation::SessionMessagePtr
> actual_msgs
;
346 base::RunLoop run_loop
;
347 EXPECT_CALL(mock_client_
, MessagesReceived())
348 .WillOnce(InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
));
349 message_cb
.Run(messages
.Pass(), pass_ownership
);
352 ExpectSessionMessages(expected_msgs
, mock_client_
.messages_received_
);
355 MockPresentationServiceDelegate mock_delegate_
;
357 scoped_ptr
<PresentationServiceImpl
> service_impl_
;
358 mojo::InterfacePtr
<presentation::PresentationService
> service_ptr_
;
360 MockPresentationServiceClient mock_client_
;
361 scoped_ptr
<mojo::Binding
<presentation::PresentationServiceClient
>>
364 base::Closure run_loop_quit_closure_
;
365 int default_session_started_count_
;
368 TEST_F(PresentationServiceImplTest
, ListenForScreenAvailability
) {
369 ListenForScreenAvailabilityAndWait(kPresentationUrl
, true);
371 SimulateScreenAvailabilityChangeAndWait(kPresentationUrl
, true);
372 SimulateScreenAvailabilityChangeAndWait(kPresentationUrl
, false);
373 SimulateScreenAvailabilityChangeAndWait(kPresentationUrl
, true);
376 TEST_F(PresentationServiceImplTest
, Reset
) {
377 ListenForScreenAvailabilityAndWait(kPresentationUrl
, true);
380 service_impl_
->Reset();
384 TEST_F(PresentationServiceImplTest
, DidNavigateThisFrame
) {
385 ListenForScreenAvailabilityAndWait(kPresentationUrl
, true);
388 service_impl_
->DidNavigateAnyFrame(
389 contents()->GetMainFrame(),
390 content::LoadCommittedDetails(),
391 content::FrameNavigateParams());
395 TEST_F(PresentationServiceImplTest
, DidNavigateOtherFrame
) {
396 ListenForScreenAvailabilityAndWait(kPresentationUrl
, true);
398 // TODO(imcheng): How to get a different RenderFrameHost?
399 service_impl_
->DidNavigateAnyFrame(
401 content::LoadCommittedDetails(),
402 content::FrameNavigateParams());
404 // Availability is reported and callback is invoked since it was not
406 SimulateScreenAvailabilityChangeAndWait(kPresentationUrl
, true);
409 TEST_F(PresentationServiceImplTest
, ThisRenderFrameDeleted
) {
410 ListenForScreenAvailabilityAndWait(kPresentationUrl
, true);
414 // Since the frame matched the service, |service_impl_| will be deleted.
415 PresentationServiceImpl
* service
= service_impl_
.release();
416 EXPECT_CALL(mock_delegate_
, RemoveObserver(_
, _
)).Times(1);
417 service
->RenderFrameDeleted(contents()->GetMainFrame());
420 TEST_F(PresentationServiceImplTest
, OtherRenderFrameDeleted
) {
421 ListenForScreenAvailabilityAndWait(kPresentationUrl
, true);
423 // TODO(imcheng): How to get a different RenderFrameHost?
424 service_impl_
->RenderFrameDeleted(nullptr);
426 // Availability is reported and callback should be invoked since listener
427 // has not been deleted.
428 SimulateScreenAvailabilityChangeAndWait(kPresentationUrl
, true);
431 TEST_F(PresentationServiceImplTest
, DelegateFails
) {
432 ListenForScreenAvailabilityAndWait(kPresentationUrl
, false);
434 service_impl_
->screen_availability_listeners_
.find(kPresentationUrl
),
435 service_impl_
->screen_availability_listeners_
.end());
438 TEST_F(PresentationServiceImplTest
, SetDefaultPresentationUrl
) {
439 std::string
url1("http://fooUrl");
440 EXPECT_CALL(mock_delegate_
,
441 SetDefaultPresentationUrl(_
, _
, Eq(url1
)))
443 service_impl_
->SetDefaultPresentationURL(url1
);
444 EXPECT_EQ(url1
, service_impl_
->default_presentation_url_
);
446 std::string
url2("http://barUrl");
447 // Sets different DPU.
448 EXPECT_CALL(mock_delegate_
,
449 SetDefaultPresentationUrl(_
, _
, Eq(url2
)))
451 service_impl_
->SetDefaultPresentationURL(url2
);
452 EXPECT_EQ(url2
, service_impl_
->default_presentation_url_
);
455 TEST_F(PresentationServiceImplTest
, SetSameDefaultPresentationUrl
) {
456 EXPECT_CALL(mock_delegate_
,
457 SetDefaultPresentationUrl(_
, _
, Eq(kPresentationUrl
)))
459 service_impl_
->SetDefaultPresentationURL(kPresentationUrl
);
460 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_
));
461 EXPECT_EQ(kPresentationUrl
, service_impl_
->default_presentation_url_
);
463 // Same URL as before; no-ops.
464 service_impl_
->SetDefaultPresentationURL(kPresentationUrl
);
465 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_
));
466 EXPECT_EQ(kPresentationUrl
, service_impl_
->default_presentation_url_
);
469 TEST_F(PresentationServiceImplTest
, StartSessionSuccess
) {
470 service_ptr_
->StartSession(
473 &PresentationServiceImplTest::ExpectNewSessionMojoCallbackSuccess
,
474 base::Unretained(this)));
475 base::RunLoop run_loop
;
476 base::Callback
<void(const PresentationSessionInfo
&)> success_cb
;
477 EXPECT_CALL(mock_delegate_
, StartSession(_
, _
, Eq(kPresentationUrl
), _
, _
))
479 InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
480 SaveArg
<3>(&success_cb
)));
482 success_cb
.Run(PresentationSessionInfo(kPresentationUrl
, kPresentationId
));
483 SaveQuitClosureAndRunLoop();
486 TEST_F(PresentationServiceImplTest
, StartSessionError
) {
487 service_ptr_
->StartSession(
490 &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError
,
491 base::Unretained(this)));
492 base::RunLoop run_loop
;
493 base::Callback
<void(const PresentationError
&)> error_cb
;
494 EXPECT_CALL(mock_delegate_
, StartSession(_
, _
, Eq(kPresentationUrl
), _
, _
))
496 InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
497 SaveArg
<4>(&error_cb
)));
499 error_cb
.Run(PresentationError(PRESENTATION_ERROR_UNKNOWN
, "Error message"));
500 SaveQuitClosureAndRunLoop();
503 TEST_F(PresentationServiceImplTest
, JoinSessionSuccess
) {
504 service_ptr_
->JoinSession(
508 &PresentationServiceImplTest::ExpectNewSessionMojoCallbackSuccess
,
509 base::Unretained(this)));
510 base::RunLoop run_loop
;
511 base::Callback
<void(const PresentationSessionInfo
&)> success_cb
;
512 EXPECT_CALL(mock_delegate_
, JoinSession(
513 _
, _
, Eq(kPresentationUrl
), Eq(kPresentationId
), _
, _
))
515 InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
516 SaveArg
<4>(&success_cb
)));
518 success_cb
.Run(PresentationSessionInfo(kPresentationUrl
, kPresentationId
));
519 SaveQuitClosureAndRunLoop();
522 TEST_F(PresentationServiceImplTest
, JoinSessionError
) {
523 service_ptr_
->JoinSession(
527 &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError
,
528 base::Unretained(this)));
529 base::RunLoop run_loop
;
530 base::Callback
<void(const PresentationError
&)> error_cb
;
531 EXPECT_CALL(mock_delegate_
, JoinSession(
532 _
, _
, Eq(kPresentationUrl
), Eq(kPresentationId
), _
, _
))
534 InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
535 SaveArg
<5>(&error_cb
)));
537 error_cb
.Run(PresentationError(PRESENTATION_ERROR_UNKNOWN
, "Error message"));
538 SaveQuitClosureAndRunLoop();
541 TEST_F(PresentationServiceImplTest
, CloseSession
) {
542 service_ptr_
->CloseSession(kPresentationUrl
, kPresentationId
);
543 base::RunLoop run_loop
;
544 EXPECT_CALL(mock_delegate_
, CloseSession(_
, _
, Eq(kPresentationId
)))
545 .WillOnce(InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
));
549 TEST_F(PresentationServiceImplTest
, ListenForSessionMessagesPassed
) {
550 std::string
text_msg("123");
551 std::vector
<uint8_t> binary_data(3, '\1');
552 RunListenForSessionMessages(text_msg
, binary_data
, true);
555 TEST_F(PresentationServiceImplTest
, ListenForSessionMessagesCopied
) {
556 std::string
text_msg("123");
557 std::vector
<uint8_t> binary_data(3, '\1');
558 RunListenForSessionMessages(text_msg
, binary_data
, false);
561 TEST_F(PresentationServiceImplTest
, ListenForSessionMessagesWithEmptyMsg
) {
562 std::string
text_msg("");
563 std::vector
<uint8_t> binary_data
;
564 RunListenForSessionMessages(text_msg
, binary_data
, false);
567 TEST_F(PresentationServiceImplTest
, StartSessionInProgress
) {
568 std::string
presentation_url1("http://fooUrl");
569 std::string
presentation_url2("http://barUrl");
570 service_ptr_
->StartSession(presentation_url1
,
571 base::Bind(&DoNothing
));
572 // This request should fail immediately, since there is already a StartSession
574 service_ptr_
->StartSession(
577 &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError
,
578 base::Unretained(this)));
579 SaveQuitClosureAndRunLoop();
582 TEST_F(PresentationServiceImplTest
, ListenForDefaultSessionStart
) {
583 presentation::PresentationSessionInfo expected_session
;
584 expected_session
.url
= kPresentationUrl
;
585 expected_session
.id
= kPresentationId
;
586 service_ptr_
->ListenForDefaultSessionStart(
587 base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionStarted
,
588 base::Unretained(this),
590 RunLoopFor(base::TimeDelta::FromMilliseconds(50));
591 service_impl_
->OnDefaultPresentationStarted(
592 content::PresentationSessionInfo(kPresentationUrl
, kPresentationId
));
593 SaveQuitClosureAndRunLoop();
594 EXPECT_EQ(1, default_session_started_count_
);
597 TEST_F(PresentationServiceImplTest
, ListenForDefaultSessionStartAfterSet
) {
598 // Note that the callback will only pick up presentation_url2/id2 since
599 // ListenForDefaultSessionStart wasn't called yet when the DPU was still
600 // presentation_url1.
601 std::string
presentation_url1("http://fooUrl1");
602 std::string
presentation_id1("presentationId1");
603 std::string
presentation_url2("http://fooUrl2");
604 std::string
presentation_id2("presentationId2");
605 service_impl_
->OnDefaultPresentationStarted(
606 content::PresentationSessionInfo(presentation_url1
, presentation_id1
));
608 presentation::PresentationSessionInfo expected_session
;
609 expected_session
.url
= presentation_url2
;
610 expected_session
.id
= presentation_id2
;
611 service_ptr_
->ListenForDefaultSessionStart(
612 base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionStarted
,
613 base::Unretained(this),
615 RunLoopFor(base::TimeDelta::FromMilliseconds(50));
616 service_impl_
->OnDefaultPresentationStarted(
617 content::PresentationSessionInfo(presentation_url2
, presentation_id2
));
618 SaveQuitClosureAndRunLoop();
619 EXPECT_EQ(1, default_session_started_count_
);
622 TEST_F(PresentationServiceImplTest
, DefaultSessionStartReset
) {
623 service_ptr_
->ListenForDefaultSessionStart(
624 base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionNull
,
625 base::Unretained(this)));
626 RunLoopFor(TestTimeouts::tiny_timeout());
629 service_impl_
->Reset();
631 SaveQuitClosureAndRunLoop();
632 EXPECT_EQ(1, default_session_started_count_
);
635 TEST_F(PresentationServiceImplTest
, SendStringMessage
) {
636 std::string
message("Test presentation session message");
638 presentation::PresentationSessionInfoPtr
session(
639 presentation::PresentationSessionInfo::New());
640 session
->url
= kPresentationUrl
;
641 session
->id
= kPresentationId
;
642 presentation::SessionMessagePtr
message_request(
643 presentation::SessionMessage::New());
644 message_request
->type
= presentation::PresentationMessageType::
645 PRESENTATION_MESSAGE_TYPE_TEXT
;
646 message_request
->message
= message
;
647 service_ptr_
->SendSessionMessage(
648 session
.Pass(), message_request
.Pass(),
649 base::Bind(&PresentationServiceImplTest::ExpectSendMessageMojoCallback
,
650 base::Unretained(this)));
652 base::RunLoop run_loop
;
653 base::Callback
<void(bool)> send_message_cb
;
654 PresentationSessionMessage
* test_message
= nullptr;
655 EXPECT_CALL(mock_delegate_
, SendMessageRawPtr(_
, _
, _
, _
, _
))
656 .WillOnce(DoAll(InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
657 SaveArg
<3>(&test_message
), SaveArg
<4>(&send_message_cb
)));
660 // Make sure |test_message| gets deleted.
661 scoped_ptr
<PresentationSessionMessage
> scoped_test_message(test_message
);
662 EXPECT_TRUE(test_message
);
663 EXPECT_FALSE(test_message
->is_binary());
664 EXPECT_LE(test_message
->message
.size(), kMaxPresentationSessionMessageSize
);
665 EXPECT_EQ(message
, test_message
->message
);
666 ASSERT_FALSE(test_message
->data
);
667 send_message_cb
.Run(true);
668 SaveQuitClosureAndRunLoop();
671 TEST_F(PresentationServiceImplTest
, SendArrayBuffer
) {
672 // Test Array buffer data.
673 const uint8 buffer
[] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
674 std::vector
<uint8
> data
;
675 data
.assign(buffer
, buffer
+ sizeof(buffer
));
677 presentation::PresentationSessionInfoPtr
session(
678 presentation::PresentationSessionInfo::New());
679 session
->url
= kPresentationUrl
;
680 session
->id
= kPresentationId
;
681 presentation::SessionMessagePtr
message_request(
682 presentation::SessionMessage::New());
683 message_request
->type
= presentation::PresentationMessageType::
684 PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER
;
685 message_request
->data
= mojo::Array
<uint8
>::From(data
);
686 service_ptr_
->SendSessionMessage(
687 session
.Pass(), message_request
.Pass(),
688 base::Bind(&PresentationServiceImplTest::ExpectSendMessageMojoCallback
,
689 base::Unretained(this)));
691 base::RunLoop run_loop
;
692 base::Callback
<void(bool)> send_message_cb
;
693 PresentationSessionMessage
* test_message
= nullptr;
694 EXPECT_CALL(mock_delegate_
, SendMessageRawPtr(_
, _
, _
, _
, _
))
695 .WillOnce(DoAll(InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
696 SaveArg
<3>(&test_message
), SaveArg
<4>(&send_message_cb
)));
699 // Make sure |test_message| gets deleted.
700 scoped_ptr
<PresentationSessionMessage
> scoped_test_message(test_message
);
701 EXPECT_TRUE(test_message
);
702 EXPECT_TRUE(test_message
->is_binary());
703 EXPECT_EQ(PresentationMessageType::ARRAY_BUFFER
, test_message
->type
);
704 EXPECT_TRUE(test_message
->message
.empty());
705 ASSERT_TRUE(test_message
->data
);
706 EXPECT_EQ(data
.size(), test_message
->data
->size());
707 EXPECT_LE(test_message
->data
->size(), kMaxPresentationSessionMessageSize
);
708 EXPECT_EQ(0, memcmp(buffer
, &(*test_message
->data
)[0], sizeof(buffer
)));
709 send_message_cb
.Run(true);
710 SaveQuitClosureAndRunLoop();
713 TEST_F(PresentationServiceImplTest
, SendArrayBufferWithExceedingLimit
) {
714 // Create buffer with size exceeding the limit.
715 // Use same size as in content::kMaxPresentationSessionMessageSize.
716 const size_t kMaxBufferSizeInBytes
= 64 * 1024; // 64 KB.
717 uint8 buffer
[kMaxBufferSizeInBytes
+1];
718 memset(buffer
, 0, kMaxBufferSizeInBytes
+1);
719 std::vector
<uint8
> data
;
720 data
.assign(buffer
, buffer
+ sizeof(buffer
));
722 presentation::PresentationSessionInfoPtr
session(
723 presentation::PresentationSessionInfo::New());
724 session
->url
= kPresentationUrl
;
725 session
->id
= kPresentationId
;
726 presentation::SessionMessagePtr
message_request(
727 presentation::SessionMessage::New());
728 message_request
->type
= presentation::PresentationMessageType::
729 PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER
;
730 message_request
->data
= mojo::Array
<uint8
>::From(data
);
731 service_ptr_
->SendSessionMessage(
732 session
.Pass(), message_request
.Pass(),
733 base::Bind(&PresentationServiceImplTest::ExpectSendMessageMojoCallback
,
734 base::Unretained(this)));
736 base::RunLoop run_loop
;
737 base::Callback
<void(bool)> send_message_cb
;
738 PresentationSessionMessage
* test_message
= nullptr;
739 EXPECT_CALL(mock_delegate_
, SendMessageRawPtr(_
, _
, _
, _
, _
))
740 .WillOnce(DoAll(InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
741 SaveArg
<3>(&test_message
), SaveArg
<4>(&send_message_cb
)));
744 EXPECT_FALSE(test_message
);
745 send_message_cb
.Run(true);
746 SaveQuitClosureAndRunLoop();
749 TEST_F(PresentationServiceImplTest
, SendBlobData
) {
750 const uint8 buffer
[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
751 std::vector
<uint8
> data
;
752 data
.assign(buffer
, buffer
+ sizeof(buffer
));
754 presentation::PresentationSessionInfoPtr
session(
755 presentation::PresentationSessionInfo::New());
756 session
->url
= kPresentationUrl
;
757 session
->id
= kPresentationId
;
758 presentation::SessionMessagePtr
message_request(
759 presentation::SessionMessage::New());
760 message_request
->type
=
761 presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_BLOB
;
762 message_request
->data
= mojo::Array
<uint8
>::From(data
);
763 service_ptr_
->SendSessionMessage(
764 session
.Pass(), message_request
.Pass(),
765 base::Bind(&PresentationServiceImplTest::ExpectSendMessageMojoCallback
,
766 base::Unretained(this)));
768 base::RunLoop run_loop
;
769 base::Callback
<void(bool)> send_message_cb
;
770 PresentationSessionMessage
* test_message
= nullptr;
771 EXPECT_CALL(mock_delegate_
, SendMessageRawPtr(_
, _
, _
, _
, _
))
772 .WillOnce(DoAll(InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
773 SaveArg
<3>(&test_message
), SaveArg
<4>(&send_message_cb
)));
776 // Make sure |test_message| gets deleted.
777 scoped_ptr
<PresentationSessionMessage
> scoped_test_message(test_message
);
778 EXPECT_TRUE(test_message
);
779 EXPECT_TRUE(test_message
->is_binary());
780 EXPECT_EQ(PresentationMessageType::BLOB
, test_message
->type
);
781 EXPECT_TRUE(test_message
->message
.empty());
782 ASSERT_TRUE(test_message
->data
);
783 EXPECT_EQ(data
.size(), test_message
->data
->size());
784 EXPECT_LE(test_message
->data
->size(), kMaxPresentationSessionMessageSize
);
785 EXPECT_EQ(0, memcmp(buffer
, &(*test_message
->data
)[0], sizeof(buffer
)));
786 send_message_cb
.Run(true);
787 SaveQuitClosureAndRunLoop();
790 TEST_F(PresentationServiceImplTest
, MaxPendingJoinSessionRequests
) {
791 const char* presentation_url
= "http://fooUrl%d";
792 const char* presentation_id
= "presentationId%d";
793 int num_requests
= PresentationServiceImpl::kMaxNumQueuedSessionRequests
;
795 EXPECT_CALL(mock_delegate_
, JoinSession(_
, _
, _
, _
, _
, _
))
796 .Times(num_requests
);
797 for (; i
< num_requests
; ++i
) {
798 service_ptr_
->JoinSession(
799 base::StringPrintf(presentation_url
, i
),
800 base::StringPrintf(presentation_id
, i
),
801 base::Bind(&DoNothing
));
804 // Exceeded maximum queue size, should invoke mojo callback with error.
805 service_ptr_
->JoinSession(
806 base::StringPrintf(presentation_url
, i
),
807 base::StringPrintf(presentation_id
, i
),
809 &PresentationServiceImplTest::ExpectNewSessionMojoCallbackError
,
810 base::Unretained(this)));
811 SaveQuitClosureAndRunLoop();
814 TEST_F(PresentationServiceImplTest
, ListenForSessionStateChange
) {
815 base::RunLoop run_loop
;
816 EXPECT_CALL(mock_delegate_
, ListenForSessionStateChange(_
, _
, _
))
817 .WillOnce(InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
));
818 service_ptr_
->ListenForSessionStateChange();
821 presentation::PresentationSessionInfo session_info
;
822 session_info
.url
= kPresentationUrl
;
823 session_info
.id
= kPresentationId
;
825 EXPECT_CALL(mock_client_
,
826 OnSessionStateChanged(
827 Equals(session_info
),
828 presentation::PRESENTATION_SESSION_STATE_CONNECTED
));
829 service_impl_
->OnSessionStateChanged(
830 content::PresentationSessionInfo(kPresentationUrl
, kPresentationId
),
831 content::PRESENTATION_SESSION_STATE_CONNECTED
);
834 } // namespace content