| // 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/discovery/mdns/cast_media_sink_service_impl.h" |
| #include "base/run_loop.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/test/mock_callback.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/test_mock_time_task_runner.h" |
| #include "base/timer/mock_timer.h" |
| #include "chrome/browser/media/router/media_router_feature.h" |
| #include "chrome/browser/media/router/test_helper.h" |
| #include "components/cast_channel/cast_socket.h" |
| #include "components/cast_channel/cast_socket_service.h" |
| #include "components/cast_channel/cast_test_util.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "content/public/test/test_utils.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::Invoke; |
| using ::testing::Return; |
| using ::testing::SaveArg; |
| using ::testing::WithArgs; |
| using ::testing::_; |
| using cast_channel::ChannelError; |
| |
| namespace { |
| |
| net::IPEndPoint CreateIPEndPoint(int num) { |
| net::IPAddress ip_address; |
| CHECK(ip_address.AssignFromIPLiteral( |
| base::StringPrintf("192.168.0.10%d", num))); |
| return net::IPEndPoint(ip_address, 8009 + num); |
| } |
| |
| media_router::MediaSinkInternal CreateCastSink(int num) { |
| std::string friendly_name = base::StringPrintf("friendly name %d", num); |
| std::string unique_id = base::StringPrintf("id %d", num); |
| net::IPEndPoint ip_endpoint = CreateIPEndPoint(num); |
| |
| media_router::MediaSink sink(unique_id, friendly_name, |
| media_router::SinkIconType::CAST); |
| media_router::CastSinkExtraData extra_data; |
| extra_data.ip_endpoint = ip_endpoint; |
| extra_data.port = ip_endpoint.port(); |
| extra_data.model_name = base::StringPrintf("model name %d", num); |
| extra_data.cast_channel_id = num; |
| extra_data.capabilities = cast_channel::CastDeviceCapability::AUDIO_OUT | |
| cast_channel::CastDeviceCapability::VIDEO_OUT; |
| return media_router::MediaSinkInternal(sink, extra_data); |
| } |
| |
| media_router::MediaSinkInternal CreateDialSink(int num) { |
| std::string friendly_name = base::StringPrintf("friendly name %d", num); |
| std::string unique_id = base::StringPrintf("id %d", num); |
| net::IPEndPoint ip_endpoint = CreateIPEndPoint(num); |
| |
| media_router::MediaSink sink(unique_id, friendly_name, |
| media_router::SinkIconType::GENERIC); |
| media_router::DialSinkExtraData extra_data; |
| extra_data.ip_address = ip_endpoint.address(); |
| extra_data.model_name = base::StringPrintf("model name %d", num); |
| return media_router::MediaSinkInternal(sink, extra_data); |
| } |
| |
| } // namespace |
| |
| namespace media_router { |
| |
| class CastMediaSinkServiceImplTest : public ::testing::Test { |
| public: |
| CastMediaSinkServiceImplTest() |
| : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), |
| mock_cast_socket_service_(new cast_channel::MockCastSocketService()), |
| mock_time_task_runner_(new base::TestMockTimeTaskRunner()), |
| media_sink_service_impl_(mock_sink_discovered_cb_.Get(), |
| mock_cast_socket_service_.get(), |
| discovery_network_monitor_.get(), |
| mock_time_task_runner_.get()) {} |
| |
| void SetUp() override { |
| fake_network_info_.clear(); |
| auto mock_timer = base::MakeUnique<base::MockTimer>( |
| true /*retain_user_task*/, false /*is_repeating*/); |
| mock_timer_ = mock_timer.get(); |
| media_sink_service_impl_.SetTimerForTest(std::move(mock_timer)); |
| } |
| |
| protected: |
| void ExpectOpenSocketInternal(cast_channel::CastSocket* socket) { |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(socket->ip_endpoint(), _, _, _)) |
| .WillOnce(Invoke([socket](const auto& ip_endpoint, auto* net_log, |
| auto open_cb, auto* observer) { |
| std::move(open_cb).Run(socket); |
| return socket->id(); |
| })); |
| } |
| |
| cast_channel::CastSocket::Observer& observer() { |
| return static_cast<cast_channel::CastSocket::Observer&>( |
| media_sink_service_impl_); |
| } |
| |
| static std::vector<DiscoveryNetworkInfo> FakeGetNetworkInfo() { |
| return fake_network_info_; |
| } |
| |
| static std::vector<DiscoveryNetworkInfo> fake_network_info_; |
| |
| std::vector<DiscoveryNetworkInfo> fake_ethernet_info_ = { |
| DiscoveryNetworkInfo{std::string("enp0s2"), std::string("ethernet1")}}; |
| std::vector<DiscoveryNetworkInfo> fake_wifi_info_ = { |
| DiscoveryNetworkInfo{std::string("wlp3s0"), std::string("wifi1")}, |
| DiscoveryNetworkInfo{std::string("wlp3s1"), std::string("wifi2")}}; |
| std::vector<DiscoveryNetworkInfo> fake_unknown_info_ = { |
| DiscoveryNetworkInfo{std::string("enp0s2"), std::string()}}; |
| |
| std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_ = |
| base::WrapUnique(net::NetworkChangeNotifier::CreateMock()); |
| |
| const content::TestBrowserThreadBundle thread_bundle_; |
| |
| std::unique_ptr<DiscoveryNetworkMonitor> discovery_network_monitor_ = |
| DiscoveryNetworkMonitor::CreateInstanceForTest(&FakeGetNetworkInfo); |
| |
| base::MockCallback<MediaSinkService::OnSinksDiscoveredCallback> |
| mock_sink_discovered_cb_; |
| std::unique_ptr<cast_channel::MockCastSocketService> |
| mock_cast_socket_service_; |
| base::MockTimer* mock_timer_; |
| scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner_; |
| CastMediaSinkServiceImpl media_sink_service_impl_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CastMediaSinkServiceImplTest); |
| }; |
| |
| // static |
| std::vector<DiscoveryNetworkInfo> |
| CastMediaSinkServiceImplTest::fake_network_info_; |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestOnChannelOpenSucceeded) { |
| auto cast_sink = CreateCastSink(1); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| cast_channel::MockCastSocket socket; |
| socket.set_id(1); |
| |
| media_sink_service_impl_.OnChannelOpenSucceeded( |
| cast_sink, &socket, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Verify sink content |
| EXPECT_CALL(mock_sink_discovered_cb_, |
| Run(std::vector<MediaSinkInternal>({cast_sink}))); |
| media_sink_service_impl_.OnFetchCompleted(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestMultipleOnChannelOpenSucceeded) { |
| auto cast_sink1 = CreateCastSink(1); |
| auto cast_sink2 = CreateCastSink(2); |
| auto cast_sink3 = CreateCastSink(3); |
| auto ip_endpoint1 = CreateIPEndPoint(1); |
| auto ip_endpoint2 = CreateIPEndPoint(2); |
| auto ip_endpoint3 = CreateIPEndPoint(3); |
| |
| cast_channel::MockCastSocket socket2; |
| socket2.set_id(2); |
| cast_channel::MockCastSocket socket3; |
| socket3.set_id(3); |
| |
| // Current round of Dns discovery finds service1 and service 2. |
| // Fail to open channel 1. |
| media_sink_service_impl_.OnChannelOpenSucceeded( |
| cast_sink2, &socket2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| media_sink_service_impl_.OnChannelOpenSucceeded( |
| cast_sink3, &socket3, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Verify sink content |
| EXPECT_CALL(mock_sink_discovered_cb_, |
| Run(std::vector<MediaSinkInternal>({cast_sink2, cast_sink3}))); |
| media_sink_service_impl_.OnFetchCompleted(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestTimer) { |
| auto cast_sink1 = CreateCastSink(1); |
| auto cast_sink2 = CreateCastSink(2); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| |
| EXPECT_FALSE(mock_timer_->IsRunning()); |
| media_sink_service_impl_.Start(); |
| EXPECT_TRUE(mock_timer_->IsRunning()); |
| |
| // Channel 2 is opened. |
| cast_channel::MockCastSocket socket2; |
| socket2.set_id(2); |
| |
| media_sink_service_impl_.OnChannelOpenSucceeded( |
| cast_sink2, &socket2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| std::vector<MediaSinkInternal> sinks; |
| EXPECT_CALL(mock_sink_discovered_cb_, Run(_)).WillOnce(SaveArg<0>(&sinks)); |
| |
| // Fire timer. |
| mock_timer_->Fire(); |
| EXPECT_EQ(sinks, std::vector<MediaSinkInternal>({cast_sink2})); |
| |
| EXPECT_FALSE(mock_timer_->IsRunning()); |
| // Channel 1 is opened and timer is restarted. |
| cast_channel::MockCastSocket socket1; |
| socket1.set_id(1); |
| |
| media_sink_service_impl_.OnChannelOpenSucceeded( |
| cast_sink1, &socket1, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| EXPECT_TRUE(mock_timer_->IsRunning()); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestOpenChannelNoRetry) { |
| MediaSinkInternal cast_sink = CreateCastSink(1); |
| net::IPEndPoint ip_endpoint = CreateIPEndPoint(1); |
| cast_channel::MockCastSocket socket; |
| socket.set_id(1); |
| socket.SetIPEndpoint(ip_endpoint); |
| socket.SetErrorState(cast_channel::ChannelError::NONE); |
| |
| // No pending sink |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint, _, _, _)) |
| .Times(1); |
| media_sink_service_impl_.OpenChannel( |
| ip_endpoint, cast_sink, nullptr, |
| CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // One pending sink, the same as |cast_sink| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint, _, _, _)) |
| .Times(0); |
| media_sink_service_impl_.OpenChannel( |
| ip_endpoint, cast_sink, nullptr, |
| CastMediaSinkServiceImpl::SinkSource::kMdns); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestOpenChannelRetryOnce) { |
| MediaSinkInternal cast_sink = CreateCastSink(1); |
| net::IPEndPoint ip_endpoint = CreateIPEndPoint(1); |
| cast_channel::MockCastSocket socket; |
| socket.set_id(1); |
| socket.SetIPEndpoint(ip_endpoint); |
| socket.SetErrorState(cast_channel::ChannelError::NONE); |
| socket.SetErrorState(cast_channel::ChannelError::CAST_SOCKET_ERROR); |
| |
| media_sink_service_impl_.SetTaskRunnerForTest(mock_time_task_runner_); |
| std::unique_ptr<net::BackoffEntry> backoff_entry( |
| new net::BackoffEntry(&CastMediaSinkServiceImpl::kDefaultBackoffPolicy)); |
| ExpectOpenSocketInternal(&socket); |
| media_sink_service_impl_.max_retry_attempts_ = 3; |
| media_sink_service_impl_.OpenChannel( |
| ip_endpoint, cast_sink, std::move(backoff_entry), |
| CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| socket.SetErrorState(cast_channel::ChannelError::NONE); |
| ExpectOpenSocketInternal(&socket); |
| // Wait for 16 seconds. |
| mock_time_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(16)); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestOpenChannelFails) { |
| MediaSinkInternal cast_sink = CreateCastSink(1); |
| net::IPEndPoint ip_endpoint = CreateIPEndPoint(1); |
| cast_channel::MockCastSocket socket; |
| socket.set_id(1); |
| socket.SetIPEndpoint(ip_endpoint); |
| socket.SetErrorState(cast_channel::ChannelError::CAST_SOCKET_ERROR); |
| |
| media_sink_service_impl_.SetTaskRunnerForTest(mock_time_task_runner_); |
| |
| ExpectOpenSocketInternal(&socket); |
| net::BackoffEntry::Policy policy = |
| CastMediaSinkServiceImpl::kDefaultBackoffPolicy; |
| std::unique_ptr<net::BackoffEntry> backoff_entry( |
| new net::BackoffEntry(&policy)); |
| auto* backoff_entry_ptr = backoff_entry.get(); |
| media_sink_service_impl_.max_retry_attempts_ = 3; |
| media_sink_service_impl_.OpenChannel( |
| ip_endpoint, cast_sink, std::move(backoff_entry), |
| CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // 1st retry attempt |
| ExpectOpenSocketInternal(&socket); |
| base::TimeDelta delay = backoff_entry_ptr->GetTimeUntilRelease() + |
| base::TimeDelta::FromSeconds(1); |
| mock_time_task_runner_->FastForwardBy(delay); |
| // 2nd retry attempt |
| ExpectOpenSocketInternal(&socket); |
| delay = backoff_entry_ptr->GetTimeUntilRelease() + |
| base::TimeDelta::FromSeconds(1); |
| mock_time_task_runner_->FastForwardBy(delay); |
| // 3rd retry attempt |
| ExpectOpenSocketInternal(&socket); |
| delay = backoff_entry_ptr->GetTimeUntilRelease() + |
| base::TimeDelta::FromSeconds(1); |
| mock_time_task_runner_->FastForwardBy(delay); |
| // No more retry. |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint, _, _, _)) |
| .Times(0); |
| mock_time_task_runner_->FastForwardBy(delay); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestMultipleOpenChannels) { |
| auto cast_sink1 = CreateCastSink(1); |
| auto cast_sink2 = CreateCastSink(2); |
| auto cast_sink3 = CreateCastSink(3); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3); |
| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint1, _, _, _)); |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint2, _, _, _)); |
| |
| // 1st round finds service 1 & 2. |
| std::vector<MediaSinkInternal> sinks1{cast_sink1, cast_sink2}; |
| media_sink_service_impl_.OpenChannels( |
| sinks1, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Channel 2 opened. |
| cast_channel::MockCastSocket socket2; |
| socket2.set_id(2); |
| socket2.SetErrorState(cast_channel::ChannelError::NONE); |
| media_sink_service_impl_.OnChannelOpened( |
| cast_sink2, nullptr, CastMediaSinkServiceImpl::SinkSource::kMdns, |
| &socket2); |
| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint2, _, _, _)); |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint3, _, _, _)); |
| |
| // 2nd round finds service 2 & 3. |
| std::vector<MediaSinkInternal> sinks2{cast_sink2, cast_sink3}; |
| media_sink_service_impl_.OpenChannels( |
| sinks2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Channel 1 and 3 opened. |
| cast_channel::MockCastSocket socket1; |
| cast_channel::MockCastSocket socket3; |
| socket1.set_id(1); |
| socket3.set_id(3); |
| socket1.SetErrorState(cast_channel::ChannelError::NONE); |
| socket3.SetErrorState(cast_channel::ChannelError::NONE); |
| media_sink_service_impl_.OnChannelOpened( |
| cast_sink1, nullptr, CastMediaSinkServiceImpl::SinkSource::kMdns, |
| &socket1); |
| media_sink_service_impl_.OnChannelOpened( |
| cast_sink3, nullptr, CastMediaSinkServiceImpl::SinkSource::kMdns, |
| &socket3); |
| |
| EXPECT_CALL(mock_sink_discovered_cb_, |
| Run(std::vector<MediaSinkInternal>( |
| {cast_sink1, cast_sink2, cast_sink3}))); |
| media_sink_service_impl_.OnFetchCompleted(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestOnChannelOpenFailed) { |
| auto cast_sink = CreateCastSink(1); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| cast_channel::MockCastSocket socket; |
| socket.set_id(1); |
| |
| media_sink_service_impl_.OnChannelOpenSucceeded( |
| cast_sink, &socket, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| EXPECT_EQ(1u, media_sink_service_impl_.current_sinks_map_.size()); |
| |
| socket.SetIPEndpoint(ip_endpoint1); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1); |
| EXPECT_TRUE(media_sink_service_impl_.current_sinks_map_.empty()); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, |
| TestOnChannelErrorMayRetryForConnectingChannel) { |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| cast_channel::MockCastSocket socket; |
| socket.set_id(1); |
| socket.SetIPEndpoint(ip_endpoint1); |
| |
| media_sink_service_impl_.SetTaskRunnerForTest(mock_time_task_runner_); |
| |
| // No op for CONNECTING cast channel. |
| EXPECT_CALL(socket, ready_state()) |
| .WillOnce(Return(cast_channel::ReadyState::CONNECTING)); |
| EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(_, _, _, _)) |
| .Times(0); |
| |
| media_sink_service_impl_.OnError( |
| socket, cast_channel::ChannelError::CHANNEL_NOT_OPEN); |
| mock_time_task_runner_->RunUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestOnChannelErrorMayRetryForCastSink) { |
| auto cast_sink = CreateCastSink(1); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| cast_channel::MockCastSocket socket; |
| socket.set_id(1); |
| socket.SetIPEndpoint(ip_endpoint1); |
| |
| media_sink_service_impl_.SetTaskRunnerForTest(mock_time_task_runner_); |
| |
| // There is an existing cast sink in |current_sinks_map_|. |
| media_sink_service_impl_.current_sinks_map_[ip_endpoint1.address()] = |
| cast_sink; |
| EXPECT_CALL(socket, ready_state()) |
| .WillRepeatedly(Return(cast_channel::ReadyState::CLOSED)); |
| media_sink_service_impl_.OnError( |
| socket, cast_channel::ChannelError::CHANNEL_NOT_OPEN); |
| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint1, _, _, _)); |
| mock_time_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(16)); |
| EXPECT_TRUE(media_sink_service_impl_.current_sinks_map_.empty()); |
| |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestOnChannelErrorNoRetryForMissingSink) { |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| cast_channel::MockCastSocket socket; |
| socket.set_id(1); |
| socket.SetIPEndpoint(ip_endpoint1); |
| EXPECT_CALL(socket, ready_state()) |
| .WillOnce(Return(cast_channel::ReadyState::CLOSED)); |
| |
| media_sink_service_impl_.SetTaskRunnerForTest(mock_time_task_runner_); |
| |
| // There is no existing cast sink. |
| media_sink_service_impl_.pending_for_open_ip_endpoints_.clear(); |
| media_sink_service_impl_.current_sinks_map_.clear(); |
| |
| media_sink_service_impl_.OnError( |
| socket, cast_channel::ChannelError::CHANNEL_NOT_OPEN); |
| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint1, _, _, _)) |
| .Times(0); |
| mock_time_task_runner_->RunUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestOnDialSinkAdded) { |
| MediaSinkInternal dial_sink1 = CreateDialSink(1); |
| MediaSinkInternal dial_sink2 = CreateDialSink(2); |
| net::IPEndPoint ip_endpoint1(dial_sink1.dial_data().ip_address, |
| CastMediaSinkServiceImpl::kCastControlPort); |
| net::IPEndPoint ip_endpoint2(dial_sink2.dial_data().ip_address, |
| CastMediaSinkServiceImpl::kCastControlPort); |
| |
| cast_channel::MockCastSocket socket1; |
| cast_channel::MockCastSocket socket2; |
| socket1.set_id(1); |
| socket2.set_id(2); |
| |
| // Channel 1, 2 opened. |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint1, _, _, _)) |
| .WillOnce(DoAll( |
| WithArgs<2>(Invoke( |
| [&](const base::Callback<void(cast_channel::CastSocket * socket)>& |
| callback) { std::move(callback).Run(&socket1); })), |
| Return(1))); |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint2, _, _, _)) |
| .WillOnce(DoAll( |
| WithArgs<2>(Invoke( |
| [&](const base::Callback<void(cast_channel::CastSocket * socket)>& |
| callback) { std::move(callback).Run(&socket2); })), |
| Return(2))); |
| |
| // Invoke CastSocketService::OpenSocket on the IO thread. |
| media_sink_service_impl_.OnDialSinkAdded(dial_sink1); |
| base::RunLoop().RunUntilIdle(); |
| |
| // Invoke CastSocketService::OpenSocket on the IO thread. |
| media_sink_service_impl_.OnDialSinkAdded(dial_sink2); |
| base::RunLoop().RunUntilIdle(); |
| // Verify sink content. |
| EXPECT_EQ(2u, media_sink_service_impl_.current_sinks_map_.size()); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestOnFetchCompleted) { |
| std::vector<MediaSinkInternal> sinks; |
| EXPECT_CALL(mock_sink_discovered_cb_, Run(_)).WillOnce(SaveArg<0>(&sinks)); |
| |
| auto cast_sink1 = CreateCastSink(1); |
| auto cast_sink2 = CreateCastSink(2); |
| auto cast_sink3 = CreateCastSink(3); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3); |
| |
| // Find Cast sink 1, 2, 3 |
| media_sink_service_impl_.current_sinks_map_[ip_endpoint1.address()] = |
| cast_sink1; |
| media_sink_service_impl_.current_sinks_map_[ip_endpoint2.address()] = |
| cast_sink2; |
| media_sink_service_impl_.current_sinks_map_[ip_endpoint3.address()] = |
| cast_sink3; |
| |
| // Callback returns Cast sink 1, 2, 3 |
| media_sink_service_impl_.OnFetchCompleted(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(base::ContainsValue(sinks, cast_sink1)); |
| EXPECT_TRUE(base::ContainsValue(sinks, cast_sink2)); |
| EXPECT_TRUE(base::ContainsValue(sinks, cast_sink3)); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestAttemptConnection) { |
| auto cast_sink1 = CreateCastSink(1); |
| auto cast_sink2 = CreateCastSink(2); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| |
| // Find Cast sink 1 |
| media_sink_service_impl_.current_sinks_map_[ip_endpoint1.address()] = |
| cast_sink1; |
| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint1, _, _, _)) |
| .Times(0); |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint2, _, _, _)); |
| |
| // Attempt to connect to Cast sink 1, 2 |
| std::vector<MediaSinkInternal> sinks{cast_sink1, cast_sink2}; |
| media_sink_service_impl_.AttemptConnection(sinks); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, CacheSinksForKnownNetwork) { |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| |
| MediaSinkInternal sink1 = CreateCastSink(1); |
| MediaSinkInternal sink2 = CreateCastSink(2); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| std::vector<MediaSinkInternal> sink_list1{sink1, sink2}; |
| |
| // Resolution will succeed for both sinks. |
| cast_channel::MockCastSocket socket1; |
| cast_channel::MockCastSocket socket2; |
| socket1.SetIPEndpoint(ip_endpoint1); |
| socket1.set_id(1); |
| socket2.SetIPEndpoint(ip_endpoint2); |
| socket2.set_id(2); |
| ExpectOpenSocketInternal(&socket1); |
| ExpectOpenSocketInternal(&socket2); |
| media_sink_service_impl_.OpenChannels( |
| sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Connect to a new network with different sinks. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| fake_network_info_ = fake_wifi_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_WIFI); |
| content::RunAllTasksUntilIdle(); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2); |
| |
| MediaSinkInternal sink3 = CreateCastSink(3); |
| net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3); |
| std::vector<MediaSinkInternal> sink_list2{sink3}; |
| |
| cast_channel::MockCastSocket socket3; |
| socket3.SetIPEndpoint(ip_endpoint3); |
| socket3.set_id(3); |
| ExpectOpenSocketInternal(&socket3); |
| media_sink_service_impl_.OpenChannels( |
| sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Reconnecting to the previous ethernet network should restore the same sinks |
| // from the cache and attempt to resolve them. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint1, _, _, _)); |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint2, _, _, _)); |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, CacheContainsOnlyResolvedSinks) { |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| |
| MediaSinkInternal sink1 = CreateCastSink(1); |
| MediaSinkInternal sink2 = CreateCastSink(2); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| std::vector<MediaSinkInternal> sink_list1{sink1, sink2}; |
| |
| // Resolution will fail for |sink2|. |
| cast_channel::MockCastSocket socket1; |
| cast_channel::MockCastSocket socket2; |
| socket1.SetIPEndpoint(ip_endpoint1); |
| socket1.set_id(1); |
| socket2.SetErrorState(cast_channel::ChannelError::CONNECT_ERROR); |
| socket2.SetIPEndpoint(ip_endpoint2); |
| socket2.set_id(2); |
| ExpectOpenSocketInternal(&socket1); |
| ExpectOpenSocketInternal(&socket2); |
| media_sink_service_impl_.OpenChannels( |
| sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Connect to a new network with different sinks. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| fake_network_info_ = fake_wifi_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_WIFI); |
| content::RunAllTasksUntilIdle(); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1); |
| |
| MediaSinkInternal sink3 = CreateCastSink(3); |
| net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3); |
| std::vector<MediaSinkInternal> sink_list2{sink3}; |
| |
| cast_channel::MockCastSocket socket3; |
| socket3.SetIPEndpoint(ip_endpoint3); |
| socket3.set_id(3); |
| ExpectOpenSocketInternal(&socket3); |
| media_sink_service_impl_.OpenChannels( |
| sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Reconnecting to the previous ethernet network should restore only |sink1|, |
| // since |sink2| failed to resolve. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint1, _, _, _)); |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint2, _, _, _)) |
| .Times(0); |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, CacheUpdatedOnChannelOpenFailed) { |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| |
| MediaSinkInternal sink1 = CreateCastSink(1); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| std::vector<MediaSinkInternal> sink_list1{sink1}; |
| |
| // Resolve |sink1| but then raise a channel error. This should remove it from |
| // the cached sinks for the ethernet network. |
| cast_channel::MockCastSocket socket1; |
| socket1.SetIPEndpoint(ip_endpoint1); |
| socket1.set_id(1); |
| ExpectOpenSocketInternal(&socket1); |
| media_sink_service_impl_.OpenChannels( |
| sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1); |
| |
| // Connect to a new network with different sinks. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| fake_network_info_ = fake_wifi_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_WIFI); |
| content::RunAllTasksUntilIdle(); |
| |
| MediaSinkInternal sink2 = CreateCastSink(2); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| std::vector<MediaSinkInternal> sink_list2{sink2}; |
| |
| cast_channel::MockCastSocket socket2; |
| socket2.SetIPEndpoint(ip_endpoint2); |
| socket2.set_id(2); |
| ExpectOpenSocketInternal(&socket2); |
| media_sink_service_impl_.OpenChannels( |
| sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Reconnecting to the previous ethernet network should not restore any sinks |
| // since the only sink to resolve successfully, |sink1|, later had a channel |
| // error. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(_, _, _, _)) |
| .Times(0); |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, UnknownNetworkNoCache) { |
| // Without any network notification here, network ID will remain __unknown__ |
| // and the cache shouldn't save any of these sinks. |
| MediaSinkInternal sink1 = CreateCastSink(1); |
| MediaSinkInternal sink2 = CreateCastSink(2); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| std::vector<MediaSinkInternal> sink_list1{sink1, sink2}; |
| |
| // Resolution will succeed for both sinks. |
| cast_channel::MockCastSocket socket1; |
| cast_channel::MockCastSocket socket2; |
| socket1.SetIPEndpoint(ip_endpoint1); |
| socket1.set_id(1); |
| socket2.SetIPEndpoint(ip_endpoint2); |
| socket2.set_id(2); |
| ExpectOpenSocketInternal(&socket1); |
| ExpectOpenSocketInternal(&socket2); |
| media_sink_service_impl_.OpenChannels( |
| sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Network is reported as disconnected but discover a new device. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2); |
| |
| MediaSinkInternal sink3 = CreateCastSink(3); |
| net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3); |
| std::vector<MediaSinkInternal> sink_list2{sink3}; |
| |
| cast_channel::MockCastSocket socket3; |
| socket3.SetIPEndpoint(ip_endpoint3); |
| socket3.set_id(3); |
| ExpectOpenSocketInternal(&socket3); |
| media_sink_service_impl_.OpenChannels( |
| sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Connecting to a network whose ID resolves to __unknown__ shouldn't pull any |
| // cache items from another unknown network. |
| EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(_, _, _, _)) |
| .Times(0); |
| fake_network_info_ = fake_unknown_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_WIFI); |
| content::RunAllTasksUntilIdle(); |
| |
| // Similarly, disconnecting from the network shouldn't pull any cache items. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, CacheUpdatedForKnownNetwork) { |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| |
| MediaSinkInternal sink1 = CreateCastSink(1); |
| MediaSinkInternal sink2 = CreateCastSink(2); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| std::vector<MediaSinkInternal> sink_list1{sink1, sink2}; |
| |
| // Resolution will succeed for both sinks. |
| cast_channel::MockCastSocket socket1; |
| cast_channel::MockCastSocket socket2; |
| socket1.SetIPEndpoint(ip_endpoint1); |
| socket1.set_id(1); |
| socket2.SetIPEndpoint(ip_endpoint2); |
| socket2.set_id(2); |
| ExpectOpenSocketInternal(&socket1); |
| ExpectOpenSocketInternal(&socket2); |
| media_sink_service_impl_.OpenChannels( |
| sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Connect to a new network with different sinks. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| fake_network_info_ = fake_wifi_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_WIFI); |
| content::RunAllTasksUntilIdle(); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2); |
| |
| MediaSinkInternal sink3 = CreateCastSink(3); |
| net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3); |
| std::vector<MediaSinkInternal> sink_list2{sink3}; |
| |
| cast_channel::MockCastSocket socket3; |
| socket3.SetIPEndpoint(ip_endpoint3); |
| socket3.set_id(3); |
| ExpectOpenSocketInternal(&socket3); |
| media_sink_service_impl_.OpenChannels( |
| sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Reconnecting to the previous ethernet network should restore the same sinks |
| // from the cache and attempt to resolve them. |sink3| is also lost. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint3); |
| |
| // Resolution will fail for cached sinks. |
| socket1.SetErrorState(cast_channel::ChannelError::CONNECT_ERROR); |
| socket2.SetErrorState(cast_channel::ChannelError::CONNECT_ERROR); |
| ExpectOpenSocketInternal(&socket1); |
| ExpectOpenSocketInternal(&socket2); |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| |
| // A new sink is found on the ethernet network. |
| MediaSinkInternal sink4 = CreateCastSink(4); |
| net::IPEndPoint ip_endpoint4 = CreateIPEndPoint(4); |
| std::vector<MediaSinkInternal> sink_list3{sink4}; |
| |
| cast_channel::MockCastSocket socket4; |
| socket4.SetIPEndpoint(ip_endpoint4); |
| socket4.set_id(4); |
| ExpectOpenSocketInternal(&socket4); |
| media_sink_service_impl_.OpenChannels( |
| sink_list3, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Disconnect from the network and lose sinks. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint4); |
| |
| // Reconnect and expect only |sink4| to be cached. |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint4, _, _, _)); |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, CacheDialDiscoveredSinks) { |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| |
| MediaSinkInternal sink1_cast = CreateCastSink(1); |
| MediaSinkInternal sink2_dial = CreateDialSink(2); |
| net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint2(sink2_dial.dial_data().ip_address, |
| CastMediaSinkServiceImpl::kCastControlPort); |
| std::vector<MediaSinkInternal> sink_list1{sink1_cast}; |
| |
| // Resolution will succeed for both sinks. |
| cast_channel::MockCastSocket socket1; |
| cast_channel::MockCastSocket socket2; |
| socket1.SetIPEndpoint(ip_endpoint1); |
| socket1.set_id(1); |
| socket2.SetIPEndpoint(ip_endpoint2); |
| socket2.set_id(2); |
| ExpectOpenSocketInternal(&socket1); |
| ExpectOpenSocketInternal(&socket2); |
| media_sink_service_impl_.OpenChannels( |
| sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| media_sink_service_impl_.OnDialSinkAdded(sink2_dial); |
| |
| // Connect to a new network with different sinks. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| fake_network_info_ = fake_wifi_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_WIFI); |
| content::RunAllTasksUntilIdle(); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2); |
| |
| MediaSinkInternal sink3_cast = CreateCastSink(3); |
| MediaSinkInternal sink4_dial = CreateDialSink(4); |
| net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3); |
| net::IPEndPoint ip_endpoint4(sink4_dial.dial_data().ip_address, |
| CastMediaSinkServiceImpl::kCastControlPort); |
| std::vector<MediaSinkInternal> sink_list2{sink3_cast}; |
| |
| cast_channel::MockCastSocket socket3; |
| cast_channel::MockCastSocket socket4; |
| socket3.SetIPEndpoint(ip_endpoint3); |
| socket3.set_id(3); |
| socket4.SetIPEndpoint(ip_endpoint4); |
| socket4.set_id(4); |
| ExpectOpenSocketInternal(&socket3); |
| ExpectOpenSocketInternal(&socket4); |
| media_sink_service_impl_.OpenChannels( |
| sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| media_sink_service_impl_.OnDialSinkAdded(sink4_dial); |
| |
| // Reconnecting to the previous ethernet network should restore the same sinks |
| // from the cache and attempt to resolve them. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint1, _, _, _)); |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint2, _, _, _)); |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, DualDiscoveryDoesntDuplicateCacheItems) { |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| |
| // The same sink will be discovered via dial and mdns. |
| MediaSinkInternal sink1_cast = CreateCastSink(1); |
| MediaSinkInternal sink1_dial = CreateDialSink(1); |
| net::IPEndPoint ip_endpoint1_cast = CreateIPEndPoint(1); |
| net::IPEndPoint ip_endpoint1_dial(sink1_dial.dial_data().ip_address, |
| CastMediaSinkServiceImpl::kCastControlPort); |
| std::vector<MediaSinkInternal> sink_list1{sink1_cast}; |
| |
| // Dial discovery will succeed first. |
| cast_channel::MockCastSocket socket1_dial; |
| socket1_dial.SetIPEndpoint(ip_endpoint1_dial); |
| socket1_dial.set_id(1); |
| ExpectOpenSocketInternal(&socket1_dial); |
| media_sink_service_impl_.OnDialSinkAdded(sink1_dial); |
| |
| // The same sink is then discovered via mdns. |
| cast_channel::MockCastSocket socket1_cast; |
| socket1_cast.SetIPEndpoint(ip_endpoint1_cast); |
| socket1_cast.set_id(2); |
| ExpectOpenSocketInternal(&socket1_cast); |
| media_sink_service_impl_.OpenChannels( |
| sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Connect to a new network with different sinks. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| fake_network_info_ = fake_wifi_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_WIFI); |
| content::RunAllTasksUntilIdle(); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1_cast); |
| media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1_dial); |
| |
| MediaSinkInternal sink2_cast = CreateCastSink(2); |
| net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); |
| std::vector<MediaSinkInternal> sink_list2{sink2_cast}; |
| |
| cast_channel::MockCastSocket socket2; |
| socket2.SetIPEndpoint(ip_endpoint2); |
| socket2.set_id(3); |
| ExpectOpenSocketInternal(&socket2); |
| media_sink_service_impl_.OpenChannels( |
| sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns); |
| |
| // Reconnecting to the previous ethernet network should restore the same sinks |
| // from the cache and attempt to resolve them. |
| fake_network_info_.clear(); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_NONE); |
| content::RunAllTasksUntilIdle(); |
| |
| EXPECT_CALL(*mock_cast_socket_service_, |
| OpenSocketInternal(ip_endpoint1_cast, _, _, _)); |
| fake_network_info_ = fake_ethernet_info_; |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| content::RunAllTasksUntilIdle(); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, |
| TestInitRetryParametersWithFeatureDisabled) { |
| // Feature not enabled. |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndDisableFeature(kEnableCastChannelRetry); |
| |
| net::BackoffEntry::Policy backoff_policy; |
| int max_retry_attempts; |
| CastMediaSinkServiceImpl::InitRetryParameters(&backoff_policy, |
| &max_retry_attempts); |
| EXPECT_EQ(0, max_retry_attempts); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestInitRetryParameters) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| std::map<std::string, std::string> params; |
| params[CastMediaSinkServiceImpl::kParamNameMaxRetryAttempts] = "20"; |
| params[CastMediaSinkServiceImpl::kParamNameInitialDelayMS] = "2000"; |
| params[CastMediaSinkServiceImpl::kParamNameExponential] = "2.0"; |
| scoped_feature_list.InitAndEnableFeatureWithParameters( |
| kEnableCastChannelRetry, params); |
| |
| net::BackoffEntry::Policy backoff_policy; |
| int max_retry_attempts; |
| CastMediaSinkServiceImpl::InitRetryParameters(&backoff_policy, |
| &max_retry_attempts); |
| EXPECT_EQ(20, max_retry_attempts); |
| EXPECT_EQ(2000, backoff_policy.initial_delay_ms); |
| EXPECT_EQ(2.0, backoff_policy.multiply_factor); |
| } |
| |
| TEST_F(CastMediaSinkServiceImplTest, TestInitRetryParametersWithDefaultValue) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndEnableFeature(kEnableCastChannelRetry); |
| |
| net::BackoffEntry::Policy backoff_policy; |
| int max_retry_attempts; |
| CastMediaSinkServiceImpl::InitRetryParameters(&backoff_policy, |
| &max_retry_attempts); |
| EXPECT_EQ(CastMediaSinkServiceImpl::kDefaultMaxRetryAttempts, |
| max_retry_attempts); |
| EXPECT_EQ(CastMediaSinkServiceImpl::kDefaultBackoffPolicy.initial_delay_ms, |
| backoff_policy.initial_delay_ms); |
| EXPECT_EQ(CastMediaSinkServiceImpl::kDefaultBackoffPolicy.multiply_factor, |
| backoff_policy.multiply_factor); |
| } |
| |
| } // namespace media_router |