package tests

import (
	"fmt"
	"path/filepath"
	"strings"
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	v1alpha1 "github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
	actionsgithubcom "github.com/actions/actions-runner-controller/controllers/actions.github.com"
	"github.com/gruntwork-io/terratest/modules/helm"
	"github.com/gruntwork-io/terratest/modules/k8s"
	"github.com/gruntwork-io/terratest/modules/logger"
	"github.com/gruntwork-io/terratest/modules/random"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	corev1 "k8s.io/api/core/v1"
	rbacv1 "k8s.io/api/rbac/v1"
)

func TestTemplateRenderedGitHubSecretWithGitHubToken(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"})

	var githubSecret corev1.Secret
	helm.UnmarshalK8SYaml(t, output, &githubSecret)

	assert.Equal(t, namespaceName, githubSecret.Namespace)
	assert.Equal(t, "test-runners-gha-rs-github-secret", githubSecret.Name)
	assert.Equal(t, "gh_token12345", string(githubSecret.Data["github_token"]))
	assert.Equal(t, "actions.github.com/cleanup-protection", githubSecret.Finalizers[0])
}

func TestTemplateRenderedGitHubSecretWithGitHubApp(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                               "https://github.com/actions",
			"githubConfigSecret.github_app_id":              "10",
			"githubConfigSecret.github_app_installation_id": "100",
			"githubConfigSecret.github_app_private_key":     "private_key",
			"controllerServiceAccount.name":                 "arc",
			"controllerServiceAccount.namespace":            "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"})

	var githubSecret corev1.Secret
	helm.UnmarshalK8SYaml(t, output, &githubSecret)

	assert.Equal(t, namespaceName, githubSecret.Namespace)
	assert.Equal(t, "10", string(githubSecret.Data["github_app_id"]))
	assert.Equal(t, "100", string(githubSecret.Data["github_app_installation_id"]))
	assert.Equal(t, "private_key", string(githubSecret.Data["github_app_private_key"]))
}

func TestTemplateRenderedGitHubSecretErrorWithMissingAuthInput(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_app_id":   "",
			"githubConfigSecret.github_token":    "",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"})
	require.Error(t, err)

	assert.ErrorContains(t, err, "provide .Values.githubConfigSecret.github_token or .Values.githubConfigSecret.github_app_id")
}

func TestTemplateRenderedGitHubSecretErrorWithMissingAppInput(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_app_id":   "10",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"})
	require.Error(t, err)

	assert.ErrorContains(t, err, "provide .Values.githubConfigSecret.github_app_installation_id and .Values.githubConfigSecret.github_app_private_key")
}

func TestTemplateNotRenderedGitHubSecretWithPredefinedSecret(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret":                 "pre-defined-secret",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"})
	assert.ErrorContains(t, err, "could not find template templates/githubsecret.yaml in chart", "secret should not be rendered since a pre-defined secret is provided")
}

func TestTemplateRenderedSetServiceAccountToNoPermission(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/no_permission_serviceaccount.yaml"})
	var serviceAccount corev1.ServiceAccount
	helm.UnmarshalK8SYaml(t, output, &serviceAccount)

	assert.Equal(t, namespaceName, serviceAccount.Namespace)
	assert.Equal(t, "test-runners-gha-rs-no-permission", serviceAccount.Name)

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, "test-runners-gha-rs-no-permission", ars.Spec.Template.Spec.ServiceAccountName)
	assert.Empty(t, ars.Annotations[actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName]) // no finalizer protections in place
}

func TestTemplateRenderedSetServiceAccountToKubeMode(t *testing.T) {
	t.Parallel()
	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"containerMode.type":                 "kubernetes",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_serviceaccount.yaml"})
	var serviceAccount corev1.ServiceAccount
	helm.UnmarshalK8SYaml(t, output, &serviceAccount)

	assert.Equal(t, namespaceName, serviceAccount.Namespace)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", serviceAccount.Name)
	assert.Equal(t, "actions.github.com/cleanup-protection", serviceAccount.Finalizers[0])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role.yaml"})
	var role rbacv1.Role
	helm.UnmarshalK8SYaml(t, output, &role)

	assert.Equal(t, namespaceName, role.Namespace)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", role.Name)

	assert.Equal(t, "actions.github.com/cleanup-protection", role.Finalizers[0])

	assert.Len(t, role.Rules, 5, "kube mode role should have 5 rules")
	assert.Equal(t, "pods", role.Rules[0].Resources[0])
	assert.Equal(t, "pods/exec", role.Rules[1].Resources[0])
	assert.Equal(t, "pods/log", role.Rules[2].Resources[0])
	assert.Equal(t, "jobs", role.Rules[3].Resources[0])
	assert.Equal(t, "secrets", role.Rules[4].Resources[0])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role_binding.yaml"})
	var roleBinding rbacv1.RoleBinding
	helm.UnmarshalK8SYaml(t, output, &roleBinding)

	assert.Equal(t, namespaceName, roleBinding.Namespace)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", roleBinding.Name)
	assert.Len(t, roleBinding.Subjects, 1)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", roleBinding.Subjects[0].Name)
	assert.Equal(t, namespaceName, roleBinding.Subjects[0].Namespace)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", roleBinding.RoleRef.Name)
	assert.Equal(t, "Role", roleBinding.RoleRef.Kind)
	assert.Equal(t, "actions.github.com/cleanup-protection", serviceAccount.Finalizers[0])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	expectedServiceAccountName := "test-runners-gha-rs-kube-mode"
	assert.Equal(t, expectedServiceAccountName, ars.Spec.Template.Spec.ServiceAccountName)
	assert.Equal(t, expectedServiceAccountName, ars.Annotations[actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName])
}

func TestTemplateRenderedSetServiceAccountToKubeNoVolumeMode(t *testing.T) {
	t.Parallel()
	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"containerMode.type":                 "kubernetes-novolume",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_serviceaccount.yaml"})
	var serviceAccount corev1.ServiceAccount
	helm.UnmarshalK8SYaml(t, output, &serviceAccount)

	assert.Equal(t, namespaceName, serviceAccount.Namespace)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", serviceAccount.Name)
	assert.Equal(t, "actions.github.com/cleanup-protection", serviceAccount.Finalizers[0])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role.yaml"})
	var role rbacv1.Role
	helm.UnmarshalK8SYaml(t, output, &role)

	assert.Equal(t, namespaceName, role.Namespace)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", role.Name)

	assert.Equal(t, "actions.github.com/cleanup-protection", role.Finalizers[0])

	assert.Len(t, role.Rules, 4, "kube mode role should have 4 rules")
	assert.Equal(t, "pods", role.Rules[0].Resources[0])
	assert.Equal(t, "pods/exec", role.Rules[1].Resources[0])
	assert.Equal(t, "pods/log", role.Rules[2].Resources[0])
	assert.Equal(t, "secrets", role.Rules[3].Resources[0])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role_binding.yaml"})
	var roleBinding rbacv1.RoleBinding
	helm.UnmarshalK8SYaml(t, output, &roleBinding)

	assert.Equal(t, namespaceName, roleBinding.Namespace)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", roleBinding.Name)
	assert.Len(t, roleBinding.Subjects, 1)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", roleBinding.Subjects[0].Name)
	assert.Equal(t, namespaceName, roleBinding.Subjects[0].Namespace)
	assert.Equal(t, "test-runners-gha-rs-kube-mode", roleBinding.RoleRef.Name)
	assert.Equal(t, "Role", roleBinding.RoleRef.Kind)
	assert.Equal(t, "actions.github.com/cleanup-protection", serviceAccount.Finalizers[0])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	expectedServiceAccountName := "test-runners-gha-rs-kube-mode"
	assert.Equal(t, expectedServiceAccountName, ars.Spec.Template.Spec.ServiceAccountName)
	assert.Equal(t, expectedServiceAccountName, ars.Annotations[actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName])
}

func TestTemplateRenderedUserProvideSetServiceAccount(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"template.spec.serviceAccountName":   "test-service-account",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/no_permission_serviceaccount.yaml"})
	assert.ErrorContains(t, err, "could not find template templates/no_permission_serviceaccount.yaml in chart", "no permission service account should not be rendered")

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, "test-service-account", ars.Spec.Template.Spec.ServiceAccountName)
	assert.Empty(t, ars.Annotations[actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName])
}

func TestTemplateRenderedAutoScalingRunnerSet(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, namespaceName, ars.Namespace)
	assert.Equal(t, "test-runners", ars.Name)

	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/name"])
	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/instance"])
	assert.Equal(t, "gha-rs", ars.Labels["app.kubernetes.io/part-of"])
	assert.Equal(t, "autoscaling-runner-set", ars.Labels["app.kubernetes.io/component"])
	assert.NotEmpty(t, ars.Labels["app.kubernetes.io/version"])

	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl)
	assert.Equal(t, "test-runners-gha-rs-github-secret", ars.Spec.GitHubConfigSecret)

	assert.Empty(t, ars.Spec.RunnerGroup, "RunnerGroup should be empty")

	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil")
	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil")
	assert.Nil(t, ars.Spec.Proxy, "Proxy should be nil")
	assert.Nil(t, ars.Spec.GitHubServerTLS, "GitHubServerTLS should be nil")

	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil")

	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "Template.Spec should have 1 container")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name)
	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image)
}

