@@ -19,15 +19,20 @@ package controller
1919
2020import (
2121 "context"
22+ "errors"
23+ "time"
2224
2325 kvmv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1"
2426 "github.com/coreos/go-systemd/v22/dbus"
27+ golibvirt "github.com/digitalocean/go-libvirt"
2528 . "github.com/onsi/ginkgo/v2"
2629 . "github.com/onsi/gomega"
27- "k8s.io/apimachinery/pkg/api/errors"
30+ apierrors "k8s.io/apimachinery/pkg/api/errors"
2831 "k8s.io/apimachinery/pkg/api/resource"
2932 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3033 "k8s.io/apimachinery/pkg/types"
34+ ctrl "sigs.k8s.io/controller-runtime"
35+ "sigs.k8s.io/controller-runtime/pkg/event"
3136 "sigs.k8s.io/controller-runtime/pkg/reconcile"
3237
3338 "github.com/cobaltcore-dev/kvm-node-agent/internal/libvirt"
@@ -36,6 +41,154 @@ import (
3641)
3742
3843var _ = Describe ("Hypervisor Controller" , func () {
44+ Context ("When testing Start method" , func () {
45+ It ("should successfully start and subscribe to libvirt events" , func () {
46+ ctx := context .Background ()
47+ eventCallbackCalled := false
48+
49+ controllerReconciler := & HypervisorReconciler {
50+ Client : k8sClient ,
51+ Scheme : k8sClient .Scheme (),
52+ Libvirt : & libvirt.InterfaceMock {
53+ ConnectFunc : func () error {
54+ return nil
55+ },
56+ WatchDomainChangesFunc : func (eventId golibvirt.DomainEventID , handlerId string , handler func (context.Context , any )) {
57+ eventCallbackCalled = true
58+ Expect (handlerId ).To (Equal ("reconcile-on-domain-lifecycle" ))
59+ },
60+ },
61+ reconcileCh : make (chan event.GenericEvent , 1 ),
62+ }
63+
64+ err := controllerReconciler .Start (ctx )
65+ Expect (err ).NotTo (HaveOccurred ())
66+ Expect (eventCallbackCalled ).To (BeTrue ())
67+ })
68+
69+ It ("should fail when libvirt connection fails" , func () {
70+ ctx := context .Background ()
71+
72+ controllerReconciler := & HypervisorReconciler {
73+ Client : k8sClient ,
74+ Scheme : k8sClient .Scheme (),
75+ Libvirt : & libvirt.InterfaceMock {
76+ ConnectFunc : func () error {
77+ return errors .New ("connection failed" )
78+ },
79+ },
80+ reconcileCh : make (chan event.GenericEvent , 1 ),
81+ }
82+
83+ err := controllerReconciler .Start (ctx )
84+ Expect (err ).To (HaveOccurred ())
85+ Expect (err .Error ()).To (ContainSubstring ("connection failed" ))
86+ })
87+ })
88+
89+ Context ("When testing triggerReconcile method" , func () {
90+ It ("should send an event to reconcile channel" , func () {
91+ const testHostname = "test-host"
92+ const testNamespace = "test-namespace"
93+
94+ // Override hostname and namespace for this test
95+ originalHostname := sys .Hostname
96+ originalNamespace := sys .Namespace
97+ sys .Hostname = testHostname
98+ sys .Namespace = testNamespace
99+ defer func () {
100+ sys .Hostname = originalHostname
101+ sys .Namespace = originalNamespace
102+ }()
103+
104+ controllerReconciler := & HypervisorReconciler {
105+ Client : k8sClient ,
106+ Scheme : k8sClient .Scheme (),
107+ reconcileCh : make (chan event.GenericEvent , 1 ),
108+ }
109+
110+ // Trigger reconcile in a goroutine to avoid blocking
111+ go controllerReconciler .triggerReconcile ()
112+
113+ // Wait for the event with a timeout
114+ select {
115+ case evt := <- controllerReconciler .reconcileCh :
116+ Expect (evt .Object ).NotTo (BeNil ())
117+ hv , ok := evt .Object .(* kvmv1.Hypervisor )
118+ Expect (ok ).To (BeTrue ())
119+ Expect (hv .Name ).To (Equal (testHostname ))
120+ Expect (hv .Namespace ).To (Equal (testNamespace ))
121+ Expect (hv .Kind ).To (Equal ("Hypervisor" ))
122+ Expect (hv .APIVersion ).To (Equal ("kvm.cloud.sap/v1" ))
123+ case <- time .After (2 * time .Second ):
124+ Fail ("timeout waiting for reconcile event" )
125+ }
126+ })
127+ })
128+
129+ Context ("When testing SetupWithManager method" , func () {
130+ It ("should successfully setup controller with manager" , func () {
131+ // Create a test manager
132+ mgr , err := ctrl .NewManager (cfg , ctrl.Options {
133+ Scheme : k8sClient .Scheme (),
134+ })
135+ Expect (err ).NotTo (HaveOccurred ())
136+
137+ controllerReconciler := & HypervisorReconciler {
138+ Client : k8sClient ,
139+ Scheme : k8sClient .Scheme (),
140+ Systemd : & systemd.InterfaceMock {
141+ DescribeFunc : func (ctx context.Context ) (* systemd.Descriptor , error ) {
142+ return & systemd.Descriptor {
143+ OperatingSystemReleaseData : []string {
144+ "PRETTY_NAME=\" Garden Linux 1877.8\" " ,
145+ "GARDENLINUX_VERSION=1877.8" ,
146+ },
147+ KernelVersion : "6.1.0" ,
148+ KernelRelease : "6.1.0-gardenlinux" ,
149+ KernelName : "Linux" ,
150+ HardwareVendor : "Test Vendor" ,
151+ HardwareModel : "Test Model" ,
152+ HardwareSerial : "TEST123" ,
153+ FirmwareVersion : "1.0" ,
154+ FirmwareVendor : "Test BIOS" ,
155+ FirmwareDate : time .Now ().UnixMicro (),
156+ }, nil
157+ },
158+ },
159+ }
160+
161+ err = controllerReconciler .SetupWithManager (mgr )
162+ Expect (err ).NotTo (HaveOccurred ())
163+ Expect (controllerReconciler .reconcileCh ).NotTo (BeNil ())
164+ Expect (controllerReconciler .osDescriptor ).NotTo (BeNil ())
165+ Expect (controllerReconciler .osDescriptor .OperatingSystemReleaseData ).To (HaveLen (2 ))
166+ })
167+
168+ It ("should fail when systemd Describe returns error" , func () {
169+ // Create a test manager
170+ mgr , err := ctrl .NewManager (cfg , ctrl.Options {
171+ Scheme : k8sClient .Scheme (),
172+ })
173+ Expect (err ).NotTo (HaveOccurred ())
174+
175+ controllerReconciler := & HypervisorReconciler {
176+ Client : k8sClient ,
177+ Scheme : k8sClient .Scheme (),
178+ Systemd : & systemd.InterfaceMock {
179+ DescribeFunc : func (ctx context.Context ) (* systemd.Descriptor , error ) {
180+ return nil , errors .New ("systemd describe failed" )
181+ },
182+ },
183+ }
184+
185+ err = controllerReconciler .SetupWithManager (mgr )
186+ Expect (err ).To (HaveOccurred ())
187+ Expect (err .Error ()).To (ContainSubstring ("unable to get Systemd hostname describe()" ))
188+ Expect (err .Error ()).To (ContainSubstring ("systemd describe failed" ))
189+ })
190+ })
191+
39192 Context ("When reconciling a resource" , func () {
40193 const resourceName = "test-resource"
41194
@@ -50,7 +203,7 @@ var _ = Describe("Hypervisor Controller", func() {
50203 BeforeEach (func () {
51204 By ("creating the custom resource for the Kind Hypervisor" )
52205 err := k8sClient .Get (ctx , typeNamespacedName , hypervisor )
53- if err != nil && errors .IsNotFound (err ) {
206+ if err != nil && apierrors .IsNotFound (err ) {
54207 resource := & kvmv1.Hypervisor {
55208 ObjectMeta : metav1.ObjectMeta {
56209 Name : resourceName ,
0 commit comments