# Test whether `networking.proxy' work as expected.

# TODO: use a real proxy node and put this test into networking.nix
# TODO: test whether nix tools work as expected behind a proxy

let
  default-config = {
    imports = [ ./common/user-account.nix ];

    services.xserver.enable = false;

  };
in
{ pkgs, ... }:
{
  name = "networking-proxy";
  meta = {
    maintainers = [ ];
  };

  nodes = {
    # no proxy
    machine =
      { ... }:

      default-config;

    # proxy default
    machine2 =
      { ... }:

      default-config
      // {
        networking.proxy.default = "http://user:pass@host:port";
      };

    # specific proxy options
    machine3 =
      { ... }:

      default-config
      // {
        networking.proxy = {
          # useless because overridden by the next options
          default = "http://user:pass@host:port";
          # advanced proxy setup
          httpProxy = "123-http://user:pass@http-host:port";
          httpsProxy = "456-http://user:pass@https-host:port";
          rsyncProxy = "789-http://user:pass@rsync-host:port";
          ftpProxy = "101112-http://user:pass@ftp-host:port";
          noProxy = "131415-127.0.0.1,localhost,.localdomain";
        };
      };

    # mix default + proxy options
    machine4 =
      { ... }:

      default-config
      // {
        networking.proxy = {
          # open for all *_proxy env var
          default = "000-http://user:pass@default-host:port";
          # except for those 2
          rsyncProxy = "123-http://user:pass@http-host:port";
          noProxy = "131415-127.0.0.1,localhost,.localdomain";
        };
      };
  };

  testScript = ''
    from typing import Dict, Optional


    def get_machine_env(machine: BaseMachine, user: Optional[str] = None) -> Dict[str, str]:
        """
        Gets the environment from a given machine, and returns it as a
        dictionary in the form:
            {"lowercase_var_name": "value"}

        Duplicate environment variables with the same name
        (e.g. "foo" and "FOO") are handled in an undefined manner.
        """
        if user is not None:
            env = machine.succeed("su - {} -c 'env -0'".format(user))
        else:
            env = machine.succeed("env -0")
        ret = {}
        for line in env.split("\0"):
            if "=" not in line:
                continue

            key, val = line.split("=", 1)
            ret[key.lower()] = val
        return ret


    start_all()

    with subtest("no proxy"):
        assert "proxy" not in machine.succeed("env").lower()
        assert "proxy" not in machine.succeed("su - alice -c env").lower()

    with subtest("default proxy"):
        assert "proxy" in machine2.succeed("env").lower()
        assert "proxy" in machine2.succeed("su - alice -c env").lower()

    with subtest("explicitly-set proxy"):
        env = get_machine_env(machine3)
        assert "123" in env["http_proxy"]
        assert "456" in env["https_proxy"]
        assert "789" in env["rsync_proxy"]
        assert "101112" in env["ftp_proxy"]
        assert "131415" in env["no_proxy"]

        env = get_machine_env(machine3, "alice")
        assert "123" in env["http_proxy"]
        assert "456" in env["https_proxy"]
        assert "789" in env["rsync_proxy"]
        assert "101112" in env["ftp_proxy"]
        assert "131415" in env["no_proxy"]

    with subtest("default proxy + some other specifics"):
        env = get_machine_env(machine4)
        assert "000" in env["http_proxy"]
        assert "000" in env["https_proxy"]
        assert "123" in env["rsync_proxy"]
        assert "000" in env["ftp_proxy"]
        assert "131415" in env["no_proxy"]

        env = get_machine_env(machine4, "alice")
        assert "000" in env["http_proxy"]
        assert "000" in env["https_proxy"]
        assert "123" in env["rsync_proxy"]
        assert "000" in env["ftp_proxy"]
        assert "131415" in env["no_proxy"]
  '';
}