func TestTemplateRenderedAutoScalingRunnerSet_RunnerScaleSetName(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	nameOverride := "test-runner-scale-set-name"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"runnerScaleSetName":                 nameOverride,
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, namespaceName, ars.Namespace)
	assert.Equal(t, nameOverride, ars.Name)

	assert.Equal(t, nameOverride, ars.Labels["app.kubernetes.io/name"])
	assert.Equal(t, nameOverride, ars.Labels["app.kubernetes.io/instance"])
	assert.Equal(t, nameOverride, ars.Labels["actions.github.com/scale-set-name"])
	assert.Equal(t, namespaceName, ars.Labels["actions.github.com/scale-set-namespace"])
	assert.Equal(t, "gha-rs", ars.Labels["app.kubernetes.io/part-of"])
	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl)
	assert.Equal(t, nameOverride+"-gha-rs-github-secret", ars.Spec.GitHubConfigSecret)
	assert.Equal(t, "test-runner-scale-set-name", ars.Spec.RunnerScaleSetName)

	assert.Empty(t, ars.Spec.RunnerGroup, "RunnerGroup should be empty")

	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil")
	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil")
	assert.Nil(t, ars.Spec.Proxy, "Proxy should be nil")
	assert.Nil(t, ars.Spec.GitHubServerTLS, "GitHubServerTLS should be nil")

	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil")

	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "Template.Spec should have 1 container")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name)
	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image)
}

func TestTemplateRenderedAutoScalingRunnerSet_ProvideMetadata(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                     "https://github.com/actions",
			"githubConfigSecret.github_token":     "gh_token12345",
			"template.metadata.labels.test1":      "test1",
			"template.metadata.labels.test2":      "test2",
			"template.metadata.annotations.test3": "test3",
			"template.metadata.annotations.test4": "test4",
			"controllerServiceAccount.name":       "arc",
			"controllerServiceAccount.namespace":  "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, namespaceName, ars.Namespace)
	assert.Equal(t, "test-runners", ars.Name)

	assert.NotNil(t, ars.Spec.Template.Labels, "Template.Spec.Labels should not be nil")
	assert.Equal(t, "test1", ars.Spec.Template.Labels["test1"], "Template.Spec.Labels should have test1")
	assert.Equal(t, "test2", ars.Spec.Template.Labels["test2"], "Template.Spec.Labels should have test2")

	assert.NotNil(t, ars.Spec.Template.Annotations, "Template.Spec.Annotations should not be nil")
	assert.Equal(t, "test3", ars.Spec.Template.Annotations["test3"], "Template.Spec.Annotations should have test3")
	assert.Equal(t, "test4", ars.Spec.Template.Annotations["test4"], "Template.Spec.Annotations should have test4")

	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil")

	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "Template.Spec should have 1 container")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name)
	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image)
}

func TestTemplateRenderedAutoScalingRunnerSet_MaxRunnersValidationError(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"maxRunners":                         "-1",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	require.Error(t, err)

	assert.ErrorContains(t, err, "maxRunners has to be greater or equal to 0")
}

func TestTemplateRenderedAutoScalingRunnerSet_MinRunnersValidationError(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"maxRunners":                         "1",
			"minRunners":                         "-1",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	require.Error(t, err)

	assert.ErrorContains(t, err, "minRunners has to be greater or equal to 0")
}

func TestTemplateRenderedAutoScalingRunnerSet_MinMaxRunnersValidationError(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"maxRunners":                         "0",
			"minRunners":                         "1",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	require.Error(t, err)

	assert.ErrorContains(t, err, "maxRunners has to be greater or equal to minRunners")
}

func TestTemplateRenderedAutoScalingRunnerSet_MinMaxRunnersValidationSameValue(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"maxRunners":                         "0",
			"minRunners":                         "0",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, 0, *ars.Spec.MinRunners, "MinRunners should be 0")
	assert.Equal(t, 0, *ars.Spec.MaxRunners, "MaxRunners should be 0")
}

func TestTemplateRenderedAutoScalingRunnerSet_MinMaxRunnersValidation_OnlyMin(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"minRunners":                         "5",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, 5, *ars.Spec.MinRunners, "MinRunners should be 5")
	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil")
}

func TestTemplateRenderedAutoScalingRunnerSet_MinMaxRunnersValidation_OnlyMax(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"maxRunners":                         "5",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, 5, *ars.Spec.MaxRunners, "MaxRunners should be 5")
	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil")
}

func TestTemplateRenderedAutoScalingRunnerSet_MinMaxRunners_FromValuesFile(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger:         logger.Discard,
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, 5, *ars.Spec.MinRunners, "MinRunners should be 5")
	assert.Equal(t, 10, *ars.Spec.MaxRunners, "MaxRunners should be 10")
}

func TestTemplateRenderedAutoScalingRunnerSet_ExtraVolumes(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values_extra_volumes.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Len(t, ars.Spec.Template.Spec.Volumes, 3, "Volumes should be 3")
	assert.Equal(t, "foo", ars.Spec.Template.Spec.Volumes[0].Name, "Volume name should be foo")
	assert.Equal(t, "bar", ars.Spec.Template.Spec.Volumes[1].Name, "Volume name should be bar")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Volumes[2].Name, "Volume name should be work")
	assert.Equal(t, "/data", ars.Spec.Template.Spec.Volumes[2].HostPath.Path, "Volume host path should be /data")
}

func TestTemplateRenderedAutoScalingRunnerSet_DinD_ExtraInitContainers(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values_dind_extra_init_containers.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Len(t, ars.Spec.Template.Spec.InitContainers, 4, "InitContainers should be 4")
	assert.Equal(t, "kube-init", ars.Spec.Template.Spec.InitContainers[2].Name, "InitContainers[1] Name should be kube-init")
	assert.Equal(t, "runner-image:latest", ars.Spec.Template.Spec.InitContainers[2].Image, "InitContainers[1] Image should be runner-image:latest")
	assert.Equal(t, "sudo", ars.Spec.Template.Spec.InitContainers[2].Command[0], "InitContainers[1] Command[0] should be sudo")
	assert.Equal(t, "chown", ars.Spec.Template.Spec.InitContainers[2].Command[1], "InitContainers[1] Command[1] should be chown")
	assert.Equal(t, "-R", ars.Spec.Template.Spec.InitContainers[2].Command[2], "InitContainers[1] Command[2] should be -R")
	assert.Equal(t, "1001:123", ars.Spec.Template.Spec.InitContainers[2].Command[3], "InitContainers[1] Command[3] should be 1001:123")
	assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.InitContainers[2].Command[4], "InitContainers[1] Command[4] should be /home/runner/_work")
	assert.Equal(t, "work", ars.Spec.Template.Spec.InitContainers[2].VolumeMounts[0].Name, "InitContainers[1] VolumeMounts[0] Name should be work")
	assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.InitContainers[2].VolumeMounts[0].MountPath, "InitContainers[1] VolumeMounts[0] MountPath should be /home/runner/_work")

	assert.Equal(t, "ls", ars.Spec.Template.Spec.InitContainers[3].Name, "InitContainers[2] Name should be ls")
	assert.Equal(t, "ubuntu:latest", ars.Spec.Template.Spec.InitContainers[3].Image, "InitContainers[2] Image should be ubuntu:latest")
	assert.Equal(t, "ls", ars.Spec.Template.Spec.InitContainers[3].Command[0], "InitContainers[2] Command[0] should be ls")
}

func TestTemplateRenderedAutoScalingRunnerSet_DinD_ExtraVolumes(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values_dind_extra_volumes.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Len(t, ars.Spec.Template.Spec.Volumes, 5, "Volumes should be 5")
	assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.Volumes[0].Name, "Volume name should be dind-sock")
	assert.Equal(t, "dind-externals", ars.Spec.Template.Spec.Volumes[1].Name, "Volume name should be dind-externals")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Volumes[2].Name, "Volume name should be work")
	assert.Equal(t, "/data", ars.Spec.Template.Spec.Volumes[2].HostPath.Path, "Volume host path should be /data")
	assert.Equal(t, "foo", ars.Spec.Template.Spec.Volumes[3].Name, "Volume name should be foo")
	assert.Equal(t, "bar", ars.Spec.Template.Spec.Volumes[4].Name, "Volume name should be bar")
}

func TestTemplateRenderedAutoScalingRunnerSet_K8S_ExtraVolumes(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values_k8s_extra_volumes.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Len(t, ars.Spec.Template.Spec.Volumes, 3, "Volumes should be 3")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Volumes[0].Name, "Volume name should be work")
	assert.Equal(t, "/data", ars.Spec.Template.Spec.Volumes[0].HostPath.Path, "Volume host path should be /data")
	assert.Equal(t, "foo", ars.Spec.Template.Spec.Volumes[1].Name, "Volume name should be foo")
	assert.Equal(t, "bar", ars.Spec.Template.Spec.Volumes[2].Name, "Volume name should be bar")
}

