@@ -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 {
@@ -94,6 +98,7 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
9498 Raw : []byte (`{"type":"object","properties":{"spec":{"type":"object","properties":{"message":{"type":"string"}}}}}` ),
9599 },
96100 Storage : true ,
101+ Served : true ,
97102 }},
98103 },
99104 }
@@ -127,7 +132,7 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
127132 err = cli .Cluster (provider ).Create (ctx , endpoitns )
128133 Expect (err ).NotTo (HaveOccurred ())
129134
130- By (fmt .Sprintf ("creating an APIBinding in the consumer workspace %q" , consumer ))
135+ By (fmt .Sprintf ("creating an APIBinding in the other workspace %q" , other ))
131136 binding := & apisv1alpha1.APIBinding {
132137 ObjectMeta : metav1.ObjectMeta {
133138 Name : "example.com" ,
@@ -141,6 +146,23 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
141146 },
142147 },
143148 }
149+ err = cli .Cluster (other ).Create (ctx , binding )
150+ Expect (err ).NotTo (HaveOccurred ())
151+
152+ By (fmt .Sprintf ("creating an APIBinding in the consumer workspace %q" , consumer ))
153+ binding = & apisv1alpha1.APIBinding {
154+ ObjectMeta : metav1.ObjectMeta {
155+ Name : "example.com" ,
156+ },
157+ Spec : apisv1alpha1.APIBindingSpec {
158+ Reference : apisv1alpha1.BindingReference {
159+ Export : & apisv1alpha1.ExportBindingReference {
160+ Path : provider .String (),
161+ Name : export .Name ,
162+ },
163+ },
164+ },
165+ }
144166 err = cli .Cluster (consumer ).Create (ctx , binding )
145167 Expect (err ).NotTo (HaveOccurred ())
146168
@@ -149,35 +171,104 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
149171 envtest .Eventually (GinkgoT (), func () (bool , string ) {
150172 err := cli .Cluster (provider ).Get (ctx , client.ObjectKey {Name : "example.com" }, endpoints )
151173 if err != nil {
152- return false , fmt .Sprintf ("failed to get APIExportEndpointSlice in %s : %v" , provider , err )
174+ return false , fmt .Sprintf ("failed to get APIExportEndpointSlice in %q : %v" , provider , err )
153175 }
154176 return len (endpoints .Status .APIExportEndpoints ) > 0 , toYAML (GinkgoT (), endpoints )
155- }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see endpoints in APIExportEndpointSlice in %s " , provider )
177+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see endpoints in APIExportEndpointSlice in %q " , provider )
156178 vwEndpoint = endpoints .Status .APIExportEndpoints [0 ].URL
179+
180+ By (fmt .Sprintf ("waiting until the APIBinding in the consumer workspace %q to be ready" , consumer ))
181+ envtest .Eventually (GinkgoT (), func () (bool , string ) {
182+ current := & apisv1alpha1.APIBinding {}
183+ err := cli .Cluster (consumer ).Get (ctx , client.ObjectKey {Name : "example.com" }, current )
184+ if err != nil {
185+ return false , fmt .Sprintf ("failed to get APIBinding in %q: %v" , consumer , err )
186+ }
187+ if current .Status .Phase != apisv1alpha1 .APIBindingPhaseBound {
188+ return false , fmt .Sprintf ("binding not bound:\n \n %s" , toYAML (GinkgoT (), current ))
189+ }
190+ return true , ""
191+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to wait for APIBinding in consumer workspace to be ready %q" , consumer )
192+
193+ By ("waiting until things can be listed in the consumer workspace" )
194+ envtest .Eventually (GinkgoT (), func () (bool , string ) {
195+ u := & unstructured.UnstructuredList {}
196+ u .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "ThingList" })
197+ err = cli .Cluster (consumer ).List (ctx , u )
198+ if err != nil {
199+ return false , fmt .Sprintf ("failed to list things in %s: %v" , consumer , err )
200+ }
201+ return true , ""
202+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to wait for things to be listable in consumer workspace %q" , consumer )
157203 })
158204
159205 Describe ("with a multicluster provider and manager" , func () {
160206 var (
161207 lock sync.RWMutex
162208 engaged = sets .NewString ()
209+ p * virtualworkspace.Provider
163210 g * errgroup.Group
164211 cancelGroup context.CancelFunc
165212 )
166213
167214 BeforeAll (func () {
215+ By ("creating a stone in the consumer workspace" , func () {
216+ thing := & unstructured.Unstructured {}
217+ thing .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "Thing" })
218+ thing .SetName ("stone" )
219+ thing .SetLabels (map [string ]string {"color" : "gray" })
220+ err := cli .Cluster (consumer ).Create (ctx , thing )
221+ Expect (err ).NotTo (HaveOccurred ())
222+ })
223+
224+ By ("creating a box in the other workspace" , func () {
225+ thing := & unstructured.Unstructured {}
226+ thing .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "Thing" })
227+ thing .SetName ("box" )
228+ thing .SetLabels (map [string ]string {"color" : "white" })
229+ err := cli .Cluster (other ).Create (ctx , thing )
230+ Expect (err ).NotTo (HaveOccurred ())
231+ })
232+
168233 By ("creating a multicluster provider for APIBindings against the apiexport virtual workspace" )
169234 vwConfig := rest .CopyConfig (kcpConfig )
170235 vwConfig .Host = vwEndpoint
171- p , err := virtualworkspace .New (vwConfig , & apisv1alpha1.APIBinding {}, virtualworkspace.Options {})
236+ var err error
237+ p , err = virtualworkspace .New (vwConfig , & apisv1alpha1.APIBinding {}, virtualworkspace.Options {})
172238 Expect (err ).NotTo (HaveOccurred ())
173239
240+ By ("waiting for discovery of the virtual workspace to show 'example.com'" )
241+ wildcardConfig := rest .CopyConfig (vwConfig )
242+ wildcardConfig .Host += logicalcluster .Wildcard .RequestPath ()
243+ disc , err := discovery .NewDiscoveryClientForConfig (wildcardConfig )
244+ Expect (err ).NotTo (HaveOccurred ())
245+ envtest .Eventually (GinkgoT (), func () (bool , string ) {
246+ ret , err := disc .ServerGroups ()
247+ Expect (err ).NotTo (HaveOccurred ())
248+ for _ , g := range ret .Groups {
249+ if g .Name == "example.com" {
250+ return true , ""
251+ }
252+ }
253+ return false , fmt .Sprintf ("failed to find group example.com in:\n %s" , toYAML (GinkgoT (), ret ))
254+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to find group example.com in the virtual workspace" )
255+
174256 By ("creating a manager against the provider workspace" )
175257 rootConfig := rest .CopyConfig (kcpConfig )
176258 rootConfig .Host += provider .RequestPath ()
177259 mgr , err = mcmanager .New (rootConfig , p , mcmanager.Options {})
178260 Expect (err ).NotTo (HaveOccurred ())
179261
180- By ("creating a reconciler for the APIBinding" )
262+ By ("adding an index on label 'color'" )
263+ thing := & unstructured.Unstructured {}
264+ thing .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "Thing" })
265+ err = mgr .GetFieldIndexer ().IndexField (ctx , thing , "color" , func (obj client.Object ) []string {
266+ u := obj .(* unstructured.Unstructured )
267+ return []string {u .GetLabels ()["color" ]}
268+ })
269+ Expect (err ).NotTo (HaveOccurred ())
270+
271+ By ("creating a reconciler for APIBindings" )
181272 err = mcbuilder .ControllerManagedBy (mgr ).
182273 Named ("things" ).
183274 For (& apisv1alpha1.APIBinding {}).
@@ -211,6 +302,46 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
211302 }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see the consumer workspace %q as a cluster" , consumer )
212303 })
213304
305+ It ("sees only the stone 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 )
313+ if err != nil {
314+ return false , fmt .Sprintf ("failed to list things in the consumer cluster cache: %v" , err )
315+ }
316+ if len (l .Items ) != 1 {
317+ return false , fmt .Sprintf ("expected 1 item, got %d\n \n %s" , len (l .Items ), toYAML (GinkgoT (), l .Object ))
318+ } else if name := l .Items [0 ].GetName (); name != "stone" {
319+ return false , fmt .Sprintf ("expected item name to be stone, got %q\n \n %s" , name , toYAML (GinkgoT (), l .Items [0 ]))
320+ }
321+ return true , ""
322+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see the stone in the consumer cluster" )
323+ })
324+
325+ It ("sees only the stone as grey thing in the consumer clusters" , func () {
326+ consumerCl , err := mgr .GetCluster (ctx , consumerWS .Spec .Cluster )
327+ Expect (err ).NotTo (HaveOccurred ())
328+
329+ envtest .Eventually (GinkgoT (), func () (success bool , reason string ) {
330+ l := & unstructured.UnstructuredList {}
331+ l .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "ThingList" })
332+ err = consumerCl .GetCache ().List (ctx , l , client.MatchingFields {"color" : "gray" })
333+ if err != nil {
334+ return false , fmt .Sprintf ("failed to list things in the consumer cluster cache: %v" , err )
335+ }
336+ if len (l .Items ) != 1 {
337+ return false , fmt .Sprintf ("expected 1 item, got %d\n \n %s" , len (l .Items ), toYAML (GinkgoT (), l .Object ))
338+ } else if name := l .Items [0 ].GetName (); name != "stone" {
339+ return false , fmt .Sprintf ("expected item name to be stone, got %q\n \n %s" , name , toYAML (GinkgoT (), l .Items [0 ]))
340+ }
341+ return true , ""
342+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see the stone as only thing of color 'grey' in the consumer cluster" )
343+ })
344+
214345 AfterAll (func () {
215346 cancelGroup ()
216347 err := g .Wait ()
0 commit comments