package main import ( "context" "encoding/json" "reflect" "testing" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/yaml" ) func TestCapturedSpec(t *testing.T) { instance, template := bundleFixture(t) ctx := context.Background() delivery, err := decodeProjectDelivery(continuousDelivery()) if err != nil { t.Fatal(err) } if err := instance.ensureWorkflow(ctx, &delivery, "first", template.GetName(), "build", nil, nil); err != nil { t.Fatal(err) } bound := boundTemplate(t, instance, "first") stored, _, _ := unstructured.NestedMap(bound.Object, "spec") if err := unstructured.SetNestedSlice(template.Object, []any{map[string]any{"name": "build", "container": map[string]any{"image": "example.invalid/builder:v2"}}}, "spec", "templates"); err != nil { t.Fatal(err) } gvr := schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "workflowtemplates"} if _, err := instance.client.Resource(gvr).Namespace("delivery").Update(ctx, template, metav1.UpdateOptions{}); err != nil { t.Fatal(err) } live, _, _ := unstructured.NestedMap(boundTemplate(t, instance, "first").Object, "spec") if !reflect.DeepEqual(stored, live) { t.Fatal("captured Workflow spec changed through its live template reference") } } func TestCapturedActions(t *testing.T) { instance, template := bundleFixture(t) ctx := context.Background() delivery, err := decodeProjectDelivery(continuousDelivery()) if err != nil { t.Fatal(err) } if err := instance.ensureWorkflow(ctx, &delivery, "first", template.GetName(), "build", nil, nil); err != nil { t.Fatal(err) } gvr := schema.GroupVersionResource{Version: "v1", Resource: "configmaps"} config, err := instance.client.Resource(gvr).Namespace("delivery").Get(ctx, "actions", metav1.GetOptions{}) if err != nil { t.Fatal(err) } config.Object["data"] = map[string]any{"build.fsx": "printfn \"new action\""} if _, err := instance.client.Resource(gvr).Namespace("delivery").Update(ctx, config, metav1.UpdateOptions{}); err != nil { t.Fatal(err) } volumes, _, _ := unstructured.NestedSlice(boundTemplate(t, instance, "first").Object, "spec", "volumes") name := volumes[0].(map[string]any)["configMap"].(map[string]any)["name"].(string) captured, err := instance.client.Resource(gvr).Namespace("delivery").Get(ctx, name, metav1.GetOptions{}) if err != nil { t.Fatal(err) } value, _, _ := unstructured.NestedString(captured.Object, "data", "build.fsx") if value != "printfn \"old action\"" { t.Fatalf("a later Pod resolves changed action content: %q", value) } } func bundleFixture(t *testing.T) (*controller, *unstructured.Unstructured) { t.Helper() now := time.Date(2026, 10, 2, 0, 0, 0, 0, time.UTC) instance := testController(t, continuousDelivery(), &mutableRefs{}, &now) ctx := context.Background() config := &unstructured.Unstructured{Object: map[string]any{ "apiVersion": "v1", "kind": "ConfigMap", "metadata": map[string]any{"name": "actions", "namespace": "delivery", "labels": map[string]any{"app.kubernetes.io/name": "project-delivery"}}, "data": map[string]any{"build.fsx": "printfn \"old action\""}, }} if _, err := instance.client.Resource(schema.GroupVersionResource{Version: "v1", Resource: "configmaps"}).Namespace("delivery").Create(ctx, config, metav1.CreateOptions{}); err != nil { t.Fatal(err) } template := &unstructured.Unstructured{Object: map[string]any{ "apiVersion": "argoproj.io/v1alpha1", "kind": "WorkflowTemplate", "metadata": map[string]any{"name": "nuthatch-delivery", "namespace": "delivery"}, "spec": map[string]any{ "entrypoint": "build", "templates": []any{map[string]any{"name": "build", "container": map[string]any{"image": "example.invalid/builder:v1"}}}, "volumes": []any{map[string]any{"name": "actions", "configMap": map[string]any{"name": "actions"}}}, }, }} gvr := schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "workflowtemplates"} if _, err := instance.client.Resource(gvr).Namespace("delivery").Update(ctx, template, metav1.UpdateOptions{}); err != nil { t.Fatal(err) } return instance, template } func boundTemplate(t *testing.T, instance *controller, name string) *unstructured.Unstructured { t.Helper() ctx := context.Background() workflow, err := instance.client.Resource(workflowGVR).Namespace("delivery").Get(ctx, name, metav1.GetOptions{}) if err != nil { t.Fatal(err) } ref, _, _ := unstructured.NestedString(workflow.Object, "spec", "workflowTemplateRef", "name") gvr := schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "workflowtemplates"} template, err := instance.client.Resource(gvr).Namespace("delivery").Get(ctx, ref, metav1.GetOptions{}) if err != nil { t.Fatal(err) } return template } func TestCapturedPatch(t *testing.T) { instance, template := bundleFixture(t) ctx := context.Background() unstructured.RemoveNestedField(template.Object, "spec", "volumes") if err := unstructured.SetNestedSlice(template.Object, []any{map[string]any{ "name": "build", "container": map[string]any{"image": "example.invalid/builder:v1"}, "podSpecPatch": "volumes:\n- name: actions\n configMap:\n name: actions\n", }}, "spec", "templates"); err != nil { t.Fatal(err) } if _, err := instance.client.Resource(templateGVR).Namespace("delivery").Update(ctx, template, metav1.UpdateOptions{}); err != nil { t.Fatal(err) } delivery, err := decodeProjectDelivery(continuousDelivery()) if err != nil { t.Fatal(err) } if err := instance.ensureWorkflow(ctx, &delivery, "first", template.GetName(), "build", nil, nil); err != nil { t.Fatal(err) } config, err := instance.client.Resource(configMapGVR).Namespace("delivery").Get(ctx, "actions", metav1.GetOptions{}) if err != nil { t.Fatal(err) } config.Object["data"] = map[string]any{"build.fsx": "printfn \"new action\""} if _, err := instance.client.Resource(configMapGVR).Namespace("delivery").Update(ctx, config, metav1.UpdateOptions{}); err != nil { t.Fatal(err) } templates, _, _ := unstructured.NestedSlice(boundTemplate(t, instance, "first").Object, "spec", "templates") patch := templates[0].(map[string]any)["podSpecPatch"].(string) data, err := yaml.YAMLToJSON([]byte(patch)) if err != nil { t.Fatal(err) } var body map[string]any if err := json.Unmarshal(data, &body); err != nil { t.Fatal(err) } name := body["volumes"].([]any)[0].(map[string]any)["configMap"].(map[string]any)["name"].(string) captured, err := instance.client.Resource(configMapGVR).Namespace("delivery").Get(ctx, name, metav1.GetOptions{}) if err != nil { t.Fatal(err) } value, _, _ := unstructured.NestedString(captured.Object, "data", "build.fsx") if value != "printfn \"old action\"" { t.Fatalf("nested podSpecPatch resolves changed actions: %q", value) } }