func TestTemplateRenderedAutoScalingRunnerSet_EnableDinD(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"containerMode.type":                 "dind",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, namespaceName, ars.Namespace)
	assert.Equal(t, "test-runners", ars.Name)

	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/name"])
	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/instance"])
	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl)
	assert.Equal(t, "test-runners-gha-rs-github-secret", ars.Spec.GitHubConfigSecret)

	assert.Empty(t, ars.Spec.RunnerGroup, "RunnerGroup should be empty")

	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil")
	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil")
	assert.Nil(t, ars.Spec.Proxy, "Proxy should be nil")
	assert.Nil(t, ars.Spec.GitHubServerTLS, "GitHubServerTLS should be nil")

	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil")

	assert.Len(t, ars.Spec.Template.Spec.InitContainers, 2, "Template.Spec should have 2 init container")
	assert.Equal(t, "init-dind-externals", ars.Spec.Template.Spec.InitContainers[0].Name)
	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.InitContainers[0].Image)
	assert.Equal(t, "cp", ars.Spec.Template.Spec.InitContainers[0].Command[0])
	assert.Equal(t, "-r /home/runner/externals/. /home/runner/tmpDir/", strings.Join(ars.Spec.Template.Spec.InitContainers[0].Args, " "))

	assert.Equal(t, "dind", ars.Spec.Template.Spec.InitContainers[1].Name)
	assert.Equal(t, "docker:dind", ars.Spec.Template.Spec.InitContainers[1].Image)
	assert.True(t, *ars.Spec.Template.Spec.InitContainers[1].SecurityContext.Privileged)
	assert.Len(t, ars.Spec.Template.Spec.InitContainers[1].VolumeMounts, 3, "The dind container should have 3 volume mounts, dind-sock, work and externals")
	assert.Equal(t, "work", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[0].Name)
	assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[0].MountPath)

	assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[1].Name)
	assert.Equal(t, "/var/run", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[1].MountPath)

	assert.Equal(t, "dind-externals", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[2].Name)
	assert.Equal(t, "/home/runner/externals", ars.Spec.Template.Spec.InitContainers[1].VolumeMounts[2].MountPath)

	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "Template.Spec should have 1 container")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name)
	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image)
	assert.Len(t, ars.Spec.Template.Spec.Containers[0].Env, 2, "The runner container should have 2 env vars, DOCKER_HOST and RUNNER_WAIT_FOR_DOCKER_IN_SECONDS")
	assert.Equal(t, "DOCKER_HOST", ars.Spec.Template.Spec.Containers[0].Env[0].Name)
	assert.Equal(t, "unix:///var/run/docker.sock", ars.Spec.Template.Spec.Containers[0].Env[0].Value)
	assert.Equal(t, "RUNNER_WAIT_FOR_DOCKER_IN_SECONDS", ars.Spec.Template.Spec.Containers[0].Env[1].Name)
	assert.Equal(t, "120", ars.Spec.Template.Spec.Containers[0].Env[1].Value)

	assert.Len(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, 2, "The runner container should have 2 volume mounts, dind-sock and work")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name)
	assert.Equal(t, "/home/runner/_work", ars.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath)
	assert.False(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts[0].ReadOnly)

	assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].Name)
	assert.Equal(t, "/var/run", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].MountPath)

	assert.Len(t, ars.Spec.Template.Spec.Volumes, 3, "Volumes should be 3")
	assert.Equal(t, "dind-sock", ars.Spec.Template.Spec.Volumes[0].Name, "Volume name should be dind-sock")
	assert.Equal(t, "dind-externals", ars.Spec.Template.Spec.Volumes[1].Name, "Volume name should be dind-externals")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Volumes[2].Name, "Volume name should be work")
	assert.NotNil(t, ars.Spec.Template.Spec.Volumes[2].EmptyDir, "Volume work should be an emptyDir")
}

func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesMode(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"containerMode.type":                 "kubernetes",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, namespaceName, ars.Namespace)
	assert.Equal(t, "test-runners", ars.Name)

	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/name"])
	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/instance"])
	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl)
	assert.Equal(t, "test-runners-gha-rs-github-secret", ars.Spec.GitHubConfigSecret)

	assert.Empty(t, ars.Spec.RunnerGroup, "RunnerGroup should be empty")
	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil")
	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil")
	assert.Nil(t, ars.Spec.Proxy, "Proxy should be nil")
	assert.Nil(t, ars.Spec.GitHubServerTLS, "GitHubServerTLS should be nil")

	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil")

	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "Template.Spec should have 1 container")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name)
	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image)

	assert.Equal(t, "ACTIONS_RUNNER_CONTAINER_HOOKS", ars.Spec.Template.Spec.Containers[0].Env[0].Name)
	assert.Equal(t, "/home/runner/k8s/index.js", ars.Spec.Template.Spec.Containers[0].Env[0].Value)
	assert.Equal(t, "ACTIONS_RUNNER_POD_NAME", ars.Spec.Template.Spec.Containers[0].Env[1].Name)
	assert.Equal(t, "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER", ars.Spec.Template.Spec.Containers[0].Env[2].Name)
	assert.Equal(t, "true", ars.Spec.Template.Spec.Containers[0].Env[2].Value)

	assert.Len(t, ars.Spec.Template.Spec.Volumes, 1, "Template.Spec should have 1 volume")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Volumes[0].Name)
	assert.NotNil(t, ars.Spec.Template.Spec.Volumes[0].Ephemeral, "Template.Spec should have 1 ephemeral volume")
}

func TestTemplateRenderedAutoScalingRunnerSet_EnableKubernetesModeNoVolume(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"containerMode.type":                 "kubernetes-novolume",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, namespaceName, ars.Namespace)
	assert.Equal(t, "test-runners", ars.Name)

	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/name"])
	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/instance"])
	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl)
	assert.Equal(t, "test-runners-gha-rs-github-secret", ars.Spec.GitHubConfigSecret)

	assert.Empty(t, ars.Spec.RunnerGroup, "RunnerGroup should be empty")
	assert.Nil(t, ars.Spec.MinRunners, "MinRunners should be nil")
	assert.Nil(t, ars.Spec.MaxRunners, "MaxRunners should be nil")
	assert.Nil(t, ars.Spec.Proxy, "Proxy should be nil")
	assert.Nil(t, ars.Spec.GitHubServerTLS, "GitHubServerTLS should be nil")

	assert.NotNil(t, ars.Spec.Template.Spec, "Template.Spec should not be nil")

	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "Template.Spec should have 1 container")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name)
	assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image)

	require.Len(t, ars.Spec.Template.Spec.Containers[0].Env, 4, "The runner container should have 4 env vars")
	assert.Equal(t, "ACTIONS_RUNNER_CONTAINER_HOOKS", ars.Spec.Template.Spec.Containers[0].Env[0].Name)
	assert.Equal(t, "/home/runner/k8s-novolume/index.js", ars.Spec.Template.Spec.Containers[0].Env[0].Value)
	assert.Equal(t, "ACTIONS_RUNNER_POD_NAME", ars.Spec.Template.Spec.Containers[0].Env[1].Name)
	assert.Equal(t, "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER", ars.Spec.Template.Spec.Containers[0].Env[2].Name)
	assert.Equal(t, "true", ars.Spec.Template.Spec.Containers[0].Env[2].Value)
	assert.Equal(t, "ACTIONS_RUNNER_IMAGE", ars.Spec.Template.Spec.Containers[0].Env[3].Name)
	assert.Equal(t, ars.Spec.Template.Spec.Containers[0].Image, ars.Spec.Template.Spec.Containers[0].Env[3].Value)

	assert.Len(t, ars.Spec.Template.Spec.Volumes, 0, "Template.Spec should have 0 volumes")
}

func TestTemplateRenderedAutoscalingRunnerSet_ListenerPodTemplate(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values_listener_template.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	require.NotNil(t, ars.Spec.ListenerTemplate, "ListenerPodTemplate should not be nil")

	assert.Equal(t, ars.Spec.ListenerTemplate.Spec.Hostname, "example")

	require.Len(t, ars.Spec.ListenerTemplate.Spec.Containers, 2, "ListenerPodTemplate should have 2 containers")
	assert.Equal(t, ars.Spec.ListenerTemplate.Spec.Containers[0].Name, "listener")
	assert.Equal(t, ars.Spec.ListenerTemplate.Spec.Containers[0].Image, "listener:latest")
	assert.ElementsMatch(t, ars.Spec.ListenerTemplate.Spec.Containers[0].Command, []string{"/path/to/entrypoint"})
	assert.Len(t, ars.Spec.ListenerTemplate.Spec.Containers[0].VolumeMounts, 1, "VolumeMounts should be 1")
	assert.Equal(t, ars.Spec.ListenerTemplate.Spec.Containers[0].VolumeMounts[0].Name, "work")
	assert.Equal(t, ars.Spec.ListenerTemplate.Spec.Containers[0].VolumeMounts[0].MountPath, "/home/example")

	assert.Equal(t, ars.Spec.ListenerTemplate.Spec.Containers[1].Name, "side-car")
	assert.Equal(t, ars.Spec.ListenerTemplate.Spec.Containers[1].Image, "nginx:latest")
}

