@@ -34,6 +34,7 @@ import (
3434 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
3535 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3636 "k8s.io/apimachinery/pkg/types"
37+ "k8s.io/apimachinery/pkg/util/sets"
3738 "k8s.io/apimachinery/pkg/util/wait"
3839 ctrlruntime "sigs.k8s.io/controller-runtime"
3940 ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -287,6 +288,98 @@ func TestARSOnlyContainsSelectedCRDVersion(t *testing.T) {
287288 }
288289}
289290
291+ func TestMultiVersionCRD (t * testing.T ) {
292+ const (
293+ apiExportName = "example.com"
294+ )
295+
296+ // force a non-standard order, because it should not matter for the sync
297+ var selectedVersions = []string {"v2" , "v1" }
298+
299+ ctx := context .Background ()
300+ ctrlruntime .SetLogger (logr .Discard ())
301+
302+ // setup a test environment in kcp
303+ orgKubconfig := utils .CreateOrganization (t , ctx , "ars-multi-versions" , apiExportName )
304+
305+ // start a service cluster
306+ envtestKubeconfig , envtestClient , _ := utils .RunEnvtest (t , []string {
307+ "test/crds/crontab-multi-versions.yaml" ,
308+ })
309+
310+ // publish Crontabs
311+ t .Logf ("Publishing CronTabs…" )
312+ pr := & syncagentv1alpha1.PublishedResource {
313+ ObjectMeta : metav1.ObjectMeta {
314+ Name : "publish-crontabs" ,
315+ },
316+ Spec : syncagentv1alpha1.PublishedResourceSpec {
317+ Resource : syncagentv1alpha1.SourceResourceDescriptor {
318+ APIGroup : "example.com" ,
319+ Versions : selectedVersions ,
320+ Kind : "CronTab" ,
321+ },
322+ },
323+ }
324+
325+ if err := envtestClient .Create (ctx , pr ); err != nil {
326+ t .Fatalf ("Failed to create PublishedResource: %v" , err )
327+ }
328+
329+ // let the agent do its thing
330+ utils .RunAgent (ctx , t , "bob" , orgKubconfig , envtestKubeconfig , apiExportName )
331+
332+ // wait for the APIExport to be updated
333+ t .Logf ("Waiting for APIExport to be updated…" )
334+ orgClient := utils .GetClient (t , orgKubconfig )
335+ apiExportKey := types.NamespacedName {Name : apiExportName }
336+
337+ var arsName string
338+ err := wait .PollUntilContextTimeout (ctx , 500 * time .Millisecond , 1 * time .Minute , false , func (ctx context.Context ) (done bool , err error ) {
339+ apiExport := & kcpapisv1alpha1.APIExport {}
340+ err = orgClient .Get (ctx , apiExportKey , apiExport )
341+ if err != nil {
342+ return false , err
343+ }
344+
345+ if len (apiExport .Spec .LatestResourceSchemas ) == 0 {
346+ return false , nil
347+ }
348+
349+ arsName = apiExport .Spec .LatestResourceSchemas [0 ]
350+
351+ return true , nil
352+ })
353+ if err != nil {
354+ t .Fatalf ("Failed to wait for APIExport to be updated: %v" , err )
355+ }
356+
357+ // check the APIResourceSchema
358+ ars := & kcpapisv1alpha1.APIResourceSchema {}
359+ err = orgClient .Get (ctx , types.NamespacedName {Name : arsName }, ars )
360+ if err != nil {
361+ t .Fatalf ("APIResourceSchema does not exist: %v" , err )
362+ }
363+
364+ if len (ars .Spec .Versions ) != len (selectedVersions ) {
365+ t .Fatalf ("Expected %d versions to remain in the ARS, but found %d." , len (selectedVersions ), len (ars .Spec .Versions ))
366+ }
367+
368+ // Projection tests already ensure the correct order, all we have to check
369+ // here is that all versions are present (and more importantly that creating
370+ // the multi-version ARS has worked at all).
371+ expectedVersions := sets .New (selectedVersions ... )
372+ foundVersions := sets .New [string ]()
373+
374+ for _ , v := range ars .Spec .Versions {
375+ foundVersions .Insert (v .Name )
376+ }
377+
378+ if ! expectedVersions .Equal (foundVersions ) {
379+ t .Fatalf ("Expected versions %v, but ARS contains %v." , sets .List (expectedVersions ), sets .List (foundVersions ))
380+ }
381+ }
382+
290383func TestProjection (t * testing.T ) {
291384 const (
292385 apiExportName = "example.com"
0 commit comments