2023-01-17 14:36:04 -05:00
package tests
import (
2023-08-21 13:50:07 +02:00
"fmt"
2023-02-23 03:40:21 -05:00
"os"
2023-01-17 14:36:04 -05:00
"path/filepath"
"strings"
"testing"
"github.com/gruntwork-io/terratest/modules/helm"
"github.com/gruntwork-io/terratest/modules/k8s"
2023-05-18 14:15:05 +02:00
"github.com/gruntwork-io/terratest/modules/logger"
2023-01-17 14:36:04 -05:00
"github.com/gruntwork-io/terratest/modules/random"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2023-02-23 03:40:21 -05:00
"gopkg.in/yaml.v2"
2023-01-17 14:36:04 -05:00
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
2025-03-18 20:41:04 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2023-01-17 14:36:04 -05:00
)
2023-02-23 03:40:21 -05:00
type Chart struct {
Version string `yaml:"version"`
AppVersion string `yaml:"appVersion"`
}
2023-01-17 14:36:04 -05:00
func TestTemplate_CreateServiceAccount ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"serviceAccount.create" : "true" ,
"serviceAccount.annotations.foo" : "bar" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/serviceaccount.yaml" })
var serviceAccount corev1 . ServiceAccount
helm . UnmarshalK8SYaml ( t , output , & serviceAccount )
assert . Equal ( t , namespaceName , serviceAccount . Namespace )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , serviceAccount . Name )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "bar" , string ( serviceAccount . Annotations [ "foo" ]))
}
func TestTemplate_CreateServiceAccount_OverwriteName ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"serviceAccount.create" : "true" ,
"serviceAccount.name" : "overwritten-name" ,
"serviceAccount.annotations.foo" : "bar" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/serviceaccount.yaml" })
var serviceAccount corev1 . ServiceAccount
helm . UnmarshalK8SYaml ( t , output , & serviceAccount )
assert . Equal ( t , namespaceName , serviceAccount . Namespace )
assert . Equal ( t , "overwritten-name" , serviceAccount . Name )
assert . Equal ( t , "bar" , string ( serviceAccount . Annotations [ "foo" ]))
}
func TestTemplate_CreateServiceAccount_CannotUseDefaultServiceAccount ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"serviceAccount.create" : "true" ,
"serviceAccount.name" : "default" ,
"serviceAccount.annotations.foo" : "bar" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
_ , err = helm . RenderTemplateE ( t , options , helmChartPath , releaseName , [] string { "templates/serviceaccount.yaml" })
assert . ErrorContains ( t , err , "serviceAccount.name cannot be set to 'default'" , "We should get an error because the default service account cannot be used" )
}
func TestTemplate_NotCreateServiceAccount ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"serviceAccount.create" : "false" ,
"serviceAccount.name" : "overwritten-name" ,
"serviceAccount.annotations.foo" : "bar" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
_ , err = helm . RenderTemplateE ( t , options , helmChartPath , releaseName , [] string { "templates/serviceaccount.yaml" })
assert . ErrorContains ( t , err , "could not find template templates/serviceaccount.yaml in chart" , "We should get an error because the template should be skipped" )
}
func TestTemplate_NotCreateServiceAccount_ServiceAccountNotSet ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"serviceAccount.create" : "false" ,
"serviceAccount.annotations.foo" : "bar" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
_ , err = helm . RenderTemplateE ( t , options , helmChartPath , releaseName , [] string { "templates/deployment.yaml" })
assert . ErrorContains ( t , err , "serviceAccount.name must be set if serviceAccount.create is false" , "We should get an error because the default service account cannot be used" )
}
2023-03-14 09:45:44 -04:00
func TestTemplate_CreateManagerClusterRole ( t * testing . T ) {
2023-01-17 14:36:04 -05:00
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
2023-03-14 09:45:44 -04:00
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/manager_cluster_role.yaml" })
2023-01-17 14:36:04 -05:00
2023-03-14 09:45:44 -04:00
var managerClusterRole rbacv1 . ClusterRole
helm . UnmarshalK8SYaml ( t , output , & managerClusterRole )
2023-01-17 14:36:04 -05:00
2023-03-14 09:45:44 -04:00
assert . Empty ( t , managerClusterRole . Namespace , "ClusterRole should not have a namespace" )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , managerClusterRole . Name )
2023-04-10 08:49:32 +02:00
assert . Equal ( t , 16 , len ( managerClusterRole . Rules ))
2023-03-14 10:52:25 -04:00
_ , err = helm . RenderTemplateE ( t , options , helmChartPath , releaseName , [] string { "templates/manager_single_namespace_controller_role.yaml" })
assert . ErrorContains ( t , err , "could not find template templates/manager_single_namespace_controller_role.yaml in chart" , "We should get an error because the template should be skipped" )
_ , err = helm . RenderTemplateE ( t , options , helmChartPath , releaseName , [] string { "templates/manager_single_namespace_watch_role.yaml" })
assert . ErrorContains ( t , err , "could not find template templates/manager_single_namespace_watch_role.yaml in chart" , "We should get an error because the template should be skipped" )
2023-01-17 14:36:04 -05:00
}
2023-03-14 09:45:44 -04:00
func TestTemplate_ManagerClusterRoleBinding ( t * testing . T ) {
2023-01-17 14:36:04 -05:00
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"serviceAccount.create" : "true" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
2023-03-14 09:45:44 -04:00
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/manager_cluster_role_binding.yaml" })
2023-01-17 14:36:04 -05:00
2023-03-14 09:45:44 -04:00
var managerClusterRoleBinding rbacv1 . ClusterRoleBinding
helm . UnmarshalK8SYaml ( t , output , & managerClusterRoleBinding )
2023-01-17 14:36:04 -05:00
2023-03-14 09:45:44 -04:00
assert . Empty ( t , managerClusterRoleBinding . Namespace , "ClusterRoleBinding should not have a namespace" )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , managerClusterRoleBinding . Name )
assert . Equal ( t , "test-arc-gha-rs-controller" , managerClusterRoleBinding . RoleRef . Name )
assert . Equal ( t , "test-arc-gha-rs-controller" , managerClusterRoleBinding . Subjects [ 0 ]. Name )
2023-03-14 09:45:44 -04:00
assert . Equal ( t , namespaceName , managerClusterRoleBinding . Subjects [ 0 ]. Namespace )
2023-03-14 10:52:25 -04:00
_ , err = helm . RenderTemplateE ( t , options , helmChartPath , releaseName , [] string { "templates/manager_single_namespace_controller_role_binding.yaml" })
assert . ErrorContains ( t , err , "could not find template templates/manager_single_namespace_controller_role_binding.yaml in chart" , "We should get an error because the template should be skipped" )
_ , err = helm . RenderTemplateE ( t , options , helmChartPath , releaseName , [] string { "templates/manager_single_namespace_watch_role_binding.yaml" })
assert . ErrorContains ( t , err , "could not find template templates/manager_single_namespace_watch_role_binding.yaml in chart" , "We should get an error because the template should be skipped" )
2023-03-14 09:45:44 -04:00
}
func TestTemplate_CreateManagerListenerRole ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-03-14 09:45:44 -04:00
SetValues : map [ string ] string {},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/manager_listener_role.yaml" })
var managerListenerRole rbacv1 . Role
helm . UnmarshalK8SYaml ( t , output , & managerListenerRole )
assert . Equal ( t , namespaceName , managerListenerRole . Namespace , "Role should have a namespace" )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-listener" , managerListenerRole . Name )
2023-03-14 09:45:44 -04:00
assert . Equal ( t , 4 , len ( managerListenerRole . Rules ))
assert . Equal ( t , "pods" , managerListenerRole . Rules [ 0 ]. Resources [ 0 ])
assert . Equal ( t , "pods/status" , managerListenerRole . Rules [ 1 ]. Resources [ 0 ])
assert . Equal ( t , "secrets" , managerListenerRole . Rules [ 2 ]. Resources [ 0 ])
assert . Equal ( t , "serviceaccounts" , managerListenerRole . Rules [ 3 ]. Resources [ 0 ])
}
func TestTemplate_ManagerListenerRoleBinding ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-03-14 09:45:44 -04:00
SetValues : map [ string ] string {
"serviceAccount.create" : "true" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/manager_listener_role_binding.yaml" })
var managerListenerRoleBinding rbacv1 . RoleBinding
helm . UnmarshalK8SYaml ( t , output , & managerListenerRoleBinding )
assert . Equal ( t , namespaceName , managerListenerRoleBinding . Namespace , "RoleBinding should have a namespace" )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-listener" , managerListenerRoleBinding . Name )
assert . Equal ( t , "test-arc-gha-rs-controller-listener" , managerListenerRoleBinding . RoleRef . Name )
assert . Equal ( t , "test-arc-gha-rs-controller" , managerListenerRoleBinding . Subjects [ 0 ]. Name )
2023-03-14 09:45:44 -04:00
assert . Equal ( t , namespaceName , managerListenerRoleBinding . Subjects [ 0 ]. Namespace )
2023-01-17 14:36:04 -05:00
}
func TestTemplate_ControllerDeployment_Defaults ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
2023-02-23 03:40:21 -05:00
chartContent , err := os . ReadFile ( filepath . Join ( helmChartPath , "Chart.yaml" ))
require . NoError ( t , err )
chart := new ( Chart )
err = yaml . Unmarshal ( chartContent , chart )
require . NoError ( t , err )
2023-01-17 14:36:04 -05:00
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"image.tag" : "dev" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/deployment.yaml" })
var deployment appsv1 . Deployment
helm . UnmarshalK8SYaml ( t , output , & deployment )
assert . Equal ( t , namespaceName , deployment . Namespace )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , deployment . Name )
assert . Equal ( t , "gha-rs-controller-" + chart . Version , deployment . Labels [ "helm.sh/chart" ])
assert . Equal ( t , "gha-rs-controller" , deployment . Labels [ "app.kubernetes.io/name" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "test-arc" , deployment . Labels [ "app.kubernetes.io/instance" ])
2023-02-23 03:40:21 -05:00
assert . Equal ( t , chart . AppVersion , deployment . Labels [ "app.kubernetes.io/version" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "Helm" , deployment . Labels [ "app.kubernetes.io/managed-by" ])
2023-03-14 09:45:44 -04:00
assert . Equal ( t , namespaceName , deployment . Labels [ "actions.github.com/controller-service-account-namespace" ])
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , deployment . Labels [ "actions.github.com/controller-service-account-name" ])
2023-03-14 10:52:25 -04:00
assert . NotContains ( t , deployment . Labels , "actions.github.com/controller-watch-single-namespace" )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller" , deployment . Labels [ "app.kubernetes.io/part-of" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , int32 ( 1 ), * deployment . Spec . Replicas )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller" , deployment . Spec . Selector . MatchLabels [ "app.kubernetes.io/name" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "test-arc" , deployment . Spec . Selector . MatchLabels [ "app.kubernetes.io/instance" ])
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller" , deployment . Spec . Template . Labels [ "app.kubernetes.io/name" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "test-arc" , deployment . Spec . Template . Labels [ "app.kubernetes.io/instance" ])
assert . Equal ( t , "manager" , deployment . Spec . Template . Annotations [ "kubectl.kubernetes.io/default-container" ])
assert . Len ( t , deployment . Spec . Template . Spec . ImagePullSecrets , 0 )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , deployment . Spec . Template . Spec . ServiceAccountName )
2023-01-17 14:36:04 -05:00
assert . Nil ( t , deployment . Spec . Template . Spec . SecurityContext )
assert . Empty ( t , deployment . Spec . Template . Spec . PriorityClassName )
assert . Equal ( t , int64 ( 10 ), * deployment . Spec . Template . Spec . TerminationGracePeriodSeconds )
assert . Len ( t , deployment . Spec . Template . Spec . Volumes , 1 )
assert . Equal ( t , "tmp" , deployment . Spec . Template . Spec . Volumes [ 0 ]. Name )
assert . NotNil ( t , 10 , deployment . Spec . Template . Spec . Volumes [ 0 ]. EmptyDir )
assert . Len ( t , deployment . Spec . Template . Spec . NodeSelector , 0 )
assert . Nil ( t , deployment . Spec . Template . Spec . Affinity )
2024-04-12 08:22:41 -04:00
assert . Len ( t , deployment . Spec . Template . Spec . TopologySpreadConstraints , 0 )
2023-01-17 14:36:04 -05:00
assert . Len ( t , deployment . Spec . Template . Spec . Tolerations , 0 )
2023-03-10 18:05:51 +01:00
managerImage := "ghcr.io/actions/gha-runner-scale-set-controller:dev"
2023-01-17 14:36:04 -05:00
assert . Len ( t , deployment . Spec . Template . Spec . Containers , 1 )
assert . Equal ( t , "manager" , deployment . Spec . Template . Spec . Containers [ 0 ]. Name )
2023-03-10 18:05:51 +01:00
assert . Equal ( t , managerImage , deployment . Spec . Template . Spec . Containers [ 0 ]. Image )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , corev1 . PullIfNotPresent , deployment . Spec . Template . Spec . Containers [ 0 ]. ImagePullPolicy )
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Command , 1 )
assert . Equal ( t , "/manager" , deployment . Spec . Template . Spec . Containers [ 0 ]. Command [ 0 ])
2023-07-05 21:06:42 +02:00
expectedArgs := [] string {
"--auto-scaling-runner-set-only" ,
"--log-level=debug" ,
"--log-format=text" ,
"--update-strategy=immediate" ,
2023-08-21 13:50:07 +02:00
"--metrics-addr=0" ,
"--listener-metrics-addr=0" ,
"--listener-metrics-endpoint=" ,
2025-01-15 15:54:33 +01:00
"--runner-max-concurrent-reconciles=2" ,
2023-07-05 21:06:42 +02:00
}
assert . ElementsMatch ( t , expectedArgs , deployment . Spec . Template . Spec . Containers [ 0 ]. Args )
2023-01-17 14:36:04 -05:00
2023-11-07 15:08:36 +01:00
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Env , 2 )
2023-03-10 18:05:51 +01:00
assert . Equal ( t , "CONTROLLER_MANAGER_CONTAINER_IMAGE" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 0 ]. Name )
assert . Equal ( t , managerImage , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 0 ]. Value )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "CONTROLLER_MANAGER_POD_NAMESPACE" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 1 ]. Name )
assert . Equal ( t , "metadata.namespace" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 1 ]. ValueFrom . FieldRef . FieldPath )
2023-04-04 19:07:20 +02:00
2023-01-17 14:36:04 -05:00
assert . Empty ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Resources )
assert . Nil ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. SecurityContext )
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts , 1 )
assert . Equal ( t , "tmp" , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts [ 0 ]. Name )
assert . Equal ( t , "/tmp" , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts [ 0 ]. MountPath )
}
func TestTemplate_ControllerDeployment_Customize ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
2023-02-23 03:40:21 -05:00
chartContent , err := os . ReadFile ( filepath . Join ( helmChartPath , "Chart.yaml" ))
require . NoError ( t , err )
chart := new ( Chart )
err = yaml . Unmarshal ( chartContent , chart )
require . NoError ( t , err )
2023-01-17 14:36:04 -05:00
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"labels.foo" : "bar" ,
"labels.github" : "actions" ,
2023-11-13 16:18:04 +01:00
"labels.team" : "GitHub Team" ,
"labels.teamMail" : "team@github.com" ,
2023-01-17 14:36:04 -05:00
"replicaCount" : "1" ,
"image.pullPolicy" : "Always" ,
"image.tag" : "dev" ,
"imagePullSecrets[0].name" : "dockerhub" ,
2023-08-09 11:11:45 +02:00
"nameOverride" : "gha-rs-controller-override" ,
"fullnameOverride" : "gha-rs-controller-fullname-override" ,
2023-03-30 15:40:28 +02:00
"env[0].name" : "ENV_VAR_NAME_1" ,
"env[0].value" : "ENV_VAR_VALUE_1" ,
2023-08-09 11:11:45 +02:00
"serviceAccount.name" : "gha-rs-controller-sa" ,
2023-01-17 14:36:04 -05:00
"podAnnotations.foo" : "bar" ,
"podSecurityContext.fsGroup" : "1000" ,
"securityContext.runAsUser" : "1000" ,
"securityContext.runAsNonRoot" : "true" ,
"resources.limits.cpu" : "500m" ,
"nodeSelector.foo" : "bar" ,
"tolerations[0].key" : "foo" ,
"affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key" : "foo" ,
"affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].operator" : "bar" ,
2024-04-12 08:22:41 -04:00
"topologySpreadConstraints[0].labelSelector.matchLabels.foo" : "bar" ,
"topologySpreadConstraints[0].maxSkew" : "1" ,
"topologySpreadConstraints[0].topologyKey" : "foo" ,
2024-02-12 08:47:09 -05:00
"priorityClassName" : "test-priority-class" ,
"flags.updateStrategy" : "eventual" ,
"flags.logLevel" : "info" ,
"flags.logFormat" : "json" ,
"volumes[0].name" : "customMount" ,
"volumes[0].configMap.name" : "my-configmap" ,
"volumeMounts[0].name" : "customMount" ,
"volumeMounts[0].mountPath" : "/my/mount/path" ,
2023-01-17 14:36:04 -05:00
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/deployment.yaml" })
var deployment appsv1 . Deployment
helm . UnmarshalK8SYaml ( t , output , & deployment )
assert . Equal ( t , namespaceName , deployment . Namespace )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller-fullname-override" , deployment . Name )
assert . Equal ( t , "gha-rs-controller-" + chart . Version , deployment . Labels [ "helm.sh/chart" ])
assert . Equal ( t , "gha-rs-controller-override" , deployment . Labels [ "app.kubernetes.io/name" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "test-arc" , deployment . Labels [ "app.kubernetes.io/instance" ])
2023-02-23 03:40:21 -05:00
assert . Equal ( t , chart . AppVersion , deployment . Labels [ "app.kubernetes.io/version" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "Helm" , deployment . Labels [ "app.kubernetes.io/managed-by" ])
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller" , deployment . Labels [ "app.kubernetes.io/part-of" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "bar" , deployment . Labels [ "foo" ])
assert . Equal ( t , "actions" , deployment . Labels [ "github" ])
2023-11-13 16:18:04 +01:00
assert . Equal ( t , "GitHub Team" , deployment . Labels [ "team" ])
assert . Equal ( t , "team@github.com" , deployment . Labels [ "teamMail" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , int32 ( 1 ), * deployment . Spec . Replicas )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller-override" , deployment . Spec . Selector . MatchLabels [ "app.kubernetes.io/name" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "test-arc" , deployment . Spec . Selector . MatchLabels [ "app.kubernetes.io/instance" ])
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller-override" , deployment . Spec . Template . Labels [ "app.kubernetes.io/name" ])
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "test-arc" , deployment . Spec . Template . Labels [ "app.kubernetes.io/instance" ])
assert . Equal ( t , "bar" , deployment . Spec . Template . Annotations [ "foo" ])
assert . Equal ( t , "manager" , deployment . Spec . Template . Annotations [ "kubectl.kubernetes.io/default-container" ])
2023-11-07 15:08:36 +01:00
assert . Equal ( t , "ENV_VAR_NAME_1" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 2 ]. Name )
assert . Equal ( t , "ENV_VAR_VALUE_1" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 2 ]. Value )
2023-03-30 15:40:28 +02:00
2023-01-17 14:36:04 -05:00
assert . Len ( t , deployment . Spec . Template . Spec . ImagePullSecrets , 1 )
assert . Equal ( t , "dockerhub" , deployment . Spec . Template . Spec . ImagePullSecrets [ 0 ]. Name )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller-sa" , deployment . Spec . Template . Spec . ServiceAccountName )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , int64 ( 1000 ), * deployment . Spec . Template . Spec . SecurityContext . FSGroup )
assert . Equal ( t , "test-priority-class" , deployment . Spec . Template . Spec . PriorityClassName )
assert . Equal ( t , int64 ( 10 ), * deployment . Spec . Template . Spec . TerminationGracePeriodSeconds )
2024-02-12 08:47:09 -05:00
assert . Len ( t , deployment . Spec . Template . Spec . Volumes , 2 )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "tmp" , deployment . Spec . Template . Spec . Volumes [ 0 ]. Name )
2024-02-12 08:47:09 -05:00
assert . NotNil ( t , deployment . Spec . Template . Spec . Volumes [ 0 ]. EmptyDir )
assert . Equal ( t , "customMount" , deployment . Spec . Template . Spec . Volumes [ 1 ]. Name )
assert . Equal ( t , "my-configmap" , deployment . Spec . Template . Spec . Volumes [ 1 ]. ConfigMap . Name )
2023-01-17 14:36:04 -05:00
assert . Len ( t , deployment . Spec . Template . Spec . NodeSelector , 1 )
assert . Equal ( t , "bar" , deployment . Spec . Template . Spec . NodeSelector [ "foo" ])
assert . NotNil ( t , deployment . Spec . Template . Spec . Affinity . NodeAffinity )
assert . Equal ( t , "foo" , deployment . Spec . Template . Spec . Affinity . NodeAffinity . RequiredDuringSchedulingIgnoredDuringExecution . NodeSelectorTerms [ 0 ]. MatchExpressions [ 0 ]. Key )
assert . Equal ( t , "bar" , string ( deployment . Spec . Template . Spec . Affinity . NodeAffinity . RequiredDuringSchedulingIgnoredDuringExecution . NodeSelectorTerms [ 0 ]. MatchExpressions [ 0 ]. Operator ))
2024-04-12 08:22:41 -04:00
assert . Len ( t , deployment . Spec . Template . Spec . TopologySpreadConstraints , 1 )
assert . Equal ( t , "bar" , deployment . Spec . Template . Spec . TopologySpreadConstraints [ 0 ]. LabelSelector . MatchLabels [ "foo" ])
assert . Equal ( t , int32 ( 1 ), deployment . Spec . Template . Spec . TopologySpreadConstraints [ 0 ]. MaxSkew )
assert . Equal ( t , "foo" , deployment . Spec . Template . Spec . TopologySpreadConstraints [ 0 ]. TopologyKey )
2023-01-17 14:36:04 -05:00
assert . Len ( t , deployment . Spec . Template . Spec . Tolerations , 1 )
assert . Equal ( t , "foo" , deployment . Spec . Template . Spec . Tolerations [ 0 ]. Key )
2023-03-10 18:05:51 +01:00
managerImage := "ghcr.io/actions/gha-runner-scale-set-controller:dev"
2023-01-17 14:36:04 -05:00
assert . Len ( t , deployment . Spec . Template . Spec . Containers , 1 )
assert . Equal ( t , "manager" , deployment . Spec . Template . Spec . Containers [ 0 ]. Name )
2023-03-10 18:05:51 +01:00
assert . Equal ( t , managerImage , deployment . Spec . Template . Spec . Containers [ 0 ]. Image )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , corev1 . PullAlways , deployment . Spec . Template . Spec . Containers [ 0 ]. ImagePullPolicy )
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Command , 1 )
assert . Equal ( t , "/manager" , deployment . Spec . Template . Spec . Containers [ 0 ]. Command [ 0 ])
2023-07-05 21:06:42 +02:00
expectArgs := [] string {
"--auto-scaling-runner-set-only" ,
"--auto-scaler-image-pull-secrets=dockerhub" ,
"--log-level=info" ,
"--log-format=json" ,
"--update-strategy=eventual" ,
2023-08-21 13:50:07 +02:00
"--listener-metrics-addr=0" ,
"--listener-metrics-endpoint=" ,
"--metrics-addr=0" ,
2025-01-15 15:54:33 +01:00
"--runner-max-concurrent-reconciles=2" ,
2023-07-05 21:06:42 +02:00
}
assert . ElementsMatch ( t , expectArgs , deployment . Spec . Template . Spec . Containers [ 0 ]. Args )
2023-01-17 14:36:04 -05:00
2023-11-07 15:08:36 +01:00
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Env , 3 )
2023-03-10 18:05:51 +01:00
assert . Equal ( t , "CONTROLLER_MANAGER_CONTAINER_IMAGE" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 0 ]. Name )
assert . Equal ( t , managerImage , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 0 ]. Value )
2023-01-17 14:36:04 -05:00
2023-09-14 15:33:29 +02:00
assert . Equal ( t , "CONTROLLER_MANAGER_POD_NAMESPACE" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 1 ]. Name )
assert . Equal ( t , "metadata.namespace" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 1 ]. ValueFrom . FieldRef . FieldPath )
2023-04-04 19:07:20 +02:00
2023-11-07 15:08:36 +01:00
assert . Equal ( t , "ENV_VAR_NAME_1" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 2 ]. Name )
assert . Equal ( t , "ENV_VAR_VALUE_1" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 2 ]. Value )
2023-03-30 15:40:28 +02:00
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "500m" , deployment . Spec . Template . Spec . Containers [ 0 ]. Resources . Limits . Cpu (). String ())
assert . True ( t , * deployment . Spec . Template . Spec . Containers [ 0 ]. SecurityContext . RunAsNonRoot )
assert . Equal ( t , int64 ( 1000 ), * deployment . Spec . Template . Spec . Containers [ 0 ]. SecurityContext . RunAsUser )
2024-02-12 08:47:09 -05:00
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts , 2 )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , "tmp" , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts [ 0 ]. Name )
assert . Equal ( t , "/tmp" , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts [ 0 ]. MountPath )
2024-02-12 08:47:09 -05:00
assert . Equal ( t , "customMount" , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts [ 1 ]. Name )
assert . Equal ( t , "/my/mount/path" , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts [ 1 ]. MountPath )
2023-01-17 14:36:04 -05:00
}
func TestTemplate_EnableLeaderElectionRole ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"replicaCount" : "2" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/leader_election_role.yaml" })
var leaderRole rbacv1 . Role
helm . UnmarshalK8SYaml ( t , output , & leaderRole )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-leader-election" , leaderRole . Name )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , namespaceName , leaderRole . Namespace )
}
func TestTemplate_EnableLeaderElectionRoleBinding ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"replicaCount" : "2" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/leader_election_role_binding.yaml" })
var leaderRoleBinding rbacv1 . RoleBinding
helm . UnmarshalK8SYaml ( t , output , & leaderRoleBinding )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-leader-election" , leaderRoleBinding . Name )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , namespaceName , leaderRoleBinding . Namespace )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-leader-election" , leaderRoleBinding . RoleRef . Name )
assert . Equal ( t , "test-arc-gha-rs-controller" , leaderRoleBinding . Subjects [ 0 ]. Name )
2023-01-17 14:36:04 -05:00
}
func TestTemplate_EnableLeaderElection ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"replicaCount" : "2" ,
"image.tag" : "dev" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/deployment.yaml" })
var deployment appsv1 . Deployment
helm . UnmarshalK8SYaml ( t , output , & deployment )
assert . Equal ( t , namespaceName , deployment . Namespace )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , deployment . Name )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , int32 ( 2 ), * deployment . Spec . Replicas )
assert . Len ( t , deployment . Spec . Template . Spec . Containers , 1 )
assert . Equal ( t , "manager" , deployment . Spec . Template . Spec . Containers [ 0 ]. Name )
2023-03-01 13:16:03 +01:00
assert . Equal ( t , "ghcr.io/actions/gha-runner-scale-set-controller:dev" , deployment . Spec . Template . Spec . Containers [ 0 ]. Image )
2023-01-17 14:36:04 -05:00
assert . Equal ( t , corev1 . PullIfNotPresent , deployment . Spec . Template . Spec . Containers [ 0 ]. ImagePullPolicy )
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Command , 1 )
assert . Equal ( t , "/manager" , deployment . Spec . Template . Spec . Containers [ 0 ]. Command [ 0 ])
2023-07-05 21:06:42 +02:00
expectedArgs := [] string {
"--auto-scaling-runner-set-only" ,
"--enable-leader-election" ,
2023-08-09 11:11:45 +02:00
"--leader-election-id=test-arc-gha-rs-controller" ,
2023-07-05 21:06:42 +02:00
"--log-level=debug" ,
"--log-format=text" ,
"--update-strategy=immediate" ,
2023-08-21 13:50:07 +02:00
"--listener-metrics-addr=0" ,
"--listener-metrics-endpoint=" ,
"--metrics-addr=0" ,
2025-01-15 15:54:33 +01:00
"--runner-max-concurrent-reconciles=2" ,
2023-07-05 21:06:42 +02:00
}
assert . ElementsMatch ( t , expectedArgs , deployment . Spec . Template . Spec . Containers [ 0 ]. Args )
2023-01-17 14:36:04 -05:00
}
func TestTemplate_ControllerDeployment_ForwardImagePullSecrets ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
2023-03-01 13:16:03 +01:00
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
2023-01-17 14:36:04 -05:00
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-01-17 14:36:04 -05:00
SetValues : map [ string ] string {
"imagePullSecrets[0].name" : "dockerhub" ,
"imagePullSecrets[1].name" : "ghcr" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/deployment.yaml" })
var deployment appsv1 . Deployment
helm . UnmarshalK8SYaml ( t , output , & deployment )
assert . Equal ( t , namespaceName , deployment . Namespace )
2023-07-05 21:06:42 +02:00
expectedArgs := [] string {
"--auto-scaling-runner-set-only" ,
2025-07-01 15:28:18 +02:00
"--auto-scaler-image-pull-secrets=dockerhub" ,
"--auto-scaler-image-pull-secrets=ghcr" ,
2023-07-05 21:06:42 +02:00
"--log-level=debug" ,
"--log-format=text" ,
"--update-strategy=immediate" ,
2023-08-21 13:50:07 +02:00
"--listener-metrics-addr=0" ,
"--listener-metrics-endpoint=" ,
"--metrics-addr=0" ,
2025-01-15 15:54:33 +01:00
"--runner-max-concurrent-reconciles=2" ,
2023-07-05 21:06:42 +02:00
}
assert . ElementsMatch ( t , expectedArgs , deployment . Spec . Template . Spec . Containers [ 0 ]. Args )
2023-01-17 14:36:04 -05:00
}
2023-03-14 10:52:25 -04:00
func TestTemplate_ControllerDeployment_WatchSingleNamespace ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
chartContent , err := os . ReadFile ( filepath . Join ( helmChartPath , "Chart.yaml" ))
require . NoError ( t , err )
chart := new ( Chart )
err = yaml . Unmarshal ( chartContent , chart )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-03-14 10:52:25 -04:00
SetValues : map [ string ] string {
"image.tag" : "dev" ,
"flags.watchSingleNamespace" : "demo" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/deployment.yaml" })
var deployment appsv1 . Deployment
helm . UnmarshalK8SYaml ( t , output , & deployment )
assert . Equal ( t , namespaceName , deployment . Namespace )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , deployment . Name )
assert . Equal ( t , "gha-rs-controller-" + chart . Version , deployment . Labels [ "helm.sh/chart" ])
assert . Equal ( t , "gha-rs-controller" , deployment . Labels [ "app.kubernetes.io/name" ])
2023-03-14 10:52:25 -04:00
assert . Equal ( t , "test-arc" , deployment . Labels [ "app.kubernetes.io/instance" ])
assert . Equal ( t , chart . AppVersion , deployment . Labels [ "app.kubernetes.io/version" ])
assert . Equal ( t , "Helm" , deployment . Labels [ "app.kubernetes.io/managed-by" ])
assert . Equal ( t , namespaceName , deployment . Labels [ "actions.github.com/controller-service-account-namespace" ])
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , deployment . Labels [ "actions.github.com/controller-service-account-name" ])
2023-03-14 10:52:25 -04:00
assert . Equal ( t , "demo" , deployment . Labels [ "actions.github.com/controller-watch-single-namespace" ])
assert . Equal ( t , int32 ( 1 ), * deployment . Spec . Replicas )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller" , deployment . Spec . Selector . MatchLabels [ "app.kubernetes.io/name" ])
2023-03-14 10:52:25 -04:00
assert . Equal ( t , "test-arc" , deployment . Spec . Selector . MatchLabels [ "app.kubernetes.io/instance" ])
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "gha-rs-controller" , deployment . Spec . Template . Labels [ "app.kubernetes.io/name" ])
2023-03-14 10:52:25 -04:00
assert . Equal ( t , "test-arc" , deployment . Spec . Template . Labels [ "app.kubernetes.io/instance" ])
assert . Equal ( t , "manager" , deployment . Spec . Template . Annotations [ "kubectl.kubernetes.io/default-container" ])
assert . Len ( t , deployment . Spec . Template . Spec . ImagePullSecrets , 0 )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , deployment . Spec . Template . Spec . ServiceAccountName )
2023-03-14 10:52:25 -04:00
assert . Nil ( t , deployment . Spec . Template . Spec . SecurityContext )
assert . Empty ( t , deployment . Spec . Template . Spec . PriorityClassName )
assert . Equal ( t , int64 ( 10 ), * deployment . Spec . Template . Spec . TerminationGracePeriodSeconds )
assert . Len ( t , deployment . Spec . Template . Spec . Volumes , 1 )
assert . Equal ( t , "tmp" , deployment . Spec . Template . Spec . Volumes [ 0 ]. Name )
assert . NotNil ( t , 10 , deployment . Spec . Template . Spec . Volumes [ 0 ]. EmptyDir )
assert . Len ( t , deployment . Spec . Template . Spec . NodeSelector , 0 )
assert . Nil ( t , deployment . Spec . Template . Spec . Affinity )
2024-04-12 08:22:41 -04:00
assert . Len ( t , deployment . Spec . Template . Spec . TopologySpreadConstraints , 0 )
2023-03-14 10:52:25 -04:00
assert . Len ( t , deployment . Spec . Template . Spec . Tolerations , 0 )
managerImage := "ghcr.io/actions/gha-runner-scale-set-controller:dev"
assert . Len ( t , deployment . Spec . Template . Spec . Containers , 1 )
assert . Equal ( t , "manager" , deployment . Spec . Template . Spec . Containers [ 0 ]. Name )
assert . Equal ( t , "ghcr.io/actions/gha-runner-scale-set-controller:dev" , deployment . Spec . Template . Spec . Containers [ 0 ]. Image )
assert . Equal ( t , corev1 . PullIfNotPresent , deployment . Spec . Template . Spec . Containers [ 0 ]. ImagePullPolicy )
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Command , 1 )
assert . Equal ( t , "/manager" , deployment . Spec . Template . Spec . Containers [ 0 ]. Command [ 0 ])
2023-07-05 21:06:42 +02:00
expectedArgs := [] string {
"--auto-scaling-runner-set-only" ,
"--log-level=debug" ,
"--log-format=text" ,
"--watch-single-namespace=demo" ,
"--update-strategy=immediate" ,
2023-08-21 13:50:07 +02:00
"--listener-metrics-addr=0" ,
"--listener-metrics-endpoint=" ,
"--metrics-addr=0" ,
2025-01-15 15:54:33 +01:00
"--runner-max-concurrent-reconciles=2" ,
2023-07-05 21:06:42 +02:00
}
assert . ElementsMatch ( t , expectedArgs , deployment . Spec . Template . Spec . Containers [ 0 ]. Args )
2023-03-14 10:52:25 -04:00
2023-11-07 15:08:36 +01:00
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Env , 2 )
2023-03-14 10:52:25 -04:00
assert . Equal ( t , "CONTROLLER_MANAGER_CONTAINER_IMAGE" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 0 ]. Name )
assert . Equal ( t , managerImage , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 0 ]. Value )
assert . Equal ( t , "CONTROLLER_MANAGER_POD_NAMESPACE" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 1 ]. Name )
assert . Equal ( t , "metadata.namespace" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 1 ]. ValueFrom . FieldRef . FieldPath )
2023-04-04 19:07:20 +02:00
2023-03-14 10:52:25 -04:00
assert . Empty ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Resources )
assert . Nil ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. SecurityContext )
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts , 1 )
assert . Equal ( t , "tmp" , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts [ 0 ]. Name )
assert . Equal ( t , "/tmp" , deployment . Spec . Template . Spec . Containers [ 0 ]. VolumeMounts [ 0 ]. MountPath )
}
2023-03-30 15:40:28 +02:00
func TestTemplate_ControllerContainerEnvironmentVariables ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-03-30 15:40:28 +02:00
SetValues : map [ string ] string {
"env[0].Name" : "ENV_VAR_NAME_1" ,
"env[0].Value" : "ENV_VAR_VALUE_1" ,
"env[1].Name" : "ENV_VAR_NAME_2" ,
"env[1].ValueFrom.SecretKeyRef.Key" : "ENV_VAR_NAME_2" ,
"env[1].ValueFrom.SecretKeyRef.Name" : "secret-name" ,
"env[1].ValueFrom.SecretKeyRef.Optional" : "true" ,
"env[2].Name" : "ENV_VAR_NAME_3" ,
"env[2].Value" : "" ,
"env[3].Name" : "ENV_VAR_NAME_4" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/deployment.yaml" })
var deployment appsv1 . Deployment
helm . UnmarshalK8SYaml ( t , output , & deployment )
assert . Equal ( t , namespaceName , deployment . Namespace )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller" , deployment . Name )
2023-03-30 15:40:28 +02:00
2023-11-07 15:08:36 +01:00
assert . Len ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Env , 6 )
assert . Equal ( t , "ENV_VAR_NAME_1" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 2 ]. Name )
assert . Equal ( t , "ENV_VAR_VALUE_1" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 2 ]. Value )
assert . Equal ( t , "ENV_VAR_NAME_2" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 3 ]. Name )
assert . Equal ( t , "secret-name" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 3 ]. ValueFrom . SecretKeyRef . Name )
assert . Equal ( t , "ENV_VAR_NAME_2" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 3 ]. ValueFrom . SecretKeyRef . Key )
assert . True ( t , * deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 3 ]. ValueFrom . SecretKeyRef . Optional )
assert . Equal ( t , "ENV_VAR_NAME_3" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 4 ]. Name )
assert . Empty ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 4 ]. Value )
assert . Equal ( t , "ENV_VAR_NAME_4" , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 5 ]. Name )
assert . Empty ( t , deployment . Spec . Template . Spec . Containers [ 0 ]. Env [ 5 ]. ValueFrom )
2023-03-30 15:40:28 +02:00
}
2023-03-14 10:52:25 -04:00
func TestTemplate_WatchSingleNamespace_NotCreateManagerClusterRole ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-03-14 10:52:25 -04:00
SetValues : map [ string ] string {
"flags.watchSingleNamespace" : "demo" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
_ , err = helm . RenderTemplateE ( t , options , helmChartPath , releaseName , [] string { "templates/manager_cluster_role.yaml" })
assert . ErrorContains ( t , err , "could not find template templates/manager_cluster_role.yaml in chart" , "We should get an error because the template should be skipped" )
}
func TestTemplate_WatchSingleNamespace_NotManagerClusterRoleBinding ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-03-14 10:52:25 -04:00
SetValues : map [ string ] string {
"serviceAccount.create" : "true" ,
"flags.watchSingleNamespace" : "demo" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
_ , err = helm . RenderTemplateE ( t , options , helmChartPath , releaseName , [] string { "templates/manager_cluster_role_binding.yaml" })
assert . ErrorContains ( t , err , "could not find template templates/manager_cluster_role_binding.yaml in chart" , "We should get an error because the template should be skipped" )
}
func TestTemplate_CreateManagerSingleNamespaceRole ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-03-14 10:52:25 -04:00
SetValues : map [ string ] string {
"flags.watchSingleNamespace" : "demo" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/manager_single_namespace_controller_role.yaml" })
var managerSingleNamespaceControllerRole rbacv1 . Role
helm . UnmarshalK8SYaml ( t , output , & managerSingleNamespaceControllerRole )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-single-namespace" , managerSingleNamespaceControllerRole . Name )
2023-03-14 10:52:25 -04:00
assert . Equal ( t , namespaceName , managerSingleNamespaceControllerRole . Namespace )
assert . Equal ( t , 10 , len ( managerSingleNamespaceControllerRole . Rules ))
output = helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/manager_single_namespace_watch_role.yaml" })
var managerSingleNamespaceWatchRole rbacv1 . Role
helm . UnmarshalK8SYaml ( t , output , & managerSingleNamespaceWatchRole )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-single-namespace-watch" , managerSingleNamespaceWatchRole . Name )
2023-03-14 10:52:25 -04:00
assert . Equal ( t , "demo" , managerSingleNamespaceWatchRole . Namespace )
2023-04-10 08:49:32 +02:00
assert . Equal ( t , 14 , len ( managerSingleNamespaceWatchRole . Rules ))
2023-03-14 10:52:25 -04:00
}
func TestTemplate_ManagerSingleNamespaceRoleBinding ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
2023-05-18 14:15:05 +02:00
Logger : logger . Discard ,
2023-03-14 10:52:25 -04:00
SetValues : map [ string ] string {
"flags.watchSingleNamespace" : "demo" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/manager_single_namespace_controller_role_binding.yaml" })
var managerSingleNamespaceControllerRoleBinding rbacv1 . RoleBinding
helm . UnmarshalK8SYaml ( t , output , & managerSingleNamespaceControllerRoleBinding )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-single-namespace" , managerSingleNamespaceControllerRoleBinding . Name )
2023-03-14 10:52:25 -04:00
assert . Equal ( t , namespaceName , managerSingleNamespaceControllerRoleBinding . Namespace )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-single-namespace" , managerSingleNamespaceControllerRoleBinding . RoleRef . Name )
assert . Equal ( t , "test-arc-gha-rs-controller" , managerSingleNamespaceControllerRoleBinding . Subjects [ 0 ]. Name )
2023-03-14 10:52:25 -04:00
assert . Equal ( t , namespaceName , managerSingleNamespaceControllerRoleBinding . Subjects [ 0 ]. Namespace )
output = helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/manager_single_namespace_watch_role_binding.yaml" })
var managerSingleNamespaceWatchRoleBinding rbacv1 . RoleBinding
helm . UnmarshalK8SYaml ( t , output , & managerSingleNamespaceWatchRoleBinding )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-single-namespace-watch" , managerSingleNamespaceWatchRoleBinding . Name )
2023-03-14 10:52:25 -04:00
assert . Equal ( t , "demo" , managerSingleNamespaceWatchRoleBinding . Namespace )
2023-08-09 11:11:45 +02:00
assert . Equal ( t , "test-arc-gha-rs-controller-single-namespace-watch" , managerSingleNamespaceWatchRoleBinding . RoleRef . Name )
assert . Equal ( t , "test-arc-gha-rs-controller" , managerSingleNamespaceWatchRoleBinding . Subjects [ 0 ]. Name )
2023-03-14 10:52:25 -04:00
assert . Equal ( t , namespaceName , managerSingleNamespaceWatchRoleBinding . Subjects [ 0 ]. Namespace )
}
2023-08-21 13:50:07 +02:00
func TestControllerDeployment_MetricsPorts ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
chartContent , err := os . ReadFile ( filepath . Join ( helmChartPath , "Chart.yaml" ))
require . NoError ( t , err )
chart := new ( Chart )
err = yaml . Unmarshal ( chartContent , chart )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"image.tag" : "dev" ,
"metrics.controllerManagerAddr" : ":8080" ,
"metrics.listenerAddr" : ":8081" ,
"metrics.listenerEndpoint" : "/metrics" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/deployment.yaml" })
var deployment appsv1 . Deployment
helm . UnmarshalK8SYaml ( t , output , & deployment )
require . Len ( t , deployment . Spec . Template . Spec . Containers , 1 , "Expected one container" )
container := deployment . Spec . Template . Spec . Containers [ 0 ]
assert . Len ( t , container . Ports , 1 )
port := container . Ports [ 0 ]
assert . Equal ( t , corev1 . Protocol ( "TCP" ), port . Protocol )
assert . Equal ( t , int32 ( 8080 ), port . ContainerPort )
metricsFlags := map [ string ] * struct {
expect string
frequency int
}{
"--listener-metrics-addr" : {
expect : ":8081" ,
},
"--listener-metrics-endpoint" : {
expect : "/metrics" ,
},
"--metrics-addr" : {
expect : ":8080" ,
},
}
for _ , cmd := range container . Args {
s := strings . Split ( cmd , "=" )
if len ( s ) != 2 {
continue
}
flag , ok := metricsFlags [ s [ 0 ]]
if ! ok {
continue
}
flag . frequency ++
assert . Equal ( t , flag . expect , s [ 1 ])
}
for key , value := range metricsFlags {
assert . Equal ( t , value . frequency , 1 , fmt . Sprintf ( "frequency of %q is not 1" , key ))
}
}
2024-06-21 12:12:14 +02:00
func TestDeployment_excludeLabelPropagationPrefixes ( t * testing . T ) {
t . Parallel ()
// Path to the helm chart we will test
helmChartPath , err := filepath . Abs ( "../../gha-runner-scale-set-controller" )
require . NoError ( t , err )
chartContent , err := os . ReadFile ( filepath . Join ( helmChartPath , "Chart.yaml" ))
require . NoError ( t , err )
chart := new ( Chart )
err = yaml . Unmarshal ( chartContent , chart )
require . NoError ( t , err )
releaseName := "test-arc"
namespaceName := "test-" + strings . ToLower ( random . UniqueId ())
options := & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"flags.excludeLabelPropagationPrefixes[0]" : "prefix.com/" ,
"flags.excludeLabelPropagationPrefixes[1]" : "complete.io/label" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , namespaceName ),
}
output := helm . RenderTemplate ( t , options , helmChartPath , releaseName , [] string { "templates/deployment.yaml" })
var deployment appsv1 . Deployment
helm . UnmarshalK8SYaml ( t , output , & deployment )
require . Len ( t , deployment . Spec . Template . Spec . Containers , 1 , "Expected one container" )
container := deployment . Spec . Template . Spec . Containers [ 0 ]
assert . Contains ( t , container . Args , "--exclude-label-propagation-prefix=prefix.com/" )
assert . Contains ( t , container . Args , "--exclude-label-propagation-prefix=complete.io/label" )
}
2025-07-01 15:28:18 +02:00
2025-03-18 20:41:04 +00:00
func TestNamespaceOverride ( t * testing . T ) {
t . Parallel ()
chartPath := "../../gha-runner-scale-set-controller"
releaseName := "test"
releaseNamespace := "test-" + strings . ToLower ( random . UniqueId ())
namespaceOverride := "test-" + strings . ToLower ( random . UniqueId ())
tt := map [ string ] struct {
file string
options * helm . Options
wantNamespace string
}{
"deployment" : {
file : "deployment.yaml" ,
options : & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"namespaceOverride" : namespaceOverride ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , releaseNamespace ),
},
wantNamespace : namespaceOverride ,
},
"leader_election_role_binding" : {
file : "leader_election_role_binding.yaml" ,
options : & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"namespaceOverride" : namespaceOverride ,
"replicaCount" : "2" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , releaseNamespace ),
},
wantNamespace : namespaceOverride ,
},
"leader_election_role" : {
file : "leader_election_role.yaml" ,
options : & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"namespaceOverride" : namespaceOverride ,
"replicaCount" : "2" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , releaseNamespace ),
},
wantNamespace : namespaceOverride ,
},
"manager_listener_role_binding" : {
file : "manager_listener_role_binding.yaml" ,
options : & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"namespaceOverride" : namespaceOverride ,
"replicaCount" : "2" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , releaseNamespace ),
},
wantNamespace : namespaceOverride ,
},
"manager_listener_role" : {
file : "manager_listener_role.yaml" ,
options : & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"namespaceOverride" : namespaceOverride ,
"replicaCount" : "2" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , releaseNamespace ),
},
wantNamespace : namespaceOverride ,
},
"manager_single_namespace_controller_role" : {
file : "manager_single_namespace_controller_role.yaml" ,
options : & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"namespaceOverride" : namespaceOverride ,
"flags.watchSingleNamespace" : "true" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , releaseNamespace ),
},
wantNamespace : namespaceOverride ,
},
"manager_single_namespace_controller_role_binding" : {
file : "manager_single_namespace_controller_role_binding.yaml" ,
options : & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"namespaceOverride" : namespaceOverride ,
"flags.watchSingleNamespace" : "true" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , releaseNamespace ),
},
wantNamespace : namespaceOverride ,
},
"manager_single_namespace_watch_role" : {
file : "manager_single_namespace_watch_role.yaml" ,
options : & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"namespaceOverride" : namespaceOverride ,
"flags.watchSingleNamespace" : "target-ns" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , releaseNamespace ),
},
wantNamespace : "target-ns" ,
},
"manager_single_namespace_watch_role_binding" : {
file : "manager_single_namespace_watch_role_binding.yaml" ,
options : & helm . Options {
Logger : logger . Discard ,
SetValues : map [ string ] string {
"namespaceOverride" : namespaceOverride ,
"flags.watchSingleNamespace" : "target-ns" ,
},
KubectlOptions : k8s . NewKubectlOptions ( "" , "" , releaseNamespace ),
},
wantNamespace : "target-ns" ,
},
}
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 , tc . wantNamespace , renderedObject . Metadata . Namespace )
})
}
}