@@ -27,9 +27,12 @@ import (
2727
2828 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2929 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3031 "k8s.io/apimachinery/pkg/runtime"
32+ runtimeschema "k8s.io/apimachinery/pkg/runtime/schema"
3133 "k8s.io/apimachinery/pkg/util/sets"
3234 "k8s.io/apimachinery/pkg/util/wait"
35+ "k8s.io/client-go/discovery"
3336 "k8s.io/client-go/rest"
3437 "sigs.k8s.io/controller-runtime/pkg/client"
3538 "sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -57,11 +60,11 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
5760 ctx context.Context
5861 cancel context.CancelFunc
5962
60- cli clusterclient.ClusterClient
61- provider , consumer logicalcluster.Path
62- consumerWS * tenancyv1alpha1.Workspace
63- mgr mcmanager.Manager
64- vwEndpoint string
63+ cli clusterclient.ClusterClient
64+ provider , consumer , other logicalcluster.Path
65+ consumerWS * tenancyv1alpha1.Workspace
66+ mgr mcmanager.Manager
67+ vwEndpoint string
6568 )
6669
6770 BeforeAll (func () {
@@ -73,6 +76,7 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
7376
7477 _ , provider = envtest .NewWorkspaceFixture (GinkgoT (), cli , core .RootCluster .Path (), envtest .WithNamePrefix ("provider" ))
7578 consumerWS , consumer = envtest .NewWorkspaceFixture (GinkgoT (), cli , core .RootCluster .Path (), envtest .WithNamePrefix ("consumer" ))
79+ _ , other = envtest .NewWorkspaceFixture (GinkgoT (), cli , core .RootCluster .Path (), envtest .WithNamePrefix ("other" ))
7680
7781 By (fmt .Sprintf ("creating a schema in the provider workspace %q" , provider ))
7882 schema := & apisv1alpha1.APIResourceSchema {
@@ -152,32 +156,101 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
152156 return false , fmt .Sprintf ("failed to get APIExportEndpointSlice in %s: %v" , provider , err )
153157 }
154158 return len (endpoints .Status .APIExportEndpoints ) > 0 , toYAML (GinkgoT (), endpoints )
155- }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see endpoints in APIExportEndpointSlice in %s " , provider )
159+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see endpoints in APIExportEndpointSlice in %q " , provider )
156160 vwEndpoint = endpoints .Status .APIExportEndpoints [0 ].URL
161+
162+ By (fmt .Sprintf ("waiting until the APIBinding in the consumer workspace %q to be ready" , consumer ))
163+ envtest .Eventually (GinkgoT (), func () (bool , string ) {
164+ current := & apisv1alpha1.APIBinding {}
165+ err := cli .Cluster (consumer ).Get (ctx , client.ObjectKey {Name : "example.com" }, current )
166+ if err != nil {
167+ return false , fmt .Sprintf ("failed to get APIBinding in %s: %v" , consumer , err )
168+ }
169+ if current .Status .Phase != apisv1alpha1 .APIBindingPhaseBound {
170+ return false , fmt .Sprintf ("binding not bound:\n \n %s" , toYAML (GinkgoT (), current ))
171+ }
172+ return true , ""
173+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to wait for APIBinding in consumer workspace to be ready %q" , consumer )
174+
175+ By ("waiting until things can be listed in the consumer workspace" )
176+ envtest .Eventually (GinkgoT (), func () (bool , string ) {
177+ u := & unstructured.UnstructuredList {}
178+ u .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "ThingList" })
179+ err = cli .Cluster (consumer ).List (ctx , u )
180+ if err != nil {
181+ return false , fmt .Sprintf ("failed to list things in %s: %v" , consumer , err )
182+ }
183+ return true , ""
184+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to wait for things to be listable in consumer workspace %q" , consumer )
157185 })
158186
159187 Describe ("with a multicluster provider and manager" , func () {
160188 var (
161189 lock sync.RWMutex
162190 engaged = sets .NewString ()
191+ p * virtualworkspace.Provider
163192 g * errgroup.Group
164193 cancelGroup context.CancelFunc
165194 )
166195
167196 BeforeAll (func () {
197+ By ("creating a stone in the consumer workspace" , func () {
198+ thing := & unstructured.Unstructured {}
199+ thing .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "Thing" })
200+ thing .SetNamespace ("stone" )
201+ thing .SetLabels (map [string ]string {"color" : "gray" })
202+ err := cli .Cluster (consumer ).Create (ctx , thing )
203+ Expect (err ).NotTo (HaveOccurred ())
204+ })
205+
206+ By ("creating a box in the other workspace" , func () {
207+ thing := & unstructured.Unstructured {}
208+ thing .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "Thing" })
209+ thing .SetNamespace ("box" )
210+ thing .SetLabels (map [string ]string {"color" : "white" })
211+ err := cli .Cluster (other ).Create (ctx , thing )
212+ Expect (err ).NotTo (HaveOccurred ())
213+ })
214+
168215 By ("creating a multicluster provider for APIBindings against the apiexport virtual workspace" )
169216 vwConfig := rest .CopyConfig (kcpConfig )
170217 vwConfig .Host = vwEndpoint
171- p , err := virtualworkspace .New (vwConfig , & apisv1alpha1.APIBinding {}, virtualworkspace.Options {})
218+ var err error
219+ p , err = virtualworkspace .New (vwConfig , & apisv1alpha1.APIBinding {}, virtualworkspace.Options {})
172220 Expect (err ).NotTo (HaveOccurred ())
173221
222+ By ("waiting for discovery of the virtual workspace to show 'example.com'" )
223+ wildcardConfig := rest .CopyConfig (vwConfig )
224+ wildcardConfig .Host += logicalcluster .Wildcard .RequestPath ()
225+ disc , err := discovery .NewDiscoveryClientForConfig (wildcardConfig )
226+ Expect (err ).NotTo (HaveOccurred ())
227+ envtest .Eventually (GinkgoT (), func () (bool , string ) {
228+ ret , err := disc .ServerGroups ()
229+ Expect (err ).NotTo (HaveOccurred ())
230+ for _ , g := range ret .Groups {
231+ if g .Name == "example.com" {
232+ return true , ""
233+ }
234+ }
235+ return false , fmt .Sprintf ("failed to find group example.com in:\n %s" , toYAML (GinkgoT (), ret ))
236+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to find group example.com in the virtual workspace" )
237+
174238 By ("creating a manager against the provider workspace" )
175239 rootConfig := rest .CopyConfig (kcpConfig )
176240 rootConfig .Host += provider .RequestPath ()
177241 mgr , err = mcmanager .New (rootConfig , p , mcmanager.Options {})
178242 Expect (err ).NotTo (HaveOccurred ())
179243
180- By ("creating a reconciler for the APIBinding" )
244+ By ("adding an index on label 'color'" )
245+ thing := & unstructured.Unstructured {}
246+ thing .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "Thing" })
247+ err = mgr .GetFieldIndexer ().IndexField (ctx , thing , "color" , func (obj client.Object ) []string {
248+ u := obj .(* unstructured.Unstructured )
249+ return []string {u .GetLabels ()["color" ]}
250+ })
251+ Expect (err ).NotTo (HaveOccurred ())
252+
253+ By ("creating a reconciler for APIBindings" )
181254 err = mcbuilder .ControllerManagedBy (mgr ).
182255 Named ("things" ).
183256 For (& apisv1alpha1.APIBinding {}).
@@ -211,6 +284,42 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
211284 }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see the consumer workspace %q as a cluster" , consumer )
212285 })
213286
287+ It ("sees only the stone in the consumer clusters" , func () {
288+ consumerCl , err := mgr .GetCluster (ctx , consumerWS .Spec .Cluster )
289+ Expect (err ).NotTo (HaveOccurred ())
290+
291+ envtest .Eventually (GinkgoT (), func () (success bool , reason string ) {
292+ l := & unstructured.UnstructuredList {}
293+ l .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "ThingList" })
294+ err = consumerCl .GetCache ().List (ctx , l )
295+ Expect (err ).NotTo (HaveOccurred ())
296+ if len (l .Items ) != 1 {
297+ return false , fmt .Sprintf ("expected 1 item, got %d\n \n %s" , len (l .Items ), toYAML (GinkgoT (), l .Object ))
298+ } else if name := l .Items [0 ].GetName (); name != "stone" {
299+ return false , fmt .Sprintf ("expected item name to be stone, got %q\n \n %s" , name , toYAML (GinkgoT (), l .Items [0 ]))
300+ }
301+ return true , ""
302+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see the stone in the consumer cluster" )
303+ })
304+
305+ It ("sees only the stone as grey thing in the consumer clusters" , func () {
306+ consumerCl , err := mgr .GetCluster (ctx , consumerWS .Spec .Cluster )
307+ Expect (err ).NotTo (HaveOccurred ())
308+
309+ envtest .Eventually (GinkgoT (), func () (success bool , reason string ) {
310+ l := & unstructured.UnstructuredList {}
311+ l .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "ThingList" })
312+ err = consumerCl .GetCache ().List (ctx , l , client.MatchingFields {"color" : "gray" })
313+ Expect (err ).NotTo (HaveOccurred ())
314+ if len (l .Items ) != 1 {
315+ return false , fmt .Sprintf ("expected 1 item, got %d\n \n %s" , len (l .Items ), toYAML (GinkgoT (), l .Object ))
316+ } else if name := l .Items [0 ].GetName (); name != "stone" {
317+ return false , fmt .Sprintf ("expected item name to be stone, got %q\n \n %s" , name , toYAML (GinkgoT (), l .Items [0 ]))
318+ }
319+ return true , ""
320+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see the stone as only thing of color 'grey' in the consumer cluster" )
321+ })
322+
214323 AfterAll (func () {
215324 cancelGroup ()
216325 err := g .Wait ()
0 commit comments