blob: 02ef1906bf6df7f2d41e9a7079ad5d1d89fa0844 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// 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/dial/dial_registry.h"
#include <stddef.h>
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
#include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
#include "chrome/browser/media/router/discovery/dial/dial_service.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using base::Time;
using ::testing::_;
using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::StrictMock;
namespace media_router {
class MockDialRegistryClient : public DialRegistry::Client {
public:
~MockDialRegistryClient() override = default;
MOCK_METHOD(void, OnDialDeviceList, (const DialRegistry::DeviceList&));
MOCK_METHOD(void, OnDialError, (DialRegistry::DialErrorCode));
};
class MockNetworkConnectionTracker : public network::NetworkConnectionTracker {
public:
~MockNetworkConnectionTracker() override = default;
MOCK_METHOD(bool,
GetConnectionType,
(network::mojom::ConnectionType*,
network::NetworkConnectionTracker::ConnectionTypeCallback));
};
class MockDialService : public DialService {
public:
~MockDialService() override = default;
MOCK_METHOD(bool, Discover, ());
};
class MockDialRegistry : public DialRegistry {
public:
explicit MockDialRegistry(DialRegistry::Client& client)
: DialRegistry(client, content::GetIOThreadTaskRunner({})) {
SetClockForTest(&clock_);
}
~MockDialRegistry() override {
// Don't let the DialRegistry delete this.
DialService* tmp = dial_.release();
if (tmp) {
CHECK_EQ(&mock_service_, tmp);
}
}
// Returns the mock Dial service.
MockDialService& mock_service() { return mock_service_; }
base::SimpleTestClock* clock() { return &clock_; }
protected:
std::unique_ptr<DialService> CreateDialService() override {
return base::WrapUnique(&mock_service_);
}
void ClearDialService() override {
// Release the pointer but don't delete the object because the test owns it.
CHECK_EQ(&mock_service_, dial_.release());
}
private:
MockDialService mock_service_;
base::SimpleTestClock clock_;
};
class DialRegistryTest : public testing::Test {
public:
DialRegistryTest()
: task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
registry_(new MockDialRegistry(mock_client_)),
first_device_("first", GURL("http://127.0.0.1/dd.xml"), Now()),
second_device_("second", GURL("http://127.0.0.2/dd.xml"), Now()),
third_device_("third", GURL("http://127.0.0.3/dd.xml"), Now()),
list_with_first_device_({first_device_}),
list_with_second_device_({second_device_}),
list_with_first_second_devices_({first_device_, second_device_}) {
ON_CALL(mock_tracker_, GetConnectionType(_, _))
.WillByDefault(DoAll(
SetArgPointee<0>(network::mojom::ConnectionType::CONNECTION_WIFI),
Return(true)));
registry_->network_connection_tracker_ = &mock_tracker_;
}
protected:
void VerifyAndResetMocks() {
testing::Mock::VerifyAndClearExpectations(&registry_->mock_service());
testing::Mock::VerifyAndClearExpectations(&mock_client_);
}
Time Now() const { return registry_->clock()->Now(); }
void AdvanceTime(base::TimeDelta duration) {
registry_->clock()->Advance(duration);
}
MockDialService& mock_service() { return registry_->mock_service(); }
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<MockDialRegistry> registry_;
StrictMock<MockDialRegistryClient> mock_client_;
NiceMock<MockNetworkConnectionTracker> mock_tracker_;
const DialDeviceData first_device_;
const DialDeviceData second_device_;
const DialDeviceData third_device_;
const DialRegistry::DeviceList empty_list_;
const DialRegistry::DeviceList list_with_first_device_;
const DialRegistry::DeviceList list_with_second_device_;
const DialRegistry::DeviceList list_with_first_second_devices_;
};
TEST_F(DialRegistryTest, TestNoDevicesDiscovered) {
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
EXPECT_CALL(mock_service(), Discover());
registry_->StartPeriodicDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDiscoveryFinished();
}
TEST_F(DialRegistryTest, TestDevicesDiscovered) {
InSequence s;
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_first_device_));
registry_->StartPeriodicDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(first_device_);
registry_->OnDiscoveryFinished();
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_first_second_devices_));
registry_->DoDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(second_device_);
registry_->OnDiscoveryFinished();
}
TEST_F(DialRegistryTest, TestDeviceExpires) {
InSequence s;
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_first_device_));
registry_->StartPeriodicDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(first_device_);
registry_->OnDiscoveryFinished();
VerifyAndResetMocks();
// First device has not expired yet.
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_first_second_devices_));
AdvanceTime(base::Seconds(100));
DialDeviceData second_device_discovered_later = second_device_;
second_device_discovered_later.set_response_time(Now());
registry_->DoDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(second_device_discovered_later);
registry_->OnDiscoveryFinished();
VerifyAndResetMocks();
// First device has expired, second device has not expired yet.
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_second_device_));
AdvanceTime(base::Seconds(200));
registry_->DoDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDiscoveryFinished();
VerifyAndResetMocks();
// Second device has expired.
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
AdvanceTime(base::Seconds(200));
registry_->DoDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDiscoveryFinished();
VerifyAndResetMocks();
}
TEST_F(DialRegistryTest, TestExpiredDeviceIsRediscovered) {
InSequence s;
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_first_device_));
registry_->StartPeriodicDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(first_device_);
registry_->OnDiscoveryFinished();
// Will expire "first" device as it is not discovered this time.
AdvanceTime(base::Seconds(300));
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
registry_->DoDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDiscoveryFinished();
// "first" device is rediscovered 300 seconds later. We pass a device object
// with a newer discovery time so it is not pruned immediately.
AdvanceTime(base::Seconds(300));
DialDeviceData rediscovered_device = first_device_;
rediscovered_device.set_response_time(Now());
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_first_device_));
registry_->DoDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(rediscovered_device);
registry_->OnDiscoveryFinished();
}
TEST_F(DialRegistryTest, TestNetworkEventConnectionLost) {
InSequence s;
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_first_device_));
registry_->StartPeriodicDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(first_device_);
registry_->OnDiscoveryFinished();
EXPECT_CALL(mock_client_,
OnDialError(DialRegistry::DIAL_NETWORK_DISCONNECTED));
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
registry_->OnConnectionChanged(
network::mojom::ConnectionType::CONNECTION_NONE);
base::RunLoop().RunUntilIdle();
registry_->OnDiscoveryRequest();
registry_->OnDiscoveryFinished();
}
TEST_F(DialRegistryTest, TestNetworkEventConnectionRestored) {
DialRegistry::DeviceList expected_list3;
expected_list3.push_back(second_device_);
expected_list3.push_back(third_device_);
InSequence s;
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_first_device_));
registry_->StartPeriodicDiscovery();
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(first_device_);
registry_->OnDiscoveryFinished();
EXPECT_CALL(mock_client_,
OnDialError(DialRegistry::DIAL_NETWORK_DISCONNECTED));
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
registry_->OnConnectionChanged(
network::mojom::ConnectionType::CONNECTION_NONE);
base::RunLoop().RunUntilIdle();
registry_->OnDiscoveryRequest();
registry_->OnDiscoveryFinished();
EXPECT_CALL(mock_service(), Discover());
EXPECT_CALL(mock_client_, OnDialDeviceList(empty_list_));
registry_->OnConnectionChanged(
network::mojom::ConnectionType::CONNECTION_WIFI);
base::RunLoop().RunUntilIdle();
EXPECT_CALL(mock_client_, OnDialDeviceList(list_with_second_device_));
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(second_device_);
registry_->OnDiscoveryFinished();
registry_->OnConnectionChanged(
network::mojom::ConnectionType::CONNECTION_ETHERNET);
base::RunLoop().RunUntilIdle();
EXPECT_CALL(mock_client_, OnDialDeviceList(expected_list3));
registry_->OnDiscoveryRequest();
registry_->OnDeviceDiscovered(third_device_);
registry_->OnDiscoveryFinished();
}
} // namespace media_router