Index: chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc |
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc b/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc |
index e08ef510cc1eea738707946def5e3d3ee41d5708..5550c60fa03b570e3cb6e2fa36aedda7f4b852ef 100644 |
--- a/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc |
+++ b/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc |
@@ -12,6 +12,9 @@ |
#include "chrome/browser/media/router/media_source_helper.h" |
#include "chrome/browser/media/router/mock_media_router.h" |
#include "chrome/browser/media/router/mock_screen_availability_listener.h" |
+#include "chrome/browser/media/router/offscreen_presentation_manager.h" |
+#include "chrome/browser/media/router/offscreen_presentation_manager_factory.h" |
+#include "chrome/browser/media/router/receiver_presentation_service_delegate_impl.h" |
#include "chrome/browser/media/router/route_request_result.h" |
#include "chrome/browser/media/router/test_helper.h" |
#include "chrome/browser/profiles/profile.h" |
@@ -34,6 +37,9 @@ using ::testing::StrictMock; |
namespace media_router { |
+using OffscreenPresentationConnection = |
+ OffscreenPresentationManager::OffscreenPresentationConnection; |
+ |
class MockDelegateObserver |
: public content::PresentationServiceDelegate::Observer { |
public: |
@@ -61,7 +67,12 @@ class MockCreatePresentationConnnectionCallbacks { |
class PresentationServiceDelegateImplTest |
: public ChromeRenderViewHostTestHarness { |
public: |
- PresentationServiceDelegateImplTest() : delegate_impl_(nullptr) {} |
+ PresentationServiceDelegateImplTest() |
+ : delegate_impl_(nullptr), |
+ receiver_web_contents_(nullptr), |
+ receiver_delegate_impl_(nullptr), |
+ receiver_render_process_id_(0), |
+ receiver_routing_id_(0) {} |
void SetUp() override { |
ChromeRenderViewHostTestHarness::SetUp(); |
@@ -72,13 +83,21 @@ class PresentationServiceDelegateImplTest |
delegate_impl_->SetMediaRouterForTest(&router_); |
} |
+ void TearDown() override { |
+ delete receiver_web_contents_; |
+ ChromeRenderViewHostTestHarness::TearDown(); |
+ } |
+ |
MOCK_METHOD1(OnDefaultPresentationStarted, |
void(const content::PresentationSessionInfo& session_info)); |
+ MOCK_METHOD1(OnReceiverConnectionAvailable, |
+ void(const content::PresentationSessionInfo&)); |
protected: |
virtual content::WebContents* GetWebContents() { return web_contents(); } |
+ virtual bool IsOffTheRecord() { return false; } |
- void RunDefaultPresentationUrlCallbackTest(bool off_the_record) { |
+ void RunDefaultPresentationUrlCallbackTest() { |
content::RenderFrameHost* main_frame = GetWebContents()->GetMainFrame(); |
ASSERT_TRUE(main_frame); |
int render_process_id = main_frame->GetProcess()->GetID(); |
@@ -109,7 +128,7 @@ class PresentationServiceDelegateImplTest |
MediaRoute* media_route = new MediaRoute( |
"differentRouteId", MediaSourceForPresentationUrl(presentation_url2), |
"mediaSinkId", "", true, "", true); |
- media_route->set_off_the_record(off_the_record); |
+ media_route->set_off_the_record(IsOffTheRecord()); |
result = RouteRequestResult::FromSuccess(base::WrapUnique(media_route), |
"differentPresentationId"); |
delegate_impl_->OnRouteResponse(different_request, *result); |
@@ -120,14 +139,192 @@ class PresentationServiceDelegateImplTest |
MediaRoute* media_route2 = new MediaRoute( |
"routeId", MediaSourceForPresentationUrl(presentation_url1), |
"mediaSinkId", "", true, "", true); |
- media_route2->set_off_the_record(off_the_record); |
+ media_route2->set_off_the_record(IsOffTheRecord()); |
result = RouteRequestResult::FromSuccess(base::WrapUnique(media_route2), |
"presentationId"); |
delegate_impl_->OnRouteResponse(request, *result); |
} |
+ void RunOffscreenPresentationTest() { |
+ content::RenderFrameHost* main_frame = GetWebContents()->GetMainFrame(); |
+ ASSERT_TRUE(main_frame); |
+ int render_process_id = main_frame->GetProcess()->GetID(); |
+ int routing_id = main_frame->GetRoutingID(); |
+ |
+ const std::string kPresentationUrl("http://url1.fakeUrl"); |
+ const std::string kPresentationId("pid"); |
+ content::PresentationSessionInfo connection(kPresentationUrl, |
+ kPresentationId); |
+ content::PresentationSessionInfo receiver_connection("", kPresentationId); |
+ |
+ // |receiver_delegate_impl_| listens for new receiver presentations with |
+ // |kPresentationId|. |
+ CreateReceiverDelegate(kPresentationId); |
+ ASSERT_TRUE(receiver_delegate_impl_); |
+ |
+ // This should have created a presentation connection in |
+ // |receiver_delegate_impl_|. |
+ // Get current receiver connections and continue to listen for new |
+ // connections. |
+ CreateOffscreenPresentationRoute(render_process_id, routing_id, |
+ kPresentationUrl, kPresentationId, |
+ "routeId1", "sinkId1"); |
+ std::vector<content::PresentationSessionInfo> receiver_connections = |
+ receiver_delegate_impl_->GetReceiverConnections( |
+ receiver_render_process_id_, receiver_routing_id_, |
+ base::Bind(&PresentationServiceDelegateImplTest:: |
+ OnReceiverConnectionAvailable, |
+ base::Unretained(this))); |
+ ASSERT_EQ(1u, receiver_connections.size()); |
+ EXPECT_EQ(receiver_connection.presentation_url, |
+ receiver_connections[0].presentation_url); |
+ EXPECT_EQ(receiver_connection.presentation_id, |
+ receiver_connections[0].presentation_id); |
+ |
+ EXPECT_CALL(*this, |
+ OnReceiverConnectionAvailable( |
+ PresentationConnectionInfoEquals(receiver_connection))); |
+ CreateOffscreenPresentationRoute(render_process_id + 1, routing_id + 1, |
+ kPresentationUrl, kPresentationId, |
+ "routeId2", "sinkId2"); |
+ |
+ MockPresentationMessagesCallback controller_messages_callback; |
+ MockPresentationMessagesCallback receiver_messages_callback; |
+ |
+ // The controller of the presentation will listen for messages from both |
+ // |router_| and the receiver. |
+ EXPECT_CALL(router_, RegisterPresentationSessionMessagesObserver(_)); |
+ delegate_impl_->ListenForSessionMessages( |
+ render_process_id, routing_id, connection, |
+ base::Bind(&MockPresentationMessagesCallback::OnMessagesReceived, |
+ base::Unretained(&controller_messages_callback))); |
+ receiver_delegate_impl_->ListenForSessionMessages( |
+ receiver_render_process_id_, receiver_routing_id_, receiver_connection, |
+ base::Bind(&MockPresentationMessagesCallback::OnMessagesReceived, |
+ base::Unretained(&receiver_messages_callback))); |
+ |
+ // Send messages from controller to receiver and vice versa. |
+ std::string message_text("controller to receiver"); |
+ std::unique_ptr<content::PresentationSessionMessage> message( |
+ new content::PresentationSessionMessage( |
+ content::PresentationMessageType::TEXT)); |
+ message->message = message_text; |
+ EXPECT_CALL(controller_messages_callback, OnMessageSent(true)); |
+ EXPECT_CALL(receiver_messages_callback, DoOnMessagesReceived(message_text)); |
+ delegate_impl_->SendMessage( |
+ render_process_id, routing_id, connection, std::move(message), |
+ base::Bind(&MockPresentationMessagesCallback::OnMessageSent, |
+ base::Unretained(&controller_messages_callback))); |
+ |
+ message_text = "receiver to controller"; |
+ message.reset(new content::PresentationSessionMessage( |
+ content::PresentationMessageType::TEXT)); |
+ message->message = message_text; |
+ EXPECT_CALL(receiver_messages_callback, OnMessageSent(true)); |
+ EXPECT_CALL(controller_messages_callback, |
+ DoOnMessagesReceived(message_text)); |
+ receiver_delegate_impl_->SendMessage( |
+ receiver_render_process_id_, receiver_routing_id_, receiver_connection, |
+ std::move(message), |
+ base::Bind(&MockPresentationMessagesCallback::OnMessageSent, |
+ base::Unretained(&receiver_messages_callback))); |
+ |
+ MockPresentationConnectionStateChangedCallback |
+ controller_state_change_callback; |
+ MockPresentationConnectionStateChangedCallback |
+ receiver_state_change_callback; |
+ |
+ // The controller of the offscreen presentation will listen for state change |
+ // from both |router_| and the receiver. |
+ content::PresentationConnectionStateChangedCallback state_change_callback = |
+ base::Bind(&MockPresentationConnectionStateChangedCallback::Run, |
+ base::Unretained(&controller_state_change_callback)); |
+ EXPECT_CALL(router_, OnAddPresentationConnectionStateChangedCallbackInvoked( |
+ Equals(state_change_callback))); |
+ delegate_impl_->ListenForConnectionStateChange( |
+ render_process_id, routing_id, connection, state_change_callback); |
+ receiver_delegate_impl_->ListenForConnectionStateChange( |
+ receiver_render_process_id_, receiver_routing_id_, receiver_connection, |
+ base::Bind(&MockPresentationConnectionStateChangedCallback::Run, |
+ base::Unretained(&receiver_state_change_callback))); |
+ |
+ // Calling Reset() on |receiver_delegate_impl_| will destroy the receiver |
+ // connection, which causes state change on the controller. |
+ content::PresentationConnectionStateChangeInfo info( |
+ content::PRESENTATION_CONNECTION_STATE_CLOSED); |
+ info.close_reason = content::PRESENTATION_CONNECTION_CLOSE_REASON_WENT_AWAY; |
+ EXPECT_CALL(controller_state_change_callback, |
+ Run(StateChageInfoEquals(info))); |
+ receiver_delegate_impl_->Reset(receiver_render_process_id_, |
+ receiver_routing_id_); |
+ |
+ EXPECT_CALL(router_, UnregisterPresentationSessionMessagesObserver(_)); |
+ } |
+ |
+ void CreateReceiverDelegate(const std::string& presentation_id) { |
+ content::WebContents* receiver_wc = GetReceiverWebContents(); |
+ ReceiverPresentationServiceDelegateImpl::CreateForWebContents( |
+ receiver_wc, presentation_id); |
+ receiver_delegate_impl_ = |
+ ReceiverPresentationServiceDelegateImpl::FromWebContents(receiver_wc); |
+ |
+ content::RenderFrameHost* main_frame = |
+ GetReceiverWebContents()->GetMainFrame(); |
+ ASSERT_TRUE(main_frame); |
+ receiver_render_process_id_ = main_frame->GetProcess()->GetID(); |
+ receiver_routing_id_ = main_frame->GetRoutingID(); |
+ } |
+ |
+ content::WebContents* GetReceiverWebContents() { |
+ if (!receiver_web_contents_) { |
+ Profile* otr_profile = profile()->GetOffTheRecordProfile(); |
+ receiver_web_contents_ = |
+ content::WebContentsTester::CreateTestWebContents(otr_profile, |
+ nullptr); |
+ } |
+ return receiver_web_contents_; |
+ } |
+ |
+ void CreateOffscreenPresentationRoute(int render_process_id, |
+ int routing_id, |
+ const std::string& presentation_url, |
+ const std::string& presentation_id, |
+ const MediaRoute::Id& route_id, |
+ const MediaSink::Id& sink_id) { |
+ // Use JoinRoute to create a route with a fixed presentation ID. |
+ std::vector<MediaRouteResponseCallback> route_response_callbacks; |
+ EXPECT_CALL(router_, JoinRoute(_, _, _, _, _, _, IsOffTheRecord())) |
+ .WillOnce(SaveArg<4>(&route_response_callbacks)); |
+ MockCreatePresentationConnnectionCallbacks mock_create_connection_callbacks; |
+ delegate_impl_->JoinSession( |
+ render_process_id, routing_id, presentation_url, presentation_id, |
+ base::Bind(&MockCreatePresentationConnnectionCallbacks:: |
+ OnCreateConnectionSuccess, |
+ base::Unretained(&mock_create_connection_callbacks)), |
+ base::Bind(&MockCreatePresentationConnnectionCallbacks:: |
+ OnCreateConnectionError, |
+ base::Unretained(&mock_create_connection_callbacks))); |
+ |
+ EXPECT_CALL(mock_create_connection_callbacks, OnCreateConnectionSuccess(_)) |
+ .Times(1); |
+ std::unique_ptr<MediaRoute> route(new MediaRoute( |
+ route_id, MediaSourceForPresentationUrl(presentation_url), sink_id, |
+ "description", true, "", true)); |
+ route->set_off_the_record(IsOffTheRecord()); |
+ route->set_is_offscreen_presentation(true); |
+ std::unique_ptr<RouteRequestResult> result = |
+ RouteRequestResult::FromSuccess(std::move(route), presentation_id); |
+ for (const auto& route_response_callback : route_response_callbacks) |
+ route_response_callback.Run(*result); |
+ } |
+ |
PresentationServiceDelegateImpl* delegate_impl_; |
MockMediaRouter router_; |
+ |
+ content::WebContents* receiver_web_contents_; |
+ ReceiverPresentationServiceDelegateImpl* receiver_delegate_impl_; |
+ int receiver_render_process_id_; |
+ int receiver_routing_id_; |
}; |
class PresentationServiceDelegateImplIncognitoTest |
@@ -147,6 +344,8 @@ class PresentationServiceDelegateImplIncognitoTest |
return incognito_web_contents_; |
} |
+ bool IsOffTheRecord() override { return true; } |
+ |
void TearDown() override { |
// We must delete the incognito WC first, as that triggers observers which |
// require RenderViewHost, etc., that in turn are deleted by |
@@ -306,12 +505,12 @@ TEST_F(PresentationServiceDelegateImplTest, SetDefaultPresentationUrl) { |
} |
TEST_F(PresentationServiceDelegateImplTest, DefaultPresentationUrlCallback) { |
- RunDefaultPresentationUrlCallbackTest(false); |
+ RunDefaultPresentationUrlCallbackTest(); |
} |
TEST_F(PresentationServiceDelegateImplIncognitoTest, |
DefaultPresentationUrlCallback) { |
- RunDefaultPresentationUrlCallbackTest(true); |
+ RunDefaultPresentationUrlCallbackTest(); |
} |
TEST_F(PresentationServiceDelegateImplTest, |
@@ -366,7 +565,7 @@ TEST_F(PresentationServiceDelegateImplTest, |
callback); |
} |
-TEST_F(PresentationServiceDelegateImplTest, ListenForConnnectionStateChange) { |
+TEST_F(PresentationServiceDelegateImplTest, ListenForConnectionStateChange) { |
GURL frame_url("http://www.google.com"); |
content::WebContentsTester::For(GetWebContents()) |
->NavigateAndCommit(frame_url); |
@@ -402,10 +601,10 @@ TEST_F(PresentationServiceDelegateImplTest, ListenForConnnectionStateChange) { |
for (const auto& route_response_callback : route_response_callbacks) |
route_response_callback.Run(*result); |
- MockPresentationConnectionStateChangedCallback mock_callback; |
+ MockPresentationConnectionStateChangedCallback mock_state_change_callback; |
content::PresentationConnectionStateChangedCallback callback = |
base::Bind(&MockPresentationConnectionStateChangedCallback::Run, |
- base::Unretained(&mock_callback)); |
+ base::Unretained(&mock_state_change_callback)); |
content::PresentationSessionInfo connection(kPresentationUrl, |
kPresentationId); |
EXPECT_CALL(router_, OnAddPresentationConnectionStateChangedCallbackInvoked( |
@@ -414,6 +613,14 @@ TEST_F(PresentationServiceDelegateImplTest, ListenForConnnectionStateChange) { |
connection, callback); |
} |
+TEST_F(PresentationServiceDelegateImplIncognitoTest, OffscreenPresentation) { |
+ RunOffscreenPresentationTest(); |
+} |
+ |
+TEST_F(PresentationServiceDelegateImplTest, OffscreenPresentation) { |
+ RunOffscreenPresentationTest(); |
+} |
+ |
TEST_F(PresentationServiceDelegateImplTest, Reset) { |
EXPECT_CALL(router_, RegisterMediaSinksObserver(_)) |
.WillRepeatedly(Return(true)); |