Files
kandev/apps/backend/internal/agent/kubernetes/compose_test.go
T
2026-09-02 13:50:03 +00:00

237 lines
7.9 KiB
Go

package kubernetes
import (
"reflect"
"testing"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
)
func TestComposePodPreservesOperatorFieldsAndInjectsOwnedFields(t *testing.T) {
t.Parallel()
template, err := ParsePodTemplate(`apiVersion: v1
kind: PodTemplate
template:
metadata:
labels:
team: platform
annotations:
example.com/note: retained
spec:
serviceAccountName: workload
automountServiceAccountToken: true
imagePullSecrets:
- name: registry
affinity:
podAffinity: {}
tolerations:
- key: dedicated
operator: Exists
containers:
- name: kandev-agent
image: example/agent:v1
resources:
requests:
cpu: 100m
- name: metrics
image: example/metrics:v2
`)
if err != nil {
t.Fatalf("ParsePodTemplate() error = %v", err)
}
original := template.DeepCopy()
profile := validProfile("")
profile.Workspace = WorkspaceConfig{Mode: WorkspaceModeManagedPVC, Size: "10Gi", AccessModes: []string{"ReadWriteOnce"}}
pod, warnings, err := ComposePod(template, profile, podOptions())
if err != nil {
t.Fatalf("ComposePod() error = %v", err)
}
wantWarningPaths := []string{
"config.pod_template_yaml.template.spec.automountServiceAccountToken",
}
if got := warningPaths(warnings); !reflect.DeepEqual(got, wantWarningPaths) {
t.Fatalf("ComposePod() warning paths = %v, want %v", got, wantWarningPaths)
}
if !reflect.DeepEqual(template, original) {
t.Fatal("ComposePod() mutated input template")
}
if pod.Name != "kandev-session-1" || pod.Namespace != "agents" {
t.Fatalf("pod identity = %s/%s", pod.Namespace, pod.Name)
}
if pod.Labels["team"] != "platform" || pod.Annotations["example.com/note"] != "retained" {
t.Fatalf("operator metadata not preserved: labels=%v annotations=%v", pod.Labels, pod.Annotations)
}
if pod.Labels["kandev.ai/session-id"] != "session-1" || pod.Labels["app.kubernetes.io/managed-by"] != "kandev" {
t.Fatalf("ownership labels = %v", pod.Labels)
}
if pod.Spec.RestartPolicy != corev1.RestartPolicyAlways {
t.Fatalf("restartPolicy = %q", pod.Spec.RestartPolicy)
}
if pod.Spec.OS == nil || pod.Spec.OS.Name != corev1.Linux {
t.Fatalf("spec.os = %#v, want linux", pod.Spec.OS)
}
if pod.Spec.NodeSelector[corev1.LabelOSStable] != "linux" || pod.Spec.NodeSelector[corev1.LabelArchStable] != "amd64" {
t.Fatalf("nodeSelector = %v", pod.Spec.NodeSelector)
}
if pod.Spec.AutomountServiceAccountToken == nil || !*pod.Spec.AutomountServiceAccountToken {
t.Fatal("explicit automountServiceAccountToken=true was not preserved")
}
if pod.Spec.ServiceAccountName != "workload" || len(pod.Spec.ImagePullSecrets) != 1 || len(pod.Spec.Tolerations) != 1 {
t.Fatalf("operator pod fields not preserved: %#v", pod.Spec)
}
main := pod.Spec.Containers[0]
if !reflect.DeepEqual(main.Command, []string{"/bin/sh"}) || !reflect.DeepEqual(main.Args, []string{"-ceu", "run-managed-entrypoint"}) || main.WorkingDir != WorkspaceMountPath {
t.Fatalf("main launch fields = command=%v args=%v workingDir=%q", main.Command, main.Args, main.WorkingDir)
}
if main.Resources.Requests.Cpu().Cmp(resource.MustParse("100m")) != 0 {
t.Fatalf("main resources not preserved: %v", main.Resources)
}
assertManagedPodVolumes(t, pod)
}
func TestComposePodDefaultsServiceAccountTokenOff(t *testing.T) {
t.Parallel()
template, err := ParsePodTemplate(validPodTemplate(""))
if err != nil {
t.Fatal(err)
}
profile := validProfile("")
pod, _, err := ComposePod(template, profile, podOptions())
if err != nil {
t.Fatalf("ComposePod() error = %v", err)
}
if pod.Spec.AutomountServiceAccountToken == nil || *pod.Spec.AutomountServiceAccountToken {
t.Fatal("automountServiceAccountToken default is not false")
}
}
func TestComposePodWorkspaceVolumeModes(t *testing.T) {
t.Parallel()
tests := []struct {
name string
workspace WorkspaceConfig
wantClaim string
wantEmpty bool
}{
{name: "managed pvc", workspace: WorkspaceConfig{Mode: WorkspaceModeManagedPVC, Size: "10Gi", AccessModes: []string{"ReadWriteOnce"}}, wantClaim: "workspace-pvc"},
{name: "existing claim", workspace: WorkspaceConfig{Mode: WorkspaceModeExistingClaim, ClaimName: "existing-pvc"}, wantClaim: "existing-pvc"},
{name: "empty dir", workspace: WorkspaceConfig{Mode: WorkspaceModeEmptyDir}, wantEmpty: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
template, err := ParsePodTemplate(validPodTemplate(""))
if err != nil {
t.Fatal(err)
}
profile := validProfile("")
profile.Workspace = tt.workspace
pod, _, err := ComposePod(template, profile, podOptions())
if err != nil {
t.Fatalf("ComposePod() error = %v", err)
}
workspace := findVolume(t, pod, WorkspaceVolumeName)
if tt.wantEmpty && workspace.EmptyDir == nil {
t.Fatalf("workspace volume = %#v, want emptyDir", workspace)
}
if tt.wantClaim != "" && (workspace.PersistentVolumeClaim == nil || workspace.PersistentVolumeClaim.ClaimName != tt.wantClaim) {
t.Fatalf("workspace volume = %#v, want claim %q", workspace, tt.wantClaim)
}
})
}
}
func TestComposePodWarnsWithoutStrippingPrivilegedHostFields(t *testing.T) {
t.Parallel()
template, err := ParsePodTemplate(`apiVersion: v1
kind: PodTemplate
template:
spec:
hostNetwork: true
volumes:
- name: host
hostPath:
path: /var/run
containers:
- name: kandev-agent
image: example/agent:v1
securityContext:
privileged: true
`)
if err != nil {
t.Fatal(err)
}
pod, warnings, err := ComposePod(template, validProfile(""), podOptions())
if err != nil {
t.Fatalf("ComposePod() error = %v", err)
}
if !pod.Spec.HostNetwork || pod.Spec.Volumes[0].HostPath == nil || pod.Spec.Containers[0].SecurityContext == nil || pod.Spec.Containers[0].SecurityContext.Privileged == nil || !*pod.Spec.Containers[0].SecurityContext.Privileged {
t.Fatal("privileged operator fields were stripped")
}
wantPaths := []string{
"config.pod_template_yaml.template.spec.hostNetwork",
"config.pod_template_yaml.template.spec.volumes[0].hostPath",
"config.pod_template_yaml.template.spec.containers[0].securityContext.privileged",
}
if got := warningPaths(warnings); !reflect.DeepEqual(got, wantPaths) {
t.Fatalf("warning paths = %v, want %v", got, wantPaths)
}
}
func podOptions() PodOptions {
return PodOptions{
Name: "kandev-session-1", Namespace: "agents",
Identity: ResourceIdentity{
ExecutorID: "executor-1", ProfileID: "profile-1", InstanceID: "instance-1",
TaskID: "task-1", SessionID: "session-1", EnvironmentID: "environment-1",
},
Command: []string{"/bin/sh"}, Args: []string{"-ceu", "run-managed-entrypoint"},
WorkingDir: WorkspaceMountPath, AgentctlPort: DefaultAgentctlPort, ManagedPVCName: "workspace-pvc",
}
}
func assertManagedPodVolumes(t *testing.T, pod *corev1.Pod) {
t.Helper()
if findVolume(t, pod, RuntimeVolumeName).EmptyDir == nil {
t.Fatal("runtime volume is not emptyDir")
}
auth := findVolume(t, pod, AuthVolumeName)
if auth.EmptyDir == nil || auth.EmptyDir.Medium != corev1.StorageMediumMemory {
t.Fatal("auth volume is not memory-backed emptyDir")
}
workspace := findVolume(t, pod, WorkspaceVolumeName)
if workspace.PersistentVolumeClaim == nil || workspace.PersistentVolumeClaim.ClaimName != "workspace-pvc" {
t.Fatalf("workspace volume = %#v", workspace)
}
main := pod.Spec.Containers[0]
if len(main.VolumeMounts) != 3 || len(main.Ports) != 1 || main.Ports[0].ContainerPort != DefaultAgentctlPort {
t.Fatalf("main mounts/ports = %#v / %#v", main.VolumeMounts, main.Ports)
}
}
func findVolume(t *testing.T, pod *corev1.Pod, name string) corev1.Volume {
t.Helper()
for _, volume := range pod.Spec.Volumes {
if volume.Name == name {
return volume
}
}
t.Fatalf("volume %q not found", name)
return corev1.Volume{}
}
func warningPaths(warnings []Warning) []string {
paths := make([]string, len(warnings))
for i, warning := range warnings {
paths[i] = warning.Path
}
return paths
}