func TestTemplateRenderedAutoScalingRunnerSet_UsePredefinedSecret(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret":                 "pre-defined-secrets",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, namespaceName, ars.Namespace)
	assert.Equal(t, "test-runners", ars.Name)

	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/name"])
	assert.Equal(t, "test-runners", ars.Labels["app.kubernetes.io/instance"])
	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl)
	assert.Equal(t, "pre-defined-secrets", ars.Spec.GitHubConfigSecret)
}

func TestTemplateRenderedAutoScalingRunnerSet_ErrorOnEmptyPredefinedSecret(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret":                 "",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	_, err = helm.RenderTemplateE(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	require.Error(t, err)

	assert.ErrorContains(t, err, "Values.githubConfigSecret is required for setting auth with GitHub server")
}

func TestTemplateRenderedWithProxy(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret":                 "pre-defined-secrets",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
			"proxy.http.url":                     "http://proxy.example.com",
			"proxy.http.credentialSecretRef":     "http-secret",
			"proxy.https.url":                    "https://proxy.example.com",
			"proxy.https.credentialSecretRef":    "https-secret",
			"proxy.noProxy":                      "{example.com,example.org}",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	require.NotNil(t, ars.Spec.Proxy)
	require.NotNil(t, ars.Spec.Proxy.HTTP)
	assert.Equal(t, "http://proxy.example.com", ars.Spec.Proxy.HTTP.Url)
	assert.Equal(t, "http-secret", ars.Spec.Proxy.HTTP.CredentialSecretRef)

	require.NotNil(t, ars.Spec.Proxy.HTTPS)
	assert.Equal(t, "https://proxy.example.com", ars.Spec.Proxy.HTTPS.Url)
	assert.Equal(t, "https-secret", ars.Spec.Proxy.HTTPS.CredentialSecretRef)

	require.NotNil(t, ars.Spec.Proxy.NoProxy)
	require.Len(t, ars.Spec.Proxy.NoProxy, 2)
	assert.Contains(t, ars.Spec.Proxy.NoProxy, "example.com")
	assert.Contains(t, ars.Spec.Proxy.NoProxy, "example.org")
}

func TestTemplateRenderedWithTLS(t *testing.T) {
	t.Parallel()

	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	render := func(t *testing.T, options *helm.Options) v1alpha1.AutoscalingRunnerSet {
		// Path to the helm chart we will test
		helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
		require.NoError(t, err)

		releaseName := "test-runners"

		output := helm.RenderTemplate(
			t,
			options,
			helmChartPath,
			releaseName,
			[]string{"templates/autoscalingrunnerset.yaml"},
		)

		var ars v1alpha1.AutoscalingRunnerSet
		helm.UnmarshalK8SYaml(t, output, &ars)

		return ars
	}

	t.Run("providing githubServerTLS.runnerMountPath", func(t *testing.T) {
		t.Run("mode default", func(t *testing.T) {
			options := &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"githubConfigUrl":    "https://github.com/actions",
					"githubConfigSecret": "pre-defined-secrets",
					"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
					"githubServerTLS.certificateFrom.configMapKeyRef.key":  "cert.pem",
					"githubServerTLS.runnerMountPath":                      "/runner/mount/path",
					"controllerServiceAccount.name":                        "arc",
					"controllerServiceAccount.namespace":                   "arc-system",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
			}

			ars := render(t, options)

			require.NotNil(t, ars.Spec.GitHubServerTLS)
			expected := &v1alpha1.TLSConfig{
				CertificateFrom: &v1alpha1.TLSCertificateSource{
					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
						LocalObjectReference: corev1.LocalObjectReference{
							Name: "certs-configmap",
						},
						Key: "cert.pem",
					},
				},
			}
			assert.Equal(t, expected, ars.Spec.GitHubServerTLS)

			var volume *corev1.Volume
			for _, v := range ars.Spec.Template.Spec.Volumes {
				if v.Name == "github-server-tls-cert" {
					volume = &v
					break
				}
			}
			require.NotNil(t, volume)
			assert.Equal(t, "certs-configmap", volume.ConfigMap.Name)
			assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Key)
			assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Path)

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
				Name:      "github-server-tls-cert",
				MountPath: "/runner/mount/path/cert.pem",
				SubPath:   "cert.pem",
			})

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "NODE_EXTRA_CA_CERTS",
				Value: "/runner/mount/path/cert.pem",
			})

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "RUNNER_UPDATE_CA_CERTS",
				Value: "1",
			})
		})

		t.Run("mode dind", func(t *testing.T) {
			options := &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"githubConfigUrl":    "https://github.com/actions",
					"githubConfigSecret": "pre-defined-secrets",
					"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
					"githubServerTLS.certificateFrom.configMapKeyRef.key":  "cert.pem",
					"githubServerTLS.runnerMountPath":                      "/runner/mount/path/",
					"containerMode.type":                                   "dind",
					"controllerServiceAccount.name":                        "arc",
					"controllerServiceAccount.namespace":                   "arc-system",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
			}

			ars := render(t, options)

			require.NotNil(t, ars.Spec.GitHubServerTLS)
			expected := &v1alpha1.TLSConfig{
				CertificateFrom: &v1alpha1.TLSCertificateSource{
					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
						LocalObjectReference: corev1.LocalObjectReference{
							Name: "certs-configmap",
						},
						Key: "cert.pem",
					},
				},
			}
			assert.Equal(t, expected, ars.Spec.GitHubServerTLS)

			var volume *corev1.Volume
			for _, v := range ars.Spec.Template.Spec.Volumes {
				if v.Name == "github-server-tls-cert" {
					volume = &v
					break
				}
			}
			require.NotNil(t, volume)
			assert.Equal(t, "certs-configmap", volume.ConfigMap.Name)
			assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Key)
			assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Path)

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
				Name:      "github-server-tls-cert",
				MountPath: "/runner/mount/path/cert.pem",
				SubPath:   "cert.pem",
			})

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "NODE_EXTRA_CA_CERTS",
				Value: "/runner/mount/path/cert.pem",
			})

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "RUNNER_UPDATE_CA_CERTS",
				Value: "1",
			})
		})

		t.Run("mode kubernetes", func(t *testing.T) {
			options := &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"githubConfigUrl":    "https://github.com/actions",
					"githubConfigSecret": "pre-defined-secrets",
					"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
					"githubServerTLS.certificateFrom.configMapKeyRef.key":  "cert.pem",
					"githubServerTLS.runnerMountPath":                      "/runner/mount/path",
					"containerMode.type":                                   "kubernetes",
					"controllerServiceAccount.name":                        "arc",
					"controllerServiceAccount.namespace":                   "arc-system",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
			}

			ars := render(t, options)

			require.NotNil(t, ars.Spec.GitHubServerTLS)
			expected := &v1alpha1.TLSConfig{
				CertificateFrom: &v1alpha1.TLSCertificateSource{
					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
						LocalObjectReference: corev1.LocalObjectReference{
							Name: "certs-configmap",
						},
						Key: "cert.pem",
					},
				},
			}
			assert.Equal(t, expected, ars.Spec.GitHubServerTLS)

			var volume *corev1.Volume
			for _, v := range ars.Spec.Template.Spec.Volumes {
				if v.Name == "github-server-tls-cert" {
					volume = &v
					break
				}
			}
			require.NotNil(t, volume)
			assert.Equal(t, "certs-configmap", volume.ConfigMap.Name)
			assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Key)
			assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Path)

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
				Name:      "github-server-tls-cert",
				MountPath: "/runner/mount/path/cert.pem",
				SubPath:   "cert.pem",
			})

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "NODE_EXTRA_CA_CERTS",
				Value: "/runner/mount/path/cert.pem",
			})

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "RUNNER_UPDATE_CA_CERTS",
				Value: "1",
			})
		})

		t.Run("mode kubernetes-novolume", func(t *testing.T) {
			options := &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"githubConfigUrl":    "https://github.com/actions",
					"githubConfigSecret": "pre-defined-secrets",
					"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
					"githubServerTLS.certificateFrom.configMapKeyRef.key":  "cert.pem",
					"githubServerTLS.runnerMountPath":                      "/runner/mount/path",
					"containerMode.type":                                   "kubernetes-novolume",
					"controllerServiceAccount.name":                        "arc",
					"controllerServiceAccount.namespace":                   "arc-system",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
			}

			ars := render(t, options)

			require.NotNil(t, ars.Spec.GitHubServerTLS)
			expected := &v1alpha1.TLSConfig{
				CertificateFrom: &v1alpha1.TLSCertificateSource{
					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
						LocalObjectReference: corev1.LocalObjectReference{
							Name: "certs-configmap",
						},
						Key: "cert.pem",
					},
				},
			}
			assert.Equal(t, expected, ars.Spec.GitHubServerTLS)

			var volume *corev1.Volume
			for _, v := range ars.Spec.Template.Spec.Volumes {
				if v.Name == "github-server-tls-cert" {
					volume = &v
					break
				}
			}
			require.NotNil(t, volume)
			assert.Equal(t, "certs-configmap", volume.ConfigMap.Name)
			assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Key)
			assert.Equal(t, "cert.pem", volume.ConfigMap.Items[0].Path)

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
				Name:      "github-server-tls-cert",
				MountPath: "/runner/mount/path/cert.pem",
				SubPath:   "cert.pem",
			})

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "NODE_EXTRA_CA_CERTS",
				Value: "/runner/mount/path/cert.pem",
			})

			assert.Contains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "RUNNER_UPDATE_CA_CERTS",
				Value: "1",
			})
		})
	})

	t.Run("without providing githubServerTLS.runnerMountPath", func(t *testing.T) {
		t.Run("mode default", func(t *testing.T) {
			options := &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"githubConfigUrl":    "https://github.com/actions",
					"githubConfigSecret": "pre-defined-secrets",
					"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
					"githubServerTLS.certificateFrom.configMapKeyRef.key":  "cert.pem",
					"controllerServiceAccount.name":                        "arc",
					"controllerServiceAccount.namespace":                   "arc-system",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
			}

			ars := render(t, options)

			require.NotNil(t, ars.Spec.GitHubServerTLS)
			expected := &v1alpha1.TLSConfig{
				CertificateFrom: &v1alpha1.TLSCertificateSource{
					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
						LocalObjectReference: corev1.LocalObjectReference{
							Name: "certs-configmap",
						},
						Key: "cert.pem",
					},
				},
			}
			assert.Equal(t, expected, ars.Spec.GitHubServerTLS)

			var volume *corev1.Volume
			for _, v := range ars.Spec.Template.Spec.Volumes {
				if v.Name == "github-server-tls-cert" {
					volume = &v
					break
				}
			}
			assert.Nil(t, volume)

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
				Name:      "github-server-tls-cert",
				MountPath: "/runner/mount/path/cert.pem",
				SubPath:   "cert.pem",
			})

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "NODE_EXTRA_CA_CERTS",
				Value: "/runner/mount/path/cert.pem",
			})

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "RUNNER_UPDATE_CA_CERTS",
				Value: "1",
			})
		})

		t.Run("mode dind", func(t *testing.T) {
			options := &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"githubConfigUrl":    "https://github.com/actions",
					"githubConfigSecret": "pre-defined-secrets",
					"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
					"githubServerTLS.certificateFrom.configMapKeyRef.key":  "cert.pem",
					"containerMode.type":                 "dind",
					"controllerServiceAccount.name":      "arc",
					"controllerServiceAccount.namespace": "arc-system",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
			}

			ars := render(t, options)

			require.NotNil(t, ars.Spec.GitHubServerTLS)
			expected := &v1alpha1.TLSConfig{
				CertificateFrom: &v1alpha1.TLSCertificateSource{
					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
						LocalObjectReference: corev1.LocalObjectReference{
							Name: "certs-configmap",
						},
						Key: "cert.pem",
					},
				},
			}
			assert.Equal(t, expected, ars.Spec.GitHubServerTLS)

			var volume *corev1.Volume
			for _, v := range ars.Spec.Template.Spec.Volumes {
				if v.Name == "github-server-tls-cert" {
					volume = &v
					break
				}
			}
			assert.Nil(t, volume)

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
				Name:      "github-server-tls-cert",
				MountPath: "/runner/mount/path/cert.pem",
				SubPath:   "cert.pem",
			})

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "NODE_EXTRA_CA_CERTS",
				Value: "/runner/mount/path/cert.pem",
			})

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "RUNNER_UPDATE_CA_CERTS",
				Value: "1",
			})
		})

		t.Run("mode kubernetes", func(t *testing.T) {
			options := &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"githubConfigUrl":    "https://github.com/actions",
					"githubConfigSecret": "pre-defined-secrets",
					"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
					"githubServerTLS.certificateFrom.configMapKeyRef.key":  "cert.pem",
					"containerMode.type":                 "kubernetes",
					"controllerServiceAccount.name":      "arc",
					"controllerServiceAccount.namespace": "arc-system",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
			}

			ars := render(t, options)

			require.NotNil(t, ars.Spec.GitHubServerTLS)
			expected := &v1alpha1.TLSConfig{
				CertificateFrom: &v1alpha1.TLSCertificateSource{
					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
						LocalObjectReference: corev1.LocalObjectReference{
							Name: "certs-configmap",
						},
						Key: "cert.pem",
					},
				},
			}
			assert.Equal(t, expected, ars.Spec.GitHubServerTLS)

			var volume *corev1.Volume
			for _, v := range ars.Spec.Template.Spec.Volumes {
				if v.Name == "github-server-tls-cert" {
					volume = &v
					break
				}
			}
			assert.Nil(t, volume)

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
				Name:      "github-server-tls-cert",
				MountPath: "/runner/mount/path/cert.pem",
				SubPath:   "cert.pem",
			})

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "NODE_EXTRA_CA_CERTS",
				Value: "/runner/mount/path/cert.pem",
			})

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "RUNNER_UPDATE_CA_CERTS",
				Value: "1",
			})
		})

		t.Run("mode kubernetes-novolume", func(t *testing.T) {
			options := &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"githubConfigUrl":    "https://github.com/actions",
					"githubConfigSecret": "pre-defined-secrets",
					"githubServerTLS.certificateFrom.configMapKeyRef.name": "certs-configmap",
					"githubServerTLS.certificateFrom.configMapKeyRef.key":  "cert.pem",
					"containerMode.type":                 "kubernetes-novolume",
					"controllerServiceAccount.name":      "arc",
					"controllerServiceAccount.namespace": "arc-system",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
			}

			ars := render(t, options)

			require.NotNil(t, ars.Spec.GitHubServerTLS)
			expected := &v1alpha1.TLSConfig{
				CertificateFrom: &v1alpha1.TLSCertificateSource{
					ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
						LocalObjectReference: corev1.LocalObjectReference{
							Name: "certs-configmap",
						},
						Key: "cert.pem",
					},
				},
			}
			assert.Equal(t, expected, ars.Spec.GitHubServerTLS)

			var volume *corev1.Volume
			for _, v := range ars.Spec.Template.Spec.Volumes {
				if v.Name == "github-server-tls-cert" {
					volume = &v
					break
				}
			}
			assert.Nil(t, volume)

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
				Name:      "github-server-tls-cert",
				MountPath: "/runner/mount/path/cert.pem",
				SubPath:   "cert.pem",
			})

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "NODE_EXTRA_CA_CERTS",
				Value: "/runner/mount/path/cert.pem",
			})

			assert.NotContains(t, ars.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
				Name:  "RUNNER_UPDATE_CA_CERTS",
				Value: "1",
			})
		})
	})
}

