Skip to content

Commit 356ce74

Browse files
committed
test/e2e: actually test that we can do CRUD on the resources
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@gmail.com>
1 parent 6fb4c62 commit 356ce74

File tree

2 files changed

+112
-8
lines changed

2 files changed

+112
-8
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ require (
1717
golang.org/x/sync v0.11.0
1818
golang.org/x/sys v0.30.0
1919
k8s.io/api v0.32.3
20+
k8s.io/apiextensions-apiserver v0.32.1
2021
k8s.io/apimachinery v0.32.3
2122
k8s.io/client-go v0.32.3
2223
k8s.io/klog/v2 v2.130.1
@@ -73,7 +74,6 @@ require (
7374
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
7475
gopkg.in/inf.v0 v0.9.1 // indirect
7576
gopkg.in/yaml.v3 v3.0.1 // indirect
76-
k8s.io/apiextensions-apiserver v0.32.1 // indirect
7777
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
7878
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
7979
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect

test/e2e/apiexport_test.go

Lines changed: 111 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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{
@@ -154,12 +158,32 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
154158
return len(endpoints.Status.APIExportEndpoints) > 0, toYAML(GinkgoT(), endpoints)
155159
}, wait.ForeverTestTimeout, time.Millisecond*100, "failed to see endpoints in APIExportEndpointSlice in %s", 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+
u := &unstructured.UnstructuredList{}
173+
u.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "ThingList"})
174+
err = cli.Cluster(consumer).List(ctx, u)
175+
if err != nil {
176+
return false, fmt.Sprintf("failed to list things in %s: %v\n\n%s", consumer, err, toYAML(GinkgoT(), current))
177+
}
178+
return true, ""
179+
}, wait.ForeverTestTimeout, time.Millisecond*100, "failed to list things in %s workspace", consumer)
157180
})
158181

159182
Describe("with a multicluster provider and manager", func() {
160183
var (
161184
lock sync.RWMutex
162185
engaged = sets.NewString()
186+
p *virtualworkspace.Provider
163187
g *errgroup.Group
164188
cancelGroup context.CancelFunc
165189
)
@@ -168,16 +192,42 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
168192
By("creating a multicluster provider for APIBindings against the apiexport virtual workspace")
169193
vwConfig := rest.CopyConfig(kcpConfig)
170194
vwConfig.Host = vwEndpoint
171-
p, err := virtualworkspace.New(vwConfig, &apisv1alpha1.APIBinding{}, virtualworkspace.Options{})
195+
var err error
196+
p, err = virtualworkspace.New(vwConfig, &apisv1alpha1.APIBinding{}, virtualworkspace.Options{})
172197
Expect(err).NotTo(HaveOccurred())
173198

199+
By("waiting for discovery of the virtual workspace to show 'example.com'")
200+
wildcardConfig := rest.CopyConfig(vwConfig)
201+
wildcardConfig.Host += logicalcluster.Wildcard.RequestPath()
202+
disc, err := discovery.NewDiscoveryClientForConfig(wildcardConfig)
203+
Expect(err).NotTo(HaveOccurred())
204+
envtest.Eventually(GinkgoT(), func() (bool, string) {
205+
ret, err := disc.ServerGroups()
206+
Expect(err).NotTo(HaveOccurred())
207+
for _, g := range ret.Groups {
208+
if g.Name == "example.com" {
209+
return true, ""
210+
}
211+
}
212+
return false, fmt.Sprintf("failed to find group example.com in:\n%s", toYAML(GinkgoT(), ret))
213+
}, wait.ForeverTestTimeout, time.Millisecond*100, "failed to find group example.com in the virtual workspace")
214+
174215
By("creating a manager against the provider workspace")
175216
rootConfig := rest.CopyConfig(kcpConfig)
176217
rootConfig.Host += provider.RequestPath()
177218
mgr, err = mcmanager.New(rootConfig, p, mcmanager.Options{})
178219
Expect(err).NotTo(HaveOccurred())
179220

180-
By("creating a reconciler for the APIBinding")
221+
By("adding an index on label 'color'")
222+
thing := &unstructured.Unstructured{}
223+
thing.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Thing"})
224+
err = mgr.GetFieldIndexer().IndexField(ctx, thing, "color", func(obj client.Object) []string {
225+
u := obj.(*unstructured.Unstructured)
226+
return []string{u.GetLabels()["color"]}
227+
})
228+
Expect(err).NotTo(HaveOccurred())
229+
230+
By("creating a reconciler for APIBindings")
181231
err = mcbuilder.ControllerManagedBy(mgr).
182232
Named("things").
183233
For(&apisv1alpha1.APIBinding{}).
@@ -211,6 +261,60 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
211261
}, wait.ForeverTestTimeout, time.Millisecond*100, "failed to see the consumer workspace %q as a cluster", consumer)
212262
})
213263

