| 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));
|
|
|