From 7daa6720de4ab43334ab4e8472386acbe3d0f09d Mon Sep 17 00:00:00 2001 From: Fabian Wiesel Date: Wed, 29 Jul 2026 14:29:35 +0200 Subject: [PATCH] test: verify HypervisorMaintenance owns the Evicting condition Assert via managedFields that the status patch in hypervisor_maintenance_controller.go claims ownership of the Evicting condition entry under the HypervisorMaintenance field manager. This pins ownership at the write site so future refactors cannot silently drop the FieldOwner or move the write to a different controller without failing the test. --- .../hypervisor_maintenance_controller_test.go | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/internal/controller/hypervisor_maintenance_controller_test.go b/internal/controller/hypervisor_maintenance_controller_test.go index bdbe615..c295e6a 100644 --- a/internal/controller/hypervisor_maintenance_controller_test.go +++ b/internal/controller/hypervisor_maintenance_controller_test.go @@ -18,6 +18,7 @@ limitations under the License. package controller import ( + "encoding/json" "fmt" "net/http" @@ -35,6 +36,38 @@ import ( kvmv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1" ) +// findManagedFieldOwnerOfCondition returns the field-manager name that owns +// the status.conditions entry keyed by the given condition type in the +// object's managedFields. It only inspects entries for the "status" +// subresource. Returns the empty string if no manager owns that key. +func findManagedFieldOwnerOfCondition(hv *kvmv1.Hypervisor, condType string) string { + for _, entry := range hv.ManagedFields { + if entry.Subresource != "status" { + continue + } + if entry.FieldsV1 == nil { + continue + } + var fields map[string]any + if err := json.Unmarshal(entry.FieldsV1.GetRawBytes(), &fields); err != nil { + continue + } + status, ok := fields["f:status"].(map[string]any) + if !ok { + continue + } + conditions, ok := status["f:conditions"].(map[string]any) + if !ok { + continue + } + key := fmt.Sprintf(`k:{"type":%q}`, condType) + if _, ok := conditions[key]; ok { + return entry.Manager + } + } + return "" +} + var _ = Describe("HypervisorMaintenanceController", func() { var ( controller *HypervisorMaintenanceController @@ -343,6 +376,23 @@ var _ = Describe("HypervisorMaintenanceController", func() { HaveField("Status", metav1.ConditionTrue), ))) }) + + // The maintenance controller's status patch at + // hypervisor_maintenance_controller.go:91 must claim + // ownership of the Evicting condition via the + // HypervisorMaintenance field manager so other + // controllers do not overwrite it silently. + It("should own the Evicting condition via managedFields", func(ctx SpecContext) { + updated := &kvmv1.Hypervisor{} + Expect(k8sClient.Get(ctx, hypervisorName, updated)).To(Succeed()) + + Expect(meta.FindStatusCondition( + updated.Status.Conditions, kvmv1.ConditionTypeEvicting, + )).NotTo(BeNil(), "precondition: Evicting condition must be set") + + Expect(findManagedFieldOwnerOfCondition(updated, kvmv1.ConditionTypeEvicting)). + To(Equal(HypervisorMaintenanceControllerName)) + }) }) When("there is a finished eviction", func() {