@@ -6688,6 +6688,53 @@ TEST ISOLATION + CLEANUP
66886688 isolation as unit tests.
66896689
66906690
6691+ REAL K8S TESTING RULES — HARD-WON, NON-NEGOTIABLE
6692+ ──────────────────────────────────────────────────
6693+ These rules prevent flaky CI failures on real K8s (--backend real).
6694+ Every new test touching real K8s MUST follow these.
6695+
6696+ 1. NEVER use raw k8s.update_deployment/service/statefulset() in tests
6697+ that run on real K8s. Deployments have controllers that race to
6698+ mutate resourceVersion → 409 Conflict. Use SDK methods (ps.scale,
6699+ deploy.deploy) which have built-in retry logic.
6700+
6701+ 2. NEVER assert immediately after delete. K8s deletion is async.
6702+ Use poll_until(fn=_get_or_none, predicate=lambda r: r is None).
6703+
6704+ 3. NEVER use time.sleep() for stabilization. Use poll_until() or
6705+ wait_for_port_open(). Sleeps waste CI time and still flake.
6706+
6707+ 4. NEVER create Deployments/Services with raw k8s.create_*() in tests
6708+ that run on real K8s. Use factory.deploy.deploy() which sets
6709+ correct labels for cleanup.
6710+
6711+ 5. Contract test updates MUST use read-modify-write + retry loop:
6712+ for _attempt in range(5):
6713+ current = k8s.get_deployment(ns, name)
6714+ current["spec"]["replicas"] = 3
6715+ try:
6716+ k8s.update_deployment(ns, name, current)
6717+ break
6718+ except FakeConflictError:
6719+ continue
6720+
6721+ 6. Namespace tests MUST clean up — use request.addfinalizer() and
6722+ k8ut- prefix so session cleanup catches strays.
6723+
6724+ 7. _wipe_namespace_resources() MUST wait for ALL resource types
6725+ (Deployment, StatefulSet, Service, Ingress, NetworkPolicy, PVC,
6726+ ConfigMap, Secret) — not just a subset.
6727+
6728+ 8. Know which fixtures route to real K8s:
6729+ - factory, k8s_client → real with --backend real
6730+ - app_factory, deployed_factory, fake_k8s → always FakeK8sClient
6731+
6732+ Shared E2E helpers (tests/e2e/helpers.py):
6733+ poll_until, wait_for_pods_ready, wait_for_port_open,
6734+ wait_for_sts_ready, wait_for_service_deleted,
6735+ wait_for_lb_address, wait_for_no_pods, find_running_pod
6736+
6737+
66916738UNIT TEST EXAMPLES
66926739──────────────────
66936740 def test_apps_create(fake_client):
0 commit comments