func TestTemplateNamingConstraints(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	setValues := map[string]string{
		"githubConfigUrl":                    "https://github.com/actions",
		"githubConfigSecret":                 "",
		"controllerServiceAccount.name":      "arc",
		"controllerServiceAccount.namespace": "arc-system",
	}

	tt := map[string]struct {
		releaseName   string
		namespaceName string
		expectedError string
	}{
		"Name too long": {
			releaseName:   strings.Repeat("a", 46),
			namespaceName: "test-" + strings.ToLower(random.UniqueId()),
			expectedError: "Name must have up to 45 characters",
		},
		"Namespace too long": {
			releaseName:   "test-" + strings.ToLower(random.UniqueId()),
			namespaceName: strings.Repeat("a", 64),
			expectedError: "Namespace must have up to 63 characters",
		},
	}

	for name, tc := range tt {
		t.Run(name, func(t *testing.T) {
			options := &helm.Options{
				Logger:         logger.Discard,
				SetValues:      setValues,
				KubectlOptions: k8s.NewKubectlOptions("", "", tc.namespaceName),
			}
			_, err = helm.RenderTemplateE(t, options, helmChartPath, tc.releaseName, []string{"templates/autoscalingrunnerset.yaml"})
			require.Error(t, err)
			assert.ErrorContains(t, err, tc.expectedError)
		})
	}
}

func TestTemplateRenderedGitHubConfigUrlEndsWIthSlash(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions/",
			"githubConfigSecret.github_token":    "gh_token12345",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, namespaceName, ars.Namespace)
	assert.Equal(t, "test-runners", ars.Name)
	assert.Equal(t, "https://github.com/actions", ars.Spec.GitHubConfigUrl)
}

func TestTemplate_CreateManagerRole(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/manager_role.yaml"})

	var managerRole rbacv1.Role
	helm.UnmarshalK8SYaml(t, output, &managerRole)

	assert.Equal(t, namespaceName, managerRole.Namespace, "namespace should match the namespace of the Helm release")
	assert.Equal(t, "test-runners-gha-rs-manager", managerRole.Name)
	assert.Equal(t, "actions.github.com/cleanup-protection", managerRole.Finalizers[0])
	assert.Equal(t, 6, len(managerRole.Rules))

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)
}

func TestTemplate_CreateManagerRole_UseConfigMaps(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                                      "https://github.com/actions",
			"githubConfigSecret.github_token":                      "gh_token12345",
			"controllerServiceAccount.name":                        "arc",
			"controllerServiceAccount.namespace":                   "arc-system",
			"githubServerTLS.certificateFrom.configMapKeyRef.name": "test",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/manager_role.yaml"})

	var managerRole rbacv1.Role
	helm.UnmarshalK8SYaml(t, output, &managerRole)

	assert.Equal(t, namespaceName, managerRole.Namespace, "namespace should match the namespace of the Helm release")
	assert.Equal(t, "test-runners-gha-rs-manager", managerRole.Name)
	assert.Equal(t, "actions.github.com/cleanup-protection", managerRole.Finalizers[0])
	assert.Equal(t, 7, len(managerRole.Rules))
	assert.Equal(t, "configmaps", managerRole.Rules[6].Resources[0])
}

func TestTemplate_CreateManagerRoleBinding(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/manager_role_binding.yaml"})

	var managerRoleBinding rbacv1.RoleBinding
	helm.UnmarshalK8SYaml(t, output, &managerRoleBinding)

	assert.Equal(t, namespaceName, managerRoleBinding.Namespace, "namespace should match the namespace of the Helm release")
	assert.Equal(t, "test-runners-gha-rs-manager", managerRoleBinding.Name)
	assert.Equal(t, "test-runners-gha-rs-manager", managerRoleBinding.RoleRef.Name)
	assert.Equal(t, "actions.github.com/cleanup-protection", managerRoleBinding.Finalizers[0])
	assert.Equal(t, "arc", managerRoleBinding.Subjects[0].Name)
	assert.Equal(t, "arc-system", managerRoleBinding.Subjects[0].Namespace)
}

func TestTemplateRenderedAutoScalingRunnerSet_ExtraContainers(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values_extra_containers.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}, "--debug")

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Len(t, ars.Spec.Template.Spec.Containers, 2, "There should be 2 containers")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name, "Container name should be runner")
	assert.Equal(t, "other", ars.Spec.Template.Spec.Containers[1].Name, "Container name should be other")
	assert.Equal(t, "250m", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().String(), "CPU Limit should be set")
	assert.Equal(t, "64Mi", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().String(), "Memory Limit should be set")
	assert.Equal(t, "250m", ars.Spec.Template.Spec.Containers[1].Resources.Limits.Cpu().String(), "CPU Limit should be set")
	assert.Equal(t, "64Mi", ars.Spec.Template.Spec.Containers[1].Resources.Limits.Memory().String(), "Memory Limit should be set")
	assert.Equal(t, "SOME_ENV", ars.Spec.Template.Spec.Containers[0].Env[0].Name, "SOME_ENV should be set")
	assert.Equal(t, "SOME_VALUE", ars.Spec.Template.Spec.Containers[0].Env[0].Value, "SOME_ENV should be set to `SOME_VALUE`")
	assert.Equal(t, "MY_NODE_NAME", ars.Spec.Template.Spec.Containers[0].Env[1].Name, "MY_NODE_NAME should be set")
	assert.Equal(t, "spec.nodeName", ars.Spec.Template.Spec.Containers[0].Env[1].ValueFrom.FieldRef.FieldPath, "MY_NODE_NAME should be set to `spec.nodeName`")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name, "VolumeMount name should be work")
	assert.Equal(t, "/work", ars.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath, "VolumeMount mountPath should be /work")
	assert.Equal(t, "others", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].Name, "VolumeMount name should be others")
	assert.Equal(t, "/others", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].MountPath, "VolumeMount mountPath should be /others")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Volumes[0].Name, "Volume name should be work")
	assert.Equal(t, corev1.DNSNone, ars.Spec.Template.Spec.DNSPolicy, "DNS Policy should be None")
	assert.Equal(t, "192.0.2.1", ars.Spec.Template.Spec.DNSConfig.Nameservers[0], "DNS Nameserver should be set")
}

func TestTemplateRenderedAutoScalingRunnerSet_RestartPolicy(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, corev1.RestartPolicyNever, ars.Spec.Template.Spec.RestartPolicy, "RestartPolicy should be Never")

	options = &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
			"template.spec.restartPolicy":        "Always",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}, "--debug")

	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Equal(t, corev1.RestartPolicyAlways, ars.Spec.Template.Spec.RestartPolicy, "RestartPolicy should be Always")
}

func TestTemplateRenderedAutoScalingRunnerSet_ExtraPodSpec(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values_extra_pod_spec.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "There should be 1 containers")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name, "Container name should be runner")
	assert.Equal(t, corev1.DNSNone, ars.Spec.Template.Spec.DNSPolicy, "DNS Policy should be None")
	assert.Equal(t, "192.0.2.1", ars.Spec.Template.Spec.DNSConfig.Nameservers[0], "DNS Nameserver should be set")
}

func TestTemplateRenderedAutoScalingRunnerSet_DinDMergePodSpec(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values_dind_merge_spec.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}, "--debug")

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "There should be 1 containers")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name, "Container name should be runner")
	assert.Equal(t, "250m", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().String(), "CPU Limit should be set")
	assert.Equal(t, "64Mi", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().String(), "Memory Limit should be set")
	assert.Equal(t, "DOCKER_HOST", ars.Spec.Template.Spec.Containers[0].Env[0].Name, "DOCKER_HOST should be set")
	assert.Equal(t, "tcp://localhost:9999", ars.Spec.Template.Spec.Containers[0].Env[0].Value, "DOCKER_HOST should be set to `tcp://localhost:9999`")
	assert.Equal(t, "MY_NODE_NAME", ars.Spec.Template.Spec.Containers[0].Env[1].Name, "MY_NODE_NAME should be set")
	assert.Equal(t, "spec.nodeName", ars.Spec.Template.Spec.Containers[0].Env[1].ValueFrom.FieldRef.FieldPath, "MY_NODE_NAME should be set to `spec.nodeName`")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name, "VolumeMount name should be work")
	assert.Equal(t, "/work", ars.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath, "VolumeMount mountPath should be /work")
	assert.Equal(t, "others", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].Name, "VolumeMount name should be others")
	assert.Equal(t, "/others", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].MountPath, "VolumeMount mountPath should be /others")
}

func TestTemplateRenderedAutoScalingRunnerSet_KubeModeMergePodSpec(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values_k8s_merge_spec.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}, "--debug")

	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)

	assert.Len(t, ars.Spec.Template.Spec.Containers, 1, "There should be 1 containers")
	assert.Equal(t, "runner", ars.Spec.Template.Spec.Containers[0].Name, "Container name should be runner")
	assert.Equal(t, "250m", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().String(), "CPU Limit should be set")
	assert.Equal(t, "64Mi", ars.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().String(), "Memory Limit should be set")
	assert.Equal(t, "ACTIONS_RUNNER_CONTAINER_HOOKS", ars.Spec.Template.Spec.Containers[0].Env[0].Name, "ACTIONS_RUNNER_CONTAINER_HOOKS should be set")
	assert.Equal(t, "/k8s/index.js", ars.Spec.Template.Spec.Containers[0].Env[0].Value, "ACTIONS_RUNNER_CONTAINER_HOOKS should be set to `/k8s/index.js`")
	assert.Equal(t, "MY_NODE_NAME", ars.Spec.Template.Spec.Containers[0].Env[1].Name, "MY_NODE_NAME should be set")
	assert.Equal(t, "spec.nodeName", ars.Spec.Template.Spec.Containers[0].Env[1].ValueFrom.FieldRef.FieldPath, "MY_NODE_NAME should be set to `spec.nodeName`")
	assert.Equal(t, "ACTIONS_RUNNER_POD_NAME", ars.Spec.Template.Spec.Containers[0].Env[2].Name, "ACTIONS_RUNNER_POD_NAME should be set")
	assert.Equal(t, "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER", ars.Spec.Template.Spec.Containers[0].Env[3].Name, "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER should be set")
	assert.Equal(t, "work", ars.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name, "VolumeMount name should be work")
	assert.Equal(t, "/work", ars.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath, "VolumeMount mountPath should be /work")
	assert.Equal(t, "others", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].Name, "VolumeMount name should be others")
	assert.Equal(t, "/others", ars.Spec.Template.Spec.Containers[0].VolumeMounts[1].MountPath, "VolumeMount mountPath should be /others")
}

func TestTemplateRenderedAutoscalingRunnerSetAnnotation_GitHubSecret(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	annotationExpectedTests := map[string]*helm.Options{
		"GitHub token": {
			Logger: logger.Discard,
			SetValues: map[string]string{
				"githubConfigUrl":                    "https://github.com/actions",
				"githubConfigSecret.github_token":    "gh_token12345",
				"controllerServiceAccount.name":      "arc",
				"controllerServiceAccount.namespace": "arc-system",
			},
			KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
		},
		"GitHub app": {
			Logger: logger.Discard,
			SetValues: map[string]string{
				"githubConfigUrl":                               "https://github.com/actions",
				"githubConfigSecret.github_app_id":              "10",
				"githubConfigSecret.github_app_installation_id": "100",
				"githubConfigSecret.github_app_private_key":     "private_key",
				"controllerServiceAccount.name":                 "arc",
				"controllerServiceAccount.namespace":            "arc-system",
			},
			KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
		},
	}

	for name, options := range annotationExpectedTests {
		t.Run("Annotation set: "+name, func(t *testing.T) {
			output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
			var autoscalingRunnerSet v1alpha1.AutoscalingRunnerSet
			helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet)

			assert.NotEmpty(t, autoscalingRunnerSet.Annotations[actionsgithubcom.AnnotationKeyGitHubSecretName])
		})
	}

	t.Run("Annotation should not be set", func(t *testing.T) {
		options := &helm.Options{
			Logger: logger.Discard,
			SetValues: map[string]string{
				"githubConfigUrl":                    "https://github.com/actions",
				"githubConfigSecret":                 "pre-defined-secret",
				"controllerServiceAccount.name":      "arc",
				"controllerServiceAccount.namespace": "arc-system",
			},
			KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
		}
		output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
		var autoscalingRunnerSet v1alpha1.AutoscalingRunnerSet
		helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet)

		assert.Empty(t, autoscalingRunnerSet.Annotations[actionsgithubcom.AnnotationKeyGitHubSecretName])
	})
}

