agentikube/chart/agentikube_test.go

223 lines
6.1 KiB
Go

package chart_test
import (
"os"
"os/exec"
"strings"
"testing"
)
// helmTemplate runs helm template with the given extra args and returns stdout.
func helmTemplate(t *testing.T, extraArgs ...string) string {
t.Helper()
args := []string{
"template", "agentikube", "chart/agentikube/",
"--namespace", "sandboxes",
"--set", "storage.filesystemId=fs-test",
"--set", "sandbox.image=test:latest",
"--set", "compute.clusterName=test-cluster",
}
args = append(args, extraArgs...)
cmd := exec.Command("helm", args...)
cmd.Dir = repoRoot(t)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("helm template failed: %v\n%s", err, out)
}
return string(out)
}
func repoRoot(t *testing.T) string {
t.Helper()
dir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
// This test file lives at chart/agentikube_test.go, so repo root is ..
return dir + "/.."
}
func TestHelmLint(t *testing.T) {
cmd := exec.Command("helm", "lint", "chart/agentikube/")
cmd.Dir = repoRoot(t)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("helm lint failed: %v\n%s", err, out)
}
if !strings.Contains(string(out), "0 chart(s) failed") {
t.Fatalf("helm lint reported failures:\n%s", out)
}
}
func TestHelmTemplateDefaultValues(t *testing.T) {
output := helmTemplate(t)
expected := []string{
"kind: StorageClass",
"kind: SandboxTemplate",
"kind: SandboxWarmPool",
"kind: NodePool",
"kind: EC2NodeClass",
"kind: NetworkPolicy",
}
for _, want := range expected {
if !strings.Contains(output, want) {
t.Errorf("expected %q in rendered output", want)
}
}
}
func TestHelmTemplateLabels(t *testing.T) {
output := helmTemplate(t)
labels := []string{
"helm.sh/chart: agentikube-0.1.0",
"app.kubernetes.io/name: agentikube",
"app.kubernetes.io/instance: agentikube",
"app.kubernetes.io/managed-by: Helm",
`app.kubernetes.io/version: "0.1.0"`,
}
for _, label := range labels {
if !strings.Contains(output, label) {
t.Errorf("expected label %q in rendered output", label)
}
}
}
func TestHelmTemplateKarpenterDisabled(t *testing.T) {
output := helmTemplate(t, "--set", "compute.type=fargate")
if strings.Contains(output, "kind: NodePool") {
t.Error("NodePool should not be rendered when compute.type=fargate")
}
if strings.Contains(output, "kind: EC2NodeClass") {
t.Error("EC2NodeClass should not be rendered when compute.type=fargate")
}
if !strings.Contains(output, "kind: StorageClass") {
t.Error("StorageClass should always be rendered")
}
if !strings.Contains(output, "kind: SandboxTemplate") {
t.Error("SandboxTemplate should always be rendered")
}
}
func TestHelmTemplateWarmPoolDisabled(t *testing.T) {
output := helmTemplate(t, "--set", "sandbox.warmPool.enabled=false")
if strings.Contains(output, "kind: SandboxWarmPool") {
t.Error("SandboxWarmPool should not be rendered when warmPool.enabled=false")
}
if !strings.Contains(output, "kind: SandboxTemplate") {
t.Error("SandboxTemplate should always be rendered")
}
}
func TestHelmTemplateEgressDisabled(t *testing.T) {
output := helmTemplate(t,
"--set", "sandbox.networkPolicy.egressAllowAll=false",
"-s", "templates/networkpolicy.yaml",
)
if strings.Contains(output, "0.0.0.0/0") {
t.Error("egress CIDR should not appear when egressAllowAll=false")
}
lines := strings.Split(output, "\n")
for i, line := range lines {
if strings.Contains(line, "policyTypes:") {
block := strings.Join(lines[i:min(i+4, len(lines))], "\n")
if strings.Contains(block, "Egress") {
t.Error("Egress should not be in policyTypes when egressAllowAll=false")
}
}
}
}
func TestHelmTemplateRequiredValues(t *testing.T) {
tests := []struct {
name string
args []string
wantErr string
}{
{
name: "missing filesystemId",
args: []string{"--set", "sandbox.image=test:latest", "--set", "compute.clusterName=test"},
wantErr: "storage.filesystemId is required",
},
{
name: "missing sandbox image",
args: []string{"--set", "storage.filesystemId=fs-test", "--set", "compute.clusterName=test"},
wantErr: "sandbox.image is required",
},
{
name: "missing clusterName for karpenter",
args: []string{"--set", "storage.filesystemId=fs-test", "--set", "sandbox.image=test:latest"},
wantErr: "compute.clusterName is required for Karpenter",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
args := append([]string{
"template", "agentikube", "chart/agentikube/",
"--namespace", "sandboxes",
}, tt.args...)
cmd := exec.Command("helm", args...)
cmd.Dir = repoRoot(t)
out, err := cmd.CombinedOutput()
if err == nil {
t.Fatal("expected helm template to fail for missing required value")
}
if !strings.Contains(string(out), tt.wantErr) {
t.Errorf("expected error containing %q, got:\n%s", tt.wantErr, out)
}
})
}
}
func TestHelmTemplateEnvVars(t *testing.T) {
output := helmTemplate(t,
"--set", "sandbox.env.MY_VAR=my-value",
"-s", "templates/sandbox-template.yaml",
)
if !strings.Contains(output, "MY_VAR") {
t.Error("expected MY_VAR in rendered env")
}
if !strings.Contains(output, "my-value") {
t.Error("expected my-value in rendered env")
}
}
func TestHelmTemplateNoEnvWhenEmpty(t *testing.T) {
output := helmTemplate(t, "-s", "templates/sandbox-template.yaml")
lines := strings.Split(output, "\n")
for _, line := range lines {
trimmed := strings.TrimSpace(line)
if trimmed == "env:" {
t.Error("env: block should not appear when sandbox.env is empty")
}
}
}
func TestHelmTemplateNamespace(t *testing.T) {
output := helmTemplate(t, "--namespace", "custom-ns")
if !strings.Contains(output, "namespace: custom-ns") {
t.Error("expected namespace: custom-ns in rendered output")
}
}
func TestHelmTemplateConsolidationDisabled(t *testing.T) {
output := helmTemplate(t,
"--set", "compute.consolidation=false",
"-s", "templates/karpenter-nodepool.yaml",
)
if !strings.Contains(output, "consolidationPolicy: WhenEmpty") {
t.Error("expected consolidationPolicy: WhenEmpty when consolidation=false")
}
if strings.Contains(output, "WhenEmptyOrUnderutilized") {
t.Error("should not have WhenEmptyOrUnderutilized when consolidation=false")
}
}