Skip to content

Commit 6425985

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 6425985

File tree

2 files changed

+118
-9
lines changed

2 files changed

+118
-9
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: 117 additions & 8 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{
@@ -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

Comments
 (0)