func TestTemplateRenderedAutoscalingRunnerSetAnnotation_KubernetesModeCleanup(t *testing.T) {
	t.Parallel()

	for _, mode := range []string{"kubernetes", "kubernetes-novolume"} {
		t.Run("containerMode "+mode, func(t *testing.T) {
			// Path to the helm chart we will test
			helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
			require.NoError(t, err)

			releaseName := "test-runners"
			namespaceName := "test-" + strings.ToLower(random.UniqueId())

			options := &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"githubConfigUrl":                    "https://github.com/actions",
					"githubConfigSecret.github_token":    "gh_token12345",
					"controllerServiceAccount.name":      "arc",
					"controllerServiceAccount.namespace": "arc-system",
					"containerMode.type":                 mode,
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
			}

			output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
			var autoscalingRunnerSet v1alpha1.AutoscalingRunnerSet
			helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet)

			annotationValues := map[string]string{
				actionsgithubcom.AnnotationKeyGitHubSecretName:                 "test-runners-gha-rs-github-secret",
				actionsgithubcom.AnnotationKeyManagerRoleName:                  "test-runners-gha-rs-manager",
				actionsgithubcom.AnnotationKeyManagerRoleBindingName:           "test-runners-gha-rs-manager",
				actionsgithubcom.AnnotationKeyKubernetesModeServiceAccountName: "test-runners-gha-rs-kube-mode",
				actionsgithubcom.AnnotationKeyKubernetesModeRoleName:           "test-runners-gha-rs-kube-mode",
				actionsgithubcom.AnnotationKeyKubernetesModeRoleBindingName:    "test-runners-gha-rs-kube-mode",
			}

			for annotation, value := range annotationValues {
				assert.Equal(t, value, autoscalingRunnerSet.Annotations[annotation], fmt.Sprintf("Annotation %q does not match the expected value", annotation))
			}
		})
	}
}

func TestRunnerContainerEnvNotEmptyMap(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger:         logger.Discard,
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	type testModel struct {
		Spec struct {
			Template struct {
				Spec struct {
					Containers []map[string]any `yaml:"containers"`
				} `yaml:"spec"`
			} `yaml:"template"`
		} `yaml:"spec"`
	}

	var m testModel
	helm.UnmarshalK8SYaml(t, output, &m)
	_, ok := m.Spec.Template.Spec.Containers[0]["env"]
	assert.False(t, ok, "env should not be set")
}

func TestRunnerContainerVolumeNotEmptyMap(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	testValuesPath, err := filepath.Abs("../tests/values.yaml")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger:         logger.Discard,
		ValuesFiles:    []string{testValuesPath},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	type testModel struct {
		Spec struct {
			Template struct {
				Spec struct {
					Containers []map[string]any `yaml:"containers"`
				} `yaml:"spec"`
			} `yaml:"template"`
		} `yaml:"spec"`
	}

	var m testModel
	helm.UnmarshalK8SYaml(t, output, &m)
	_, ok := m.Spec.Template.Spec.Containers[0]["volumeMounts"]
	assert.False(t, ok, "volumeMounts should not be set")
}

func TestAutoscalingRunnerSetAnnotationValuesHash(t *testing.T) {
	t.Parallel()

	const valuesHash = "actions.github.com/values-hash"

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token12345",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var autoscalingRunnerSet v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet)

	firstHash := autoscalingRunnerSet.Annotations["actions.github.com/values-hash"]
	assert.NotEmpty(t, firstHash)
	assert.LessOrEqual(t, len(firstHash), 63)

	helmChartPath, err = filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	options = &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                    "https://github.com/actions",
			"githubConfigSecret.github_token":    "gh_token1234567890",
			"controllerServiceAccount.name":      "arc",
			"controllerServiceAccount.namespace": "arc-system",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet)
	secondHash := autoscalingRunnerSet.Annotations[valuesHash]
	assert.NotEmpty(t, secondHash)
	assert.NotEqual(t, firstHash, secondHash)
	assert.LessOrEqual(t, len(secondHash), 63)
}

