chromium/chromeos/ash/components/network/proxy/proxy_config_service_impl_unittest.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/components/network/proxy/proxy_config_service_impl.h"

#include <memory>

#include "base/task/single_thread_task_runner.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/components/network/network_handler_test_helper.h"
#include "chromeos/ash/components/network/network_state.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/network/proxy/proxy_config_handler.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/constants/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {
namespace {

const char kFixedPacUrl[] = "http://fixed/";

class TestProxyConfigService : public net::ProxyConfigService {
 public:
  TestProxyConfigService(const net::ProxyConfig& config,
                         ConfigAvailability availability)
      : config_(config), availability_(availability) {}

 private:
  void AddObserver(net::ProxyConfigService::Observer* observer) override {}
  void RemoveObserver(net::ProxyConfigService::Observer* observer) override {}

  net::ProxyConfigService::ConfigAvailability GetLatestProxyConfig(
      net::ProxyConfigWithAnnotation* config) override {
    *config =
        net::ProxyConfigWithAnnotation(config_, TRAFFIC_ANNOTATION_FOR_TESTS);
    return availability_;
  }

  net::ProxyConfig config_;
  ConfigAvailability availability_;
};

}  // namespace

class ProxyConfigServiceImplTest : public testing::Test {
 public:
  void SetUp() override {
    network_handler_test_helper_ = std::make_unique<NetworkHandlerTestHelper>();

    PrefProxyConfigTrackerImpl::RegisterProfilePrefs(profile_prefs_.registry());
    proxy_config_service_ = std::make_unique<ProxyConfigServiceImpl>(
        &profile_prefs_, &local_state_prefs_,
        base::SingleThreadTaskRunner::GetCurrentDefault());

    // Wait for network initialization events to propagate.
    environment_.RunUntilIdle();
  }

  void TearDown() override { proxy_config_service_->DetachFromPrefService(); }

  void CreateTrackingProxyConfigService(
      std::unique_ptr<TestProxyConfigService> nested_service) {
    proxy_resolution_service_ =
        proxy_config_service_->CreateTrackingProxyConfigService(
            std::move(nested_service));
    environment_.RunUntilIdle();
  }

  void DetermineEffectiveConfigFromDefaultNetwork() {
    proxy_config_service_->DetermineEffectiveConfigFromDefaultNetwork();
    environment_.RunUntilIdle();
  }

  net::ProxyConfigService::ConfigAvailability GetLatestProxyConfig(
      net::ProxyConfigWithAnnotation* config) {
    return proxy_resolution_service_->GetLatestProxyConfig(config);
  }

  void SetUseSharedProxies() {
    profile_prefs_.SetUserPref(::proxy_config::prefs::kUseSharedProxies,
                               std::make_unique<base::Value>(true));
    environment_.RunUntilIdle();
  }

  void SetCaptivePortalSignin() {
    profile_prefs_.SetUserPref(chromeos::prefs::kCaptivePortalSignin,
                               std::make_unique<base::Value>(true));
    environment_.RunUntilIdle();
  }

  void SetCaptivePortalAuthenticationIgnoresProxy() {
    profile_prefs_.SetUserPref(
        chromeos::prefs::kCaptivePortalAuthenticationIgnoresProxy,
        std::make_unique<base::Value>(false));
    environment_.RunUntilIdle();
  }

  void SetProxyPref() {
    base::Value::Dict fixed_config;
    fixed_config.Set("mode", "pac_script");
    fixed_config.Set("pac_url", kFixedPacUrl);
    profile_prefs_.SetUserPref(::proxy_config::prefs::kProxy,
                               std::move(fixed_config));
    environment_.RunUntilIdle();
  }

  net::ProxyConfig SetDefaultNetworkProxyConfig() {
    SetUseSharedProxies();
    const NetworkState* default_network =
        NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
    CHECK(default_network);
    proxy_config::SetProxyConfigForNetwork(
        ProxyConfigDictionary(ProxyConfigDictionary::CreateAutoDetect()),
        *default_network);
    environment_.RunUntilIdle();
    return net::ProxyConfig::CreateAutoDetect();
  }

  NetworkHandlerTestHelper* network_handler_test_helper() {
    return network_handler_test_helper_.get();
  }

 protected:
  base::test::TaskEnvironment environment_;
  std::unique_ptr<NetworkHandlerTestHelper> network_handler_test_helper_;
  TestingPrefServiceSimple profile_prefs_;
  TestingPrefServiceSimple local_state_prefs_;
  std::unique_ptr<ProxyConfigServiceImpl> proxy_config_service_;
  std::unique_ptr<net::ProxyConfigService> proxy_resolution_service_;
};

TEST_F(ProxyConfigServiceImplTest, Default) {
  CreateTrackingProxyConfigService(nullptr);

  net::ProxyConfigWithAnnotation config;
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_TRUE(config.value().Equals(net::ProxyConfig::CreateDirect()));
}

