blob: 04f74195c21dfb60f5f520e01e5d5c74b8efc6ed [file] [log] [blame]
// Copyright 2018 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 "services/network/network_quality_estimator_manager.h"
#include <algorithm>
#include <utility>
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "net/log/test_net_log.h"
#include "net/nqe/effective_connection_type.h"
#include "net/nqe/network_quality_estimator.h"
#include "services/network/public/mojom/network_quality_estimator_manager.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
namespace {
class TestNetworkQualityEstimatorManagerClient
: public mojom::NetworkQualityEstimatorManagerClient {
public:
explicit TestNetworkQualityEstimatorManagerClient(
NetworkQualityEstimatorManager* network_quality_estimator_manager)
: network_quality_estimator_manager_(network_quality_estimator_manager),
num_network_quality_changed_(0),
run_loop_(std::make_unique<base::RunLoop>()),
effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
http_rtt_(base::TimeDelta()),
transport_rtt_(base::TimeDelta()),
downlink_bandwidth_kbps_(INT32_MAX),
binding_(this) {
mojom::NetworkQualityEstimatorManagerPtr manager_ptr;
mojom::NetworkQualityEstimatorManagerRequest request(
mojo::MakeRequest(&manager_ptr));
network_quality_estimator_manager_->AddRequest(std::move(request));
mojom::NetworkQualityEstimatorManagerClientPtr client_ptr;
mojom::NetworkQualityEstimatorManagerClientRequest client_request(
mojo::MakeRequest(&client_ptr));
binding_.Bind(std::move(client_request));
manager_ptr->RequestNotifications(std::move(client_ptr));
}
~TestNetworkQualityEstimatorManagerClient() override {}
void OnNetworkQualityChanged(net::EffectiveConnectionType type,
base::TimeDelta http_rtt,
base::TimeDelta transport_rtt,
int32_t downlink_bandwidth_kbps) override {
num_network_quality_changed_++;
effective_connection_type_ = type;
http_rtt_ = http_rtt;
transport_rtt_ = transport_rtt;
downlink_bandwidth_kbps_ = downlink_bandwidth_kbps;
if (run_loop_wait_effective_connection_type_ == type)
run_loop_->Quit();
}
// Returns the number of OnNetworkQualityChanged() notifications. Note that
// the number may change based on the order in which underlying network
// quality estimator provides notifications when effective connection
// type, RTT and downlink estimates change simultaneously.
size_t num_network_quality_changed() const {
return num_network_quality_changed_;
}
void WaitForNotification(
net::EffectiveConnectionType effective_connection_type) {
run_loop_wait_effective_connection_type_ = effective_connection_type;
run_loop_->Run();
run_loop_.reset(new base::RunLoop());
}
net::EffectiveConnectionType effective_connection_type() const {
return effective_connection_type_;
}
base::TimeDelta http_rtt() const { return http_rtt_; }
base::TimeDelta transport_rtt() const { return transport_rtt_; }
int32_t downlink_bandwidth_kbps() const { return downlink_bandwidth_kbps_; }
private:
NetworkQualityEstimatorManager* network_quality_estimator_manager_;
size_t num_network_quality_changed_;
std::unique_ptr<base::RunLoop> run_loop_;
net::EffectiveConnectionType run_loop_wait_effective_connection_type_;
net::EffectiveConnectionType effective_connection_type_;
base::TimeDelta http_rtt_;
base::TimeDelta transport_rtt_;
int32_t downlink_bandwidth_kbps_;
mojo::Binding<mojom::NetworkQualityEstimatorManagerClient> binding_;
DISALLOW_COPY_AND_ASSIGN(TestNetworkQualityEstimatorManagerClient);
};
} // namespace
class NetworkQualityEstimatorManagerTest : public testing::Test {
public:
NetworkQualityEstimatorManagerTest()
: net_log_(std::make_unique<net::BoundTestNetLog>()),
network_quality_estimator_manager_(
std::make_unique<NetworkQualityEstimatorManager>(
net_log_->bound().net_log())) {
// Change the network quality to UNKNOWN to prevent any spurious
// notifications.
SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
network_quality_estimator_manager_client_ =
std::make_unique<TestNetworkQualityEstimatorManagerClient>(
network_quality_estimator_manager_.get());
}
~NetworkQualityEstimatorManagerTest() override {}
TestNetworkQualityEstimatorManagerClient*
network_quality_estimator_manager_client() {
return network_quality_estimator_manager_client_.get();
}
NetworkQualityEstimatorManager* network_quality_estimator_manager() const {
return network_quality_estimator_manager_.get();
}
void SimulateNetworkQualityChange(net::EffectiveConnectionType type) {
network_quality_estimator_manager_->GetNetworkQualityEstimator()
->SimulateNetworkQualityChangeForTesting(type);
}
private:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<net::BoundTestNetLog> net_log_;
std::unique_ptr<NetworkQualityEstimatorManager>
network_quality_estimator_manager_;
std::unique_ptr<TestNetworkQualityEstimatorManagerClient>
network_quality_estimator_manager_client_;
DISALLOW_COPY_AND_ASSIGN(NetworkQualityEstimatorManagerTest);
};
TEST_F(NetworkQualityEstimatorManagerTest, ClientNotified) {
// Simulate a new network quality change.
SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_3G);
network_quality_estimator_manager_client()->WaitForNotification(
net::EFFECTIVE_CONNECTION_TYPE_3G);
EXPECT_EQ(
net::EFFECTIVE_CONNECTION_TYPE_3G,
network_quality_estimator_manager_client()->effective_connection_type());
base::RunLoop().RunUntilIdle();
// Verify that not more than 2 notifications were received.
EXPECT_GE(2u, network_quality_estimator_manager_client()
->num_network_quality_changed());
// Typical RTT and downlink values when effective connection type is 3G. Taken
// from net::NetworkQualityEstimatorParams.
EXPECT_EQ(base::TimeDelta::FromMilliseconds(450),
network_quality_estimator_manager_client()->http_rtt());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(400),
network_quality_estimator_manager_client()->transport_rtt());
EXPECT_EQ(
400,
network_quality_estimator_manager_client()->downlink_bandwidth_kbps());
}
// Test that when the network quality is unavailable, network quality estimator
// manager reports the estimated network quality values as negative.
TEST_F(NetworkQualityEstimatorManagerTest,
ClientNotifiedUnknownNetworkQuality) {
EXPECT_EQ(
net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
network_quality_estimator_manager_client()->effective_connection_type());
base::RunLoop().RunUntilIdle();
SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_3G);
network_quality_estimator_manager_client()->WaitForNotification(
net::EFFECTIVE_CONNECTION_TYPE_3G);
base::RunLoop().RunUntilIdle();
// Typical RTT and downlink values when effective connection type is 3G. Taken
// from net::NetworkQualityEstimatorParams.
EXPECT_EQ(base::TimeDelta::FromMilliseconds(450),
network_quality_estimator_manager_client()->http_rtt());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(400),
network_quality_estimator_manager_client()->transport_rtt());
EXPECT_EQ(
400,
network_quality_estimator_manager_client()->downlink_bandwidth_kbps());
SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
network_quality_estimator_manager_client()->WaitForNotification(
net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
base::RunLoop().RunUntilIdle();
EXPECT_GT(base::TimeDelta(),
network_quality_estimator_manager_client()->http_rtt());
EXPECT_GT(base::TimeDelta(),
network_quality_estimator_manager_client()->transport_rtt());
EXPECT_GT(
0, network_quality_estimator_manager_client()->downlink_bandwidth_kbps());
}
TEST_F(NetworkQualityEstimatorManagerTest, OneClientPipeBroken) {
auto network_quality_estimator_manager_client2 =
std::make_unique<TestNetworkQualityEstimatorManagerClient>(
network_quality_estimator_manager());
// Simulate a network quality change.
SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_4G);
network_quality_estimator_manager_client()->WaitForNotification(
net::EFFECTIVE_CONNECTION_TYPE_4G);
network_quality_estimator_manager_client2->WaitForNotification(
net::EFFECTIVE_CONNECTION_TYPE_4G);
EXPECT_EQ(
net::EFFECTIVE_CONNECTION_TYPE_4G,
network_quality_estimator_manager_client()->effective_connection_type());
EXPECT_EQ(
net::EFFECTIVE_CONNECTION_TYPE_4G,
network_quality_estimator_manager_client2->effective_connection_type());
// Typical RTT and downlink values when effective connection type is 4G. Taken
// from net::NetworkQualityEstimatorParams.
EXPECT_EQ(base::TimeDelta::FromMilliseconds(175),
network_quality_estimator_manager_client2->http_rtt());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(125),
network_quality_estimator_manager_client()->transport_rtt());
EXPECT_EQ(
1600,
network_quality_estimator_manager_client2->downlink_bandwidth_kbps());
base::RunLoop().RunUntilIdle();
EXPECT_GE(2u, network_quality_estimator_manager_client()
->num_network_quality_changed());
EXPECT_GE(
2u,
network_quality_estimator_manager_client2->num_network_quality_changed());
network_quality_estimator_manager_client2.reset();
base::RunLoop().RunUntilIdle();
// Simulate a second network quality change, and the remaining client should
// be notified.
SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_2G);
network_quality_estimator_manager_client()->WaitForNotification(
net::EFFECTIVE_CONNECTION_TYPE_2G);
EXPECT_EQ(
net::EFFECTIVE_CONNECTION_TYPE_2G,
network_quality_estimator_manager_client()->effective_connection_type());
EXPECT_GE(3u, network_quality_estimator_manager_client()
->num_network_quality_changed());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(1800),
network_quality_estimator_manager_client()->http_rtt());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
network_quality_estimator_manager_client()->transport_rtt());
EXPECT_EQ(
75,
network_quality_estimator_manager_client()->downlink_bandwidth_kbps());
}
TEST_F(NetworkQualityEstimatorManagerTest,
NewClientReceivesCurrentEffectiveType) {
// Simulate a network quality change.
SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_2G);
network_quality_estimator_manager_client()->WaitForNotification(
net::EFFECTIVE_CONNECTION_TYPE_2G);
EXPECT_EQ(
net::EFFECTIVE_CONNECTION_TYPE_2G,
network_quality_estimator_manager_client()->effective_connection_type());
base::RunLoop().RunUntilIdle();
// Typical RTT and downlink values when effective connection type is 2G. Taken
// from net::NetworkQualityEstimatorParams.
EXPECT_EQ(base::TimeDelta::FromMilliseconds(1800),
network_quality_estimator_manager_client()->http_rtt());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
network_quality_estimator_manager_client()->transport_rtt());
EXPECT_EQ(
75,
network_quality_estimator_manager_client()->downlink_bandwidth_kbps());
// Register a new client after the network quality change and it should
// receive the up-to-date effective connection type.
TestNetworkQualityEstimatorManagerClient
network_quality_estimator_manager_client2(
network_quality_estimator_manager());
network_quality_estimator_manager_client2.WaitForNotification(
net::EFFECTIVE_CONNECTION_TYPE_2G);
EXPECT_EQ(
net::EFFECTIVE_CONNECTION_TYPE_2G,
network_quality_estimator_manager_client2.effective_connection_type());
// Typical RTT and downlink values when when effective connection type is 2G.
// Taken from net::NetworkQualityEstimatorParams.
EXPECT_EQ(base::TimeDelta::FromMilliseconds(1800),
network_quality_estimator_manager_client2.http_rtt());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(1500),
network_quality_estimator_manager_client()->transport_rtt());
EXPECT_EQ(
75, network_quality_estimator_manager_client2.downlink_bandwidth_kbps());
}
} // namespace network