github.com/buildkite/agent-stack-k8s@v0.4.0/scheduler/scheduler_test.go (about)

     1  package scheduler
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/buildkite/agent-stack-k8s/api"
     9  	"github.com/buildkite/agent-stack-k8s/monitor"
    10  	"github.com/stretchr/testify/require"
    11  	"go.uber.org/zap/zaptest"
    12  	corev1 "k8s.io/api/core/v1"
    13  )
    14  
    15  //go:generate mockgen -destination=mock_handler_test.go -source=scheduler.go -package scheduler_test
    16  func TestJobPluginConversion(t *testing.T) {
    17  	pluginConfig := KubernetesPlugin{
    18  		PodSpec: &corev1.PodSpec{
    19  			Containers: []corev1.Container{
    20  				{
    21  					Image:   "alpine:latest",
    22  					Command: []string{"hello world a=b=c"},
    23  					EnvFrom: []corev1.EnvFromSource{
    24  						{
    25  							ConfigMapRef: &corev1.ConfigMapEnvSource{
    26  								LocalObjectReference: corev1.LocalObjectReference{Name: "some-configmap"},
    27  							},
    28  						},
    29  					},
    30  				},
    31  			},
    32  		},
    33  		GitEnvFrom: []corev1.EnvFromSource{
    34  			{
    35  				SecretRef: &corev1.SecretEnvSource{
    36  					LocalObjectReference: corev1.LocalObjectReference{Name: "git-secret"},
    37  				},
    38  			},
    39  		},
    40  	}
    41  	pluginsJSON, err := json.Marshal([]map[string]interface{}{
    42  		{
    43  			"github.com/buildkite-plugins/kubernetes-buildkite-plugin": pluginConfig,
    44  		},
    45  		{
    46  			"github.com/buildkite-plugins/some-other-buildkite-plugin": map[string]interface{}{"foo": "bar"},
    47  		},
    48  	})
    49  	require.NoError(t, err)
    50  
    51  	input := &monitor.Job{
    52  		CommandJob: api.CommandJob{
    53  			Uuid: "abc",
    54  			Env:  []string{fmt.Sprintf("BUILDKITE_PLUGINS=%s", string(pluginsJSON))},
    55  		},
    56  		Tag: "queue=kubernetes",
    57  	}
    58  	wrapper := NewJobWrapper(zaptest.NewLogger(t), input, api.Config{AgentTokenSecret: "token-secret"})
    59  	result, err := wrapper.ParsePlugins().Build()
    60  	require.NoError(t, err)
    61  
    62  	require.Len(t, result.Spec.Template.Spec.Containers, 3)
    63  
    64  	commandContainer := findContainer(t, result.Spec.Template.Spec.Containers, "container-0")
    65  	commandEnv := findEnv(t, commandContainer.Env, "BUILDKITE_COMMAND")
    66  	require.Equal(t, pluginConfig.PodSpec.Containers[0].Command[0], commandEnv.Value)
    67  
    68  	var envFromNames []string
    69  	for _, envFrom := range commandContainer.EnvFrom {
    70  		if envFrom.ConfigMapRef != nil {
    71  			envFromNames = append(envFromNames, envFrom.ConfigMapRef.Name)
    72  		}
    73  		if envFrom.SecretRef != nil {
    74  			envFromNames = append(envFromNames, envFrom.SecretRef.Name)
    75  		}
    76  	}
    77  	require.ElementsMatch(t, envFromNames, []string{"some-configmap", "git-secret"})
    78  
    79  	tokenEnv := findEnv(t, commandContainer.Env, "BUILDKITE_AGENT_TOKEN")
    80  	require.Equal(t, "token-secret", tokenEnv.ValueFrom.SecretKeyRef.Name)
    81  
    82  	tagLabel := result.Labels[api.TagLabel]
    83  	require.Equal(t, api.TagToLabel(input.Tag), tagLabel)
    84  
    85  	pluginsEnv := findEnv(t, commandContainer.Env, "BUILDKITE_PLUGINS")
    86  	require.Equal(t, pluginsEnv.Value, `[{"github.com/buildkite-plugins/some-other-buildkite-plugin":{"foo":"bar"}}]`)
    87  }
    88  
    89  func TestJobWithNoKubernetesPlugin(t *testing.T) {
    90  	input := &monitor.Job{
    91  		CommandJob: api.CommandJob{
    92  			Uuid:    "abc",
    93  			Command: "echo hello world",
    94  		},
    95  	}
    96  	wrapper := NewJobWrapper(zaptest.NewLogger(t), input, api.Config{})
    97  	result, err := wrapper.ParsePlugins().Build()
    98  	require.NoError(t, err)
    99  
   100  	require.Len(t, result.Spec.Template.Spec.Containers, 3)
   101  
   102  	commandContainer := findContainer(t, result.Spec.Template.Spec.Containers, "container-0")
   103  	commandEnv := findEnv(t, commandContainer.Env, "BUILDKITE_COMMAND")
   104  	require.Equal(t, input.Command, commandEnv.Value)
   105  	pluginsEnv := findEnv(t, commandContainer.Env, "BUILDKITE_PLUGINS")
   106  	require.Nil(t, pluginsEnv)
   107  }
   108  
   109  func TestFailureJobs(t *testing.T) {
   110  	pluginsJSON, err := json.Marshal([]map[string]interface{}{
   111  		{
   112  			"github.com/buildkite-plugins/kubernetes-buildkite-plugin": `"some-invalid-json"`,
   113  		},
   114  	})
   115  
   116  	input := &monitor.Job{
   117  		CommandJob: api.CommandJob{
   118  			Uuid: "abc",
   119  			Env:  []string{fmt.Sprintf("BUILDKITE_PLUGINS=%s", string(pluginsJSON))},
   120  		},
   121  		Tag: "queue=kubernetes",
   122  	}
   123  	wrapper := NewJobWrapper(zaptest.NewLogger(t), input, api.Config{})
   124  	_, err = wrapper.ParsePlugins().Build()
   125  	require.Error(t, err)
   126  
   127  	result, err := wrapper.BuildFailureJob(err)
   128  	require.NoError(t, err)
   129  
   130  	commandContainer := findContainer(t, result.Spec.Template.Spec.Containers, "container-0")
   131  	commandEnv := findEnv(t, commandContainer.Env, "BUILDKITE_COMMAND")
   132  	require.Equal(t, `echo "failed parsing Kubernetes plugin: json: cannot unmarshal string into Go value of type scheduler.KubernetesPlugin" && exit 1`, commandEnv.Value)
   133  
   134  }
   135  
   136  func findContainer(t *testing.T, containers []corev1.Container, name string) corev1.Container {
   137  	for _, container := range containers {
   138  		if container.Name == name {
   139  			return container
   140  		}
   141  	}
   142  	t.Helper()
   143  	require.FailNow(t, "container not found")
   144  
   145  	return corev1.Container{}
   146  }
   147  
   148  func findEnv(t *testing.T, envs []corev1.EnvVar, name string) *corev1.EnvVar {
   149  	for _, env := range envs {
   150  		if env.Name == name {
   151  			return &env
   152  		}
   153  	}
   154  
   155  	return nil
   156  }