@@ -17,22 +17,30 @@ limitations under the License.
1717package vmware
1818
1919import (
20+ "context"
2021 "os"
2122 "path/filepath"
23+ "reflect"
2224 "testing"
2325
2426 . "github.com/onsi/ginkgo/v2"
2527 "github.com/onsi/ginkgo/v2/types"
2628 . "github.com/onsi/gomega"
27- topologyv1 "github.com/vmware-tanzu/vm-operator/external/tanzu-topology/api/v1alpha1"
2829 corev1 "k8s.io/api/core/v1"
2930 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31+ "k8s.io/apimachinery/pkg/runtime"
3032 apirecord "k8s.io/client-go/tools/record"
33+ utilfeature "k8s.io/component-base/featuregate/testing"
34+ "k8s.io/utils/ptr"
3135 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
3236 "sigs.k8s.io/cluster-api/util/conditions"
3337 ctrl "sigs.k8s.io/controller-runtime"
38+ "sigs.k8s.io/controller-runtime/pkg/client"
39+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
3440
3541 vmwarev1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/vmware/v1beta1"
42+ "sigs.k8s.io/cluster-api-provider-vsphere/feature"
43+ topologyv1 "sigs.k8s.io/cluster-api-provider-vsphere/internal/apis/topology/v1alpha1"
3644 capvcontext "sigs.k8s.io/cluster-api-provider-vsphere/pkg/context"
3745 "sigs.k8s.io/cluster-api-provider-vsphere/pkg/context/vmware"
3846 "sigs.k8s.io/cluster-api-provider-vsphere/pkg/services/network"
@@ -128,34 +136,149 @@ var _ = Describe("Cluster Controller Tests", func() {
128136 Expect (c .Reason ).NotTo (Equal (clusterv1 .DeletingReason ))
129137 })
130138 })
139+ })
131140
132- Context ("Test getFailureDomains" , func () {
133- It ("should not find FailureDomains" , func () {
134- fds , err := reconciler .getFailureDomains (ctx )
135- Expect (err ).ToNot (HaveOccurred ())
136- Expect (fds ).Should (BeEmpty ())
137- })
141+ func TestClusterReconciler_getFailureDomains (t * testing.T ) {
142+ g := NewWithT (t )
143+ ctx := context .Background ()
138144
139- It ("should find FailureDomains" , func () {
140- zoneNames := []string {"homer" , "marge" , "bart" }
141- for _ , name := range zoneNames {
142- zone := & topologyv1.AvailabilityZone {
143- TypeMeta : metav1.TypeMeta {
144- APIVersion : topologyv1 .GroupVersion .String (),
145- Kind : "AvailabilityZone" ,
146- },
147- ObjectMeta : metav1.ObjectMeta {
148- Name : name ,
149- },
150- }
151-
152- Expect (controllerManagerContext .Client .Create (ctx , zone )).To (Succeed ())
153- }
145+ scheme := runtime .NewScheme ()
146+ g .Expect (corev1 .AddToScheme (scheme )).To (Succeed ())
147+ g .Expect (topologyv1 .AddToScheme (scheme )).To (Succeed ())
154148
155- fds , err := reconciler .getFailureDomains (ctx )
156- Expect (err ).ToNot (HaveOccurred ())
157- Expect (fds ).NotTo (BeNil ())
158- Expect (fds ).Should (HaveLen (3 ))
149+ namespace := & corev1.Namespace {
150+ ObjectMeta : metav1.ObjectMeta {
151+ Name : "test-namespace" ,
152+ },
153+ }
154+
155+ tests := []struct {
156+ name string
157+ objects []client.Object
158+ want clusterv1.FailureDomains
159+ wantErr bool
160+ featureGate bool
161+ }{
162+ {
163+ name : "Cluster-Wide: should not find any FailureDomains if no exists" ,
164+ objects : []client.Object {},
165+ want : nil ,
166+ wantErr : false ,
167+ featureGate : false ,
168+ },
169+ {
170+ name : "Namespaced: should not find any FailureDomains if no exists" ,
171+ objects : []client.Object {},
172+ want : nil ,
173+ wantErr : false ,
174+ featureGate : true ,
175+ },
176+ {
177+ name : "Cluster-Wide: should not find any FailureDomains if only namespaced exist" ,
178+ objects : []client.Object {zone (namespace .Name , "ns-one" , false )},
179+ want : nil ,
180+ wantErr : false ,
181+ featureGate : false ,
182+ },
183+ {
184+ name : "Namespaced: should not find any FailureDomains if only cluster-wide exist" ,
185+ objects : []client.Object {availabilityZone ("c-one" )},
186+ want : nil ,
187+ wantErr : false ,
188+ featureGate : true ,
189+ },
190+ {
191+ name : "Cluster-Wide: should find FailureDomains if only cluster-wide exist" ,
192+ objects : []client.Object {availabilityZone ("c-one" )},
193+ want : failureDomains ("c-one" ),
194+ wantErr : false ,
195+ featureGate : false ,
196+ },
197+ {
198+ name : "Namespaced: should find FailureDomains if only namespaced exist" ,
199+ objects : []client.Object {zone (namespace .Name , "ns-one" , false )},
200+ want : failureDomains ("ns-one" ),
201+ wantErr : false ,
202+ featureGate : true ,
203+ },
204+ {
205+ name : "Cluster-Wide: should only find cluster-wide FailureDomains if both types exist" ,
206+ objects : []client.Object {availabilityZone ("c-one" ), zone (namespace .Name , "ns-one" , false )},
207+ want : failureDomains ("c-one" ),
208+ wantErr : false ,
209+ featureGate : false ,
210+ },
211+ {
212+ name : "Namespaced: should only find namespaced FailureDomains if both types exist" ,
213+ objects : []client.Object {availabilityZone ("c-one" ), zone (namespace .Name , "ns-one" , false )},
214+ want : failureDomains ("ns-one" ),
215+ wantErr : false ,
216+ featureGate : true ,
217+ },
218+ {
219+ name : "Namespaced: should only find non-deleting namespaced FailureDomains" ,
220+ objects : []client.Object {
221+ availabilityZone ("c-one" ),
222+ zone (namespace .Name , "ns-one" , false ),
223+ zone (namespace .Name , "ns-two" , false ),
224+ zone (namespace .Name , "ns-three" , false ),
225+ zone (namespace .Name , "ns-four" , true ),
226+ },
227+ want : failureDomains ("ns-one" , "ns-two" , "ns-three" ),
228+ wantErr : false ,
229+ featureGate : true ,
230+ },
231+ }
232+ for _ , tt := range tests {
233+ t .Run (tt .name , func (t * testing.T ) {
234+ r := & ClusterReconciler {
235+ Client : fake .NewClientBuilder ().
236+ WithScheme (scheme ).
237+ WithObjects (append ([]client.Object {namespace }, tt .objects ... )... ).
238+ Build (),
239+ }
240+ defer utilfeature .SetFeatureGateDuringTest (t , feature .Gates , feature .NamespaceScopedZones , tt .featureGate )()
241+ got , err := r .getFailureDomains (ctx , namespace .Name )
242+ if (err != nil ) != tt .wantErr {
243+ t .Errorf ("ClusterReconciler.getFailureDomains() error = %v, wantErr %v" , err , tt .wantErr )
244+ return
245+ }
246+ if ! reflect .DeepEqual (got , tt .want ) {
247+ t .Errorf ("ClusterReconciler.getFailureDomains() = %v, want %v" , got , tt .want )
248+ }
159249 })
160- })
161- })
250+ }
251+ }
252+
253+ func availabilityZone (name string ) * topologyv1.AvailabilityZone {
254+ return & topologyv1.AvailabilityZone {
255+ ObjectMeta : metav1.ObjectMeta {
256+ Name : name ,
257+ },
258+ }
259+ }
260+
261+ func zone (namespace , name string , deleting bool ) * topologyv1.Zone {
262+ z := & topologyv1.Zone {
263+ ObjectMeta : metav1.ObjectMeta {
264+ Namespace : namespace ,
265+ Name : name ,
266+ },
267+ }
268+
269+ if deleting {
270+ z .ObjectMeta .DeletionTimestamp = ptr .To (metav1 .Now ())
271+ z .ObjectMeta .Finalizers = []string {"deletion.test.io/protection" }
272+ }
273+ return z
274+ }
275+
276+ func failureDomains (names ... string ) clusterv1.FailureDomains {
277+ fds := clusterv1.FailureDomains {}
278+ for _ , name := range names {
279+ fds [name ] = clusterv1.FailureDomainSpec {
280+ ControlPlane : true ,
281+ }
282+ }
283+ return fds
284+ }
0 commit comments