@@ -7,20 +7,24 @@ Licensed under the MIT license.
77package utils
88
99import (
10+ "context"
1011 "os"
1112 "testing"
1213
1314 "github.com/google/go-cmp/cmp"
1415 "github.com/google/go-cmp/cmp/cmpopts"
16+ admv1 "k8s.io/api/admissionregistration/v1"
1517 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
18+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1619 "k8s.io/apimachinery/pkg/runtime"
20+ "k8s.io/apimachinery/pkg/types"
21+ "sigs.k8s.io/controller-runtime/pkg/client"
22+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
1723)
1824
19- var (
20- lessFunc = func (s1 , s2 string ) bool {
21- return s1 < s2
22- }
23- )
25+ var lessFunc = func (s1 , s2 string ) bool {
26+ return s1 < s2
27+ }
2428
2529// Test using the actual config/crd/bases directory.
2630func TestCollectCRDFileNamesWithActualPath (t * testing.T ) {
@@ -114,3 +118,221 @@ func runTest(t *testing.T, crdPath string) {
114118 })
115119 }
116120}
121+
122+ func TestInstallCRD (t * testing.T ) {
123+ scheme := runtime .NewScheme ()
124+ if err := apiextensionsv1 .AddToScheme (scheme ); err != nil {
125+ t .Fatalf ("Failed to add apiextensions scheme: %v" , err )
126+ }
127+
128+ testCRD := & apiextensionsv1.CustomResourceDefinition {
129+ ObjectMeta : metav1.ObjectMeta {
130+ Name : "test.example.com" ,
131+ },
132+ Spec : apiextensionsv1.CustomResourceDefinitionSpec {
133+ Group : "example.com" ,
134+ Versions : []apiextensionsv1.CustomResourceDefinitionVersion {
135+ {
136+ Name : "v1" ,
137+ Served : true ,
138+ Storage : true ,
139+ Schema : & apiextensionsv1.CustomResourceValidation {
140+ OpenAPIV3Schema : & apiextensionsv1.JSONSchemaProps {
141+ Type : "object" ,
142+ },
143+ },
144+ },
145+ },
146+ Scope : apiextensionsv1 .NamespaceScoped ,
147+ Names : apiextensionsv1.CustomResourceDefinitionNames {
148+ Plural : "tests" ,
149+ Singular : "test" ,
150+ Kind : "Test" ,
151+ },
152+ },
153+ }
154+
155+ tests := []struct {
156+ name string
157+ crd * apiextensionsv1.CustomResourceDefinition
158+ wantError bool
159+ }{
160+ {
161+ name : "successful CRD installation" ,
162+ crd : testCRD ,
163+ wantError : false ,
164+ },
165+ }
166+
167+ for _ , tt := range tests {
168+ t .Run (tt .name , func (t * testing.T ) {
169+ fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).Build ()
170+ err := InstallCRD (context .Background (), fakeClient , tt .crd )
171+
172+ if tt .wantError {
173+ if err == nil {
174+ t .Errorf ("InstallCRD() expected error but got none" )
175+ }
176+ return
177+ }
178+
179+ if err != nil {
180+ t .Errorf ("InstallCRD() unexpected error: %v" , err )
181+ return
182+ }
183+
184+ var installedCRD apiextensionsv1.CustomResourceDefinition
185+ err = fakeClient .Get (context .Background (), types.NamespacedName {Name : tt .crd .Name }, & installedCRD )
186+ if err != nil {
187+ t .Errorf ("Failed to get installed CRD: %v" , err )
188+ return
189+ }
190+
191+ if installedCRD .Labels [CRDInstallerLabelKey ] != "true" {
192+ t .Errorf ("Expected CRD label %s to be 'true', got %q" , CRDInstallerLabelKey , installedCRD .Labels [CRDInstallerLabelKey ])
193+ }
194+
195+ if installedCRD .Labels [AzureManagedLabelKey ] != FleetLabelValue {
196+ t .Errorf ("Expected CRD label %s to be %q, got %q" , AzureManagedLabelKey , FleetLabelValue , installedCRD .Labels [AzureManagedLabelKey ])
197+ }
198+
199+ if diff := cmp .Diff (tt .crd .Spec , installedCRD .Spec ); diff != "" {
200+ t .Errorf ("CRD spec mismatch (-want +got):\n %s" , diff )
201+ }
202+ })
203+ }
204+ }
205+
206+ func TestInstall (t * testing.T ) {
207+ scheme := runtime .NewScheme ()
208+ if err := apiextensionsv1 .AddToScheme (scheme ); err != nil {
209+ t .Fatalf ("Failed to add apiextensions scheme: %v" , err )
210+ }
211+
212+ testCRD := & apiextensionsv1.CustomResourceDefinition {
213+ ObjectMeta : metav1.ObjectMeta {
214+ Name : "test.example.com" ,
215+ },
216+ Spec : apiextensionsv1.CustomResourceDefinitionSpec {
217+ Group : "example.com" ,
218+ Versions : []apiextensionsv1.CustomResourceDefinitionVersion {
219+ {
220+ Name : "v1" ,
221+ Served : true ,
222+ Storage : true ,
223+ Schema : & apiextensionsv1.CustomResourceValidation {
224+ OpenAPIV3Schema : & apiextensionsv1.JSONSchemaProps {
225+ Type : "object" ,
226+ },
227+ },
228+ },
229+ },
230+ Scope : apiextensionsv1 .NamespaceScoped ,
231+ Names : apiextensionsv1.CustomResourceDefinitionNames {
232+ Plural : "tests" ,
233+ Singular : "test" ,
234+ Kind : "Test" ,
235+ },
236+ },
237+ }
238+
239+ tests := []struct {
240+ name string
241+ obj client.Object
242+ mutFunc func () error
243+ wantError bool
244+ }{
245+ {
246+ name : "successful install with mutation" ,
247+ obj : testCRD ,
248+ mutFunc : func () error {
249+ if testCRD .Labels == nil {
250+ testCRD .Labels = make (map [string ]string )
251+ }
252+ testCRD .Labels ["test" ] = "value"
253+ return nil
254+ },
255+ wantError : false ,
256+ },
257+ {
258+ name : "successful install without mutation" ,
259+ obj : & apiextensionsv1.CustomResourceDefinition {
260+ ObjectMeta : metav1.ObjectMeta {
261+ Name : "test2.example.com" ,
262+ },
263+ Spec : testCRD .Spec ,
264+ },
265+ mutFunc : func () error {
266+ return nil
267+ },
268+ wantError : false ,
269+ },
270+ }
271+
272+ for _ , tt := range tests {
273+ t .Run (tt .name , func (t * testing.T ) {
274+ fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).Build ()
275+ err := install (context .Background (), fakeClient , tt .obj , tt .mutFunc )
276+
277+ if tt .wantError {
278+ if err == nil {
279+ t .Errorf ("install() expected error but got none" )
280+ }
281+ return
282+ }
283+
284+ if err != nil {
285+ t .Errorf ("install() unexpected error: %v" , err )
286+ return
287+ }
288+
289+ var installed apiextensionsv1.CustomResourceDefinition
290+ err = fakeClient .Get (context .Background (), types.NamespacedName {Name : tt .obj .GetName ()}, & installed )
291+ if err != nil {
292+ t .Errorf ("Failed to get installed object: %v" , err )
293+ return
294+ }
295+
296+ if tt .mutFunc != nil && tt .obj .GetName () == "test.example.com" {
297+ if installed .Labels ["test" ] != "value" {
298+ t .Errorf ("Expected label 'test' to be 'value', got %q" , installed .Labels ["test" ])
299+ }
300+ }
301+ })
302+ }
303+ }
304+
305+ func TestInstallManagedResourceVAP (t * testing.T ) {
306+ tests := []struct {
307+ name string
308+ mode string
309+ }{
310+ {
311+ name : "hub mode" ,
312+ mode : "hub" ,
313+ },
314+ {
315+ name : "member mode" ,
316+ mode : "member" ,
317+ },
318+ }
319+
320+ for _ , tt := range tests {
321+ t .Run (tt .name , func (t * testing.T ) {
322+ scheme := runtime .NewScheme ()
323+ if err := admv1 .AddToScheme (scheme ); err != nil {
324+ t .Fatalf ("Failed to add admissionregistration scheme: %v" , err )
325+ }
326+
327+ fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).Build ()
328+ err := InstallManagedResourceVAP (context .Background (), fakeClient , tt .mode )
329+
330+ // The function should complete without errors
331+ // The actual installation behavior depends on the RESTMapper implementation
332+ // which is difficult to test reliably with the fake client
333+ if err != nil {
334+ t .Errorf ("InstallManagedResourceVAP() unexpected error: %v" , err )
335+ }
336+ })
337+ }
338+ }
0 commit comments