// Copyright 2013 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/net/dns_probe_test_util.h"

#include <stdint.h>

#include <utility>

#include "base/notreached.h"
#include "chrome/browser/net/dns_probe_runner.h"
#include "net/base/ip_address.h"
#include "net/base/network_anonymization_key.h"
#include "net/dns/public/resolve_error_info.h"
#include "services/network/public/mojom/clear_data_filter.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace chrome_browser_net {

namespace {

static net::AddressList AddressListForResponse(
    FakeHostResolver::Response response) {
  switch (response) {
    case FakeHostResolver::kNoResponse:
      return net::AddressList();
    case FakeHostResolver::kOneAddressResponse:
      return net::AddressList(
          net::IPEndPoint(net::IPAddress(192, 168, 1, 1), 0));
  }
  NOTREACHED();
}

}  // namespace

FakeHostResolver::SingleResult::SingleResult(
    int32_t result,
    net::ResolveErrorInfo resolve_error_info,
    Response response)
    : result(result),
      resolve_error_info(resolve_error_info),
      response(response) {
  DCHECK(result == net::OK || result == net::ERR_NAME_NOT_RESOLVED);
}

FakeHostResolver::FakeHostResolver(
    mojo::PendingReceiver<network::mojom::HostResolver> resolver_receiver,
    std::vector<SingleResult> result_list)
    : receiver_(this, std::move(resolver_receiver)),
      result_list_(result_list) {}

FakeHostResolver::FakeHostResolver(
    mojo::PendingReceiver<network::mojom::HostResolver> resolver_receiver,
    int32_t result,
    net::ResolveErrorInfo resolve_error_info,
    Response response)
    : FakeHostResolver(std::move(resolver_receiver),
                       {SingleResult(result, resolve_error_info, response)}) {}

FakeHostResolver::~FakeHostResolver() = default;

void FakeHostResolver::ResolveHost(
    network::mojom::HostResolverHostPtr host,
    const net::NetworkAnonymizationKey& network_anonymization_key,
    network::mojom::ResolveHostParametersPtr optional_parameters,
    mojo::PendingRemote<network::mojom::ResolveHostClient>
        pending_response_client) {
  EXPECT_TRUE(network_anonymization_key.IsTransient());

  const SingleResult& cur_result = result_list_[next_result_];
  if (next_result_ + 1 < result_list_.size())
    next_result_++;
  mojo::Remote<network::mojom::ResolveHostClient> response_client(
      std::move(pending_response_client));
  response_client->OnComplete(cur_result.result, cur_result.resolve_error_info,
                              AddressListForResponse(cur_result.response),
                              /*alternative_endpoints=*/{});
}

void FakeHostResolver::MdnsListen(
    const net::HostPortPair& host,
    net::DnsQueryType query_type,
    mojo::PendingRemote<network::mojom::MdnsListenClient> response_client,
    MdnsListenCallback callback) {
  NOTREACHED();
}

HangingHostResolver::HangingHostResolver(
    mojo::PendingReceiver<network::mojom::HostResolver> resolver_receiver)
    : receiver_(this, std::move(resolver_receiver)) {}

HangingHostResolver::~HangingHostResolver() = default;

void HangingHostResolver::ResolveHost(
    network::mojom::HostResolverHostPtr host,
    const net::NetworkAnonymizationKey& network_anonymization_key,
    network::mojom::ResolveHostParametersPtr optional_parameters,
    mojo::PendingRemote<network::mojom::ResolveHostClient> response_client) {
  EXPECT_TRUE(network_anonymization_key.IsTransient());

  // Intentionally do not call response_client->OnComplete, but hang onto the
  // |response_client| since destroying that also causes the mojo
  // set_connection_error_handler handler to be called.
  response_client_.Bind(std::move(response_client));
}

void HangingHostResolver::MdnsListen(
    const net::HostPortPair& host,
    net::DnsQueryType query_type,
    mojo::PendingRemote<network::mojom::MdnsListenClient> response_client,
    MdnsListenCallback callback) {
  NOTREACHED();
}

FakeHostResolverNetworkContext::FakeHostResolverNetworkContext(
    std::vector<FakeHostResolver::SingleResult> current_config_result_list,
    std::vector<FakeHostResolver::SingleResult> google_config_result_list)
    : current_config_result_list_(std::move(current_config_result_list)),
      google_config_result_list_(std::move(google_config_result_list)) {}

FakeHostResolverNetworkContext::~FakeHostResolverNetworkContext() = default;

void FakeHostResolverNetworkContext::CreateHostResolver(
    const std::optional<net::DnsConfigOverrides>& config_overrides,
    mojo::PendingReceiver<network::mojom::HostResolver> receiver) {
  ASSERT_TRUE(config_overrides);
  if (!config_overrides->nameservers) {
    if (!current_config_resolver_) {
      current_config_resolver_ = std::make_unique<FakeHostResolver>(
          std::move(receiver), current_config_result_list_);
    }
  } else {
    if (!google_config_resolver_) {
      google_config_resolver_ = std::make_unique<FakeHostResolver>(
          std::move(receiver), google_config_result_list_);
    }
  }
}

HangingHostResolverNetworkContext::HangingHostResolverNetworkContext() =
    default;
HangingHostResolverNetworkContext::~HangingHostResolverNetworkContext() =
    default;

void HangingHostResolverNetworkContext::CreateHostResolver(
    const std::optional<net::DnsConfigOverrides>& config_overrides,
    mojo::PendingReceiver<network::mojom::HostResolver> receiver) {
  resolver_ = std::make_unique<HangingHostResolver>(std::move(receiver));
}

FakeDnsConfigChangeManager::FakeDnsConfigChangeManager(
    mojo::PendingReceiver<network::mojom::DnsConfigChangeManager> receiver)
    : receiver_(this, std::move(receiver)) {}

FakeDnsConfigChangeManager::~FakeDnsConfigChangeManager() = default;

void FakeDnsConfigChangeManager::RequestNotifications(
    mojo::PendingRemote<network::mojom::DnsConfigChangeManagerClient> client) {
  ASSERT_FALSE(client_);
  client_.Bind(std::move(client));
}

void FakeDnsConfigChangeManager::SimulateDnsConfigChange() {
  ASSERT_TRUE(client_);
  client_->OnDnsConfigChanged();
}

}  // namespace chrome_browser_net