func TestCustomLabels(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                                              "https://github.com/actions",
			"githubConfigSecret.github_token":                              "gh_token12345",
			"controllerServiceAccount.name":                                "arc",
			"containerMode.type":                                           "kubernetes",
			"controllerServiceAccount.namespace":                           "arc-system",
			`labels.argocd\.argoproj\.io/sync-wave`:                        `"1"`,
			`labels.app\.kubernetes\.io/part-of`:                           "no-override", // this shouldn't be overwritten
			"resourceMeta.autoscalingRunnerSet.labels.ars-custom":          "ars-custom-value",
			"resourceMeta.githubConfigSecret.labels.gh-custom":             "gh-custom-value",
			"resourceMeta.kubernetesModeRole.labels.kmr-custom":            "kmr-custom-value",
			"resourceMeta.kubernetesModeRoleBinding.labels.kmrb-custom":    "kmrb-custom-value",
			"resourceMeta.kubernetesModeServiceAccount.labels.kmsa-custom": "kmsa-custom-value",
			"resourceMeta.managerRole.labels.mr-custom":                    "mr-custom-value",
			"resourceMeta.managerRoleBinding.labels.mrb-custom":            "mrb-custom-value",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"})

	const targetLabel = "argocd.argoproj.io/sync-wave"
	const wantCustomValue = `"1"`
	const reservedLabel = "app.kubernetes.io/part-of"
	const wantReservedValue = "gha-rs"

	var githubSecret corev1.Secret
	helm.UnmarshalK8SYaml(t, output, &githubSecret)
	assert.Equal(t, wantCustomValue, githubSecret.Labels[targetLabel])
	assert.Equal(t, wantReservedValue, githubSecret.Labels[reservedLabel])
	assert.Equal(t, "gh-custom-value", githubSecret.Labels["gh-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role.yaml"})
	var role rbacv1.Role
	helm.UnmarshalK8SYaml(t, output, &role)
	assert.Equal(t, wantCustomValue, role.Labels[targetLabel])
	assert.Equal(t, wantReservedValue, role.Labels[reservedLabel])
	assert.Equal(t, "kmr-custom-value", role.Labels["kmr-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role_binding.yaml"})
	var roleBinding rbacv1.RoleBinding
	helm.UnmarshalK8SYaml(t, output, &roleBinding)
	assert.Equal(t, wantCustomValue, roleBinding.Labels[targetLabel])
	assert.Equal(t, wantReservedValue, roleBinding.Labels[reservedLabel])
	assert.Equal(t, "kmrb-custom-value", roleBinding.Labels["kmrb-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)
	assert.Equal(t, wantCustomValue, ars.Labels[targetLabel])
	assert.Equal(t, wantReservedValue, ars.Labels[reservedLabel])
	assert.Equal(t, "ars-custom-value", ars.Labels["ars-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_serviceaccount.yaml"})
	var serviceAccount corev1.ServiceAccount
	helm.UnmarshalK8SYaml(t, output, &serviceAccount)
	assert.Equal(t, wantCustomValue, serviceAccount.Labels[targetLabel])
	assert.Equal(t, wantReservedValue, serviceAccount.Labels[reservedLabel])
	assert.Equal(t, "kmsa-custom-value", serviceAccount.Labels["kmsa-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/manager_role.yaml"})
	var managerRole rbacv1.Role
	helm.UnmarshalK8SYaml(t, output, &managerRole)
	assert.Equal(t, wantCustomValue, managerRole.Labels[targetLabel])
	assert.Equal(t, wantReservedValue, managerRole.Labels[reservedLabel])
	assert.Equal(t, "mr-custom-value", managerRole.Labels["mr-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/manager_role_binding.yaml"})
	var managerRoleBinding rbacv1.RoleBinding
	helm.UnmarshalK8SYaml(t, output, &managerRoleBinding)
	assert.Equal(t, wantCustomValue, managerRoleBinding.Labels[targetLabel])
	assert.Equal(t, wantReservedValue, managerRoleBinding.Labels[reservedLabel])
	assert.Equal(t, "mrb-custom-value", managerRoleBinding.Labels["mrb-custom"])

	options = &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                                            "https://github.com/actions",
			"githubConfigSecret.github_token":                            "gh_token12345",
			"controllerServiceAccount.name":                              "arc",
			"controllerServiceAccount.namespace":                         "arc-system",
			`labels.argocd\.argoproj\.io/sync-wave`:                      `"1"`,
			"resourceMeta.noPermissionServiceAccount.labels.npsa-custom": "npsa-custom-value",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/no_permission_serviceaccount.yaml"})
	var noPermissionServiceAccount corev1.ServiceAccount
	helm.UnmarshalK8SYaml(t, output, &noPermissionServiceAccount)
	assert.Equal(t, wantCustomValue, noPermissionServiceAccount.Labels[targetLabel])
	assert.Equal(t, wantReservedValue, noPermissionServiceAccount.Labels[reservedLabel])
	assert.Equal(t, "npsa-custom-value", noPermissionServiceAccount.Labels["npsa-custom"])
}

func TestCustomAnnotations(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                                                   "https://github.com/actions",
			"githubConfigSecret.github_token":                                   "gh_token12345",
			"containerMode.type":                                                "kubernetes",
			"controllerServiceAccount.name":                                     "arc",
			"controllerServiceAccount.namespace":                                "arc-system",
			`annotations.argocd\.argoproj\.io/sync-wave`:                        `"1"`,
			"resourceMeta.autoscalingRunnerSet.annotations.ars-custom":          "ars-custom-value",
			"resourceMeta.githubConfigSecret.annotations.gh-custom":             "gh-custom-value",
			"resourceMeta.kubernetesModeRole.annotations.kmr-custom":            "kmr-custom-value",
			"resourceMeta.kubernetesModeRoleBinding.annotations.kmrb-custom":    "kmrb-custom-value",
			"resourceMeta.kubernetesModeServiceAccount.annotations.kmsa-custom": "kmsa-custom-value",
			"resourceMeta.managerRole.annotations.mr-custom":                    "mr-custom-value",
			"resourceMeta.managerRoleBinding.annotations.mrb-custom":            "mrb-custom-value",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	const targetAnnotations = "argocd.argoproj.io/sync-wave"
	const wantCustomValue = `"1"`

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/githubsecret.yaml"})

	var githubSecret corev1.Secret
	helm.UnmarshalK8SYaml(t, output, &githubSecret)
	assert.Equal(t, wantCustomValue, githubSecret.Annotations[targetAnnotations])
	assert.Equal(t, "gh-custom-value", githubSecret.Annotations["gh-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role.yaml"})
	var role rbacv1.Role
	helm.UnmarshalK8SYaml(t, output, &role)
	assert.Equal(t, wantCustomValue, role.Annotations[targetAnnotations])
	assert.Equal(t, "kmr-custom-value", role.Annotations["kmr-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_role_binding.yaml"})
	var roleBinding rbacv1.RoleBinding
	helm.UnmarshalK8SYaml(t, output, &roleBinding)
	assert.Equal(t, wantCustomValue, roleBinding.Annotations[targetAnnotations])
	assert.Equal(t, "kmrb-custom-value", roleBinding.Annotations["kmrb-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})
	var ars v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &ars)
	assert.Equal(t, wantCustomValue, ars.Annotations[targetAnnotations])
	assert.Equal(t, "ars-custom-value", ars.Annotations["ars-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/kube_mode_serviceaccount.yaml"})
	var serviceAccount corev1.ServiceAccount
	helm.UnmarshalK8SYaml(t, output, &serviceAccount)
	assert.Equal(t, wantCustomValue, serviceAccount.Annotations[targetAnnotations])
	assert.Equal(t, "kmsa-custom-value", serviceAccount.Annotations["kmsa-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/manager_role.yaml"})
	var managerRole rbacv1.Role
	helm.UnmarshalK8SYaml(t, output, &managerRole)
	assert.Equal(t, wantCustomValue, managerRole.Annotations[targetAnnotations])
	assert.Equal(t, "mr-custom-value", managerRole.Annotations["mr-custom"])

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/manager_role_binding.yaml"})
	var managerRoleBinding rbacv1.RoleBinding
	helm.UnmarshalK8SYaml(t, output, &managerRoleBinding)
	assert.Equal(t, wantCustomValue, managerRoleBinding.Annotations[targetAnnotations])
	assert.Equal(t, "mrb-custom-value", managerRoleBinding.Annotations["mrb-custom"])

	options = &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                                                 "https://github.com/actions",
			"githubConfigSecret.github_token":                                 "gh_token12345",
			"controllerServiceAccount.name":                                   "arc",
			"controllerServiceAccount.namespace":                              "arc-system",
			`annotations.argocd\.argoproj\.io/sync-wave`:                      `"1"`,
			"resourceMeta.noPermissionServiceAccount.annotations.npsa-custom": "npsa-custom-value",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output = helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/no_permission_serviceaccount.yaml"})
	var noPermissionServiceAccount corev1.ServiceAccount
	helm.UnmarshalK8SYaml(t, output, &noPermissionServiceAccount)
	assert.Equal(t, wantCustomValue, noPermissionServiceAccount.Annotations[targetAnnotations])
	assert.Equal(t, "npsa-custom-value", noPermissionServiceAccount.Annotations["npsa-custom"])
}

func TestNamespaceOverride(t *testing.T) {
	t.Parallel()

	chartPath := "../../gha-runner-scale-set"

	releaseName := "test"
	releaseNamespace := "test-" + strings.ToLower(random.UniqueId())
	namespaceOverride := "test-" + strings.ToLower(random.UniqueId())

	tt := map[string]struct {
		file    string
		options *helm.Options
	}{
		"manager_role": {
			file: "manager_role.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"manager_role_binding": {
			file: "manager_role_binding.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"no_permission_serviceaccount": {
			file: "no_permission_serviceaccount.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"autoscalingrunnerset": {
			file: "autoscalingrunnerset.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"githubsecret": {
			file: "githubsecret.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"kube_mode_role": {
			file: "kube_mode_role.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"containerMode.type":                 "kubernetes",
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"kube_novolume_mode_role": {
			file: "kube_mode_role.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"containerMode.type":                 "kubernetes-novolume",
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"kube_mode_role_binding": {
			file: "kube_mode_role_binding.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"containerMode.type":                 "kubernetes",
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"kube_novolume_mode_role_binding": {
			file: "kube_mode_role_binding.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"containerMode.type":                 "kubernetes-novolume",
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"kube_mode_serviceaccount": {
			file: "kube_mode_serviceaccount.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"containerMode.type":                 "kubernetes",
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
		"kube_novolume_mode_serviceaccount": {
			file: "kube_mode_serviceaccount.yaml",
			options: &helm.Options{
				Logger: logger.Discard,
				SetValues: map[string]string{
					"namespaceOverride":                  namespaceOverride,
					"containerMode.type":                 "kubernetes-novolume",
					"controllerServiceAccount.name":      "foo",
					"controllerServiceAccount.namespace": "bar",
					"githubConfigSecret.github_token":    "gh_token12345",
					"githubConfigUrl":                    "https://github.com",
				},
				KubectlOptions: k8s.NewKubectlOptions("", "", releaseNamespace),
			},
		},
	}

	for name, tc := range tt {
		c := tc
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			templateFile := filepath.Join("./templates", c.file)

			output, err := helm.RenderTemplateE(t, c.options, chartPath, releaseName, []string{templateFile})
			if err != nil {
				t.Errorf("Error rendering template %s from chart %s: %s", c.file, chartPath, err)
			}

			type object struct {
				Metadata metav1.ObjectMeta
			}
			var renderedObject object
			helm.UnmarshalK8SYaml(t, output, &renderedObject)
			assert.Equal(t, namespaceOverride, renderedObject.Metadata.Namespace)
		})
	}
}

func TestAutoscalingRunnerSetCustomAnnotationsAndLabelsApplied(t *testing.T) {
	t.Parallel()

	// Path to the helm chart we will test
	helmChartPath, err := filepath.Abs("../../gha-runner-scale-set")
	require.NoError(t, err)

	releaseName := "test-runners"
	namespaceName := "test-" + strings.ToLower(random.UniqueId())

	options := &helm.Options{
		Logger: logger.Discard,
		SetValues: map[string]string{
			"githubConfigUrl":                                              "https://github.com/actions",
			"githubConfigSecret.github_token":                              "gh_token12345",
			"controllerServiceAccount.name":                                "arc",
			"controllerServiceAccount.namespace":                           "arc-system",
			"annotations.actions\\.github\\.com/vault":                     "azure_key_vault",
			"annotations.actions\\.github\\.com/cleanup-manager-role-name": "not-propagated",
			"labels.custom":                                                "custom",
			"labels.app\\.kubernetes\\.io/component":                       "not-propagated",
		},
		KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
	}

	output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"})

	var autoscalingRunnerSet v1alpha1.AutoscalingRunnerSet
	helm.UnmarshalK8SYaml(t, output, &autoscalingRunnerSet)

	vault := autoscalingRunnerSet.Annotations["actions.github.com/vault"]
	assert.Equal(t, "azure_key_vault", vault)

	custom := autoscalingRunnerSet.Labels["custom"]
	assert.Equal(t, "custom", custom)

	assert.NotEqual(t, "not-propagated", autoscalingRunnerSet.Annotations["actions.github.com/cleanup-manager-role-name"])
	assert.NotEqual(t, "not-propagated", autoscalingRunnerSet.Labels["app.kubernetes.io/component"])
}
