Skip to content

Commit dbce2c0

Browse files
committed
test/e2e: test scoped indexes and make them actually work
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@gmail.com>
1 parent b394627 commit dbce2c0

File tree

2 files changed

+121
-11
lines changed

2 files changed

+121
-11
lines changed

test/e2e/apiexport_test.go

Lines changed: 112 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
runtimeschema "k8s.io/apimachinery/pkg/runtime/schema"
3333
"k8s.io/apimachinery/pkg/util/sets"
3434
"k8s.io/apimachinery/pkg/util/wait"
35+
"k8s.io/client-go/discovery"
3536
"k8s.io/client-go/rest"
3637
"sigs.k8s.io/controller-runtime/pkg/client"
3738
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -59,11 +60,11 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
5960
ctx context.Context
6061
cancel context.CancelFunc
6162

62-
cli clusterclient.ClusterClient
63-
provider, consumer logicalcluster.Path
64-
consumerWS *tenancyv1alpha1.Workspace
65-
mgr mcmanager.Manager
66-
vwEndpoint string
63+
cli clusterclient.ClusterClient
64+
provider, consumer, other logicalcluster.Path
65+
consumerWS *tenancyv1alpha1.Workspace
66+
mgr mcmanager.Manager
67+
vwEndpoint string
6768
)
6869

6970
BeforeAll(func() {
@@ -75,6 +76,7 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
7576

7677
_, provider = envtest.NewWorkspaceFixture(GinkgoT(), cli, core.RootCluster.Path(), envtest.WithNamePrefix("provider"))
7778
consumerWS, consumer = envtest.NewWorkspaceFixture(GinkgoT(), cli, core.RootCluster.Path(), envtest.WithNamePrefix("consumer"))
79+
_, other = envtest.NewWorkspaceFixture(GinkgoT(), cli, core.RootCluster.Path(), envtest.WithNamePrefix("other"))
7880

7981
By(fmt.Sprintf("creating a schema in the provider workspace %q", provider))
8082
schema := &apisv1alpha1.APIResourceSchema{
@@ -130,7 +132,7 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
130132
err = cli.Cluster(provider).Create(ctx, endpoitns)
131133
Expect(err).NotTo(HaveOccurred())
132134

133-
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))
134136
binding := &apisv1alpha1.APIBinding{
135137
ObjectMeta: metav1.ObjectMeta{
136138
Name: "example.com",
@@ -144,6 +146,23 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
144146
},
145147
},
146148
}
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+
}
147166
err = cli.Cluster(consumer).Create(ctx, binding)
148167
Expect(err).NotTo(HaveOccurred())
149168

@@ -187,24 +206,69 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
187206
var (
188207
lock sync.RWMutex
189208
engaged = sets.NewString()
209+
p *virtualworkspace.Provider
190210
g *errgroup.Group
191211
cancelGroup context.CancelFunc
192212
)
193213

194214
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+
195233
By("creating a multicluster provider for APIBindings against the apiexport virtual workspace")
196234
vwConfig := rest.CopyConfig(kcpConfig)
197235
vwConfig.Host = vwEndpoint
198-
p, err := virtualworkspace.New(vwConfig, &apisv1alpha1.APIBinding{}, virtualworkspace.Options{})
236+
var err error
237+
p, err = virtualworkspace.New(vwConfig, &apisv1alpha1.APIBinding{}, virtualworkspace.Options{})
199238
Expect(err).NotTo(HaveOccurred())
200239

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+
201256
By("creating a manager against the provider workspace")
202257
rootConfig := rest.CopyConfig(kcpConfig)
203258
rootConfig.Host += provider.RequestPath()
204259
mgr, err = mcmanager.New(rootConfig, p, mcmanager.Options{})
205260
Expect(err).NotTo(HaveOccurred())
206261

207-
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")
208272
err = mcbuilder.ControllerManagedBy(mgr).
209273
Named("things").
210274
For(&apisv1alpha1.APIBinding{}).
@@ -238,6 +302,46 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
238302
}, wait.ForeverTestTimeout, time.Millisecond*100, "failed to see the consumer workspace %q as a cluster", consumer)
239303
})
240304

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+
241345
AfterAll(func() {
242346
cancelGroup()
243347
err := g.Wait()

virtualworkspace/forked_cache_reader.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ func byIndexes(indexer cache.Indexer, requires fields.Requirements, clusterName
212212
indexers := indexer.GetIndexers()
213213
_, isClusterAware := indexers[kcpcache.ClusterAndNamespaceIndexName]
214214
for idx, req := range requires {
215-
indexName := fieldIndexName(req.Field)
215+
indexName := fieldIndexName(isClusterAware, req.Field)
216216
var indexedValue string
217217
if isClusterAware {
218218
indexedValue = keyToClusteredKey(clusterName.String(), namespace, req.Value)
@@ -270,7 +270,10 @@ func objectKeyToStoreKey(k client.ObjectKey) string {
270270

271271
// fieldIndexName constructs the name of the index over the given field,
272272
// for use with an indexer.
273-
func fieldIndexName(field string) string {
273+
func fieldIndexName(clusterAware bool, field string) string {
274+
if clusterAware {
275+
return "field:cluster/" + field
276+
}
274277
return "field:" + field
275278
}
276279

@@ -289,7 +292,10 @@ func keyToNamespacedKey(ns string, baseKey string) string {
289292
// keyToClusteredKey prefixes the given index key with a cluster name
290293
// for use in field selector indexes.
291294
func keyToClusteredKey(clusterName string, ns string, baseKey string) string {
292-
return clusterName + "|" + keyToNamespacedKey(ns, baseKey)
295+
if ns != "" {
296+
return ns + "/" + clusterName + "/" + baseKey
297+
}
298+
return allNamespacesNamespace + "/" + clusterName + "/" + baseKey
293299
}
294300

295301
// requiresExactMatch checks if the given field selector is of the form `k=v` or `k==v`.

0 commit comments

Comments
 (0)