blob: 14c9ffc05d7a2726d671ff85a048be24ca0fcc13 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media/router/mojo/media_router_desktop.h"
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/media/router/event_page_request_manager.h"
#include "chrome/browser/media/router/event_page_request_manager_factory.h"
#include "chrome/browser/media/router/media_router_factory.h"
#include "chrome/browser/media/router/media_router_feature.h"
#include "chrome/browser/media/router/test/media_router_mojo_test.h"
#include "chrome/browser/media/router/test/test_helper.h"
#include "chrome/common/media_router/media_source.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::Invoke;
using testing::Mock;
using testing::Return;
namespace media_router {
namespace {
const char kOrigin[] = "http://origin/";
const char kRouteId[] = "routeId";
const char kSource[] = "source1";
class NullMessageObserver : public RouteMessageObserver {
public:
NullMessageObserver(MediaRouter* router, const MediaRoute::Id& route_id)
: RouteMessageObserver(router, route_id) {}
~NullMessageObserver() final {}
void OnMessagesReceived(const std::vector<mojom::RouteMessagePtr>) final {}
};
} // namespace
class MediaRouterDesktopTest : public MediaRouterMojoTest {
public:
MediaRouterDesktopTest() {}
~MediaRouterDesktopTest() override {}
DualMediaSinkService* media_sink_service() {
return media_sink_service_.get();
}
MockCastMediaSinkService* cast_media_sink_service() {
return cast_media_sink_service_;
}
protected:
std::unique_ptr<MediaRouterMojoImpl> CreateMediaRouter() override {
std::unique_ptr<MockCastMediaSinkService> cast_media_sink_service;
// We disable the DIAL MRP because initializing the DIAL MRP requires
// initialization of objects it depends on, which is outside the scope of
// this unit test. DIAL MRP initialization is covered by Media Router
// browser tests.
feature_list_.InitAndDisableFeature(kDialMediaRouteProvider);
cast_media_sink_service = std::make_unique<MockCastMediaSinkService>();
cast_media_sink_service_ = cast_media_sink_service.get();
media_sink_service_ = std::unique_ptr<DualMediaSinkService>(
new DualMediaSinkService(std::move(cast_media_sink_service),
std::make_unique<MockDialMediaSinkService>()));
return std::unique_ptr<MediaRouterDesktop>(
new MediaRouterDesktop(profile(), media_sink_service_.get()));
}
private:
base::test::ScopedFeatureList feature_list_;
std::unique_ptr<DualMediaSinkService> media_sink_service_;
// Owned by |media_sink_service_|.
MockCastMediaSinkService* cast_media_sink_service_;
DISALLOW_COPY_AND_ASSIGN(MediaRouterDesktopTest);
};
#if defined(OS_WIN)
TEST_F(MediaRouterDesktopTest, EnableMdnsAfterEachRegister) {
EXPECT_CALL(mock_extension_provider_, EnableMdnsDiscovery()).Times(0);
EXPECT_CALL(*cast_media_sink_service(), StartMdnsDiscovery()).Times(0);
RegisterExtensionProvider();
base::RunLoop().RunUntilIdle();
EXPECT_CALL(mock_extension_provider_, EnableMdnsDiscovery()).Times(0);
EXPECT_CALL(*cast_media_sink_service(), StartMdnsDiscovery());
router()->OnUserGesture();
base::RunLoop().RunUntilIdle();
// EnableMdnsDiscovery() is called on this RegisterExtensionProvider() because
// we've already seen an mdns-enabling event.
EXPECT_CALL(mock_extension_provider_, EnableMdnsDiscovery()).Times(0);
EXPECT_CALL(*cast_media_sink_service(), StartMdnsDiscovery());
RegisterExtensionProvider();
base::RunLoop().RunUntilIdle();
}
#endif
TEST_F(MediaRouterDesktopTest, OnUserGesture) {
EXPECT_CALL(mock_extension_provider_,
UpdateMediaSinks(MediaSource::ForDesktop().id()));
router()->OnUserGesture();
base::RunLoop().RunUntilIdle();
}
TEST_F(MediaRouterDesktopTest, SyncStateToMediaRouteProvider) {
MediaSource media_source(kSource);
std::unique_ptr<MockMediaSinksObserver> sinks_observer;
std::unique_ptr<MockMediaRoutesObserver> routes_observer;
std::unique_ptr<NullMessageObserver> messages_observer;
ProvideTestRoute(MediaRouteProviderId::EXTENSION, kRouteId);
router()->OnSinkAvailabilityUpdated(
MediaRouteProviderId::EXTENSION,
mojom::MediaRouter::SinkAvailability::PER_SOURCE);
EXPECT_CALL(mock_extension_provider_,
StartObservingMediaSinks(media_source.id()));
sinks_observer = std::make_unique<MockMediaSinksObserver>(
router(), media_source, url::Origin::Create(GURL(kOrigin)));
EXPECT_TRUE(sinks_observer->Init());
EXPECT_CALL(mock_extension_provider_,
StartObservingMediaRoutes(media_source.id()));
routes_observer =
std::make_unique<MockMediaRoutesObserver>(router(), media_source.id());
EXPECT_CALL(mock_extension_provider_,
StartListeningForRouteMessages(kRouteId));
messages_observer = std::make_unique<NullMessageObserver>(router(), kRouteId);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_extension_provider_));
}
TEST_F(MediaRouterDesktopTest, ProvideSinks) {
std::vector<MediaSinkInternal> sinks;
MediaSink sink("sinkId", "sinkName", SinkIconType::CAST,
MediaRouteProviderId::EXTENSION);
CastSinkExtraData extra_data;
net::IPAddress ip_address;
EXPECT_TRUE(ip_address.AssignFromIPLiteral("192.168.1.3"));
extra_data.ip_endpoint = net::IPEndPoint(ip_address, 0);
extra_data.capabilities = 2;
extra_data.cast_channel_id = 3;
MediaSinkInternal expected_sink(sink, extra_data);
sinks.push_back(expected_sink);
const std::string kCastProviderName = "cast";
// |router()| is already registered with |media_sink_service_| during
// |SetUp()|.
EXPECT_CALL(mock_extension_provider_, ProvideSinks(kCastProviderName, sinks));
media_sink_service()->OnSinksDiscovered(kCastProviderName, sinks);
base::RunLoop().RunUntilIdle();
EXPECT_CALL(mock_extension_provider_, ProvideSinks(kCastProviderName, sinks));
static_cast<MediaRouterDesktop*>(router())->ProvideSinksToExtension();
base::RunLoop().RunUntilIdle();
const std::string kDialProviderName = "dial";
EXPECT_CALL(mock_extension_provider_, ProvideSinks(kCastProviderName, sinks));
EXPECT_CALL(mock_extension_provider_, ProvideSinks(kDialProviderName, sinks))
.Times(0);
media_sink_service()->OnSinksDiscovered(kDialProviderName, sinks);
static_cast<MediaRouterDesktop*>(router())->ProvideSinksToExtension();
base::RunLoop().RunUntilIdle();
}
// Tests that auto-join and Cast SDK join requests are routed to the extension
// MediaRouteProvider.
TEST_F(MediaRouterDesktopTest, SendCastJoinRequestsToExtension) {
TestJoinRoute(kAutoJoinPresentationId);
TestJoinRoute(kCastPresentationIdPrefix + std::string("123"));
}
TEST_F(MediaRouterDesktopTest, ExtensionMrpRecoversFromConnectionError) {
MediaRouterDesktop* media_router_desktop =
static_cast<MediaRouterDesktop*>(router());
auto* extension_mrp_proxy =
media_router_desktop->extension_provider_proxy_.get();
// |media_router_desktop| detects connection error and reconnects with
// |extension_mrp_proxy|.
for (int i = 0; i < MediaRouterDesktop::kMaxMediaRouteProviderErrorCount;
i++) {
ignore_result(extension_mrp_proxy->receiver_.Unbind());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(extension_mrp_proxy->receiver_.is_bound());
}
ignore_result(extension_mrp_proxy->receiver_.Unbind());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(extension_mrp_proxy->receiver_.is_bound());
}
} // namespace media_router