mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-02-14 18:09:58 +00:00
610 lines
18 KiB
Go
610 lines
18 KiB
Go
// Copyright 2020-2023 Project Capsule Authors.
|
||
// SPDX-License-Identifier: Apache-2.0
|
||
|
||
package e2e
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
|
||
. "github.com/onsi/ginkgo/v2"
|
||
. "github.com/onsi/gomega"
|
||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||
"k8s.io/apimachinery/pkg/labels"
|
||
"k8s.io/apimachinery/pkg/selection"
|
||
"k8s.io/apimachinery/pkg/types"
|
||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||
"k8s.io/client-go/kubernetes/scheme"
|
||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
|
||
|
||
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
|
||
"github.com/projectcapsule/capsule/pkg/api"
|
||
"github.com/projectcapsule/capsule/pkg/utils"
|
||
)
|
||
|
||
var _ = Describe("when Tenant handles Gateway classes", Label("tenant", "classes", "gateway"), func() {
|
||
authorized := &gatewayv1.GatewayClass{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "customer-class",
|
||
Labels: map[string]string{
|
||
"env": "production",
|
||
},
|
||
},
|
||
Spec: gatewayv1.GatewayClassSpec{
|
||
ControllerName: "projectcapsule.dev/customer-controller",
|
||
},
|
||
}
|
||
|
||
exact := &gatewayv1.GatewayClass{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "legacy",
|
||
Labels: map[string]string{
|
||
"env": "e2e",
|
||
},
|
||
},
|
||
Spec: gatewayv1.GatewayClassSpec{
|
||
ControllerName: "projectcapsule.dev/customer-controller",
|
||
},
|
||
}
|
||
|
||
exactU := &gatewayv1.GatewayClass{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "legacy-2",
|
||
Labels: map[string]string{
|
||
"env": "e2e",
|
||
},
|
||
},
|
||
Spec: gatewayv1.GatewayClassSpec{
|
||
ControllerName: "projectcapsule.dev/customer-controller",
|
||
},
|
||
}
|
||
|
||
unauthorized := &gatewayv1.GatewayClass{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "unauthorized-class",
|
||
Labels: map[string]string{
|
||
"env": "production55",
|
||
},
|
||
},
|
||
Spec: gatewayv1.GatewayClassSpec{
|
||
ControllerName: "projectcapsule.dev/customer-controller",
|
||
},
|
||
}
|
||
|
||
tntWithDefault := &capsulev1beta2.Tenant{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "e2e-gateway-default-and-label-selector",
|
||
},
|
||
Spec: capsulev1beta2.TenantSpec{
|
||
Owners: []api.OwnerSpec{
|
||
{
|
||
CoreOwnerSpec: api.CoreOwnerSpec{
|
||
UserSpec: api.UserSpec{
|
||
Name: "gateway-default-and-label-selector",
|
||
Kind: "User",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
GatewayOptions: capsulev1beta2.GatewayOptions{
|
||
AllowedClasses: &api.DefaultAllowedListSpec{
|
||
Default: "customer-class",
|
||
SelectorAllowedListSpec: api.SelectorAllowedListSpec{
|
||
AllowedListSpec: api.AllowedListSpec{
|
||
Exact: []string{"legacy-2"},
|
||
},
|
||
LabelSelector: v1.LabelSelector{
|
||
MatchLabels: map[string]string{
|
||
"env": "production",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
tntWithoutDefault := &capsulev1beta2.Tenant{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "e2e-gateway-label-selector-only",
|
||
},
|
||
Spec: capsulev1beta2.TenantSpec{
|
||
Owners: []api.OwnerSpec{
|
||
{
|
||
CoreOwnerSpec: api.CoreOwnerSpec{
|
||
UserSpec: api.UserSpec{
|
||
Name: "gateway-with-label-selector-only",
|
||
Kind: "User",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
GatewayOptions: capsulev1beta2.GatewayOptions{
|
||
AllowedClasses: &api.DefaultAllowedListSpec{
|
||
SelectorAllowedListSpec: api.SelectorAllowedListSpec{
|
||
AllowedListSpec: api.AllowedListSpec{
|
||
Exact: []string{"legacy"},
|
||
},
|
||
LabelSelector: v1.LabelSelector{
|
||
MatchLabels: map[string]string{
|
||
"env": "production",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
tntNoRestrictions := &capsulev1beta2.Tenant{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "e2e-gateway-no-restrictions",
|
||
},
|
||
Spec: capsulev1beta2.TenantSpec{
|
||
Owners: []api.OwnerSpec{
|
||
{
|
||
CoreOwnerSpec: api.CoreOwnerSpec{
|
||
UserSpec: api.UserSpec{
|
||
Name: "e2e-gateway-no-restrictions",
|
||
Kind: "User",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
JustBeforeEach(func() {
|
||
for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefault, tntWithoutDefault, tntNoRestrictions} {
|
||
tnt.ResourceVersion = ""
|
||
EventuallyCreation(func() error {
|
||
return k8sClient.Create(context.TODO(), tnt)
|
||
}).Should(Succeed())
|
||
}
|
||
|
||
if err := k8sClient.List(context.Background(), &gatewayv1.GatewayClassList{}); err != nil {
|
||
if utils.IsUnsupportedAPI(err) {
|
||
Skip(fmt.Sprintf("Running test due to unsupported API kind: %s", err.Error()))
|
||
}
|
||
}
|
||
|
||
utilruntime.Must(gatewayv1.Install(scheme.Scheme))
|
||
|
||
for _, crd := range []*gatewayv1.GatewayClass{authorized, unauthorized, exact, exactU} {
|
||
Eventually(func() error {
|
||
crd.ResourceVersion = ""
|
||
return k8sClient.Create(context.TODO(), crd)
|
||
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
||
}
|
||
})
|
||
JustAfterEach(func() {
|
||
utilruntime.Must(gatewayv1.Install(scheme.Scheme))
|
||
for _, tnt := range []*capsulev1beta2.Tenant{tntWithDefault, tntWithoutDefault, tntNoRestrictions} {
|
||
EventuallyCreation(func() error {
|
||
return ignoreNotFound(k8sClient.Delete(context.TODO(), tnt))
|
||
}).Should(Succeed())
|
||
}
|
||
|
||
if err := k8sClient.List(context.Background(), &gatewayv1.GatewayClassList{}); err != nil {
|
||
if utils.IsUnsupportedAPI(err) {
|
||
Skip(fmt.Sprintf("Running test due to unsupported API kind: %s", err.Error()))
|
||
}
|
||
}
|
||
|
||
Eventually(func() (err error) {
|
||
req, _ := labels.NewRequirement("env", selection.Exists, nil)
|
||
|
||
return k8sClient.DeleteAllOf(context.TODO(), &gatewayv1.GatewayClass{}, &client.DeleteAllOfOptions{
|
||
ListOptions: client.ListOptions{
|
||
LabelSelector: labels.NewSelector().Add(*req),
|
||
},
|
||
})
|
||
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
||
})
|
||
It("should allow all classes", func() {
|
||
if err := k8sClient.List(context.Background(), &gatewayv1.GatewayClassList{}); err != nil {
|
||
if utils.IsUnsupportedAPI(err) {
|
||
Skip(fmt.Sprintf("Running test due to unsupported API kind: %s", err.Error()))
|
||
}
|
||
}
|
||
|
||
By("Verify Status (Creation)", func() {
|
||
Eventually(func() ([]string, error) {
|
||
t := &capsulev1beta2.Tenant{}
|
||
if err := k8sClient.Get(
|
||
context.TODO(),
|
||
types.NamespacedName{Name: tntNoRestrictions.GetName()},
|
||
t,
|
||
); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return t.Status.Classes.GatewayClasses, nil
|
||
}, defaultTimeoutInterval, defaultPollInterval).
|
||
Should(ConsistOf(exact.GetName(), exactU.GetName(), authorized.GetName(), unauthorized.GetName()))
|
||
})
|
||
|
||
ns := NewNamespace("")
|
||
NamespaceCreation(ns, tntNoRestrictions.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
|
||
TenantNamespaceList(tntNoRestrictions, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
|
||
|
||
By("providing any storageclass", func() {
|
||
for _, class := range []*gatewayv1.GatewayClass{authorized, unauthorized, exact, exactU} {
|
||
c := class.GetName()
|
||
Eventually(func() (err error) {
|
||
g := &gatewayv1.Gateway{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: class.GetName() + "-gateway",
|
||
Namespace: ns.GetName(),
|
||
},
|
||
Spec: gatewayv1.GatewaySpec{
|
||
Listeners: []gatewayv1.Listener{
|
||
{
|
||
Name: "http",
|
||
Protocol: gatewayv1.HTTPProtocolType,
|
||
Port: 80,
|
||
},
|
||
},
|
||
GatewayClassName: gatewayv1.ObjectName(c),
|
||
},
|
||
}
|
||
|
||
err = k8sClient.Create(context.TODO(), g)
|
||
return
|
||
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
||
}
|
||
})
|
||
|
||
By("providing nonexistent gatewayClassName", func() {
|
||
Eventually(func() (err error) {
|
||
g := &gatewayv1.Gateway{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "nonexistent-gateway",
|
||
Namespace: ns.GetName(),
|
||
},
|
||
Spec: gatewayv1.GatewaySpec{
|
||
Listeners: []gatewayv1.Listener{
|
||
{
|
||
Name: "http",
|
||
Protocol: gatewayv1.HTTPProtocolType,
|
||
Port: 80,
|
||
},
|
||
},
|
||
GatewayClassName: gatewayv1.ObjectName("very-unauthorized-and-nonexistent-class"),
|
||
},
|
||
}
|
||
err = k8sClient.Create(context.TODO(), g)
|
||
return
|
||
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
||
})
|
||
|
||
By("Verify Status (Deletion)", func() {
|
||
for _, crd := range []*gatewayv1.GatewayClass{authorized} {
|
||
Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
|
||
}
|
||
Eventually(func() ([]string, error) {
|
||
t := &capsulev1beta2.Tenant{}
|
||
if err := k8sClient.Get(
|
||
context.TODO(),
|
||
types.NamespacedName{Name: tntNoRestrictions.GetName()},
|
||
t,
|
||
); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return t.Status.Classes.GatewayClasses, nil
|
||
}, defaultTimeoutInterval, defaultPollInterval).
|
||
Should(ConsistOf(exact.GetName(), exactU.GetName(), unauthorized.GetName()))
|
||
})
|
||
|
||
})
|
||
|
||
It("should block Gateway", func() {
|
||
if err := k8sClient.List(context.Background(), &gatewayv1.GatewayClassList{}); err != nil {
|
||
if utils.IsUnsupportedAPI(err) {
|
||
Skip(fmt.Sprintf("Running test due to unsupported API kind: %s", err.Error()))
|
||
}
|
||
}
|
||
|
||
By("Verify Status (Creation)", func() {
|
||
Eventually(func() ([]string, error) {
|
||
t := &capsulev1beta2.Tenant{}
|
||
|
||
// return the error so Eventually will retry until it’s nil
|
||
if err := k8sClient.Get(
|
||
context.TODO(),
|
||
types.NamespacedName{Name: tntWithDefault.GetName()},
|
||
t,
|
||
); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return t.Status.Classes.GatewayClasses, nil
|
||
}, defaultTimeoutInterval, defaultPollInterval).
|
||
Should(ConsistOf(exactU.GetName(), authorized.GetName()))
|
||
})
|
||
|
||
ns := NewNamespace("")
|
||
NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
|
||
TenantNamespaceList(tntWithDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
|
||
|
||
By("providing unauthorized gatewayClassName", func() {
|
||
Eventually(func() (err error) {
|
||
g := &gatewayv1.Gateway{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "denied-gateway",
|
||
Namespace: ns.GetName(),
|
||
},
|
||
Spec: gatewayv1.GatewaySpec{
|
||
Listeners: []gatewayv1.Listener{
|
||
{
|
||
Name: "http",
|
||
Protocol: gatewayv1.HTTPProtocolType,
|
||
Port: 80,
|
||
},
|
||
},
|
||
GatewayClassName: gatewayv1.ObjectName("unauthorized-class"),
|
||
},
|
||
}
|
||
err = k8sClient.Create(context.TODO(), g)
|
||
return
|
||
}, defaultTimeoutInterval, defaultPollInterval).ShouldNot(Succeed())
|
||
})
|
||
|
||
By("providing nonexistent gatewayClassName", func() {
|
||
Eventually(func() (err error) {
|
||
g := &gatewayv1.Gateway{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "nonexistent-gateway",
|
||
Namespace: ns.GetName(),
|
||
},
|
||
Spec: gatewayv1.GatewaySpec{
|
||
Listeners: []gatewayv1.Listener{
|
||
{
|
||
Name: "http",
|
||
Protocol: gatewayv1.HTTPProtocolType,
|
||
Port: 80,
|
||
},
|
||
},
|
||
GatewayClassName: gatewayv1.ObjectName("very-unauthorized-and-nonexistent-class"),
|
||
},
|
||
}
|
||
err = k8sClient.Create(context.TODO(), g)
|
||
return
|
||
}, defaultTimeoutInterval, defaultPollInterval).ShouldNot(Succeed())
|
||
})
|
||
|
||
By("Verify Status (Deletion)", func() {
|
||
for _, crd := range []*gatewayv1.GatewayClass{authorized} {
|
||
Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
|
||
}
|
||
Eventually(func() ([]string, error) {
|
||
t := &capsulev1beta2.Tenant{}
|
||
|
||
// return the error so Eventually will retry until it’s nil
|
||
if err := k8sClient.Get(
|
||
context.TODO(),
|
||
types.NamespacedName{Name: tntWithDefault.GetName()},
|
||
t,
|
||
); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return t.Status.Classes.GatewayClasses, nil
|
||
}, defaultTimeoutInterval, defaultPollInterval).
|
||
Should(ConsistOf(exactU.GetName()))
|
||
|
||
for _, crd := range []*gatewayv1.GatewayClass{exactU} {
|
||
Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
|
||
}
|
||
Eventually(func() ([]string, error) {
|
||
t := &capsulev1beta2.Tenant{}
|
||
|
||
// return the error so Eventually will retry until it’s nil
|
||
if err := k8sClient.Get(
|
||
context.TODO(),
|
||
types.NamespacedName{Name: tntWithDefault.GetName()},
|
||
t,
|
||
); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return t.Status.Classes.GatewayClasses, nil
|
||
}, defaultTimeoutInterval, defaultPollInterval).
|
||
Should(ConsistOf())
|
||
})
|
||
|
||
})
|
||
It("should allow Gateway", func() {
|
||
if err := k8sClient.List(context.Background(), &gatewayv1.GatewayClassList{}); err != nil {
|
||
if utils.IsUnsupportedAPI(err) {
|
||
Skip(fmt.Sprintf("Running test due to unsupported API kind: %s", err.Error()))
|
||
}
|
||
}
|
||
|
||
By("Verify Status (Creation)", func() {
|
||
Eventually(func() ([]string, error) {
|
||
t := &capsulev1beta2.Tenant{}
|
||
|
||
// return the error so Eventually will retry until it’s nil
|
||
if err := k8sClient.Get(
|
||
context.TODO(),
|
||
types.NamespacedName{Name: tntWithDefault.GetName()},
|
||
t,
|
||
); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return t.Status.Classes.GatewayClasses, nil
|
||
}, defaultTimeoutInterval, defaultPollInterval).
|
||
Should(ConsistOf(exactU.GetName(), authorized.GetName()))
|
||
})
|
||
|
||
ns := NewNamespace("")
|
||
NamespaceCreation(ns, tntWithDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
|
||
TenantNamespaceList(tntWithDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
|
||
By("providing authorized class", func() {
|
||
Eventually(func() (err error) {
|
||
g := &gatewayv1.Gateway{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "authorized-gateway",
|
||
Namespace: ns.GetName(),
|
||
},
|
||
Spec: gatewayv1.GatewaySpec{
|
||
Listeners: []gatewayv1.Listener{
|
||
{
|
||
Name: "http",
|
||
Protocol: gatewayv1.HTTPProtocolType,
|
||
Port: 80,
|
||
},
|
||
},
|
||
GatewayClassName: gatewayv1.ObjectName("customer-class"),
|
||
},
|
||
}
|
||
err = k8sClient.Create(context.TODO(), g)
|
||
return
|
||
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
||
})
|
||
|
||
By("providing authorized class (exact)", func() {
|
||
Eventually(func() (err error) {
|
||
g := &gatewayv1.Gateway{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "authorized-gateway-exact",
|
||
Namespace: ns.GetName(),
|
||
},
|
||
Spec: gatewayv1.GatewaySpec{
|
||
Listeners: []gatewayv1.Listener{
|
||
{
|
||
Name: "http",
|
||
Protocol: gatewayv1.HTTPProtocolType,
|
||
Port: 80,
|
||
},
|
||
},
|
||
GatewayClassName: gatewayv1.ObjectName("legacy-2"),
|
||
},
|
||
}
|
||
err = k8sClient.Create(context.TODO(), g)
|
||
return
|
||
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
|
||
})
|
||
|
||
By("providing no gatewayClassName", func() {
|
||
g := &gatewayv1.Gateway{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "mutated-gateway",
|
||
Namespace: ns.GetName(),
|
||
},
|
||
Spec: gatewayv1.GatewaySpec{
|
||
Listeners: []gatewayv1.Listener{
|
||
{
|
||
Name: "http",
|
||
Protocol: gatewayv1.HTTPProtocolType,
|
||
Port: 80,
|
||
},
|
||
},
|
||
},
|
||
}
|
||
Expect(k8sClient.Create(context.TODO(), g)).Should(Succeed())
|
||
gw := &gatewayv1.Gateway{}
|
||
Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: g.GetName(), Namespace: g.Namespace}, gw)).Should(Succeed())
|
||
Expect(gw.Spec.GatewayClassName).Should(Equal(gatewayv1.ObjectName("customer-class")))
|
||
|
||
return
|
||
})
|
||
})
|
||
It("should fail on invalid configuration", func() {
|
||
if err := k8sClient.List(context.Background(), &gatewayv1.GatewayClassList{}); err != nil {
|
||
if utils.IsUnsupportedAPI(err) {
|
||
Skip(fmt.Sprintf("Running test due to unsupported API kind: %s", err.Error()))
|
||
}
|
||
}
|
||
|
||
By("Verify Status (Creation)", func() {
|
||
Eventually(func() ([]string, error) {
|
||
t := &capsulev1beta2.Tenant{}
|
||
|
||
// return the error so Eventually will retry until it’s nil
|
||
if err := k8sClient.Get(
|
||
context.TODO(),
|
||
types.NamespacedName{Name: tntWithoutDefault.GetName()},
|
||
t,
|
||
); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return t.Status.Classes.GatewayClasses, nil
|
||
}, defaultTimeoutInterval, defaultPollInterval).
|
||
Should(ConsistOf(exact.GetName(), authorized.GetName()))
|
||
})
|
||
|
||
ns := NewNamespace("")
|
||
NamespaceCreation(ns, tntWithoutDefault.Spec.Owners[0].UserSpec, defaultTimeoutInterval).Should(Succeed())
|
||
TenantNamespaceList(tntWithoutDefault, defaultTimeoutInterval).Should(ContainElement(ns.GetName()))
|
||
By("providing empty GatewayClassName", func() {
|
||
Eventually(func() (err error) {
|
||
g := &gatewayv1.Gateway{
|
||
ObjectMeta: metav1.ObjectMeta{
|
||
Name: "empty-gateway",
|
||
Namespace: ns.GetName(),
|
||
},
|
||
Spec: gatewayv1.GatewaySpec{
|
||
Listeners: []gatewayv1.Listener{
|
||
{
|
||
Name: "http",
|
||
Protocol: gatewayv1.HTTPProtocolType,
|
||
Port: 80,
|
||
},
|
||
},
|
||
},
|
||
}
|
||
err = k8sClient.Create(context.TODO(), g)
|
||
return
|
||
}, defaultTimeoutInterval, defaultPollInterval).ShouldNot(Succeed())
|
||
})
|
||
|
||
By("Verify Status (Deletion)", func() {
|
||
for _, crd := range []*gatewayv1.GatewayClass{authorized} {
|
||
Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
|
||
}
|
||
Eventually(func() ([]string, error) {
|
||
t := &capsulev1beta2.Tenant{}
|
||
|
||
// return the error so Eventually will retry until it’s nil
|
||
if err := k8sClient.Get(
|
||
context.TODO(),
|
||
types.NamespacedName{Name: tntWithoutDefault.GetName()},
|
||
t,
|
||
); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return t.Status.Classes.GatewayClasses, nil
|
||
}, defaultTimeoutInterval, defaultPollInterval).
|
||
Should(ConsistOf(exact.GetName()))
|
||
|
||
for _, crd := range []*gatewayv1.GatewayClass{exact} {
|
||
Expect(ignoreNotFound(k8sClient.Delete(context.TODO(), crd))).To(Succeed())
|
||
}
|
||
Eventually(func() ([]string, error) {
|
||
t := &capsulev1beta2.Tenant{}
|
||
|
||
// return the error so Eventually will retry until it’s nil
|
||
if err := k8sClient.Get(
|
||
context.TODO(),
|
||
types.NamespacedName{Name: tntWithoutDefault.GetName()},
|
||
t,
|
||
); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return t.Status.Classes.GatewayClasses, nil
|
||
}, defaultTimeoutInterval, defaultPollInterval).
|
||
Should(ConsistOf())
|
||
})
|
||
})
|
||
})
|