blob: cc0e6dc9f96351eb676a1068eb4e0d60125b7bee [file] [log] [blame]
// Copyright 2013 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/net/dns_probe_runner.h"
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "chrome/browser/net/dns_probe_test_util.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "services/network/test/test_network_context.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::RunLoop;
using content::TestBrowserThreadBundle;
namespace chrome_browser_net {
namespace {
class TestDnsProbeRunnerCallback {
public:
TestDnsProbeRunnerCallback() : called_(false) {}
base::OnceClosure callback() {
return base::BindOnce(&TestDnsProbeRunnerCallback::OnCalled,
base::Unretained(this));
}
bool called() const { return called_; }
private:
void OnCalled() {
EXPECT_FALSE(called_);
called_ = true;
}
bool called_;
};
class FakeNetworkContext : public network::TestNetworkContext {
public:
explicit FakeNetworkContext(
std::vector<FakeHostResolver::SingleResult> result_list)
: result_list_(std::move(result_list)) {}
void CreateHostResolver(
const base::Optional<net::DnsConfigOverrides>& config_overrides,
network::mojom::HostResolverRequest request) override {
ASSERT_FALSE(resolver_);
resolver_ = std::make_unique<FakeHostResolver>(std::move(request),
std::move(result_list_));
}
private:
std::unique_ptr<FakeHostResolver> resolver_;
std::vector<FakeHostResolver::SingleResult> result_list_;
};
class FirstHangingThenFakeResolverNetworkContext
: public network::TestNetworkContext {
public:
explicit FirstHangingThenFakeResolverNetworkContext(
std::vector<FakeHostResolver::SingleResult> result_list)
: result_list_(std::move(result_list)) {}
void CreateHostResolver(
const base::Optional<net::DnsConfigOverrides>& config_overrides,
network::mojom::HostResolverRequest request) override {
if (call_num == 0) {
resolver_ = std::make_unique<HangingHostResolver>(std::move(request));
} else {
resolver_ = std::make_unique<FakeHostResolver>(std::move(request),
std::move(result_list_));
}
call_num++;
}
void DestroyHostResolver() { resolver_ = nullptr; }
private:
int call_num = 0;
std::unique_ptr<network::mojom::HostResolver> resolver_;
std::vector<FakeHostResolver::SingleResult> result_list_;
};
class DnsProbeRunnerTest : public testing::Test {
protected:
void SetupTest(int query_result, FakeHostResolver::Response query_response);
void SetupTest(std::vector<FakeHostResolver::SingleResult> result_list);
void RunTest(DnsProbeRunner::Result expected_probe_results);
network::mojom::NetworkContext* network_context() const {
return network_context_.get();
}
TestBrowserThreadBundle bundle_;
std::unique_ptr<network::mojom::NetworkContext> network_context_;
std::unique_ptr<DnsProbeRunner> runner_;
};
void DnsProbeRunnerTest::SetupTest(int query_result,
FakeHostResolver::Response query_response) {
SetupTest({{query_result, query_response}});
}
void DnsProbeRunnerTest::SetupTest(
std::vector<FakeHostResolver::SingleResult> result_list) {
network_context_ =
std::make_unique<FakeNetworkContext>(std::move(result_list));
runner_ = std::make_unique<DnsProbeRunner>(
net::DnsConfigOverrides(),
base::BindRepeating(&DnsProbeRunnerTest::network_context,
base::Unretained(this)));
}
void DnsProbeRunnerTest::RunTest(DnsProbeRunner::Result expected_probe_result) {
TestDnsProbeRunnerCallback callback;
runner_->RunProbe(callback.callback());
EXPECT_TRUE(runner_->IsRunning());
RunLoop().RunUntilIdle();
EXPECT_FALSE(runner_->IsRunning());
EXPECT_TRUE(callback.called());
EXPECT_EQ(expected_probe_result, runner_->result());
}
TEST_F(DnsProbeRunnerTest, Probe_OK) {
SetupTest(net::OK, FakeHostResolver::kOneAddressResponse);
RunTest(DnsProbeRunner::CORRECT);
}
TEST_F(DnsProbeRunnerTest, Probe_EMPTY) {
SetupTest(net::OK, FakeHostResolver::kEmptyResponse);
RunTest(DnsProbeRunner::INCORRECT);
}
TEST_F(DnsProbeRunnerTest, Probe_TIMEOUT) {
SetupTest(net::ERR_DNS_TIMED_OUT, FakeHostResolver::kNoResponse);
RunTest(DnsProbeRunner::UNREACHABLE);
}
TEST_F(DnsProbeRunnerTest, Probe_NXDOMAIN) {
SetupTest(net::ERR_NAME_NOT_RESOLVED, FakeHostResolver::kNoResponse);
RunTest(DnsProbeRunner::INCORRECT);
}
TEST_F(DnsProbeRunnerTest, Probe_FAILING) {
SetupTest(net::ERR_DNS_SERVER_FAILED, FakeHostResolver::kNoResponse);
RunTest(DnsProbeRunner::FAILING);
}
TEST_F(DnsProbeRunnerTest, TwoProbes) {
SetupTest({{net::OK, FakeHostResolver::kOneAddressResponse},
{net::ERR_NAME_NOT_RESOLVED, FakeHostResolver::kNoResponse}});
RunTest(DnsProbeRunner::CORRECT);
RunTest(DnsProbeRunner::INCORRECT);
}
TEST_F(DnsProbeRunnerTest, MojoConnectionError) {
// Use a HostResolverGetter that returns a HangingHostResolver on the first
// call, and a FakeHostResolver on the second call.
FirstHangingThenFakeResolverNetworkContext network_context(
{{net::OK, FakeHostResolver::kOneAddressResponse}});
runner_ = std::make_unique<DnsProbeRunner>(
net::DnsConfigOverrides(),
base::BindRepeating(
[](network::mojom::NetworkContext* context) { return context; },
base::Unretained(&network_context)));
TestDnsProbeRunnerCallback callback;
runner_->RunProbe(callback.callback());
EXPECT_TRUE(runner_->IsRunning());
RunLoop().RunUntilIdle();
EXPECT_TRUE(runner_->IsRunning());
EXPECT_FALSE(callback.called());
// Destroy the HangingHostResolver while runner_ is still waiting for a
// response. The set_connection_error_handler callback should be invoked.
network_context.DestroyHostResolver();
RunLoop().RunUntilIdle();
// That should cause the RunProbe callback to be called with an UNKNOWN
// status since the HostResolver request never returned.
EXPECT_FALSE(runner_->IsRunning());
EXPECT_TRUE(callback.called());
EXPECT_EQ(DnsProbeRunner::UNKNOWN, runner_->result());
// Try another probe. The DnsProbeRunner should call the HostResolverGetter
// again, this time getting a FakeHostResolver that will successfully return
// an OK result.
RunTest(DnsProbeRunner::CORRECT);
}
} // namespace
} // namespace chrome_browser_net