164 lines
6.8 KiB
Go
164 lines
6.8 KiB
Go
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)
|
|
}
|
|
}
|