# Tests whether container images are imported and auto deploying Helm charts,
# including the bundled traefik, work
import ../make-test-python.nix (
  {
    k3s,
    lib,
    pkgs,
    ...
  }:
  let
    testImageEnv = pkgs.buildEnv {
      name = "k3s-pause-image-env";
      paths = with pkgs; [
        busybox
        hello
      ];
    };
    testImage = pkgs.dockerTools.buildImage {
      name = "test.local/test";
      tag = "local";
      # Slightly reduces the time needed to import image
      compressor = "zstd";
      copyToRoot = testImageEnv;
    };
    # pack the test helm chart as a .tgz archive
    package =
      pkgs.runCommand "k3s-test-chart.tgz"
        {
          nativeBuildInputs = [ pkgs.kubernetes-helm ];
        }
        ''
          helm package ${./k3s-test-chart}
          mv ./*.tgz $out
        '';
    # The common Helm chart that is used in this test
    testChart = {
      inherit package;
      values = {
        runCommand = "hello";
        image = {
          repository = testImage.imageName;
          tag = testImage.imageTag;
        };
      };
    };
  in
  {
    name = "${k3s.name}-auto-deploy-helm";
    meta.maintainers = lib.teams.k3s.members;
    nodes.machine =
      { pkgs, ... }:
      {
        # k3s uses enough resources the default vm fails.
        virtualisation = {
          memorySize = 1536;
          diskSize = 4096;
        };
        environment.systemPackages = [ pkgs.yq-go ];
        services.k3s = {
          enable = true;
          package = k3s;
          # Slightly reduce resource usage
          extraFlags = [
            "--disable coredns"
            "--disable local-storage"
            "--disable metrics-server"
            "--disable servicelb"
          ];
          images = [
            # Provides the k3s Helm controller
            k3s.airgap-images
            testImage
          ];
          autoDeployCharts = {
            # regular test chart that should get installed
            hello = testChart;
            # disabled chart that should not get installed
            disabled = testChart // {
              enable = false;
            };
            # chart with values set via YAML file
            values-file = testChart // {
              # Remove unsafeDiscardStringContext workaround when Nix can convert a string to a path
              # https://github.com/NixOS/nix/issues/12407
              values =
                /.
                + builtins.unsafeDiscardStringContext (
                  builtins.toFile "k3s-test-chart-values.yaml" ''
                    runCommand: "echo 'Hello, file!'"
                    image:
                      repository: test.local/test
                      tag: local
                  ''
                );
            };
            # advanced chart that should get installed in the "test" namespace with a custom
            # timeout and overridden values
            advanced = testChart // {
              # create the "test" namespace via extraDeploy for testing
              extraDeploy = [
                {
                  apiVersion = "v1";
                  kind = "Namespace";
                  metadata.name = "test";
                }
              ];
              extraFieldDefinitions = {
                spec = {
                  # overwrite chart values
                  valuesContent = ''
                    runCommand: "echo 'advanced hello'"
                    image:
                      repository: ${testImage.imageName}
                      tag: ${testImage.imageTag}
                  '';
                  # overwrite the chart namespace
                  targetNamespace = "test";
                  # set a custom timeout
                  timeout = "69s";
                };
              };
            };
          };
        };
      };

    testScript = # python
      ''
        import json

        machine.wait_for_unit("k3s")
        # check existence/absence of chart manifest files
        machine.succeed("test -e /var/lib/rancher/k3s/server/manifests/hello.yaml")
        machine.succeed("test ! -e /var/lib/rancher/k3s/server/manifests/disabled.yaml")
        machine.succeed("test -e /var/lib/rancher/k3s/server/manifests/values-file.yaml")
        machine.succeed("test -e /var/lib/rancher/k3s/server/manifests/advanced.yaml")
        # check that the timeout is set correctly, select only the first doc in advanced.yaml
        advancedManifest = json.loads(machine.succeed("yq -o json 'select(di == 0)' /var/lib/rancher/k3s/server/manifests/advanced.yaml"))
        t.assertEqual(advancedManifest["spec"]["timeout"], "69s", "unexpected value for spec.timeout")
        # wait for test jobs to complete
        machine.wait_until_succeeds("kubectl wait --for=condition=complete job/hello", timeout=180)
        machine.wait_until_succeeds("kubectl wait --for=condition=complete job/values-file", timeout=180)
        machine.wait_until_succeeds("kubectl -n test wait --for=condition=complete job/advanced", timeout=180)
        # check output of test jobs
        hello_output = machine.succeed("kubectl logs -l batch.kubernetes.io/job-name=hello")
        values_file_output = machine.succeed("kubectl logs -l batch.kubernetes.io/job-name=values-file")
        advanced_output = machine.succeed("kubectl -n test logs -l batch.kubernetes.io/job-name=advanced")
        # strip the output to remove trailing whitespaces
        t.assertEqual(hello_output.rstrip(), "Hello, world!", "unexpected output of hello job")
        t.assertEqual(values_file_output.rstrip(), "Hello, file!", "unexpected output of values file job")
        t.assertEqual(advanced_output.rstrip(), "advanced hello", "unexpected output of advanced job")
        # wait for bundled traefik deployment
        machine.wait_until_succeeds("kubectl -n kube-system rollout status deployment traefik", timeout=180)
      '';
  }
)
