Skip to content

Commit c0da82c

Browse files
authored
Merge pull request kubernetes#91830 from cmluciano/cml/ingressclassconformance
ingress: Add CRUD tests for IngressClass API verbs
2 parents 64d2545 + ea03097 commit c0da82c

File tree

1 file changed

+158
-5
lines changed

1 file changed

+158
-5
lines changed

test/e2e/network/ingressclass.go

Lines changed: 158 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ package network
1818

1919
import (
2020
"context"
21+
"fmt"
2122
"strings"
2223
"time"
2324

2425
networkingv1beta1 "k8s.io/api/networking/v1beta1"
26+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2527
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
types "k8s.io/apimachinery/pkg/types"
2629
"k8s.io/apimachinery/pkg/util/intstr"
2730
"k8s.io/apimachinery/pkg/util/wait"
31+
"k8s.io/apimachinery/pkg/watch"
2832
clientset "k8s.io/client-go/kubernetes"
2933
"k8s.io/kubernetes/test/e2e/framework"
3034

@@ -39,7 +43,7 @@ var _ = SIGDescribe("IngressClass [Feature:Ingress]", func() {
3943
})
4044

4145
ginkgo.It("should set default value on new IngressClass", func() {
42-
ingressClass1, err := createIngressClass(cs, "ingressclass1", true)
46+
ingressClass1, err := createIngressClass(cs, "ingressclass1", true, f.UniqueName)
4347
framework.ExpectNoError(err)
4448
defer deleteIngressClass(cs, ingressClass1.Name)
4549

@@ -54,7 +58,7 @@ var _ = SIGDescribe("IngressClass [Feature:Ingress]", func() {
5458
})
5559

5660
ginkgo.It("should not set default value if no default IngressClass", func() {
57-
ingressClass1, err := createIngressClass(cs, "ingressclass1", false)
61+
ingressClass1, err := createIngressClass(cs, "ingressclass1", false, f.UniqueName)
5862
framework.ExpectNoError(err)
5963
defer deleteIngressClass(cs, ingressClass1.Name)
6064

@@ -67,11 +71,11 @@ var _ = SIGDescribe("IngressClass [Feature:Ingress]", func() {
6771
})
6872

6973
ginkgo.It("should prevent Ingress creation if more than 1 IngressClass marked as default", func() {
70-
ingressClass1, err := createIngressClass(cs, "ingressclass1", true)
74+
ingressClass1, err := createIngressClass(cs, "ingressclass1", true, f.UniqueName)
7175
framework.ExpectNoError(err)
7276
defer deleteIngressClass(cs, ingressClass1.Name)
7377

74-
ingressClass2, err := createIngressClass(cs, "ingressclass2", true)
78+
ingressClass2, err := createIngressClass(cs, "ingressclass2", true, f.UniqueName)
7579
framework.ExpectNoError(err)
7680
defer deleteIngressClass(cs, ingressClass2.Name)
7781

@@ -93,10 +97,14 @@ var _ = SIGDescribe("IngressClass [Feature:Ingress]", func() {
9397

9498
})
9599

96-
func createIngressClass(cs clientset.Interface, name string, isDefault bool) (*networkingv1beta1.IngressClass, error) {
100+
func createIngressClass(cs clientset.Interface, name string, isDefault bool, uniqueName string) (*networkingv1beta1.IngressClass, error) {
97101
ingressClass := &networkingv1beta1.IngressClass{
98102
ObjectMeta: metav1.ObjectMeta{
99103
Name: name,
104+
Labels: map[string]string{
105+
"ingressclass": uniqueName,
106+
"special-label": "generic",
107+
},
100108
},
101109
Spec: networkingv1beta1.IngressClassSpec{
102110
Controller: "example.com/controller",
@@ -128,3 +136,148 @@ func deleteIngressClass(cs clientset.Interface, name string) {
128136
err := cs.NetworkingV1beta1().IngressClasses().Delete(context.TODO(), name, metav1.DeleteOptions{})
129137
framework.ExpectNoError(err)
130138
}
139+
140+
var _ = SIGDescribe("IngressClass API", func() {
141+
f := framework.NewDefaultFramework("ingressclass")
142+
var cs clientset.Interface
143+
ginkgo.BeforeEach(func() {
144+
cs = f.ClientSet
145+
})
146+
/*
147+
Release: v1.19
148+
Testname: IngressClass API
149+
Description:
150+
- The networking.k8s.io API group MUST exist in the /apis discovery document.
151+
- The networking.k8s.io/v1beta1 API group/version MUST exist in the /apis/networking.k8s.io discovery document.
152+
- The IngressClasses resources MUST exist in the /apis/networking.k8s.io/v1beta1 discovery document.
153+
- The IngressClass resource must support create, get, list, watch, update, patch, delete, and deletecollection.
154+
*/
155+
ginkgo.It(" should support creating IngressClass API operations", func() {
156+
157+
// Setup
158+
icClient := f.ClientSet.NetworkingV1beta1().IngressClasses()
159+
icVersion := "v1beta1"
160+
161+
// Discovery
162+
ginkgo.By("getting /apis")
163+
{
164+
discoveryGroups, err := f.ClientSet.Discovery().ServerGroups()
165+
framework.ExpectNoError(err)
166+
found := false
167+
for _, group := range discoveryGroups.Groups {
168+
if group.Name == networkingv1beta1.GroupName {
169+
for _, version := range group.Versions {
170+
if version.Version == icVersion {
171+
found = true
172+
break
173+
}
174+
}
175+
}
176+
}
177+
framework.ExpectEqual(found, true, fmt.Sprintf("expected networking API group/version, got %#v", discoveryGroups.Groups))
178+
}
179+
ginkgo.By("getting /apis/networking.k8s.io")
180+
{
181+
group := &metav1.APIGroup{}
182+
err := f.ClientSet.Discovery().RESTClient().Get().AbsPath("/apis/networking.k8s.io").Do(context.TODO()).Into(group)
183+
framework.ExpectNoError(err)
184+
found := false
185+
for _, version := range group.Versions {
186+
if version.Version == icVersion {
187+
found = true
188+
break
189+
}
190+
}
191+
framework.ExpectEqual(found, true, fmt.Sprintf("expected networking API version, got %#v", group.Versions))
192+
}
193+
194+
ginkgo.By("getting /apis/networking.k8s.io" + icVersion)
195+
{
196+
resources, err := f.ClientSet.Discovery().ServerResourcesForGroupVersion(networkingv1beta1.SchemeGroupVersion.String())
197+
framework.ExpectNoError(err)
198+
foundIC := false
199+
for _, resource := range resources.APIResources {
200+
switch resource.Name {
201+
case "ingressclasses":
202+
foundIC = true
203+
}
204+
}
205+
framework.ExpectEqual(foundIC, true, fmt.Sprintf("expected ingressclasses, got %#v", resources.APIResources))
206+
}
207+
208+
// IngressClass resource create/read/update/watch verbs
209+
ginkgo.By("creating")
210+
ingressClass1, err := createIngressClass(cs, "ingressclass1", true, f.UniqueName)
211+
framework.ExpectNoError(err)
212+
_, err = createIngressClass(cs, "ingressclass2", true, f.UniqueName)
213+
framework.ExpectNoError(err)
214+
_, err = createIngressClass(cs, "ingressclass3", true, f.UniqueName)
215+
framework.ExpectNoError(err)
216+
217+
ginkgo.By("getting")
218+
gottenIC, err := icClient.Get(context.TODO(), ingressClass1.Name, metav1.GetOptions{})
219+
framework.ExpectNoError(err)
220+
framework.ExpectEqual(gottenIC.UID, ingressClass1.UID)
221+
framework.ExpectEqual(gottenIC.UID, ingressClass1.UID)
222+
223+
ginkgo.By("listing")
224+
ics, err := icClient.List(context.TODO(), metav1.ListOptions{LabelSelector: "special-label=generic"})
225+
framework.ExpectNoError(err)
226+
framework.ExpectEqual(len(ics.Items), 3, "filtered list should have 3 items")
227+
228+
ginkgo.By("watching")
229+
framework.Logf("starting watch")
230+
icWatch, err := icClient.Watch(context.TODO(), metav1.ListOptions{ResourceVersion: ics.ResourceVersion, LabelSelector: "ingressclass=" + f.UniqueName})
231+
framework.ExpectNoError(err)
232+
233+
ginkgo.By("patching")
234+
patchedIC, err := icClient.Patch(context.TODO(), ingressClass1.Name, types.MergePatchType, []byte(`{"metadata":{"annotations":{"patched":"true"}}}`), metav1.PatchOptions{})
235+
framework.ExpectNoError(err)
236+
framework.ExpectEqual(patchedIC.Annotations["patched"], "true", "patched object should have the applied annotation")
237+
238+
ginkgo.By("updating")
239+
icToUpdate := patchedIC.DeepCopy()
240+
icToUpdate.Annotations["updated"] = "true"
241+
updatedIC, err := icClient.Update(context.TODO(), icToUpdate, metav1.UpdateOptions{})
242+
framework.ExpectNoError(err)
243+
framework.ExpectEqual(updatedIC.Annotations["updated"], "true", "updated object should have the applied annotation")
244+
245+
framework.Logf("waiting for watch events with expected annotations")
246+
for sawAnnotations := false; !sawAnnotations; {
247+
select {
248+
case evt, ok := <-icWatch.ResultChan():
249+
framework.ExpectEqual(ok, true, "watch channel should not close")
250+
framework.ExpectEqual(evt.Type, watch.Modified)
251+
watchedIngress, isIngress := evt.Object.(*networkingv1beta1.IngressClass)
252+
framework.ExpectEqual(isIngress, true, fmt.Sprintf("expected Ingress, got %T", evt.Object))
253+
if watchedIngress.Annotations["patched"] == "true" {
254+
framework.Logf("saw patched and updated annotations")
255+
sawAnnotations = true
256+
icWatch.Stop()
257+
} else {
258+
framework.Logf("missing expected annotations, waiting: %#v", watchedIngress.Annotations)
259+
}
260+
case <-time.After(wait.ForeverTestTimeout):
261+
framework.Fail("timed out waiting for watch event")
262+
}
263+
}
264+
265+
// IngressClass resource delete operations
266+
ginkgo.By("deleting")
267+
err = icClient.Delete(context.TODO(), ingressClass1.Name, metav1.DeleteOptions{})
268+
framework.ExpectNoError(err)
269+
_, err = icClient.Get(context.TODO(), ingressClass1.Name, metav1.GetOptions{})
270+
framework.ExpectEqual(apierrors.IsNotFound(err), true, fmt.Sprintf("expected 404, got %#v", err))
271+
ics, err = icClient.List(context.TODO(), metav1.ListOptions{LabelSelector: "ingressclass=" + f.UniqueName})
272+
framework.ExpectNoError(err)
273+
framework.ExpectEqual(len(ics.Items), 2, "filtered list should have 2 items")
274+
275+
ginkgo.By("deleting a collection")
276+
err = icClient.DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "ingressclass=" + f.UniqueName})
277+
framework.ExpectNoError(err)
278+
ics, err = icClient.List(context.TODO(), metav1.ListOptions{LabelSelector: "ingressclass=" + f.UniqueName})
279+
framework.ExpectNoError(err)
280+
framework.ExpectEqual(len(ics.Items), 0, "filtered list should have 0 items")
281+
})
282+
283+
})

0 commit comments

Comments
 (0)