264+
It("sees only the stone in the consumer clusters", func() {
265+
By("creating a stone in the consumer workspace", func() {
266+
thing := &unstructured.Unstructured{}
267+
thing.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Thing"})
268+
thing.SetNamespace("stone")
269+
thing.SetLabels(map[string]string{"color": "gray"})
270+
err := cli.Cluster(consumer).Create(ctx, thing)
271+
Expect(err).NotTo(HaveOccurred())
272+
})
273+
274+
By("creating a box in the other workspace", func() {
275+
thing := &unstructured.Unstructured{}
276+
thing.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Thing"})
277+
thing.SetNamespace("box")
278+
thing.SetLabels(map[string]string{"color": "white"})
279+
err := cli.Cluster(other).Create(ctx, thing)
280+
Expect(err).NotTo(HaveOccurred())
281+
})
282+
283+
consumerCl, err := mgr.GetCluster(ctx, consumerWS.Spec.Cluster)
284+
Expect(err).NotTo(HaveOccurred())
285+
286+
envtest.Eventually(GinkgoT(), func() (success bool, reason string) {
287+
l := &unstructured.UnstructuredList{}
288+
l.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "ThingList"})
289+
err = consumerCl.GetCache().List(ctx, l)
290+
Expect(err).NotTo(HaveOccurred())
291+
if len(l.Items) != 1 {
292+
return false, fmt.Sprintf("expected 1 item, got %d\n\n%s", len(l.Items), toYAML(GinkgoT(), l.Object))
293+
} else if name := l.Items[0].GetName(); name != "stone" {
294+
return false, fmt.Sprintf("expected item name to be stone, got %q\n\n%s", name, toYAML(GinkgoT(), l.Items[0]))
295+
}
296+
return true, ""
297+
}, wait.ForeverTestTimeout, time.Millisecond*100, "failed to see the stone in the consumer cluster")
298+
})
299+
300+
It("sees only the stone as grey thing in the consumer clusters", func() {
301+
consumerCl, err := mgr.GetCluster(ctx, consumerWS.Spec.Cluster)
302+
Expect(err).NotTo(HaveOccurred())
303+
304+
envtest.Eventually(GinkgoT(), func() (success bool, reason string) {
305+
l := &unstructured.UnstructuredList{}
306+
l.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "ThingList"})
307+
err = consumerCl.GetCache().List(ctx, l, client.MatchingFields{"color": "gray"})
308+
Expect(err).NotTo(HaveOccurred())
309+
if len(l.Items) != 1 {
310+
return false, fmt.Sprintf("expected 1 item, got %d\n\n%s", len(l.Items), toYAML(GinkgoT(), l.Object))
311+
} else if name := l.Items[0].GetName(); name != "stone" {
312+
return false, fmt.Sprintf("expected item name to be stone, got %q\n\n%s", name, toYAML(GinkgoT(), l.Items[0]))
313+
}
314+
return true, ""
315+
}, wait.ForeverTestTimeout, time.Millisecond*100, "failed to see the stone as only thing of color 'grey' in the consumer cluster")
316+
})
317+
214318
AfterAll(func() {
215319
cancelGroup()
216320
err := g.Wait()

0 commit comments

Comments
 (0)