From 6f14473e00bb34055b0b3daa5146792ab19ae283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20K=C3=A4stner?= Date: Fri, 11 Sep 2026 17:19:12 +0200 Subject: [PATCH 1/2] Isolate per-device provider state in controller tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test provider was a singleton shared by all controllers. Every test creates a distinct Device via GenerateName, but the provider stored all state (DNS, BGP, NTP, LLDP, etc.) in flat fields on a single struct. This caused state bleed between test suites and intermittent failures. Refactor the test provider into three parts: - DeviceState: per-device mutable state (all resource fields, ConnectFailure, LastRebootTime), each with its own mutex - DeviceStore: shared map of device name to DeviceState, with a StateFor(name) accessor that creates entries on demand - Provider: lightweight per-reconcile instance created by the ProviderFunc factory, capturing the device name during Connect via the new Connection.DeviceName field Add DeviceName to deviceutil.Connection and set it in GetDeviceConnection so the mock provider can identify the device without changing any controller code. Signed-off-by: Felix Kästner --- .../controller/core/acl_controller_test.go | 4 +- .../controller/core/banner_controller_test.go | 20 +- .../controller/core/bgp_controller_test.go | 8 +- .../core/bgp_peer_controller_test.go | 10 +- .../core/certificate_controller_test.go | 4 +- .../core/configbackup_controller_test.go | 40 +- .../controller/core/device_controller_test.go | 10 +- .../core/dhcprelay_controller_test.go | 16 +- .../controller/core/dns_controller_test.go | 8 +- .../core/ethernetsegment_controller_test.go | 4 +- .../core/evpninstance_controller_test.go | 4 +- .../core/interface_controller_test.go | 26 +- .../controller/core/isis_controller_test.go | 4 +- .../controller/core/lldp_controller_test.go | 70 +-- .../core/managementaccess_controller_test.go | 4 +- .../controller/core/ntp_controller_test.go | 8 +- .../controller/core/nve_controller_test.go | 48 +- .../controller/core/ospf_controller_test.go | 4 +- .../controller/core/pim_controller_test.go | 4 +- .../core/prefixset_controller_test.go | 4 +- .../controller/core/probe_controller_test.go | 6 +- .../core/routingpolicy_controller_test.go | 8 +- .../controller/core/snmp_controller_test.go | 8 +- internal/controller/core/suite_test.go | 565 ++++++++++-------- .../controller/core/syslog_controller_test.go | 4 +- .../controller/core/user_controller_test.go | 4 +- .../controller/core/vlan_controller_test.go | 4 +- .../controller/core/vrf_controller_test.go | 8 +- internal/deviceutil/deviceutil.go | 11 +- 29 files changed, 502 insertions(+), 416 deletions(-) diff --git a/internal/controller/core/acl_controller_test.go b/internal/controller/core/acl_controller_test.go index bd2294365..ea1420864 100644 --- a/internal/controller/core/acl_controller_test.go +++ b/internal/controller/core/acl_controller_test.go @@ -76,7 +76,7 @@ var _ = Describe("AccessControlList Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.ACLs.Has(name)).To(BeFalse(), "Provider shouldn't have AccessControlList configured anymore") + g.Expect(testDevices.StateFor(name).ACLs.Has(name)).To(BeFalse(), "Provider shouldn't have AccessControlList configured anymore") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -123,7 +123,7 @@ var _ = Describe("AccessControlList Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.ACLs.Has(name)).To(BeTrue(), "Provider should have AccessControlList configured") + g.Expect(testDevices.StateFor(name).ACLs.Has(name)).To(BeTrue(), "Provider should have AccessControlList configured") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/banner_controller_test.go b/internal/controller/core/banner_controller_test.go index 22cdfc9a2..ed786b57d 100644 --- a/internal/controller/core/banner_controller_test.go +++ b/internal/controller/core/banner_controller_test.go @@ -45,8 +45,8 @@ var _ = Describe("Banner Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.PreLoginBanner).To(BeNil(), "Provider PreLogin Banner should be nil") - g.Expect(testProvider.PostLoginBanner).To(BeNil(), "Provider PostLogin Banner should be nil") + g.Expect(testDevices.StateFor(name).PreLoginBanner).To(BeNil(), "Provider PreLogin Banner should be nil") + g.Expect(testDevices.StateFor(name).PostLoginBanner).To(BeNil(), "Provider PostLogin Banner should be nil") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -107,10 +107,10 @@ var _ = Describe("Banner Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.PreLoginBanner).ToNot(BeNil(), "Provider Banner should not be nil") - g.Expect(testProvider.PostLoginBanner).To(BeNil(), "Provider PostLogin Banner should be nil") - if testProvider.PreLoginBanner != nil { - g.Expect(*testProvider.PreLoginBanner).To(Equal("Test Banner")) + g.Expect(testDevices.StateFor(name).PreLoginBanner).ToNot(BeNil(), "Provider Banner should not be nil") + g.Expect(testDevices.StateFor(name).PostLoginBanner).To(BeNil(), "Provider PostLogin Banner should be nil") + if testDevices.StateFor(name).PreLoginBanner != nil { + g.Expect(*testDevices.StateFor(name).PreLoginBanner).To(Equal("Test Banner")) } }).Should(Succeed()) }) @@ -166,10 +166,10 @@ var _ = Describe("Banner Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.PreLoginBanner).To(BeNil(), "Provider PreLogin Banner should be nil") - g.Expect(testProvider.PostLoginBanner).ToNot(BeNil(), "Provider PostLogin Banner should not be nil") - if testProvider.PostLoginBanner != nil { - g.Expect(*testProvider.PostLoginBanner).To(Equal("Test Banner")) + g.Expect(testDevices.StateFor(name).PreLoginBanner).To(BeNil(), "Provider PreLogin Banner should be nil") + g.Expect(testDevices.StateFor(name).PostLoginBanner).ToNot(BeNil(), "Provider PostLogin Banner should not be nil") + if testDevices.StateFor(name).PostLoginBanner != nil { + g.Expect(*testDevices.StateFor(name).PostLoginBanner).To(Equal("Test Banner")) } }).Should(Succeed()) }) diff --git a/internal/controller/core/bgp_controller_test.go b/internal/controller/core/bgp_controller_test.go index 8f7238b68..cadbdf007 100644 --- a/internal/controller/core/bgp_controller_test.go +++ b/internal/controller/core/bgp_controller_test.go @@ -64,7 +64,7 @@ var _ = Describe("BGP Controller", func() { By("Verifying BGP is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.BGP).To(BeNil(), "Provider should not have BGP instance configured") + g.Expect(testDevices.StateFor(device.Name).BGP).To(BeNil(), "Provider should not have BGP instance configured") }).Should(Succeed()) By("Deleting the Device resource") @@ -120,7 +120,7 @@ var _ = Describe("BGP Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.BGP).ToNot(BeNil(), "Provider should have BGP instance configured") + g.Expect(testDevices.StateFor(device.Name).BGP).ToNot(BeNil(), "Provider should have BGP instance configured") }).Should(Succeed()) }) @@ -176,8 +176,8 @@ var _ = Describe("BGP Controller", func() { By("Ensuring the provider receives the VRF") Eventually(func(g Gomega) { - g.Expect(testProvider.BGPVRF).ToNot(BeNil()) - g.Expect(testProvider.BGPVRF.Spec.Name).To(Equal("CC-MGMT")) + g.Expect(testDevices.StateFor(device.Name).BGPVRF).ToNot(BeNil()) + g.Expect(testDevices.StateFor(device.Name).BGPVRF.Spec.Name).To(Equal("CC-MGMT")) }).Should(Succeed()) By("Ensuring ReadyCondition is True") diff --git a/internal/controller/core/bgp_peer_controller_test.go b/internal/controller/core/bgp_peer_controller_test.go index ee9fa6b0d..42a3d7c76 100644 --- a/internal/controller/core/bgp_peer_controller_test.go +++ b/internal/controller/core/bgp_peer_controller_test.go @@ -65,7 +65,7 @@ var _ = Describe("BGPPeer Controller", func() { By("Verifying BGP peer is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.BGPPeers.Len()).To(Equal(0), "Provider should not have any BGP peers configured") + g.Expect(testDevices.StateFor(device.Name).BGPPeers.Len()).To(Equal(0), "Provider should not have any BGP peers configured") }).Should(Succeed()) By("Deleting the Device resource") @@ -145,7 +145,7 @@ var _ = Describe("BGPPeer Controller", func() { By("Verifying the BGP peer is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.BGPPeers.Has(host)).To(BeTrue(), "Provider should have BGP peer configured") + g.Expect(testDevices.StateFor(device.Name).BGPPeers.Has(host)).To(BeTrue(), "Provider should have BGP peer configured") }).Should(Succeed()) }) @@ -215,7 +215,7 @@ var _ = Describe("BGPPeer Controller", func() { By("Verifying the BGP peer is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.BGPPeers.Has(host)).To(BeTrue(), "Provider should have BGP peer configured") + g.Expect(testDevices.StateFor(device.Name).BGPPeers.Has(host)).To(BeTrue(), "Provider should have BGP peer configured") }).Should(Succeed()) }) @@ -378,7 +378,7 @@ var _ = Describe("BGPPeer Controller", func() { By("Verifying the BGP peer is NOT configured in the provider") Consistently(func(g Gomega) { - g.Expect(testProvider.BGPPeers.Has(host)).To(BeFalse(), "Provider should not have BGP peer configured") + g.Expect(testDevices.StateFor(device.Name).BGPPeers.Has(host)).To(BeFalse(), "Provider should not have BGP peer configured") }).Should(Succeed()) }) @@ -429,7 +429,7 @@ var _ = Describe("BGPPeer Controller", func() { By("Verifying the BGP peer is NOT configured in the provider") Consistently(func(g Gomega) { - g.Expect(testProvider.BGPPeers.Has("10.0.0.3")).To(BeFalse(), "Provider should not have BGP peer configured") + g.Expect(testDevices.StateFor(device.Name).BGPPeers.Has("10.0.0.3")).To(BeFalse(), "Provider should not have BGP peer configured") }).Should(Succeed()) }) diff --git a/internal/controller/core/certificate_controller_test.go b/internal/controller/core/certificate_controller_test.go index 33a2ccdc7..6689acf4e 100644 --- a/internal/controller/core/certificate_controller_test.go +++ b/internal/controller/core/certificate_controller_test.go @@ -89,7 +89,7 @@ var _ = Describe("Certificate Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Certs.Has("cert1")).To(BeFalse(), "Certificate should be deleted from the provider") + g.Expect(testDevices.StateFor(name).Certs.Has("cert1")).To(BeFalse(), "Certificate should be deleted from the provider") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -136,7 +136,7 @@ var _ = Describe("Certificate Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Certs.Has("cert1")).To(BeTrue(), "Certificate should be present in the provider") + g.Expect(testDevices.StateFor(name).Certs.Has("cert1")).To(BeTrue(), "Certificate should be present in the provider") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/configbackup_controller_test.go b/internal/controller/core/configbackup_controller_test.go index 0b8df0f71..e409c4814 100644 --- a/internal/controller/core/configbackup_controller_test.go +++ b/internal/controller/core/configbackup_controller_test.go @@ -52,10 +52,10 @@ var _ = Describe("ConfigBackup Controller", func() { }).Should(Succeed()) By("Resetting the test provider state") - testProvider.Lock() - testProvider.ConfigBackups = nil - testProvider.StartupConfig = nil - testProvider.Unlock() + testDevices.StateFor(device.Name).Lock() + testDevices.StateFor(device.Name).ConfigBackups = nil + testDevices.StateFor(device.Name).StartupConfig = nil + testDevices.StateFor(device.Name).Unlock() }) AfterEach(func() { @@ -156,22 +156,22 @@ var _ = Describe("ConfigBackup Controller", func() { By("Verifying the provider received the startup backup") Eventually(func(g Gomega) { - testProvider.Lock() - defer testProvider.Unlock() - g.Expect(testProvider.StartupConfig).NotTo(BeNil()) + testDevices.StateFor(device.Name).Lock() + defer testDevices.StateFor(device.Name).Unlock() + g.Expect(testDevices.StateFor(device.Name).StartupConfig).NotTo(BeNil()) }).Should(Succeed()) }) It("Should rotate old backups according to retention policy", func() { By("Pre-seeding the provider with existing backups") - testProvider.Lock() + testDevices.StateFor(device.Name).Lock() size := int64(1024) - testProvider.ConfigBackups = []*provider.ConfigBackupFile{ + testDevices.StateFor(device.Name).ConfigBackups = []*provider.ConfigBackupFile{ {Path: "bootflash:///backups/configbackup-old-1", SizeBytes: &size, CreatedAt: time.Date(2026, time.April, 10, 2, 0, 0, 0, time.UTC)}, {Path: "bootflash:///backups/configbackup-old-2", SizeBytes: &size, CreatedAt: time.Date(2026, time.April, 11, 2, 0, 0, 0, time.UTC)}, {Path: "bootflash:///backups/configbackup-old-3", SizeBytes: &size, CreatedAt: time.Date(2026, time.April, 12, 2, 0, 0, 0, time.UTC)}, } - testProvider.Unlock() + testDevices.StateFor(device.Name).Unlock() By("Creating a ConfigBackup with retention keepLast: 2") backup = &v1alpha1.ConfigBackup{ @@ -188,10 +188,10 @@ var _ = Describe("ConfigBackup Controller", func() { By("Verifying old backups are rotated") Eventually(func(g Gomega) { - testProvider.Lock() - defer testProvider.Unlock() + testDevices.StateFor(device.Name).Lock() + defer testDevices.StateFor(device.Name).Unlock() // 3 pre-seeded + 1 new = 4, keepLast=2 means 2 oldest deleted → 2 remain - g.Expect(testProvider.ConfigBackups).To(HaveLen(2)) + g.Expect(testDevices.StateFor(device.Name).ConfigBackups).To(HaveLen(2)) }).Should(Succeed()) By("Verifying the status reflects the retained count") @@ -205,13 +205,13 @@ var _ = Describe("ConfigBackup Controller", func() { It("Should block backup when storage threshold is exceeded", func() { By("Pre-seeding the provider to simulate full storage") - testProvider.Lock() + testDevices.StateFor(device.Name).Lock() size := int64(95) - testProvider.ConfigBackups = []*provider.ConfigBackupFile{ + testDevices.StateFor(device.Name).ConfigBackups = []*provider.ConfigBackupFile{ {Path: "bootflash:///backups/existing-file", SizeBytes: &size, CreatedAt: time.Now()}, } - testProvider.StorageTotal = 100 - testProvider.Unlock() + testDevices.StateFor(device.Name).StorageTotal = 100 + testDevices.StateFor(device.Name).Unlock() By("Creating a ConfigBackup with a storage threshold") minFreeBytes := int64(10) @@ -264,9 +264,9 @@ var _ = Describe("ConfigBackup Controller", func() { By("Verifying the provider only has one backup (no re-runs)") Consistently(func(g Gomega) { - testProvider.Lock() - defer testProvider.Unlock() - g.Expect(testProvider.ConfigBackups).To(HaveLen(1)) + testDevices.StateFor(device.Name).Lock() + defer testDevices.StateFor(device.Name).Unlock() + g.Expect(testDevices.StateFor(device.Name).ConfigBackups).To(HaveLen(1)) }).Should(Succeed()) }) diff --git a/internal/controller/core/device_controller_test.go b/internal/controller/core/device_controller_test.go index 4a94dd5bd..4e3dd3877 100644 --- a/internal/controller/core/device_controller_test.go +++ b/internal/controller/core/device_controller_test.go @@ -377,10 +377,10 @@ var _ = Describe("Device Controller", func() { It("Should set Reachable=False and Ready=Unknown when the device is unreachable", func() { By("Making the provider return a connect error") - testProvider.SetConnectError(errors.New("connection refused")) + testDevices.StateFor(name).SetConnectFailure(errors.New("connection refused")) DeferCleanup(func() { - testProvider.SetConnectError(nil) + testDevices.StateFor(name).SetConnectFailure(nil) }) By("Creating the custom resource for the Kind Device") @@ -415,7 +415,7 @@ var _ = Describe("Device Controller", func() { }).Should(Succeed()) By("Clearing the connect error to simulate recovery") - testProvider.SetConnectError(nil) + testDevices.StateFor(name).SetConnectFailure(nil) By("Verifying Reachable=True and Ready=True after recovery") Eventually(func(g Gomega) { @@ -568,9 +568,9 @@ var _ = Describe("Device Controller", func() { By("Advancing the reboot time in the provider to simulate a device reboot") newRebootTime := lastRebootTime.Add(time.Hour) - testProvider.SetLastRebootTime(newRebootTime) + testDevices.StateFor(name).SetLastRebootTime(newRebootTime) DeferCleanup(func() { - testProvider.SetLastRebootTime(lastRebootTime) + testDevices.StateFor(name).SetLastRebootTime(lastRebootTime) }) By("Verifying LastRebootTime in status is updated to the new value") diff --git a/internal/controller/core/dhcprelay_controller_test.go b/internal/controller/core/dhcprelay_controller_test.go index ac066a433..4f743c472 100644 --- a/internal/controller/core/dhcprelay_controller_test.go +++ b/internal/controller/core/dhcprelay_controller_test.go @@ -128,7 +128,7 @@ var _ = Describe("DHCPRelay Controller", func() { By("Verifying the resource has been deleted") Eventually(func(g Gomega) { - g.Expect(testProvider.DHCPRelay).To(BeNil(), "Provider should have no DHCPRelay configured") + g.Expect(testDevices.StateFor(deviceName).DHCPRelay).To(BeNil(), "Provider should have no DHCPRelay configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -197,9 +197,9 @@ var _ = Describe("DHCPRelay Controller", func() { By("Ensuring the DHCPRelay is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.DHCPRelay).ToNot(BeNil(), "Provider DHCPRelay should not be nil") - if testProvider.DHCPRelay != nil { - g.Expect(testProvider.DHCPRelay.GetName()).To(Equal(resourceName), "Provider should have DHCPRelay configured") + g.Expect(testDevices.StateFor(deviceName).DHCPRelay).ToNot(BeNil(), "Provider DHCPRelay should not be nil") + if testDevices.StateFor(deviceName).DHCPRelay != nil { + g.Expect(testDevices.StateFor(deviceName).DHCPRelay.GetName()).To(Equal(resourceName), "Provider should have DHCPRelay configured") } }).Should(Succeed()) }) @@ -288,7 +288,7 @@ var _ = Describe("DHCPRelay Controller", func() { By("Verifying DHCPRelay is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.DHCPRelay).ToNot(BeNil()) + g.Expect(testDevices.StateFor(deviceName).DHCPRelay).ToNot(BeNil()) }).Should(Succeed()) By("Deleting the DHCPRelay resource") @@ -296,7 +296,7 @@ var _ = Describe("DHCPRelay Controller", func() { By("Verifying the DHCPRelay is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.DHCPRelay).To(BeNil(), "Provider should have no DHCPRelay configured after deletion") + g.Expect(testDevices.StateFor(deviceName).DHCPRelay).To(BeNil(), "Provider should have no DHCPRelay configured after deletion") }).Should(Succeed()) By("Verifying the resource is fully deleted") @@ -857,7 +857,7 @@ var _ = Describe("DHCPRelay Controller", func() { By("Verifying the provider has been cleaned up") Eventually(func(g Gomega) { - g.Expect(testProvider.DHCPRelay).To(BeNil(), "Provider should have no DHCPRelay configured") + g.Expect(testDevices.StateFor(deviceName).DHCPRelay).To(BeNil(), "Provider should have no DHCPRelay configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -903,7 +903,7 @@ var _ = Describe("DHCPRelay Controller", func() { By("Ensuring the DHCPRelay is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.DHCPRelay).ToNot(BeNil(), "Provider DHCPRelay should not be nil") + g.Expect(testDevices.StateFor(deviceName).DHCPRelay).ToNot(BeNil(), "Provider DHCPRelay should not be nil") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/dns_controller_test.go b/internal/controller/core/dns_controller_test.go index d1eb18aa2..85136d108 100644 --- a/internal/controller/core/dns_controller_test.go +++ b/internal/controller/core/dns_controller_test.go @@ -62,7 +62,7 @@ var _ = Describe("DNS Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.DNS).To(BeNil(), "Provider DNS should be nil") + g.Expect(testDevices.StateFor(name).DNS).To(BeNil(), "Provider DNS should be nil") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -109,9 +109,9 @@ var _ = Describe("DNS Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.DNS).ToNot(BeNil(), "Provider DNS should not be nil") - if testProvider.DNS != nil { - g.Expect(testProvider.DNS.Spec.Domain).To(Equal("example.com")) + g.Expect(testDevices.StateFor(name).DNS).ToNot(BeNil(), "Provider DNS should not be nil") + if testDevices.StateFor(name).DNS != nil { + g.Expect(testDevices.StateFor(name).DNS.Spec.Domain).To(Equal("example.com")) } }).Should(Succeed()) }) diff --git a/internal/controller/core/ethernetsegment_controller_test.go b/internal/controller/core/ethernetsegment_controller_test.go index ff3bdccaa..aa0136e03 100644 --- a/internal/controller/core/ethernetsegment_controller_test.go +++ b/internal/controller/core/ethernetsegment_controller_test.go @@ -53,7 +53,7 @@ var _ = Describe("EthernetSegment Controller", func() { By("Verifying the EthernetSegment is removed from the provider") Eventually(func(g Gomega) { - _, exists := testProvider.GetEthernetSegment(name) + _, exists := testDevices.StateFor(name).GetEthernetSegment(name) g.Expect(exists).To(BeFalse(), "Provider shouldn't have ESI configured anymore") }).Should(Succeed()) @@ -145,7 +145,7 @@ var _ = Describe("EthernetSegment Controller", func() { By("Verifying the EthernetSegment is configured in the provider") Eventually(func(g Gomega) { - storedESI, exists := testProvider.GetEthernetSegment(name) + storedESI, exists := testDevices.StateFor(name).GetEthernetSegment(name) g.Expect(exists).To(BeTrue(), "Provider should have ESI configured") g.Expect(storedESI).To(Equal(esi)) }).Should(Succeed()) diff --git a/internal/controller/core/evpninstance_controller_test.go b/internal/controller/core/evpninstance_controller_test.go index dee7b738e..fb002f45d 100644 --- a/internal/controller/core/evpninstance_controller_test.go +++ b/internal/controller/core/evpninstance_controller_test.go @@ -52,7 +52,7 @@ var _ = Describe("EVPNInstance Controller", func() { By("Verifying the EVPNInstance is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.EVIs.Has(vni)).To(BeFalse(), "Provider shouldn't have VNI configured anymore") + g.Expect(testDevices.StateFor(name).EVIs.Has(vni)).To(BeFalse(), "Provider shouldn't have VNI configured anymore") }).Should(Succeed()) By("Cleaning up the test Device resource") @@ -148,7 +148,7 @@ var _ = Describe("EVPNInstance Controller", func() { By("Verifying the EVPNInstance is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.EVIs.Has(vni)).To(BeTrue(), "Provider should have VNI configured") + g.Expect(testDevices.StateFor(name).EVIs.Has(vni)).To(BeTrue(), "Provider should have VNI configured") }).Should(Succeed()) }) diff --git a/internal/controller/core/interface_controller_test.go b/internal/controller/core/interface_controller_test.go index 3adad9e1a..715e9d90e 100644 --- a/internal/controller/core/interface_controller_test.go +++ b/internal/controller/core/interface_controller_test.go @@ -72,7 +72,7 @@ var _ = Describe("Interface Controller", func() { By("Verifying the Interface is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Ports.Has(name)).To(BeFalse(), "Provider shouldn't have Interface configured anymore") + g.Expect(testDevices.StateFor(name).Ports.Has(name)).To(BeFalse(), "Provider shouldn't have Interface configured anymore") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -141,7 +141,7 @@ var _ = Describe("Interface Controller", func() { By("Verifying the Interface is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Ports.Has(name)).To(BeTrue(), "Provider should have Interface configured") + g.Expect(testDevices.StateFor(name).Ports.Has(name)).To(BeTrue(), "Provider should have Interface configured") }).Should(Succeed()) }) @@ -365,7 +365,7 @@ var _ = Describe("Interface Controller", func() { By("Verifying the Aggregate Interface is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Ports.Has(name)).To(BeTrue(), "Provider should have Aggregate Interface configured") + g.Expect(testDevices.StateFor(name).Ports.Has(name)).To(BeTrue(), "Provider should have Aggregate Interface configured") }).Should(Succeed()) }) @@ -656,7 +656,7 @@ var _ = Describe("Interface Controller", func() { By("Verifying the Aggregate Interface is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Ports.Has(name)).To(BeTrue(), "Provider should have L3 Aggregate Interface configured") + g.Expect(testDevices.StateFor(name).Ports.Has(name)).To(BeTrue(), "Provider should have L3 Aggregate Interface configured") }).Should(Succeed()) }) @@ -715,7 +715,7 @@ var _ = Describe("Interface Controller", func() { By("Verifying the member Physical interface is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Ports.Has("eth1-100")).To(BeTrue(), "Provider should have member Physical Interface configured") + g.Expect(testDevices.StateFor(name).Ports.Has("eth1-100")).To(BeTrue(), "Provider should have member Physical Interface configured") }).Should(Succeed()) }) @@ -841,12 +841,12 @@ var _ = Describe("Interface Controller", func() { By("Verifying the Subinterface is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Ports.Has(parentName+".100")).To(BeTrue(), "Provider should have Subinterface configured") + g.Expect(testDevices.StateFor(name).Ports.Has(parentName+".100")).To(BeTrue(), "Provider should have Subinterface configured") }).Should(Succeed()) By("Verifying the parent Physical interface is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Ports.Has(parentName)).To(BeTrue(), "Provider should have parent Physical Interface configured") + g.Expect(testDevices.StateFor(name).Ports.Has(parentName)).To(BeTrue(), "Provider should have parent Physical Interface configured") }).Should(Succeed()) }) @@ -960,7 +960,7 @@ var _ = Describe("Interface Controller", func() { By("Verifying the Interface is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Ports.Has(name)).To(BeTrue(), "Provider should have RoutedVLAN Interface configured") + g.Expect(testDevices.StateFor(name).Ports.Has(name)).To(BeTrue(), "Provider should have RoutedVLAN Interface configured") }).Should(Succeed()) }) @@ -1103,7 +1103,7 @@ var _ = Describe("Interface Controller", func() { By("Verifying the Interface is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Ports.Has(name)).To(BeTrue(), "Provider should have Interface with VRF configured") + g.Expect(testDevices.StateFor(name).Ports.Has(name)).To(BeTrue(), "Provider should have Interface with VRF configured") }).Should(Succeed()) }) @@ -1263,7 +1263,7 @@ var _ = Describe("Interface Controller", func() { }).Should(Succeed()) By("Configuring LLDP neighbor on the provider for the local interface") - testProvider.SetLLDPNeighbor("Ethernet1/2", "remote-switch.example.com", "aa:bb:cc:dd:ee:ff", "Ethernet1/1", 120) + testDevices.StateFor(localDevice.Name).SetLLDPNeighbor("Ethernet1/2", "remote-switch.example.com", "aa:bb:cc:dd:ee:ff", "Ethernet1/1", 120) By("Creating a local Physical Interface with neighbor label pointing to the remote interface") localIntf = &v1alpha1.Interface{ @@ -1284,9 +1284,9 @@ var _ = Describe("Interface Controller", func() { AfterEach(func() { By("Cleaning up LLDP neighbor configuration") - testProvider.Lock() - delete(testProvider.LLDPNeighbors, "Ethernet1/2") - testProvider.Unlock() + testDevices.StateFor(localDevice.Name).Lock() + delete(testDevices.StateFor(localDevice.Name).LLDPNeighbors, "Ethernet1/2") + testDevices.StateFor(localDevice.Name).Unlock() By("Cleaning up all Interface resources") intfList := &v1alpha1.InterfaceList{} diff --git a/internal/controller/core/isis_controller_test.go b/internal/controller/core/isis_controller_test.go index 47a40abd6..6dc646838 100644 --- a/internal/controller/core/isis_controller_test.go +++ b/internal/controller/core/isis_controller_test.go @@ -63,7 +63,7 @@ var _ = Describe("ISIS Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.ISIS.Has("UNDERLAY")).To(BeFalse(), "Provider should not have ISIS instance configured") + g.Expect(testDevices.StateFor(name).ISIS.Has("UNDERLAY")).To(BeFalse(), "Provider should not have ISIS instance configured") }).Should(Succeed()) By("Cleanup the Device resource") @@ -110,7 +110,7 @@ var _ = Describe("ISIS Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.ISIS.Has("UNDERLAY")).To(BeTrue(), "Provider should have ISIS instance configured") + g.Expect(testDevices.StateFor(name).ISIS.Has("UNDERLAY")).To(BeTrue(), "Provider should have ISIS instance configured") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/lldp_controller_test.go b/internal/controller/core/lldp_controller_test.go index aacc05a05..a4d806809 100644 --- a/internal/controller/core/lldp_controller_test.go +++ b/internal/controller/core/lldp_controller_test.go @@ -58,7 +58,7 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the resource has been deleted") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).To(BeNil(), "Provider should have no LLDP configured") + g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -124,9 +124,9 @@ var _ = Describe("LLDP Controller", func() { By("Ensuring the LLDP is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).ToNot(BeNil(), "Provider LLDP should not be nil") - if testProvider.LLDP != nil { - g.Expect(testProvider.LLDP.GetName()).To(Equal(deviceName+"-lldp"), "Provider should have LLDP configured") + g.Expect(testDevices.StateFor(deviceName).LLDP).ToNot(BeNil(), "Provider LLDP should not be nil") + if testDevices.StateFor(deviceName).LLDP != nil { + g.Expect(testDevices.StateFor(deviceName).LLDP.GetName()).To(Equal(deviceName+"-lldp"), "Provider should have LLDP configured") } }).Should(Succeed()) }) @@ -163,9 +163,9 @@ var _ = Describe("LLDP Controller", func() { By("Ensuring the LLDP is created in the provider with AdminState Down") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).ToNot(BeNil()) - if testProvider.LLDP != nil { - g.Expect(testProvider.LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateDown)) + g.Expect(testDevices.StateFor(deviceName).LLDP).ToNot(BeNil()) + if testDevices.StateFor(deviceName).LLDP != nil { + g.Expect(testDevices.StateFor(deviceName).LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateDown)) } }).Should(Succeed()) }) @@ -242,7 +242,7 @@ var _ = Describe("LLDP Controller", func() { By("Verifying LLDP is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).ToNot(BeNil()) + g.Expect(testDevices.StateFor(deviceName).LLDP).ToNot(BeNil()) }).Should(Succeed()) By("Deleting the LLDP resource") @@ -250,7 +250,7 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the LLDP is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).To(BeNil(), "Provider should have no LLDP configured after deletion") + g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured after deletion") }).Should(Succeed()) By("Verifying the resource is fully deleted") @@ -335,7 +335,7 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the provider has been cleaned up") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).To(BeNil(), "Provider should have no LLDP configured") + g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -394,8 +394,8 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the provider still has AdminState Up (reconciliation was skipped)") Consistently(func(g Gomega) { - g.Expect(testProvider.LLDP).ToNot(BeNil()) - g.Expect(testProvider.LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateUp)) + g.Expect(testDevices.StateFor(deviceName).LLDP).ToNot(BeNil()) + g.Expect(testDevices.StateFor(deviceName).LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateUp)) }).Should(Succeed()) By("Unpausing the Device") @@ -408,8 +408,8 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the provider now has AdminState Down (reconciliation resumed)") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).ToNot(BeNil()) - g.Expect(testProvider.LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateDown)) + g.Expect(testDevices.StateFor(deviceName).LLDP).ToNot(BeNil()) + g.Expect(testDevices.StateFor(deviceName).LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateDown)) }).Should(Succeed()) }) }) @@ -455,7 +455,7 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the resource has been deleted") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).To(BeNil(), "Provider should have no LLDP configured") + g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -594,7 +594,7 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the resource has been deleted") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).To(BeNil(), "Provider should have no LLDP configured") + g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -812,7 +812,7 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the resource has been deleted") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).To(BeNil(), "Provider should have no LLDP configured") + g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -846,8 +846,8 @@ var _ = Describe("LLDP Controller", func() { By("Verifying provider has AdminState Up") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).ToNot(BeNil()) - g.Expect(testProvider.LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateUp)) + g.Expect(testDevices.StateFor(deviceName).LLDP).ToNot(BeNil()) + g.Expect(testDevices.StateFor(deviceName).LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateUp)) }).Should(Succeed()) By("Updating AdminState to Down") @@ -860,8 +860,8 @@ var _ = Describe("LLDP Controller", func() { By("Verifying provider has AdminState Down") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).ToNot(BeNil()) - g.Expect(testProvider.LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateDown)) + g.Expect(testDevices.StateFor(deviceName).LLDP).ToNot(BeNil()) + g.Expect(testDevices.StateFor(deviceName).LLDP.Spec.AdminState).To(Equal(v1alpha1.AdminStateDown)) }).Should(Succeed()) }) @@ -1053,7 +1053,7 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the provider has been cleaned up") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).To(BeNil(), "Provider should have no LLDP configured") + g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -1207,9 +1207,9 @@ var _ = Describe("LLDP Controller", func() { AfterEach(func() { By("Resetting provider LLDP operational status to true") - testProvider.Lock() - testProvider.LLDPOperStatus = true - testProvider.Unlock() + testDevices.StateFor(deviceName).Lock() + testDevices.StateFor(deviceName).LLDPOperStatus = true + testDevices.StateFor(deviceName).Unlock() By("Cleaning up the LLDP resource") lldp = &v1alpha1.LLDP{} @@ -1225,7 +1225,7 @@ var _ = Describe("LLDP Controller", func() { By("Verifying the provider has been cleaned up") Eventually(func(g Gomega) { - g.Expect(testProvider.LLDP).To(BeNil(), "Provider should have no LLDP configured") + g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -1237,9 +1237,9 @@ var _ = Describe("LLDP Controller", func() { It("Should set OperationalCondition to False when LLDP is operationally down", func() { By("Setting provider to return operational status down") - testProvider.Lock() - testProvider.LLDPOperStatus = false - testProvider.Unlock() + testDevices.StateFor(deviceName).Lock() + testDevices.StateFor(deviceName).LLDPOperStatus = false + testDevices.StateFor(deviceName).Unlock() By("Creating LLDP resource") lldp = &v1alpha1.LLDP{ @@ -1277,9 +1277,9 @@ var _ = Describe("LLDP Controller", func() { It("Should recover when LLDP becomes operationally up", func() { By("Setting provider to return operational status down") - testProvider.Lock() - testProvider.LLDPOperStatus = false - testProvider.Unlock() + testDevices.StateFor(deviceName).Lock() + testDevices.StateFor(deviceName).LLDPOperStatus = false + testDevices.StateFor(deviceName).Unlock() By("Creating LLDP resource") lldp = &v1alpha1.LLDP{ @@ -1303,9 +1303,9 @@ var _ = Describe("LLDP Controller", func() { }).Should(Succeed()) By("Setting provider to return operational status up") - testProvider.Lock() - testProvider.LLDPOperStatus = true - testProvider.Unlock() + testDevices.StateFor(deviceName).Lock() + testDevices.StateFor(deviceName).LLDPOperStatus = true + testDevices.StateFor(deviceName).Unlock() By("Verifying OperationalCondition becomes True after requeue") Eventually(func(g Gomega) { diff --git a/internal/controller/core/managementaccess_controller_test.go b/internal/controller/core/managementaccess_controller_test.go index e896b9693..74ef976e4 100644 --- a/internal/controller/core/managementaccess_controller_test.go +++ b/internal/controller/core/managementaccess_controller_test.go @@ -60,7 +60,7 @@ var _ = Describe("ManagementAccess Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Access).To(BeNil(), "Provider should not have ManagementAccess configured") + g.Expect(testDevices.StateFor(name).Access).To(BeNil(), "Provider should not have ManagementAccess configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -107,7 +107,7 @@ var _ = Describe("ManagementAccess Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Access).ToNot(BeNil(), "Provider should have ManagementAccess configured") + g.Expect(testDevices.StateFor(name).Access).ToNot(BeNil(), "Provider should have ManagementAccess configured") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/ntp_controller_test.go b/internal/controller/core/ntp_controller_test.go index 7e1f7ae71..74ff162b8 100644 --- a/internal/controller/core/ntp_controller_test.go +++ b/internal/controller/core/ntp_controller_test.go @@ -63,7 +63,7 @@ var _ = Describe("NTP Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.NTP).To(BeNil(), "Provider NTP should be nil") + g.Expect(testDevices.StateFor(name).NTP).To(BeNil(), "Provider NTP should be nil") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -110,9 +110,9 @@ var _ = Describe("NTP Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.NTP).ToNot(BeNil(), "Provider NTP should not be nil") - if testProvider.NTP != nil { - g.Expect(testProvider.NTP.Spec.SourceInterfaceName).To(Equal("mgmt0")) + g.Expect(testDevices.StateFor(name).NTP).ToNot(BeNil(), "Provider NTP should not be nil") + if testDevices.StateFor(name).NTP != nil { + g.Expect(testDevices.StateFor(name).NTP.Spec.SourceInterfaceName).To(Equal("mgmt0")) } }).Should(Succeed()) }) diff --git a/internal/controller/core/nve_controller_test.go b/internal/controller/core/nve_controller_test.go index 45f1c547b..beaef5496 100644 --- a/internal/controller/core/nve_controller_test.go +++ b/internal/controller/core/nve_controller_test.go @@ -106,7 +106,7 @@ var _ = Describe("NVE Controller", func() { }).Should(BeTrue()) Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).To(BeNil(), "Provider NVE should be empty") + g.Expect(testDevices.StateFor(name).NVE).To(BeNil(), "Provider NVE should be empty") }).Should(Succeed()) }) @@ -147,13 +147,13 @@ var _ = Describe("NVE Controller", func() { By("Ensuring the NVE is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).ToNot(BeNil(), "Provider NVE should not be nil") - g.Expect(testProvider.NVE.Spec.AdminState).To(BeEquivalentTo(v1alpha1.AdminStateUp)) - g.Expect(testProvider.NVE.Spec.SuppressARP).To(BeTrue()) - g.Expect(testProvider.NVE.Spec.HostReachability).To(BeEquivalentTo("BGP")) - g.Expect(testProvider.NVE.Spec.SourceInterfaceRef.Name).To(Equal(name + "-lo0")) - g.Expect(testProvider.NVE.Spec.MulticastGroups).ToNot(BeNil()) - g.Expect(testProvider.NVE.Spec.MulticastGroups.L2).To(HaveValue(Equal(v1alpha1.MustParsePrefix("234.0.0.0/8")))) + g.Expect(testDevices.StateFor(name).NVE).ToNot(BeNil(), "Provider NVE should not be nil") + g.Expect(testDevices.StateFor(name).NVE.Spec.AdminState).To(BeEquivalentTo(v1alpha1.AdminStateUp)) + g.Expect(testDevices.StateFor(name).NVE.Spec.SuppressARP).To(BeTrue()) + g.Expect(testDevices.StateFor(name).NVE.Spec.HostReachability).To(BeEquivalentTo("BGP")) + g.Expect(testDevices.StateFor(name).NVE.Spec.SourceInterfaceRef.Name).To(Equal(name + "-lo0")) + g.Expect(testDevices.StateFor(name).NVE.Spec.MulticastGroups).ToNot(BeNil()) + g.Expect(testDevices.StateFor(name).NVE.Spec.MulticastGroups.L2).To(HaveValue(Equal(v1alpha1.MustParsePrefix("234.0.0.0/8")))) }).Should(Succeed()) By("Verifying referenced interfaces exist and are loopbacks") @@ -273,7 +273,7 @@ var _ = Describe("NVE Controller", func() { }).Should(BeTrue()) Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).To(BeNil(), "Provider NVE should be empty") + g.Expect(testDevices.StateFor(name).NVE).To(BeNil(), "Provider NVE should be empty") }).Should(Succeed()) }) @@ -284,9 +284,9 @@ var _ = Describe("NVE Controller", func() { By("Verifying reconciliation modifies provider and status") Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).ToNot(BeNil()) - g.Expect(testProvider.NVE.Spec.SourceInterfaceRef.Name).To(Equal(name + "-lo1")) - g.Expect(testProvider.NVE.Status.SourceInterfaceName).To(Equal(name + "-lo1")) + g.Expect(testDevices.StateFor(name).NVE).ToNot(BeNil()) + g.Expect(testDevices.StateFor(name).NVE.Spec.SourceInterfaceRef.Name).To(Equal(name + "-lo1")) + g.Expect(testDevices.StateFor(name).NVE.Status.SourceInterfaceName).To(Equal(name + "-lo1")) }).Should(Succeed()) }) @@ -297,10 +297,10 @@ var _ = Describe("NVE Controller", func() { By("Verifying reconciliation modifies provider and status") Eventually(func(g Gomega) { - if testProvider.NVE != nil { - g.Expect(testProvider.NVE).ToNot(BeNil()) - g.Expect(testProvider.NVE.Spec.AnycastSourceInterfaceRef.Name).To(Equal(name + "-lo2")) - g.Expect(testProvider.NVE.Status.AnycastSourceInterfaceName).To(Equal(name + "-lo2")) + if testDevices.StateFor(name).NVE != nil { + g.Expect(testDevices.StateFor(name).NVE).ToNot(BeNil()) + g.Expect(testDevices.StateFor(name).NVE.Spec.AnycastSourceInterfaceRef.Name).To(Equal(name + "-lo2")) + g.Expect(testDevices.StateFor(name).NVE.Status.AnycastSourceInterfaceName).To(Equal(name + "-lo2")) } }, 5*time.Second, 100*time.Millisecond).Should(Succeed()) }) @@ -358,7 +358,7 @@ var _ = Describe("NVE Controller", func() { }).Should(BeTrue()) Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).To(BeNil(), "Provider NVE should be empty") + g.Expect(testDevices.StateFor(name).NVE).To(BeNil(), "Provider NVE should be empty") }).Should(Succeed()) }) @@ -450,14 +450,14 @@ var _ = Describe("NVE Controller", func() { }).Should(BeTrue()) Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).To(BeNil(), "Provider NVE should be empty") + g.Expect(testDevices.StateFor(name).NVE).To(BeNil(), "Provider NVE should be empty") }).Should(Succeed()) }) It("Should reconcile with nil anycast and empty status AnycastSourceInterfaceName", func() { Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).NotTo(BeNil()) - g.Expect(testProvider.NVE.Spec.AnycastSourceInterfaceRef).To(BeNil()) + g.Expect(testDevices.StateFor(name).NVE).NotTo(BeNil()) + g.Expect(testDevices.StateFor(name).NVE.Spec.AnycastSourceInterfaceRef).To(BeNil()) }).Should(Succeed()) Eventually(func(g Gomega) { @@ -562,7 +562,7 @@ var _ = Describe("NVE Controller", func() { }).Should(BeTrue()) Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).To(BeNil(), "Provider NVE should be empty") + g.Expect(testDevices.StateFor(name).NVE).To(BeNil(), "Provider NVE should be empty") }).Should(Succeed()) }) @@ -660,7 +660,7 @@ var _ = Describe("NVE Controller", func() { }).Should(BeTrue()) Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).To(BeNil(), "Provider NVE should be empty") + g.Expect(testDevices.StateFor(name).NVE).To(BeNil(), "Provider NVE should be empty") }).Should(Succeed()) }) @@ -776,7 +776,7 @@ var _ = Describe("NVE Controller", func() { }).Should(BeTrue()) Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).To(BeNil(), "Provider NVE should be empty") + g.Expect(testDevices.StateFor(name).NVE).To(BeNil(), "Provider NVE should be empty") }).Should(Succeed()) }) @@ -878,7 +878,7 @@ var _ = Describe("NVE Controller", func() { }).Should(BeTrue()) Eventually(func(g Gomega) { - g.Expect(testProvider.NVE).To(BeNil(), "Provider NVE should be empty") + g.Expect(testDevices.StateFor(name).NVE).To(BeNil(), "Provider NVE should be empty") }).Should(Succeed()) }) diff --git a/internal/controller/core/ospf_controller_test.go b/internal/controller/core/ospf_controller_test.go index 548d41b70..dc271ac6d 100644 --- a/internal/controller/core/ospf_controller_test.go +++ b/internal/controller/core/ospf_controller_test.go @@ -61,7 +61,7 @@ var _ = Describe("OSPF Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.OSPF.Has("UNDERLAY")).ToNot(BeTrue(), "Provider should not have OSPF instance configured") + g.Expect(testDevices.StateFor(name).OSPF.Has("UNDERLAY")).ToNot(BeTrue(), "Provider should not have OSPF instance configured") }).Should(Succeed()) By("Cleanup the Device resource") @@ -112,7 +112,7 @@ var _ = Describe("OSPF Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.OSPF.Has("UNDERLAY")).To(BeTrue(), "Provider should have OSPF instance configured") + g.Expect(testDevices.StateFor(name).OSPF.Has("UNDERLAY")).To(BeTrue(), "Provider should have OSPF instance configured") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/pim_controller_test.go b/internal/controller/core/pim_controller_test.go index f744b7eb1..72a9c801f 100644 --- a/internal/controller/core/pim_controller_test.go +++ b/internal/controller/core/pim_controller_test.go @@ -56,7 +56,7 @@ var _ = Describe("PIM Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.PIM).To(BeNil(), "Provider should not have PIM instance configured") + g.Expect(testDevices.StateFor(name).PIM).To(BeNil(), "Provider should not have PIM instance configured") }).Should(Succeed()) By("Cleanup the Device resource") @@ -103,7 +103,7 @@ var _ = Describe("PIM Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.PIM).ToNot(BeNil(), "Provider should have PIM instance configured") + g.Expect(testDevices.StateFor(name).PIM).ToNot(BeNil(), "Provider should have PIM instance configured") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/prefixset_controller_test.go b/internal/controller/core/prefixset_controller_test.go index 4b633b37f..8f8cfcea8 100644 --- a/internal/controller/core/prefixset_controller_test.go +++ b/internal/controller/core/prefixset_controller_test.go @@ -67,7 +67,7 @@ var _ = Describe("PrefixSet Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.PrefixSets.Has(set)).To(BeFalse(), "Provider should not have PrefixSet configured") + g.Expect(testDevices.StateFor(name).PrefixSets.Has(set)).To(BeFalse(), "Provider should not have PrefixSet configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -114,7 +114,7 @@ var _ = Describe("PrefixSet Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.PrefixSets.Has(set)).To(BeTrue(), "Provider should have PrefixSet configured") + g.Expect(testDevices.StateFor(name).PrefixSets.Has(set)).To(BeTrue(), "Provider should have PrefixSet configured") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/probe_controller_test.go b/internal/controller/core/probe_controller_test.go index 9c798329b..da6821288 100644 --- a/internal/controller/core/probe_controller_test.go +++ b/internal/controller/core/probe_controller_test.go @@ -62,8 +62,8 @@ var _ = Describe("Probe Controller", func() { }) It("Should wait for its Device to become reachable", func() { - testProvider.SetConnectError(errors.New("device unreachable")) - DeferCleanup(func() { testProvider.SetConnectError(nil) }) + testDevices.StateFor(name).SetConnectFailure(errors.New("device unreachable")) + DeferCleanup(func() { testDevices.StateFor(name).SetConnectFailure(nil) }) Eventually(func(g Gomega) { device := &v1alpha1.Device{} @@ -98,7 +98,7 @@ var _ = Describe("Probe Controller", func() { ))) }).Should(Succeed()) - testProvider.SetConnectError(nil) + testDevices.StateFor(name).SetConnectFailure(nil) Eventually(func(g Gomega) { resource := &v1alpha1.Probe{} g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed()) diff --git a/internal/controller/core/routingpolicy_controller_test.go b/internal/controller/core/routingpolicy_controller_test.go index 4594cd67f..ccb2027d8 100644 --- a/internal/controller/core/routingpolicy_controller_test.go +++ b/internal/controller/core/routingpolicy_controller_test.go @@ -54,7 +54,7 @@ var _ = Describe("RoutingPolicy Controller", func() { By("Verifying the RoutingPolicy is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.RoutingPolicies.Has(name)).To(BeFalse(), "Provider shouldn't have RoutingPolicy configured anymore") + g.Expect(testDevices.StateFor(name).RoutingPolicies.Has(name)).To(BeFalse(), "Provider shouldn't have RoutingPolicy configured anymore") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -119,7 +119,7 @@ var _ = Describe("RoutingPolicy Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.RoutingPolicies.Has(name)).To(BeTrue(), "Provider should have RoutingPolicy configured") + g.Expect(testDevices.StateFor(name).RoutingPolicies.Has(name)).To(BeTrue(), "Provider should have RoutingPolicy configured") }).Should(Succeed()) }) @@ -186,7 +186,7 @@ var _ = Describe("RoutingPolicy Controller", func() { By("Verifying the RoutingPolicy is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.RoutingPolicies.Has(name)).To(BeTrue(), "Provider should have RoutingPolicy configured") + g.Expect(testDevices.StateFor(name).RoutingPolicies.Has(name)).To(BeTrue(), "Provider should have RoutingPolicy configured") }).Should(Succeed()) }) @@ -331,7 +331,7 @@ var _ = Describe("RoutingPolicy Controller", func() { By("Verifying the RoutingPolicy is configured in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.RoutingPolicies.Has(name)).To(BeTrue(), "Provider should have RoutingPolicy configured") + g.Expect(testDevices.StateFor(name).RoutingPolicies.Has(name)).To(BeTrue(), "Provider should have RoutingPolicy configured") }).Should(Succeed()) }) diff --git a/internal/controller/core/snmp_controller_test.go b/internal/controller/core/snmp_controller_test.go index 33d26a160..7dcaf0a5f 100644 --- a/internal/controller/core/snmp_controller_test.go +++ b/internal/controller/core/snmp_controller_test.go @@ -74,7 +74,7 @@ var _ = Describe("SNMP Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.SNMP).To(BeNil(), "Provider should not have SNMP configured") + g.Expect(testDevices.StateFor(name).SNMP).To(BeNil(), "Provider should not have SNMP configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -121,9 +121,9 @@ var _ = Describe("SNMP Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.SNMP).ToNot(BeNil(), "Provider should have SNMP configured") - if testProvider.SNMP != nil { - g.Expect(testProvider.SNMP.Spec.Contact).To(Equal("123")) + g.Expect(testDevices.StateFor(name).SNMP).ToNot(BeNil(), "Provider should have SNMP configured") + if testDevices.StateFor(name).SNMP != nil { + g.Expect(testDevices.StateFor(name).SNMP.Spec.Contact).To(Equal("123")) } }).Should(Succeed()) }) diff --git a/internal/controller/core/suite_test.go b/internal/controller/core/suite_test.go index 15d38f8c5..c98534d2a 100644 --- a/internal/controller/core/suite_test.go +++ b/internal/controller/core/suite_test.go @@ -42,13 +42,13 @@ import ( // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. var ( - ctx context.Context - cancel context.CancelFunc - testEnv *envtest.Environment - k8sClient client.Client - k8sManager ctrl.Manager - testProvider = NewProvider() - testLocker *resourcelock.ResourceLocker + ctx context.Context + cancel context.CancelFunc + testEnv *envtest.Environment + k8sClient client.Client + k8sManager ctrl.Manager + testDevices = NewDeviceStore() + testLocker *resourcelock.ResourceLocker // testEvents is a slice that stores events recorded during the tests. It is used to verify that the expected events are generated by the controllers. testEvents []string testS3Store = NewMockObjectStorage() @@ -121,7 +121,7 @@ var _ = BeforeSuite(func() { _, err = k8sManager.GetCache().GetInformer(ctx, &coordinationv1.Lease{}) Expect(err).NotTo(HaveOccurred()) - prov := func() provider.Provider { return testProvider } + prov := func() provider.Provider { return &Provider{devices: testDevices} } err = (&DeviceReconciler{ Client: k8sManager.GetClient(), @@ -451,8 +451,9 @@ var ( _ provider.ProbeProvider = (*Provider)(nil) ) -// Provider is a simple in-memory provider for testing purposes only. -type Provider struct { +// DeviceState holds per-device mutable state for testing. Each device created in +// a test gets its own DeviceState, preventing state bleed between test suites. +type DeviceState struct { sync.Mutex ConnectError error // if non-nil, Connect returns this error @@ -491,8 +492,8 @@ type Provider struct { StorageTotal int64 } -func NewProvider() *Provider { - return &Provider{ +func NewDeviceState() *DeviceState { + return &DeviceState{ LastRebootTime: lastRebootTime, Ports: sets.New[string](), User: sets.New[string](), @@ -513,26 +514,63 @@ func NewProvider() *Provider { } } -// SetConnectError sets the error that Connect will return on subsequent calls. -// Pass nil to clear the error and allow connections to succeed. -func (p *Provider) SetConnectError(err error) { - p.Lock() - defer p.Unlock() - p.ConnectError = err +// DeviceStore holds per-device state for all test devices, keyed by device name. +type DeviceStore struct { + sync.Mutex + states map[string]*DeviceState } -// SetLastRebootTime sets the time returned by GetLastRebootTime on subsequent calls. -func (p *Provider) SetLastRebootTime(t time.Time) { - p.Lock() - defer p.Unlock() - p.LastRebootTime = t +func NewDeviceStore() *DeviceStore { + return &DeviceStore{states: make(map[string]*DeviceState)} } -func (p *Provider) Connect(_ context.Context, _ *deviceutil.Connection) error { - p.Lock() - defer p.Unlock() - return p.ConnectError +// StateFor returns the DeviceState for the given device name, creating one if it doesn't exist. +func (s *DeviceStore) StateFor(name string) *DeviceState { + s.Lock() + defer s.Unlock() + ds, ok := s.states[name] + if !ok { + ds = NewDeviceState() + s.states[name] = ds + } + return ds } + +// Provider is an in-memory provider for testing. The ProviderFunc factory creates +// a new Provider per reconcile call, sharing the DeviceStore. Connect captures the +// device name from the Connection so subsequent method calls dispatch to the correct +// DeviceState. +type Provider struct { + devices *DeviceStore + deviceName string // set during Connect +} + +// SetConnectFailure sets the error that Connect will return for this device. +func (s *DeviceState) SetConnectFailure(err error) { + s.Lock() + defer s.Unlock() + s.ConnectError = err +} + +// SetLastRebootTime sets the time returned by GetLastRebootTime for this device. +func (s *DeviceState) SetLastRebootTime(t time.Time) { + s.Lock() + defer s.Unlock() + s.LastRebootTime = t +} + +func (p *Provider) Connect(_ context.Context, conn *deviceutil.Connection) error { + s := p.devices.StateFor(conn.DeviceName) + s.Lock() + err := s.ConnectError + s.Unlock() + if err != nil { + return err + } + p.deviceName = conn.DeviceName + return nil +} + func (p *Provider) Disconnect(context.Context, *deviceutil.Connection) error { return nil } func (p *Provider) ListPorts(context.Context) (ports []provider.DevicePort, err error) { @@ -548,9 +586,10 @@ func (p *Provider) ListPorts(context.Context) (ports []provider.DevicePort, err } func (p *Provider) GetLastRebootTime(_ context.Context) (time.Time, error) { - p.Lock() - defer p.Unlock() - return p.LastRebootTime, nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + return s.LastRebootTime, nil } func (p *Provider) GetDeviceInfo(context.Context) (*provider.DeviceInfo, error) { @@ -570,44 +609,42 @@ func (p *Provider) VerifyProvisioned(context.Context, *deviceutil.Connection, *v return true } -func (p *Provider) Reboot(ctx context.Context, conn *deviceutil.Connection) error { +func (p *Provider) Reboot(context.Context, *deviceutil.Connection) error { return nil } -func (p *Provider) FactoryReset(ctx context.Context, conn *deviceutil.Connection) error { +func (p *Provider) FactoryReset(context.Context, *deviceutil.Connection) error { return nil } -func (p *Provider) Reprovision(ctx context.Context, conn *deviceutil.Connection) (reterr error) { +func (p *Provider) Reprovision(context.Context, *deviceutil.Connection) error { return nil } -func (p *Provider) EnsureInterface(ctx context.Context, req *provider.EnsureInterfaceRequest) error { - p.Lock() - defer p.Unlock() - p.Ports.Insert(req.Interface.Spec.Name) +func (p *Provider) EnsureInterface(_ context.Context, req *provider.EnsureInterfaceRequest) error { + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.Ports.Insert(req.Interface.Spec.Name) return nil } func (p *Provider) DeleteInterface(_ context.Context, req *provider.InterfaceRequest) error { - p.Lock() - defer p.Unlock() - p.Ports.Delete(req.Interface.Spec.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.Ports.Delete(req.Interface.Spec.Name) return nil } func (p *Provider) GetInterfaceStatus(_ context.Context, req *provider.InterfaceRequest) (provider.InterfaceStatus, error) { - p.Lock() - defer p.Unlock() - - status := provider.InterfaceStatus{ - OperStatus: true, - } - - if neighbor, ok := p.LLDPNeighbors[req.Interface.Spec.Name]; ok { + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + status := provider.InterfaceStatus{OperStatus: true} + if neighbor, ok := s.LLDPNeighbors[req.Interface.Spec.Name]; ok { status.LLDPAdjacencies = []provider.LLDPAdjacency{*neighbor} } - return status, nil } @@ -620,13 +657,14 @@ func (p *Provider) LoopbackInterfaceName(id int) (string, error) { } func (p *Provider) EnsureBanner(_ context.Context, req *provider.EnsureBannerRequest) error { - p.Lock() - defer p.Unlock() + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() switch req.Type { case v1alpha1.BannerTypePreLogin: - p.PreLoginBanner = &req.Message + s.PreLoginBanner = &req.Message case v1alpha1.BannerTypePostLogin: - p.PostLoginBanner = &req.Message + s.PostLoginBanner = &req.Message default: return errors.New("unknown banner type") } @@ -634,13 +672,14 @@ func (p *Provider) EnsureBanner(_ context.Context, req *provider.EnsureBannerReq } func (p *Provider) DeleteBanner(_ context.Context, req *provider.DeleteBannerRequest) error { - p.Lock() - defer p.Unlock() + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() switch req.Type { case v1alpha1.BannerTypePreLogin: - p.PreLoginBanner = nil + s.PreLoginBanner = nil case v1alpha1.BannerTypePostLogin: - p.PostLoginBanner = nil + s.PostLoginBanner = nil default: return errors.New("unknown banner type") } @@ -648,186 +687,212 @@ func (p *Provider) DeleteBanner(_ context.Context, req *provider.DeleteBannerReq } func (p *Provider) EnsureUser(_ context.Context, req *provider.EnsureUserRequest) error { - p.Lock() - defer p.Unlock() - p.User.Insert(req.Username) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.User.Insert(req.Username) return nil } func (p *Provider) DeleteUser(_ context.Context, req *provider.DeleteUserRequest) error { - p.Lock() - defer p.Unlock() - p.User.Delete(req.Username) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.User.Delete(req.Username) return nil } func (p *Provider) EnsureDNS(_ context.Context, req *provider.EnsureDNSRequest) error { - p.Lock() - defer p.Unlock() - p.DNS = req.DNS + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.DNS = req.DNS return nil } func (p *Provider) DeleteDNS(_ context.Context) error { - p.Lock() - defer p.Unlock() - p.DNS = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.DNS = nil return nil } func (p *Provider) EnsureNTP(_ context.Context, req *provider.EnsureNTPRequest) error { - p.Lock() - defer p.Unlock() - p.NTP = req.NTP + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.NTP = req.NTP return nil } func (p *Provider) DeleteNTP(context.Context) error { - p.Lock() - defer p.Unlock() - p.NTP = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.NTP = nil return nil } func (p *Provider) EnsureACL(_ context.Context, req *provider.ACLRequest) error { - p.Lock() - defer p.Unlock() - p.ACLs.Insert(req.ACL.Spec.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.ACLs.Insert(req.ACL.Spec.Name) return nil } func (p *Provider) DeleteACL(_ context.Context, req *provider.ACLRequest) error { - p.Lock() - defer p.Unlock() - p.ACLs.Delete(req.ACL.Spec.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.ACLs.Delete(req.ACL.Spec.Name) return nil } func (p *Provider) EnsureCertificate(_ context.Context, req *provider.EnsureCertificateRequest) error { - p.Lock() - defer p.Unlock() - p.Certs.Insert(req.ID) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.Certs.Insert(req.ID) return nil } func (p *Provider) DeleteCertificate(_ context.Context, req *provider.DeleteCertificateRequest) error { - p.Lock() - defer p.Unlock() - p.Certs.Delete(req.ID) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.Certs.Delete(req.ID) return nil } func (p *Provider) EnsureSNMP(_ context.Context, req *provider.EnsureSNMPRequest) error { - p.Lock() - defer p.Unlock() - p.SNMP = req.SNMP + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.SNMP = req.SNMP return nil } func (p *Provider) DeleteSNMP(_ context.Context, req *provider.DeleteSNMPRequest) error { - p.Lock() - defer p.Unlock() - p.SNMP = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.SNMP = nil return nil } func (p *Provider) EnsureSyslog(_ context.Context, req *provider.EnsureSyslogRequest) error { - p.Lock() - defer p.Unlock() - p.Syslog = req.Syslog + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.Syslog = req.Syslog return nil } func (p *Provider) DeleteSyslog(_ context.Context) error { - p.Lock() - defer p.Unlock() - p.Syslog = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.Syslog = nil return nil } func (p *Provider) EnsureManagementAccess(_ context.Context, req *provider.EnsureManagementAccessRequest) error { - p.Lock() - defer p.Unlock() - p.Access = req.ManagementAccess + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.Access = req.ManagementAccess return nil } func (p *Provider) DeleteManagementAccess(context.Context, *provider.DeleteManagementAccessRequest) error { - p.Lock() - defer p.Unlock() - p.Access = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.Access = nil return nil } func (p *Provider) EnsureISIS(_ context.Context, req *provider.EnsureISISRequest) error { - p.Lock() - defer p.Unlock() - p.ISIS.Insert(req.ISIS.Spec.Instance) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.ISIS.Insert(req.ISIS.Spec.Instance) return nil } func (p *Provider) DeleteISIS(_ context.Context, req *provider.DeleteISISRequest) error { - p.Lock() - defer p.Unlock() - p.ISIS.Delete(req.ISIS.Spec.Instance) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.ISIS.Delete(req.ISIS.Spec.Instance) return nil } func (p *Provider) EnsureVRF(_ context.Context, req *provider.VRFRequest) error { - p.Lock() - defer p.Unlock() - p.VRF.Insert(req.VRF.Spec.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.VRF.Insert(req.VRF.Spec.Name) return nil } func (p *Provider) DeleteVRF(_ context.Context, req *provider.VRFRequest) error { - p.Lock() - defer p.Unlock() - p.VRF.Delete(req.VRF.Spec.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.VRF.Delete(req.VRF.Spec.Name) return nil } func (p *Provider) EnsurePIM(_ context.Context, req *provider.EnsurePIMRequest) error { - p.Lock() - defer p.Unlock() - p.PIM = req.PIM + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.PIM = req.PIM return nil } func (p *Provider) DeletePIM(context.Context, *provider.DeletePIMRequest) error { - p.Lock() - defer p.Unlock() - p.PIM = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.PIM = nil return nil } func (p *Provider) EnsureBGP(_ context.Context, req *provider.EnsureBGPRequest) error { - p.Lock() - defer p.Unlock() - p.BGP = req.BGP - p.BGPVRF = req.VRF + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.BGP = req.BGP + s.BGPVRF = req.VRF return nil } func (p *Provider) DeleteBGP(context.Context, *provider.DeleteBGPRequest) error { - p.Lock() - defer p.Unlock() - p.BGP = nil - p.BGPVRF = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.BGP = nil + s.BGPVRF = nil return nil } func (p *Provider) EnsureBGPPeer(_ context.Context, req *provider.EnsureBGPPeerRequest) error { - p.Lock() - defer p.Unlock() - p.BGPPeers.Insert(req.BGPPeer.Spec.Address) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.BGPPeers.Insert(req.BGPPeer.Spec.Address) return nil } func (p *Provider) DeleteBGPPeer(_ context.Context, req *provider.DeleteBGPPeerRequest) error { - p.Lock() - defer p.Unlock() - p.BGPPeers.Delete(req.BGPPeer.Spec.Address) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.BGPPeers.Delete(req.BGPPeer.Spec.Address) return nil } @@ -845,112 +910,120 @@ func (p *Provider) GetPeerStatus(context.Context, *provider.BGPPeerStatusRequest } func (p *Provider) EnsureOSPF(_ context.Context, req *provider.EnsureOSPFRequest) error { - p.Lock() - defer p.Unlock() - p.OSPF.Insert(req.OSPF.Spec.Instance) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.OSPF.Insert(req.OSPF.Spec.Instance) return nil } func (p *Provider) DeleteOSPF(_ context.Context, req *provider.DeleteOSPFRequest) error { - p.Lock() - defer p.Unlock() - p.OSPF.Delete(req.OSPF.Spec.Instance) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.OSPF.Delete(req.OSPF.Spec.Instance) return nil } func (p *Provider) GetOSPFStatus(context.Context, *provider.OSPFStatusRequest) (provider.OSPFStatus, error) { - return provider.OSPFStatus{ - OperStatus: true, - }, nil + return provider.OSPFStatus{OperStatus: true}, nil } func (p *Provider) EnsureVLAN(_ context.Context, req *provider.VLANRequest) error { - p.Lock() - defer p.Unlock() - p.VLANs.Insert(req.VLAN.Spec.ID) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.VLANs.Insert(req.VLAN.Spec.ID) return nil } func (p *Provider) DeleteVLAN(_ context.Context, req *provider.VLANRequest) error { - p.Lock() - defer p.Unlock() - p.VLANs.Delete(req.VLAN.Spec.ID) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.VLANs.Delete(req.VLAN.Spec.ID) return nil } func (p *Provider) GetVLANStatus(context.Context, *provider.VLANRequest) (provider.VLANStatus, error) { - return provider.VLANStatus{ - OperStatus: true, - }, nil + return provider.VLANStatus{OperStatus: true}, nil } func (p *Provider) EnsureEVPNInstance(_ context.Context, req *provider.EVPNInstanceRequest) error { - p.Lock() - defer p.Unlock() - p.EVIs.Insert(req.EVPNInstance.Spec.VNI) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.EVIs.Insert(req.EVPNInstance.Spec.VNI) return nil } func (p *Provider) DeleteEVPNInstance(_ context.Context, req *provider.EVPNInstanceRequest) error { - p.Lock() - defer p.Unlock() - p.EVIs.Delete(req.EVPNInstance.Spec.VNI) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.EVIs.Delete(req.EVPNInstance.Spec.VNI) return nil } -// EnsurePrefixSet implements provider.PrefixSetProvider. func (p *Provider) EnsurePrefixSet(_ context.Context, req *provider.PrefixSetRequest) error { - p.Lock() - defer p.Unlock() - p.PrefixSets.Insert(req.PrefixSet.Spec.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.PrefixSets.Insert(req.PrefixSet.Spec.Name) return nil } func (p *Provider) DeletePrefixSet(_ context.Context, req *provider.PrefixSetRequest) error { - p.Lock() - defer p.Unlock() - p.PrefixSets.Delete(req.PrefixSet.Spec.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.PrefixSets.Delete(req.PrefixSet.Spec.Name) return nil } func (p *Provider) EnsureRoutingPolicy(_ context.Context, req *provider.EnsureRoutingPolicyRequest) error { - p.Lock() - defer p.Unlock() - p.RoutingPolicies.Insert(req.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.RoutingPolicies.Insert(req.Name) return nil } func (p *Provider) DeleteRoutingPolicy(_ context.Context, req *provider.DeleteRoutingPolicyRequest) error { - p.Lock() - defer p.Unlock() - p.RoutingPolicies.Delete(req.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.RoutingPolicies.Delete(req.Name) return nil } func (p *Provider) EnsureNVE(_ context.Context, req *provider.NVERequest) error { - p.Lock() - defer p.Unlock() - p.NVE = req.NVE + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.NVE = req.NVE return nil } func (p *Provider) DeleteNVE(_ context.Context, req *provider.NVERequest) error { - p.Lock() - defer p.Unlock() - p.NVE = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.NVE = nil return nil } func (p *Provider) GetNVEStatus(_ context.Context, _ *provider.NVERequest) (provider.NVEStatus, error) { - status := provider.NVEStatus{ - OperStatus: true, - } - if p.NVE != nil { - if p.NVE.Spec.SourceInterfaceRef.Name != "" { - status.SourceInterfaceName = p.NVE.Spec.SourceInterfaceRef.Name + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + status := provider.NVEStatus{OperStatus: true} + if s.NVE != nil { + if s.NVE.Spec.SourceInterfaceRef.Name != "" { + status.SourceInterfaceName = s.NVE.Spec.SourceInterfaceRef.Name } - if p.NVE.Spec.AnycastSourceInterfaceRef != nil { - status.AnycastSourceInterfaceName = p.NVE.Spec.AnycastSourceInterfaceRef.Name + if s.NVE.Spec.AnycastSourceInterfaceRef != nil { + status.AnycastSourceInterfaceName = s.NVE.Spec.AnycastSourceInterfaceRef.Name } } return status, nil @@ -961,97 +1034,103 @@ func (p *Provider) RunningConfig(context.Context) ([]byte, error) { } func (p *Provider) CreateConfigBackup(_ context.Context, req *provider.ConfigBackupRequest) (*provider.ConfigBackupFile, error) { - p.Lock() - defer p.Unlock() - + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() if req.ConfigBackup.Spec.Type == v1alpha1.ConfigBackupTypeStartup { - p.StartupConfig = req.ConfigBackup + s.StartupConfig = req.ConfigBackup return nil, nil //nolint:nilnil } - file := &provider.ConfigBackupFile{ Path: path.Join(req.ConfigBackup.Spec.Path, fmt.Sprintf("configbackup-%s-", req.ConfigBackup.UID)) + time.Now().Format("20060102T150405Z"), SizeBytes: new(int64(1024)), CreatedAt: time.Now(), } - p.ConfigBackups = append(p.ConfigBackups, file) + s.ConfigBackups = append(s.ConfigBackups, file) return file, nil } func (p *Provider) ListConfigBackups(_ context.Context, _ *provider.ConfigBackupRequest) (*provider.ConfigBackupInventory, error) { - p.Lock() - defer p.Unlock() + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() var used int64 - for _, f := range p.ConfigBackups { + for _, f := range s.ConfigBackups { if f.SizeBytes != nil { used += *f.SizeBytes } } return &provider.ConfigBackupInventory{ - Backups: p.ConfigBackups, - TotalBytes: &p.StorageTotal, + Backups: s.ConfigBackups, + TotalBytes: &s.StorageTotal, UsedBytes: &used, - FreeBytes: new(p.StorageTotal - used), + FreeBytes: new(s.StorageTotal - used), }, nil } func (p *Provider) DeleteConfigBackups(_ context.Context, files ...*provider.ConfigBackupFile) error { - p.Lock() - defer p.Unlock() + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() remove := make(map[string]struct{}, len(files)) for _, f := range files { remove[f.Path] = struct{}{} } - filtered := p.ConfigBackups[:0] - for _, b := range p.ConfigBackups { + filtered := s.ConfigBackups[:0] + for _, b := range s.ConfigBackups { if _, ok := remove[b.Path]; !ok { filtered = append(filtered, b) } } - p.ConfigBackups = filtered + s.ConfigBackups = filtered return nil } func (p *Provider) EnsureLLDP(_ context.Context, req *provider.LLDPRequest) error { - p.Lock() - defer p.Unlock() - p.LLDP = req.LLDP + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.LLDP = req.LLDP return nil } func (p *Provider) DeleteLLDP(_ context.Context, req *provider.LLDPRequest) error { - p.Lock() - defer p.Unlock() - p.LLDP = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.LLDP = nil return nil } func (p *Provider) GetLLDPStatus(_ context.Context, _ *provider.LLDPRequest) (provider.LLDPStatus, error) { - p.Lock() - defer p.Unlock() - return provider.LLDPStatus{OperStatus: p.LLDPOperStatus}, nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + return provider.LLDPStatus{OperStatus: s.LLDPOperStatus}, nil } func (p *Provider) EnsureDHCPRelay(_ context.Context, req *provider.DHCPRelayRequest) error { - p.Lock() - defer p.Unlock() - p.DHCPRelay = req.DHCPRelay + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.DHCPRelay = req.DHCPRelay return nil } func (p *Provider) DeleteDHCPRelay(_ context.Context, req *provider.DHCPRelayRequest) error { - p.Lock() - defer p.Unlock() - p.DHCPRelay = nil + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + s.DHCPRelay = nil return nil } func (p *Provider) GetDHCPRelayStatus(_ context.Context, req *provider.DHCPRelayRequest) (provider.DHCPRelayStatus, error) { - p.Lock() - defer p.Unlock() + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() status := provider.DHCPRelayStatus{} - if p.DHCPRelay != nil { - // Return the interface names from the request (simulating what the device would return) + if s.DHCPRelay != nil { for _, intf := range req.Interfaces { status.ConfiguredInterfaces = append(status.ConfiguredInterfaces, intf.Spec.Name) } @@ -1060,35 +1139,39 @@ func (p *Provider) GetDHCPRelayStatus(_ context.Context, req *provider.DHCPRelay } func (p *Provider) EnsureEthernetSegment(_ context.Context, req *provider.EnsureEthernetSegmentRequest) error { - p.Lock() - defer p.Unlock() + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() esi := req.EthernetSegment.Spec.ESI if esi == "" { // Simulate auto-generated ESI (Type 3 MAC-based) esi = "03:aa:bb:cc:dd:ee:ff:00:00:01" } - p.EthernetSegments[req.EthernetSegment.Name] = esi + s.EthernetSegments[req.EthernetSegment.Name] = esi return nil } func (p *Provider) DeleteEthernetSegment(_ context.Context, req *provider.DeleteEthernetSegmentRequest) error { - p.Lock() - defer p.Unlock() - delete(p.EthernetSegments, req.EthernetSegment.Name) + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + delete(s.EthernetSegments, req.EthernetSegment.Name) return nil } func (p *Provider) GetEthernetSegmentStatus(_ context.Context, req *provider.EthernetSegmentStatusRequest) (provider.EthernetSegmentStatus, error) { - p.Lock() - defer p.Unlock() - esi := p.EthernetSegments[req.EthernetSegment.Name] + s := p.devices.StateFor(p.deviceName) + s.Lock() + defer s.Unlock() + esi := s.EthernetSegments[req.EthernetSegment.Name] return provider.EthernetSegmentStatus{ESI: esi, OperStatus: esi != ""}, nil } -func (p *Provider) GetEthernetSegment(name string) (string, bool) { - p.Lock() - defer p.Unlock() - esi, ok := p.EthernetSegments[name] +// GetEthernetSegment is a test helper to retrieve the ESI for an ethernet segment by name. +func (s *DeviceState) GetEthernetSegment(name string) (string, bool) { + s.Lock() + defer s.Unlock() + esi, ok := s.EthernetSegments[name] return esi, ok } @@ -1115,10 +1198,10 @@ func (p *Provider) GetVTEPPeers(context.Context, *provider.VTEPPeersRequest) ([] } // SetLLDPNeighbor is a test helper to configure LLDP neighbor information for an interface. -func (p *Provider) SetLLDPNeighbor(interfaceName, sysName, chassisID, portID string, ttl uint32) { - p.Lock() - defer p.Unlock() - p.LLDPNeighbors[interfaceName] = &provider.LLDPAdjacency{ +func (s *DeviceState) SetLLDPNeighbor(interfaceName, sysName, chassisID, portID string, ttl uint32) { + s.Lock() + defer s.Unlock() + s.LLDPNeighbors[interfaceName] = &provider.LLDPAdjacency{ SysName: sysName, ChassisID: chassisID, ChassisIDType: 4, // MACAddress diff --git a/internal/controller/core/syslog_controller_test.go b/internal/controller/core/syslog_controller_test.go index 9feade252..d3fee509b 100644 --- a/internal/controller/core/syslog_controller_test.go +++ b/internal/controller/core/syslog_controller_test.go @@ -69,7 +69,7 @@ var _ = Describe("Syslog Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Syslog).To(BeNil(), "Provider should not have Syslog configured") + g.Expect(testDevices.StateFor(name).Syslog).To(BeNil(), "Provider should not have Syslog configured") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -116,7 +116,7 @@ var _ = Describe("Syslog Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.Syslog).NotTo(BeNil(), "Provider should have Syslog configured") + g.Expect(testDevices.StateFor(name).Syslog).NotTo(BeNil(), "Provider should have Syslog configured") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/user_controller_test.go b/internal/controller/core/user_controller_test.go index a5b1438af..920660505 100644 --- a/internal/controller/core/user_controller_test.go +++ b/internal/controller/core/user_controller_test.go @@ -77,7 +77,7 @@ var _ = Describe("User Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.User.Has(username)).To(BeFalse(), "User should not exist") + g.Expect(testDevices.StateFor(name).User.Has(username)).To(BeFalse(), "User should not exist") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -124,7 +124,7 @@ var _ = Describe("User Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.User.Has(username)).To(BeTrue(), "User should exist") + g.Expect(testDevices.StateFor(name).User.Has(username)).To(BeTrue(), "User should exist") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/vlan_controller_test.go b/internal/controller/core/vlan_controller_test.go index 985e2f46d..633c439c3 100644 --- a/internal/controller/core/vlan_controller_test.go +++ b/internal/controller/core/vlan_controller_test.go @@ -59,7 +59,7 @@ var _ = Describe("VLAN Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.VLANs.Has(id)).To(BeFalse(), "Provider VLAN should not exist") + g.Expect(testDevices.StateFor(name).VLANs.Has(id)).To(BeFalse(), "Provider VLAN should not exist") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -110,7 +110,7 @@ var _ = Describe("VLAN Controller", func() { By("Ensuring the resource is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.VLANs.Has(id)).To(BeTrue(), "Provider VLAN should exist") + g.Expect(testDevices.StateFor(name).VLANs.Has(id)).To(BeTrue(), "Provider VLAN should exist") }).Should(Succeed()) }) }) diff --git a/internal/controller/core/vrf_controller_test.go b/internal/controller/core/vrf_controller_test.go index d28ef4dbf..7ff117e33 100644 --- a/internal/controller/core/vrf_controller_test.go +++ b/internal/controller/core/vrf_controller_test.go @@ -78,7 +78,7 @@ var _ = Describe("VRF Controller", func() { By("Verifying the resource is removed from the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.VRF.Has("CC-ADMIN-TEST")).To(BeFalse(), "Provider should not have VRF configured anymore") + g.Expect(testDevices.StateFor(name).VRF.Has("CC-ADMIN-TEST")).To(BeFalse(), "Provider should not have VRF configured anymore") }).Should(Succeed()) By("Cleaning up the Device resource") @@ -121,9 +121,9 @@ var _ = Describe("VRF Controller", func() { By("Ensuring the VRF is created in the provider") Eventually(func(g Gomega) { - g.Expect(testProvider.VRF).ToNot(BeNil(), "Provider VRF should not be nil") - if testProvider.VRF != nil { - g.Expect(testProvider.VRF.Has("CC-ADMIN-TEST")).To(BeTrue(), "Provider should have VRF configured") + g.Expect(testDevices.StateFor(name).VRF).ToNot(BeNil(), "Provider VRF should not be nil") + if testDevices.StateFor(name).VRF != nil { + g.Expect(testDevices.StateFor(name).VRF.Has("CC-ADMIN-TEST")).To(BeTrue(), "Provider should have VRF configured") } }).Should(Succeed()) }) diff --git a/internal/deviceutil/deviceutil.go b/internal/deviceutil/deviceutil.go index 44bbb36dd..dac8f3e89 100644 --- a/internal/deviceutil/deviceutil.go +++ b/internal/deviceutil/deviceutil.go @@ -107,6 +107,8 @@ func GetDeviceBySerial(ctx context.Context, r client.Reader, serial string) (*v1 // Connection holds the necessary information to connect to a device's API. type Connection struct { + // DeviceName is the name of the Device object this connection belongs to. + DeviceName string // Address is the API address of the device, in the format "host:port". Address string // Username for basic authentication. Might be empty if the device does not require authentication. @@ -156,9 +158,10 @@ func GetDeviceConnection(ctx context.Context, r client.Reader, obj *v1alpha1.Dev } return &Connection{ - Address: obj.Spec.Endpoint.Address, - Username: string(user), - Password: string(pass), - TLS: conf, + DeviceName: obj.Name, + Address: obj.Spec.Endpoint.Address, + Username: string(user), + Password: string(pass), + TLS: conf, }, nil } From 20cba39e16e64adc700c3e32aecbbeec3c9ebcfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20K=C3=A4stner?= Date: Mon, 14 Sep 2026 15:19:22 +0200 Subject: [PATCH 2/2] Wait for resource deletion before Device in AfterEach MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every controller calls GetDeviceByName before the DeletionTimestamp check. If the Device is deleted before a dependent resource completes its finalizer, the resource enters an infinite error-retry loop that creates API server contention and causes flaky test timeouts. Add Eventually waits for dependent resources to be fully deleted before deleting the Device in all AfterEach hooks. Signed-off-by: Felix Kästner --- .../cisco/nx/bordergateway_controller_test.go | 7 ++++ .../cisco/nx/system_controller_test.go | 7 ++++ .../cisco/nx/vpcdomain_controller_test.go | 13 +++++++ .../controller/core/acl_controller_test.go | 7 ++++ .../controller/core/banner_controller_test.go | 7 ++++ .../controller/core/bgp_controller_test.go | 24 ++++++++++-- .../core/bgp_peer_controller_test.go | 24 ++++++++++-- .../core/certificate_controller_test.go | 7 ++++ .../controller/core/device_controller_test.go | 7 ++++ .../core/dhcprelay_controller_test.go | 28 +++++++++++++ .../controller/core/dns_controller_test.go | 7 ++++ .../core/ethernetsegment_controller_test.go | 39 ++++++++++++++++--- .../core/evpninstance_controller_test.go | 9 +++++ .../core/interface_controller_test.go | 13 +++++-- .../controller/core/isis_controller_test.go | 13 +++++++ .../controller/core/lldp_controller_test.go | 24 ++++++++++++ .../core/managementaccess_controller_test.go | 7 ++++ .../controller/core/ntp_controller_test.go | 7 ++++ .../controller/core/ospf_controller_test.go | 17 ++++++++ .../controller/core/pim_controller_test.go | 11 ++++++ .../core/prefixset_controller_test.go | 7 ++++ .../core/routingpolicy_controller_test.go | 13 +++++++ .../controller/core/snmp_controller_test.go | 7 ++++ .../controller/core/syslog_controller_test.go | 7 ++++ .../controller/core/user_controller_test.go | 7 ++++ .../controller/core/vlan_controller_test.go | 7 ++++ .../controller/core/vrf_controller_test.go | 10 ++++- 27 files changed, 316 insertions(+), 20 deletions(-) diff --git a/internal/controller/cisco/nx/bordergateway_controller_test.go b/internal/controller/cisco/nx/bordergateway_controller_test.go index d72cb015d..604d76dde 100644 --- a/internal/controller/cisco/nx/bordergateway_controller_test.go +++ b/internal/controller/cisco/nx/bordergateway_controller_test.go @@ -8,6 +8,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -76,6 +77,12 @@ var _ = Describe("BorderGateway Controller", func() { bg.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, bg))).To(Succeed()) + By("Waiting for BorderGateway to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &nxv1alpha1.BorderGateway{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Ensuring the resource is deleted from the provider") Eventually(func(g Gomega) { g.Expect(testProvider.BorderGateway).To(BeNil(), "Provider BorderGateway settings should be reset after deletion") diff --git a/internal/controller/cisco/nx/system_controller_test.go b/internal/controller/cisco/nx/system_controller_test.go index ebd3670ab..08deb0686 100644 --- a/internal/controller/cisco/nx/system_controller_test.go +++ b/internal/controller/cisco/nx/system_controller_test.go @@ -6,6 +6,7 @@ package nx import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -57,6 +58,12 @@ var _ = Describe("System Controller", func() { system.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, system))).To(Succeed()) + By("Waiting for System to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &nxv1alpha1.System{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Ensuring the resource is deleted from the provider") Eventually(func(g Gomega) { g.Expect(testProvider.Settings).To(BeNil(), "Provider System settings should be reset after deletion") diff --git a/internal/controller/cisco/nx/vpcdomain_controller_test.go b/internal/controller/cisco/nx/vpcdomain_controller_test.go index f4a1abd5d..be9de0f01 100644 --- a/internal/controller/cisco/nx/vpcdomain_controller_test.go +++ b/internal/controller/cisco/nx/vpcdomain_controller_test.go @@ -6,6 +6,7 @@ package nx import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -114,6 +115,12 @@ var _ = Describe("VPCDomain Controller", func() { By("Cleanup the specific resource instance VPCDomain") Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + By("Waiting for VPCDomain to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, vpcdomainKey, &nxv1.VPCDomain{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Ensuring the resource is deleted from the provider") Eventually(func(g Gomega) { g.Expect(testProvider.VPCDomain).To(BeNil(), "Provider VPCDomain should be nil") @@ -292,6 +299,12 @@ var _ = Describe("VPCDomain Controller", func() { By("Cleanup the VPCDomain") Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + By("Waiting for VPCDomain to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, vpcdomainKey, &nxv1.VPCDomain{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleanup Interface and VRF resources") for _, ifName := range []string{name + "-phys", name + "-po", name + "-phys-b", name + "-po-b", name + "-lo0"} { intf := &corev1.Interface{} diff --git a/internal/controller/core/acl_controller_test.go b/internal/controller/core/acl_controller_test.go index ea1420864..31aa84edf 100644 --- a/internal/controller/core/acl_controller_test.go +++ b/internal/controller/core/acl_controller_test.go @@ -8,6 +8,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -79,6 +80,12 @@ var _ = Describe("AccessControlList Controller", func() { g.Expect(testDevices.StateFor(name).ACLs.Has(name)).To(BeFalse(), "Provider shouldn't have AccessControlList configured anymore") }).Should(Succeed()) + By("Waiting for the AccessControlList to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.AccessControlList{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/banner_controller_test.go b/internal/controller/core/banner_controller_test.go index ed786b57d..9fc1f11ee 100644 --- a/internal/controller/core/banner_controller_test.go +++ b/internal/controller/core/banner_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -49,6 +50,12 @@ var _ = Describe("Banner Controller", func() { g.Expect(testDevices.StateFor(name).PostLoginBanner).To(BeNil(), "Provider PostLogin Banner should be nil") }).Should(Succeed()) + By("Waiting for the Banner to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.Banner{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/bgp_controller_test.go b/internal/controller/core/bgp_controller_test.go index cadbdf007..0f958bc2b 100644 --- a/internal/controller/core/bgp_controller_test.go +++ b/internal/controller/core/bgp_controller_test.go @@ -34,23 +34,25 @@ var _ = Describe("BGP Controller", func() { }) AfterEach(func() { + // Use the manager client for MatchingFields queries — the direct k8sClient + // does not have the custom field indexes registered on the API server. By("Cleaning up BGP resources for this device") bgpList := &v1alpha1.BGPList{} - Expect(k8sClient.List(ctx, bgpList, client.InNamespace(metav1.NamespaceDefault), client.MatchingLabels{v1alpha1.DeviceLabel: device.Name})).To(Succeed()) + Expect(k8sManager.GetClient().List(ctx, bgpList, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) for i := range bgpList.Items { Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &bgpList.Items[i]))).To(Succeed()) } By("Cleaning up VRF resources for this device") vrfList := &v1alpha1.VRFList{} - Expect(k8sClient.List(ctx, vrfList, client.InNamespace(metav1.NamespaceDefault), client.MatchingLabels{v1alpha1.DeviceLabel: device.Name})).To(Succeed()) + Expect(k8sManager.GetClient().List(ctx, vrfList, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) for i := range vrfList.Items { Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &vrfList.Items[i]))).To(Succeed()) } By("Cleaning up RoutingPolicy resources for this device") rpList := &v1alpha1.RoutingPolicyList{} - Expect(k8sClient.List(ctx, rpList, client.InNamespace(metav1.NamespaceDefault), client.MatchingLabels{v1alpha1.DeviceLabel: device.Name})).To(Succeed()) + Expect(k8sManager.GetClient().List(ctx, rpList, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) for i := range rpList.Items { Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &rpList.Items[i]))).To(Succeed()) } @@ -58,7 +60,21 @@ var _ = Describe("BGP Controller", func() { By("Waiting for BGP resources to be fully deleted") Eventually(func(g Gomega) { list := &v1alpha1.BGPList{} - g.Expect(k8sClient.List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingLabels{v1alpha1.DeviceLabel: device.Name})).To(Succeed()) + g.Expect(k8sManager.GetClient().List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) + g.Expect(list.Items).To(BeEmpty()) + }).Should(Succeed()) + + By("Waiting for VRF resources to be fully deleted") + Eventually(func(g Gomega) { + list := &v1alpha1.VRFList{} + g.Expect(k8sManager.GetClient().List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) + g.Expect(list.Items).To(BeEmpty()) + }).Should(Succeed()) + + By("Waiting for RoutingPolicy resources to be fully deleted") + Eventually(func(g Gomega) { + list := &v1alpha1.RoutingPolicyList{} + g.Expect(k8sManager.GetClient().List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) g.Expect(list.Items).To(BeEmpty()) }).Should(Succeed()) diff --git a/internal/controller/core/bgp_peer_controller_test.go b/internal/controller/core/bgp_peer_controller_test.go index 42a3d7c76..b160575c2 100644 --- a/internal/controller/core/bgp_peer_controller_test.go +++ b/internal/controller/core/bgp_peer_controller_test.go @@ -35,23 +35,25 @@ var _ = Describe("BGPPeer Controller", func() { }) AfterEach(func() { + // Use the manager client for MatchingFields queries — the direct k8sClient + // does not have the custom field indexes registered on the API server. By("Cleaning up BGPPeer resources for this device") peerList := &v1alpha1.BGPPeerList{} - Expect(k8sClient.List(ctx, peerList, client.InNamespace(metav1.NamespaceDefault), client.MatchingLabels{v1alpha1.DeviceLabel: device.Name})).To(Succeed()) + Expect(k8sManager.GetClient().List(ctx, peerList, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) for i := range peerList.Items { Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &peerList.Items[i]))).To(Succeed()) } By("Cleaning up BGP resources for this device") bgpList := &v1alpha1.BGPList{} - Expect(k8sClient.List(ctx, bgpList, client.InNamespace(metav1.NamespaceDefault), client.MatchingLabels{v1alpha1.DeviceLabel: device.Name})).To(Succeed()) + Expect(k8sManager.GetClient().List(ctx, bgpList, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) for i := range bgpList.Items { Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &bgpList.Items[i]))).To(Succeed()) } By("Cleaning up Interface resources for this device") intfList := &v1alpha1.InterfaceList{} - Expect(k8sClient.List(ctx, intfList, client.InNamespace(metav1.NamespaceDefault), client.MatchingLabels{v1alpha1.DeviceLabel: device.Name})).To(Succeed()) + Expect(k8sManager.GetClient().List(ctx, intfList, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) for i := range intfList.Items { Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &intfList.Items[i]))).To(Succeed()) } @@ -59,7 +61,21 @@ var _ = Describe("BGPPeer Controller", func() { By("Waiting for BGPPeer resources to be fully deleted") Eventually(func(g Gomega) { list := &v1alpha1.BGPPeerList{} - g.Expect(k8sClient.List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingLabels{v1alpha1.DeviceLabel: device.Name})).To(Succeed()) + g.Expect(k8sManager.GetClient().List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) + g.Expect(list.Items).To(BeEmpty()) + }).Should(Succeed()) + + By("Waiting for BGP resources to be fully deleted") + Eventually(func(g Gomega) { + list := &v1alpha1.BGPList{} + g.Expect(k8sManager.GetClient().List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) + g.Expect(list.Items).To(BeEmpty()) + }).Should(Succeed()) + + By("Waiting for Interface resources to be fully deleted") + Eventually(func(g Gomega) { + list := &v1alpha1.InterfaceList{} + g.Expect(k8sManager.GetClient().List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: device.Name})).To(Succeed()) g.Expect(list.Items).To(BeEmpty()) }).Should(Succeed()) diff --git a/internal/controller/core/certificate_controller_test.go b/internal/controller/core/certificate_controller_test.go index 6689acf4e..af58bd588 100644 --- a/internal/controller/core/certificate_controller_test.go +++ b/internal/controller/core/certificate_controller_test.go @@ -17,6 +17,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -92,6 +93,12 @@ var _ = Describe("Certificate Controller", func() { g.Expect(testDevices.StateFor(name).Certs.Has("cert1")).To(BeFalse(), "Certificate should be deleted from the provider") }).Should(Succeed()) + By("Waiting for the Certificate to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.Certificate{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/device_controller_test.go b/internal/controller/core/device_controller_test.go index 4e3dd3877..8d7af776b 100644 --- a/internal/controller/core/device_controller_test.go +++ b/internal/controller/core/device_controller_test.go @@ -10,6 +10,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/client" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -47,6 +48,12 @@ var _ = Describe("Device Controller", func() { device.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, device))).To(Succeed()) + By("Waiting for Device to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, client.ObjectKey{Name: name, Namespace: metav1.NamespaceDefault}, &v1alpha1.Device{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleanup the specific resource instance Secret") secret := &corev1.Secret{} secret.Name = name diff --git a/internal/controller/core/dhcprelay_controller_test.go b/internal/controller/core/dhcprelay_controller_test.go index 4f743c472..c02c36d73 100644 --- a/internal/controller/core/dhcprelay_controller_test.go +++ b/internal/controller/core/dhcprelay_controller_test.go @@ -517,12 +517,20 @@ var _ = Describe("DHCPRelay Controller", func() { otherIntf.Name = otherIntfKey.Name otherIntf.Namespace = otherIntfKey.Namespace Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, otherIntf))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, otherIntfKey, &v1alpha1.Interface{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Cleaning up the VLAN resource") otherVlan := &v1alpha1.VLAN{} otherVlan.Name = otherVlanKey.Name otherVlan.Namespace = otherVlanKey.Namespace Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, otherVlan))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, otherVlanKey, &v1alpha1.VLAN{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Cleaning up the Device resources") device := &v1alpha1.Device{} @@ -687,18 +695,30 @@ var _ = Describe("DHCPRelay Controller", func() { otherVrf.Name = otherVrfKey.Name otherVrf.Namespace = otherVrfKey.Namespace Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, otherVrf))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, otherVrfKey, &v1alpha1.VRF{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Cleaning up the Interface resource") intf := &v1alpha1.Interface{} intf.Name = interfaceKey.Name intf.Namespace = interfaceKey.Namespace Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, intf))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, interfaceKey, &v1alpha1.Interface{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Cleaning up the VLAN resource") vlan := &v1alpha1.VLAN{} vlan.Name = vlanKey.Name vlan.Namespace = vlanKey.Namespace Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, vlan))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, vlanKey, &v1alpha1.VLAN{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Cleaning up the Device resources") device := &v1alpha1.Device{} @@ -1001,12 +1021,20 @@ var _ = Describe("DHCPRelay Controller", func() { i.Name = interfaceKey.Name i.Namespace = interfaceKey.Namespace Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, i))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, interfaceKey, &v1alpha1.Interface{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Cleaning up the VLAN resource") vlan := &v1alpha1.VLAN{} vlan.Name = vlanKey.Name vlan.Namespace = vlanKey.Namespace Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, vlan))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, vlanKey, &v1alpha1.VLAN{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Cleaning up the Device resource") device := &v1alpha1.Device{} diff --git a/internal/controller/core/dns_controller_test.go b/internal/controller/core/dns_controller_test.go index 85136d108..ba91dca17 100644 --- a/internal/controller/core/dns_controller_test.go +++ b/internal/controller/core/dns_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -65,6 +66,12 @@ var _ = Describe("DNS Controller", func() { g.Expect(testDevices.StateFor(name).DNS).To(BeNil(), "Provider DNS should be nil") }).Should(Succeed()) + By("Waiting for the DNS to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.DNS{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/ethernetsegment_controller_test.go b/internal/controller/core/ethernetsegment_controller_test.go index aa0136e03..6b1e70d78 100644 --- a/internal/controller/core/ethernetsegment_controller_test.go +++ b/internal/controller/core/ethernetsegment_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -17,8 +18,9 @@ var _ = Describe("EthernetSegment Controller", func() { Context("When reconciling a resource", func() { const esi = "00:11:22:33:44:55:66:77:88:01" var ( - name string - key client.ObjectKey + name string + key client.ObjectKey + memberIntf *v1alpha1.Interface ) BeforeEach(func() { @@ -42,6 +44,19 @@ var _ = Describe("EthernetSegment Controller", func() { g.Expect(k8sClient.Get(ctx, key, d)).To(Succeed()) g.Expect(d.Status.Phase).To(Equal(v1alpha1.DevicePhaseRunning)) }).Should(Succeed()) + + By("Creating a Physical member interface for Aggregate references") + memberIntf = &v1alpha1.Interface{ + GenerateName: "test-es-member-", + Namespace: metav1.NamespaceDefault, + Spec: v1alpha1.InterfaceSpec{ + DeviceRef: v1alpha1.LocalObjectReference{Name: name}, + Name: "Ethernet1/1", + AdminState: v1alpha1.AdminStateUp, + Type: v1alpha1.InterfaceTypePhysical, + }, + } + Expect(k8sClient.Create(ctx, memberIntf)).To(Succeed()) }) AfterEach(func() { @@ -51,6 +66,12 @@ var _ = Describe("EthernetSegment Controller", func() { es.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, es))).To(Succeed()) + By("Waiting for EthernetSegment resource to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, client.ObjectKey{Name: name, Namespace: metav1.NamespaceDefault}, &v1alpha1.EthernetSegment{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Verifying the EthernetSegment is removed from the provider") Eventually(func(g Gomega) { _, exists := testDevices.StateFor(name).GetEthernetSegment(name) @@ -63,6 +84,12 @@ var _ = Describe("EthernetSegment Controller", func() { intf.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, intf))).To(Succeed()) + By("Waiting for Interface resource to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, client.ObjectKey{Name: name, Namespace: metav1.NamespaceDefault}, &v1alpha1.Interface{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the test Device resource") device := &v1alpha1.Device{} device.Name = name @@ -84,7 +111,7 @@ var _ = Describe("EthernetSegment Controller", func() { Mode: v1alpha1.SwitchportModeTrunk, }, Aggregation: &v1alpha1.Aggregation{ - MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: "eth1"}}, + MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: memberIntf.Name}}, ControlProtocol: v1alpha1.ControlProtocol{Mode: v1alpha1.LACPModeActive}, }, }, @@ -204,7 +231,7 @@ var _ = Describe("EthernetSegment Controller", func() { Mode: v1alpha1.SwitchportModeTrunk, }, Aggregation: &v1alpha1.Aggregation{ - MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: "eth1"}}, + MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: memberIntf.Name}}, ControlProtocol: v1alpha1.ControlProtocol{Mode: v1alpha1.LACPModeActive}, }, }, @@ -299,7 +326,7 @@ var _ = Describe("EthernetSegment Controller", func() { Type: v1alpha1.InterfaceTypeAggregate, AdminState: v1alpha1.AdminStateUp, Aggregation: &v1alpha1.Aggregation{ - MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: "eth1"}}, + MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: memberIntf.Name}}, ControlProtocol: v1alpha1.ControlProtocol{Mode: v1alpha1.LACPModeActive}, }, }, @@ -349,7 +376,7 @@ var _ = Describe("EthernetSegment Controller", func() { Mode: v1alpha1.SwitchportModeTrunk, }, Aggregation: &v1alpha1.Aggregation{ - MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: "eth1"}}, + MemberInterfaceRefs: []v1alpha1.LocalObjectReference{{Name: memberIntf.Name}}, ControlProtocol: v1alpha1.ControlProtocol{Mode: v1alpha1.LACPModeActive}, }, }, diff --git a/internal/controller/core/evpninstance_controller_test.go b/internal/controller/core/evpninstance_controller_test.go index fb002f45d..ae155ee29 100644 --- a/internal/controller/core/evpninstance_controller_test.go +++ b/internal/controller/core/evpninstance_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -43,12 +44,20 @@ var _ = Describe("EVPNInstance Controller", func() { evi.Name = name evi.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, evi))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.EVPNInstance{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Cleaning up test VLAN resource") vlan := &v1alpha1.VLAN{} vlan.Name = name vlan.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, vlan))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.VLAN{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Verifying the EVPNInstance is removed from the provider") Eventually(func(g Gomega) { diff --git a/internal/controller/core/interface_controller_test.go b/internal/controller/core/interface_controller_test.go index 715e9d90e..0ee0d46d9 100644 --- a/internal/controller/core/interface_controller_test.go +++ b/internal/controller/core/interface_controller_test.go @@ -9,6 +9,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -54,7 +55,7 @@ var _ = Describe("Interface Controller", func() { By("Waiting for Interfaces to be fully deleted") Eventually(func(g Gomega) { list := &v1alpha1.InterfaceList{} - g.Expect(k8sClient.List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingLabels{v1alpha1.DeviceLabel: name})).To(Succeed()) + g.Expect(k8sManager.GetClient().List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: name})).To(Succeed()) g.Expect(list.Items).To(BeEmpty()) }).Should(Succeed()) @@ -1307,15 +1308,19 @@ var _ = Describe("Interface Controller", func() { By("Cleaning up DNS resource") if dns != nil { - Expect(k8sClient.Delete(ctx, dns)).To(Succeed()) + Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, dns))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dns), &v1alpha1.DNS{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) } By("Cleaning up Device resources") if localDevice != nil { - Expect(k8sClient.Delete(ctx, localDevice)).To(Succeed()) + Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, localDevice))).To(Succeed()) } if remoteDevice != nil { - Expect(k8sClient.Delete(ctx, remoteDevice)).To(Succeed()) + Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, remoteDevice))).To(Succeed()) } }) diff --git a/internal/controller/core/isis_controller_test.go b/internal/controller/core/isis_controller_test.go index 6dc646838..48472b846 100644 --- a/internal/controller/core/isis_controller_test.go +++ b/internal/controller/core/isis_controller_test.go @@ -5,6 +5,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" @@ -66,6 +67,12 @@ var _ = Describe("ISIS Controller", func() { g.Expect(testDevices.StateFor(name).ISIS.Has("UNDERLAY")).To(BeFalse(), "Provider should not have ISIS instance configured") }).Should(Succeed()) + By("Waiting for the ISIS to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.ISIS{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleanup the Device resource") device := &v1alpha1.Device{} device.Name = name @@ -144,6 +151,12 @@ var _ = Describe("ISIS Controller", func() { isis.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, isis))).To(Succeed()) + By("Waiting for the ISIS to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.ISIS{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleanup the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/lldp_controller_test.go b/internal/controller/core/lldp_controller_test.go index a4d806809..9ce6cafb8 100644 --- a/internal/controller/core/lldp_controller_test.go +++ b/internal/controller/core/lldp_controller_test.go @@ -597,6 +597,18 @@ var _ = Describe("LLDP Controller", func() { g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured") }).Should(Succeed()) + By("Cleaning up Interface resources for this device") + intfList := &v1alpha1.InterfaceList{} + Expect(k8sManager.GetClient().List(ctx, intfList, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: deviceName})).To(Succeed()) + for i := range intfList.Items { + Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &intfList.Items[i]))).To(Succeed()) + } + Eventually(func(g Gomega) { + list := &v1alpha1.InterfaceList{} + g.Expect(k8sManager.GetClient().List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: deviceName})).To(Succeed()) + g.Expect(list.Items).To(BeEmpty()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device = &v1alpha1.Device{} device.Name = deviceKey.Name @@ -815,6 +827,18 @@ var _ = Describe("LLDP Controller", func() { g.Expect(testDevices.StateFor(deviceName).LLDP).To(BeNil(), "Provider should have no LLDP configured") }).Should(Succeed()) + By("Cleaning up Interface resources for this device") + intfList := &v1alpha1.InterfaceList{} + Expect(k8sManager.GetClient().List(ctx, intfList, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: deviceName})).To(Succeed()) + for i := range intfList.Items { + Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &intfList.Items[i]))).To(Succeed()) + } + Eventually(func(g Gomega) { + list := &v1alpha1.InterfaceList{} + g.Expect(k8sManager.GetClient().List(ctx, list, client.InNamespace(metav1.NamespaceDefault), client.MatchingFields{v1alpha1.DeviceRefIndexKey: deviceName})).To(Succeed()) + g.Expect(list.Items).To(BeEmpty()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device = &v1alpha1.Device{} device.Name = deviceKey.Name diff --git a/internal/controller/core/managementaccess_controller_test.go b/internal/controller/core/managementaccess_controller_test.go index 74ef976e4..1efefbe9e 100644 --- a/internal/controller/core/managementaccess_controller_test.go +++ b/internal/controller/core/managementaccess_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -63,6 +64,12 @@ var _ = Describe("ManagementAccess Controller", func() { g.Expect(testDevices.StateFor(name).Access).To(BeNil(), "Provider should not have ManagementAccess configured") }).Should(Succeed()) + By("Waiting for the ManagementAccess to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.ManagementAccess{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/ntp_controller_test.go b/internal/controller/core/ntp_controller_test.go index 74ff162b8..1bbf387cf 100644 --- a/internal/controller/core/ntp_controller_test.go +++ b/internal/controller/core/ntp_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -66,6 +67,12 @@ var _ = Describe("NTP Controller", func() { g.Expect(testDevices.StateFor(name).NTP).To(BeNil(), "Provider NTP should be nil") }).Should(Succeed()) + By("Waiting for the NTP to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.NTP{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/ospf_controller_test.go b/internal/controller/core/ospf_controller_test.go index dc271ac6d..403bab908 100644 --- a/internal/controller/core/ospf_controller_test.go +++ b/internal/controller/core/ospf_controller_test.go @@ -8,6 +8,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" @@ -64,6 +65,12 @@ var _ = Describe("OSPF Controller", func() { g.Expect(testDevices.StateFor(name).OSPF.Has("UNDERLAY")).ToNot(BeTrue(), "Provider should not have OSPF instance configured") }).Should(Succeed()) + By("Waiting for the OSPF to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.OSPF{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleanup the Device resource") device := &v1alpha1.Device{} device.Name = name @@ -165,6 +172,10 @@ var _ = Describe("OSPF Controller", func() { AfterEach(func() { Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &v1alpha1.OSPF{Name: name, Namespace: metav1.NamespaceDefault}))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.OSPF{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &v1alpha1.Interface{Name: name, Namespace: metav1.NamespaceDefault}))).To(Succeed()) Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &v1alpha1.Device{Name: name, Namespace: metav1.NamespaceDefault}))).To(Succeed()) }) @@ -227,6 +238,12 @@ var _ = Describe("OSPF Controller", func() { ospf.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, ospf))).To(Succeed()) + By("Waiting for the OSPF to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.OSPF{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleanup the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/pim_controller_test.go b/internal/controller/core/pim_controller_test.go index 72a9c801f..1618e9123 100644 --- a/internal/controller/core/pim_controller_test.go +++ b/internal/controller/core/pim_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" @@ -59,6 +60,12 @@ var _ = Describe("PIM Controller", func() { g.Expect(testDevices.StateFor(name).PIM).To(BeNil(), "Provider should not have PIM instance configured") }).Should(Succeed()) + By("Waiting for the PIM to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.PIM{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleanup the Device resource") device := &v1alpha1.Device{} device.Name = name @@ -136,6 +143,10 @@ var _ = Describe("PIM Controller", func() { pim.Name = name pim.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, pim))).To(Succeed()) + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.PIM{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) By("Cleanup the Device resource") device := &v1alpha1.Device{} diff --git a/internal/controller/core/prefixset_controller_test.go b/internal/controller/core/prefixset_controller_test.go index 8f8cfcea8..2244f751a 100644 --- a/internal/controller/core/prefixset_controller_test.go +++ b/internal/controller/core/prefixset_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -70,6 +71,12 @@ var _ = Describe("PrefixSet Controller", func() { g.Expect(testDevices.StateFor(name).PrefixSets.Has(set)).To(BeFalse(), "Provider should not have PrefixSet configured") }).Should(Succeed()) + By("Waiting for the PrefixSet to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.PrefixSet{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/routingpolicy_controller_test.go b/internal/controller/core/routingpolicy_controller_test.go index ccb2027d8..cb0e2e724 100644 --- a/internal/controller/core/routingpolicy_controller_test.go +++ b/internal/controller/core/routingpolicy_controller_test.go @@ -8,6 +8,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" @@ -46,12 +47,24 @@ var _ = Describe("RoutingPolicy Controller", func() { rp.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, rp))).To(Succeed()) + By("Waiting for RoutingPolicy resource to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, client.ObjectKey{Name: name, Namespace: metav1.NamespaceDefault}, &v1alpha1.RoutingPolicy{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the PrefixSet resource") ps := &v1alpha1.PrefixSet{} ps.Name = name ps.Namespace = metav1.NamespaceDefault Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, ps))).To(Succeed()) + By("Waiting for PrefixSet resource to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, client.ObjectKey{Name: name, Namespace: metav1.NamespaceDefault}, &v1alpha1.PrefixSet{}) + g.Expect(errors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Verifying the RoutingPolicy is removed from the provider") Eventually(func(g Gomega) { g.Expect(testDevices.StateFor(name).RoutingPolicies.Has(name)).To(BeFalse(), "Provider shouldn't have RoutingPolicy configured anymore") diff --git a/internal/controller/core/snmp_controller_test.go b/internal/controller/core/snmp_controller_test.go index 7dcaf0a5f..558f074fb 100644 --- a/internal/controller/core/snmp_controller_test.go +++ b/internal/controller/core/snmp_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -77,6 +78,12 @@ var _ = Describe("SNMP Controller", func() { g.Expect(testDevices.StateFor(name).SNMP).To(BeNil(), "Provider should not have SNMP configured") }).Should(Succeed()) + By("Waiting for the SNMP to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.SNMP{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/syslog_controller_test.go b/internal/controller/core/syslog_controller_test.go index d3fee509b..a79569887 100644 --- a/internal/controller/core/syslog_controller_test.go +++ b/internal/controller/core/syslog_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -72,6 +73,12 @@ var _ = Describe("Syslog Controller", func() { g.Expect(testDevices.StateFor(name).Syslog).To(BeNil(), "Provider should not have Syslog configured") }).Should(Succeed()) + By("Waiting for the Syslog to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.Syslog{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/user_controller_test.go b/internal/controller/core/user_controller_test.go index 920660505..38f378dbc 100644 --- a/internal/controller/core/user_controller_test.go +++ b/internal/controller/core/user_controller_test.go @@ -7,6 +7,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -80,6 +81,12 @@ var _ = Describe("User Controller", func() { g.Expect(testDevices.StateFor(name).User.Has(username)).To(BeFalse(), "User should not exist") }).Should(Succeed()) + By("Waiting for the User to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.User{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/vlan_controller_test.go b/internal/controller/core/vlan_controller_test.go index 633c439c3..3d6c4554a 100644 --- a/internal/controller/core/vlan_controller_test.go +++ b/internal/controller/core/vlan_controller_test.go @@ -6,6 +6,7 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -62,6 +63,12 @@ var _ = Describe("VLAN Controller", func() { g.Expect(testDevices.StateFor(name).VLANs.Has(id)).To(BeFalse(), "Provider VLAN should not exist") }).Should(Succeed()) + By("Waiting for the VLAN to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.VLAN{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name diff --git a/internal/controller/core/vrf_controller_test.go b/internal/controller/core/vrf_controller_test.go index 7ff117e33..a020573a2 100644 --- a/internal/controller/core/vrf_controller_test.go +++ b/internal/controller/core/vrf_controller_test.go @@ -6,11 +6,11 @@ package core import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/ironcore-dev/network-operator/api/core/v1alpha1" ) @@ -81,6 +81,12 @@ var _ = Describe("VRF Controller", func() { g.Expect(testDevices.StateFor(name).VRF.Has("CC-ADMIN-TEST")).To(BeFalse(), "Provider should not have VRF configured anymore") }).Should(Succeed()) + By("Waiting for the VRF to be fully deleted") + Eventually(func(g Gomega) { + err := k8sClient.Get(ctx, key, &v1alpha1.VRF{}) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) + }).Should(Succeed()) + By("Cleaning up the Device resource") device := &v1alpha1.Device{} device.Name = name