// By default, ProxyConfigServiceImpl should ignore the state of the nested
// ProxyConfigService.
TEST_F(ProxyConfigServiceImplTest, IgnoresNestedProxyConfigServiceByDefault) {
  auto fixed_config =
      net::ProxyConfig::CreateFromCustomPacURL(GURL(kFixedPacUrl));
  std::unique_ptr<TestProxyConfigService> nested_service =
      std::make_unique<TestProxyConfigService>(
          fixed_config, net::ProxyConfigService::CONFIG_VALID);

  CreateTrackingProxyConfigService(std::move(nested_service));

  net::ProxyConfigWithAnnotation config;
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_TRUE(config.value().Equals(net::ProxyConfig::CreateDirect()));
}

// Sets proxy_config::prefs::kUseSharedProxies to true, and makes sure the
// nested ProxyConfigService is used.
TEST_F(ProxyConfigServiceImplTest, UsesNestedProxyConfigService) {
  SetUseSharedProxies();

  auto fixed_config =
      net::ProxyConfig::CreateFromCustomPacURL(GURL(kFixedPacUrl));
  std::unique_ptr<TestProxyConfigService> nested_service =
      std::make_unique<TestProxyConfigService>(
          fixed_config, net::ProxyConfigService::CONFIG_VALID);

  CreateTrackingProxyConfigService(std::move(nested_service));

  net::ProxyConfigWithAnnotation config;
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_TRUE(config.value().Equals(fixed_config));
}

TEST_F(ProxyConfigServiceImplTest, DetermineEffectiveConfigFromDefaultNetwork) {
  CreateTrackingProxyConfigService(nullptr);

  // No proxy set
  DetermineEffectiveConfigFromDefaultNetwork();
  net::ProxyConfigWithAnnotation config;
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_EQ(config.value().ToValue(),
            net::ProxyConfig::CreateDirect().ToValue());

  // Per-network proxy set
  net::ProxyConfig network_proxy_config = SetDefaultNetworkProxyConfig();
  DetermineEffectiveConfigFromDefaultNetwork();
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_EQ(config.value().ToValue(), network_proxy_config.ToValue());
}

TEST_F(ProxyConfigServiceImplTest,
       DetermineEffectiveConfigFromDefaultNetworkAndPref) {
  CreateTrackingProxyConfigService(nullptr);

  // No proxy set
  DetermineEffectiveConfigFromDefaultNetwork();
  net::ProxyConfigWithAnnotation config;
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_EQ(config.value().ToValue(),
            net::ProxyConfig::CreateDirect().ToValue());

  // Proxy pref set
  SetProxyPref();
  DetermineEffectiveConfigFromDefaultNetwork();
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_EQ(
      config.value().ToValue(),
      net::ProxyConfig::CreateFromCustomPacURL(GURL(kFixedPacUrl)).ToValue());
}

class ProxyConfigServiceImplCaptivePortalPopupWindowTest
    : public ProxyConfigServiceImplTest {
 public:
  void SetUp() override {
    feature_list_.InitAndEnableFeature(
        chromeos::features::kCaptivePortalPopupWindow);
    profile_prefs_.registry()->RegisterBooleanPref(
        chromeos::prefs::kCaptivePortalSignin, false);
    profile_prefs_.registry()->RegisterBooleanPref(
        chromeos::prefs::kCaptivePortalAuthenticationIgnoresProxy, true);
    ProxyConfigServiceImplTest::SetUp();
  }

 private:
  base::test::ScopedFeatureList feature_list_;
};

TEST_F(ProxyConfigServiceImplCaptivePortalPopupWindowTest,
       DetermineEffectiveConfigFromDefaultNetworkAndPref) {
  CreateTrackingProxyConfigService(nullptr);

  // No proxy set
  DetermineEffectiveConfigFromDefaultNetwork();
  net::ProxyConfigWithAnnotation config;
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_EQ(config.value().ToValue(),
            net::ProxyConfig::CreateDirect().ToValue());

  // Proxy pref set
  SetProxyPref();
  DetermineEffectiveConfigFromDefaultNetwork();
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_EQ(
      config.value().ToValue(),
      net::ProxyConfig::CreateFromCustomPacURL(GURL(kFixedPacUrl)).ToValue());
}

TEST_F(ProxyConfigServiceImplCaptivePortalPopupWindowTest,
       NetworkPortalSignin) {
  SetCaptivePortalSignin();
  CreateTrackingProxyConfigService(nullptr);

  // Proxy pref set but ignored for captive portal signin.
  SetProxyPref();
  DetermineEffectiveConfigFromDefaultNetwork();
  net::ProxyConfigWithAnnotation config;
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_EQ(config.value().ToValue(),
            net::ProxyConfig::CreateDirect().ToValue());
}

TEST_F(ProxyConfigServiceImplCaptivePortalPopupWindowTest,
       CaptivePortalAuthenticationIgnoresProxy) {
  SetCaptivePortalSignin();
  SetCaptivePortalAuthenticationIgnoresProxy();
  CreateTrackingProxyConfigService(nullptr);

  // Proxy pref set and not ignored for captive portal signin.
  SetProxyPref();
  DetermineEffectiveConfigFromDefaultNetwork();
  net::ProxyConfigWithAnnotation config;
  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
            GetLatestProxyConfig(&config));
  EXPECT_EQ(
      config.value().ToValue(),
      net::ProxyConfig::CreateFromCustomPacURL(GURL(kFixedPacUrl)).ToValue());
}

}  // namespace ash