From 36d14d758d22b28882aa03b3e08cefa33f21403d Mon Sep 17 00:00:00 2001 From: Evan Vetere Date: Wed, 1 Jul 2026 15:01:29 -0400 Subject: [PATCH 1/5] test: migrate network-crud e2e from infra Migrate the Network CRUD API-contract test out of datum/infra's live-env Chainsaw suite into NSO's local kind harness, per datum-cloud/infra#3006. This test validates a networking.datumapis.com contract owned by NSO, so it belongs in this repo and runs against the local operator pre-merge. Key changes: - Drop the datumctl auth update-kubeconfig setup step and the clusters/cluster: project blocks that targeted ./test-kubeconfig; the test now runs on spec.cluster: nso-standard like the sibling tests. - Remove spec.skip: true; the live blockers in #2733 don't apply to the local operator. - Keep the Network resource body, the Ready assertion (2m timeout), and the delete step intact. --- test/e2e/network-crud/chainsaw-test.yaml | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 test/e2e/network-crud/chainsaw-test.yaml diff --git a/test/e2e/network-crud/chainsaw-test.yaml b/test/e2e/network-crud/chainsaw-test.yaml new file mode 100644 index 00000000..151dd72b --- /dev/null +++ b/test/e2e/network-crud/chainsaw-test.yaml @@ -0,0 +1,48 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: network-crud +spec: + cluster: nso-standard + steps: + - name: Create Network + try: + - create: + resource: + apiVersion: networking.datumapis.com/v1alpha + kind: Network + metadata: + name: (to_lower(concat('e2e-net-', replace_all(time_now(), ':', '-')))) + namespace: default + spec: + ipam: + mode: Auto + outputs: + - name: NETWORK_NAME + value: (@.metadata.name) + + - name: Assert Network is Ready + try: + - assert: + timeout: 2m + resource: + apiVersion: networking.datumapis.com/v1alpha + kind: Network + metadata: + name: ($NETWORK_NAME) + namespace: default + status: + (conditions[?type == 'Ready'][0].status): 'True' + + - name: Delete Network + try: + - script: + timeout: 1m + env: + - name: NETWORK_NAME + value: ($NETWORK_NAME) + content: | + set -e + kubectl delete network.networking.datumapis.com $NETWORK_NAME -n default --wait=true --timeout=60s + echo "Network $NETWORK_NAME deleted" From d41efdee63ffdd15e840159a316f67f3aff37f9c Mon Sep 17 00:00:00 2001 From: Evan Vetere Date: Mon, 13 Jul 2026 18:00:53 -0400 Subject: [PATCH 2/5] test: add network-crud e2e for Network lifecycle No e2e covers the bare Network contract NSO owns. Add one that exercises admission and the finalizer lifecycle in the local kind harness. Key changes: - assert Network admission and the network-controller finalizer - assert clean deletion (finalizer release, no NetworkContext GC) - use chainsaw's native delete op Readiness is intentionally not asserted: NSO writes no condition on a bare Network; readiness is provider-driven and no provider runs in the local harness. --- test/e2e/network-crud/chainsaw-test.yaml | 29 ++++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/test/e2e/network-crud/chainsaw-test.yaml b/test/e2e/network-crud/chainsaw-test.yaml index 151dd72b..d1902c3b 100644 --- a/test/e2e/network-crud/chainsaw-test.yaml +++ b/test/e2e/network-crud/chainsaw-test.yaml @@ -22,27 +22,32 @@ spec: - name: NETWORK_NAME value: (@.metadata.name) - - name: Assert Network is Ready + - name: Assert Network is admitted and finalized + description: | + NSO's network controller writes no readiness condition on a bare + Network; readiness is provider-driven and no provider runs in the local + kind harness. What NSO owns here is admission and the finalizer + lifecycle, so that is what this asserts. try: - assert: - timeout: 2m + timeout: 30s resource: apiVersion: networking.datumapis.com/v1alpha kind: Network metadata: name: ($NETWORK_NAME) namespace: default - status: - (conditions[?type == 'Ready'][0].status): 'True' + (contains(finalizers, 'networking.datumapis.com/network-controller')): true - name: Delete Network + description: | + Delete blocks until the object is gone, asserting the network controller + releases its finalizer (no NetworkContexts exist to garbage-collect). try: - - script: + - delete: timeout: 1m - env: - - name: NETWORK_NAME - value: ($NETWORK_NAME) - content: | - set -e - kubectl delete network.networking.datumapis.com $NETWORK_NAME -n default --wait=true --timeout=60s - echo "Network $NETWORK_NAME deleted" + ref: + apiVersion: networking.datumapis.com/v1alpha + kind: Network + name: ($NETWORK_NAME) + namespace: default From 054212aa8dcd08f820a9c53416f0df0ce217c4f4 Mon Sep 17 00:00:00 2001 From: Evan Vetere Date: Mon, 13 Jul 2026 18:08:39 -0400 Subject: [PATCH 3/5] test: add network-context lifecycle e2e Two NSO behaviors have no e2e coverage in the local kind harness: the networkcontext controller deriving Ready from Programmed, and the Network finalizer garbage-collecting an owned NetworkContext on delete. Add a test that drives both. Key changes: - build the Network -> NetworkBinding -> NetworkContext chain - patch the context Programmed and assert the controller sets Ready - assert the NetworkBinding then reaches Ready - delete the Network and assert the owned context is cascade-deleted before the finalizer releases A plugin normally sets Programmed; none runs locally, so the condition is patched directly, mirroring the networkbinding test. --- .../chainsaw-test.yaml | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 test/e2e/network-context-lifecycle/chainsaw-test.yaml diff --git a/test/e2e/network-context-lifecycle/chainsaw-test.yaml b/test/e2e/network-context-lifecycle/chainsaw-test.yaml new file mode 100644 index 00000000..99ab69fc --- /dev/null +++ b/test/e2e/network-context-lifecycle/chainsaw-test.yaml @@ -0,0 +1,114 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: network-context-lifecycle +spec: + cluster: nso-standard + steps: + - name: Create Network + try: + - create: + resource: + apiVersion: networking.datumapis.com/v1alpha + kind: Network + metadata: + name: test-cascade-network + namespace: default + spec: + ipam: + mode: Auto + + - name: Create NetworkBinding and assert NetworkContext is created + description: | + The binding controller creates a NetworkContext owned by the Network. + This ownership is what the Network finalizer relies on to garbage-collect + the context on delete. + try: + - create: + resource: + apiVersion: networking.datumapis.com/v1alpha + kind: NetworkBinding + metadata: + name: test-cascade-binding + namespace: default + spec: + network: + name: test-cascade-network + location: + name: test-location + namespace: default + - assert: + resource: + apiVersion: networking.datumapis.com/v1alpha + kind: NetworkContext + metadata: + name: test-cascade-network-default-test-location + namespace: default + (length(ownerReferences[?kind == 'Network' && controller == `true`]) == `1`): true + + - name: Mark NetworkContext as Programmed + description: | + A plugin is expected to program the context at its backend and set the + Programmed condition. No such plugin runs in the local harness, so the + condition is set directly. A kubectl command is used because Chainsaw + does not support updating subresources. + See https://github.com/kyverno/chainsaw/issues/300. + try: + - script: + content: | + kubectl -n default patch networkcontext test-cascade-network-default-test-location \ + --subresource=status --type=merge \ + -p '{"status":{"conditions":[{"type": "Programmed", "status": "True", "reason": "Test", "message": "test", "lastTransitionTime": "2025-02-24T23:59:09Z"}]}}' + + - name: Assert NetworkContext becomes Ready + description: | + The networkcontext controller derives Ready from Programmed. This asserts + that transition, which no other e2e exercises. + try: + - assert: + timeout: 1m + resource: + apiVersion: networking.datumapis.com/v1alpha + kind: NetworkContext + metadata: + name: test-cascade-network-default-test-location + namespace: default + status: + (conditions[?type == 'Ready'][0].status): 'True' + + - name: Assert NetworkBinding becomes Ready + try: + - wait: + apiVersion: networking.datumapis.com/v1alpha + kind: NetworkBinding + name: test-cascade-binding + namespace: default + timeout: 1m + for: + condition: + name: Ready + value: 'true' + + - name: Delete Network and assert cascade cleanup + description: | + Deleting the Network drives its finalizer to garbage-collect the owned + NetworkContext before releasing. The delete blocks until the Network is + gone, which can only happen after the context is removed; the script then + confirms the context is absent. + try: + - delete: + timeout: 1m + ref: + apiVersion: networking.datumapis.com/v1alpha + kind: Network + name: test-cascade-network + namespace: default + - script: + content: | + set -e + if kubectl -n default get networkcontext test-cascade-network-default-test-location 2>/dev/null; then + echo "NetworkContext still exists after Network deletion" >&2 + exit 1 + fi + echo "NetworkContext garbage-collected" From de2be0377cd7189d555eec4cd6fce028c906b16f Mon Sep 17 00:00:00 2001 From: Evan Vetere Date: Mon, 13 Jul 2026 18:42:42 -0400 Subject: [PATCH 4/5] test: fix chainsaw assertions in network e2e The first CI run failed on two test-authoring bugs, not operator behavior. Key changes: - network-crud: use a fixed Network name; create outputs do not propagate across steps, so $NETWORK_NAME was undefined in the assert - network-crud: assert the finalizer via array containment instead of a JMESPath contains() expression - network-context-lifecycle: assert Ready via array containment; the filter projection conditions[?type=='Ready'][0].status is not indexable and errored with "types are not comparable, string - slice" --- .../e2e/network-context-lifecycle/chainsaw-test.yaml | 4 +++- test/e2e/network-crud/chainsaw-test.yaml | 12 +++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/e2e/network-context-lifecycle/chainsaw-test.yaml b/test/e2e/network-context-lifecycle/chainsaw-test.yaml index 99ab69fc..8eef616e 100644 --- a/test/e2e/network-context-lifecycle/chainsaw-test.yaml +++ b/test/e2e/network-context-lifecycle/chainsaw-test.yaml @@ -75,7 +75,9 @@ spec: name: test-cascade-network-default-test-location namespace: default status: - (conditions[?type == 'Ready'][0].status): 'True' + conditions: + - type: Ready + status: 'True' - name: Assert NetworkBinding becomes Ready try: diff --git a/test/e2e/network-crud/chainsaw-test.yaml b/test/e2e/network-crud/chainsaw-test.yaml index d1902c3b..7abe45e8 100644 --- a/test/e2e/network-crud/chainsaw-test.yaml +++ b/test/e2e/network-crud/chainsaw-test.yaml @@ -13,14 +13,11 @@ spec: apiVersion: networking.datumapis.com/v1alpha kind: Network metadata: - name: (to_lower(concat('e2e-net-', replace_all(time_now(), ':', '-')))) + name: test-network-crud namespace: default spec: ipam: mode: Auto - outputs: - - name: NETWORK_NAME - value: (@.metadata.name) - name: Assert Network is admitted and finalized description: | @@ -35,9 +32,10 @@ spec: apiVersion: networking.datumapis.com/v1alpha kind: Network metadata: - name: ($NETWORK_NAME) + name: test-network-crud namespace: default - (contains(finalizers, 'networking.datumapis.com/network-controller')): true + finalizers: + - networking.datumapis.com/network-controller - name: Delete Network description: | @@ -49,5 +47,5 @@ spec: ref: apiVersion: networking.datumapis.com/v1alpha kind: Network - name: ($NETWORK_NAME) + name: test-network-crud namespace: default From 3158953e9fc7c948f43d558c6c1fe0d65e2020fc Mon Sep 17 00:00:00 2001 From: Evan Vetere Date: Mon, 13 Jul 2026 18:56:39 -0400 Subject: [PATCH 5/5] test: fix Ready assertion in network-context lifecycle e2e Chainsaw array assertions are length-strict, not containment: asserting a single condition against a status that holds both Programmed and Ready failed with "lengths of slices don't match". Assert via a length() filter instead, matching the ownerReferences assertion in the same test. --- test/e2e/network-context-lifecycle/chainsaw-test.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/e2e/network-context-lifecycle/chainsaw-test.yaml b/test/e2e/network-context-lifecycle/chainsaw-test.yaml index 8eef616e..f171da9e 100644 --- a/test/e2e/network-context-lifecycle/chainsaw-test.yaml +++ b/test/e2e/network-context-lifecycle/chainsaw-test.yaml @@ -75,9 +75,7 @@ spec: name: test-cascade-network-default-test-location namespace: default status: - conditions: - - type: Ready - status: 'True' + (length(conditions[?type == 'Ready' && status == 'True']) == `1`): true - name: Assert NetworkBinding becomes Ready try: