Skip to content

Commit fee56d5

Browse files
authored
fix: conformance test (#103)
Signed-off-by: ashing <[email protected]>
1 parent c134251 commit fee56d5

File tree

3 files changed

+174
-2
lines changed

3 files changed

+174
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,5 @@ api7-ingress-controller
3232
api7-ingress-controller-conformance-report.yaml
3333

3434
*.mdx
35+
.cursor/
36+

test/conformance/suite_test.go

Lines changed: 166 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
package conformance
22

33
import (
4+
"context"
45
"fmt"
56
"os"
67
"testing"
8+
"time"
79

810
"github.com/api7/api7-ingress-controller/test/e2e/framework"
911
"github.com/gruntwork-io/terratest/modules/k8s"
12+
"github.com/gruntwork-io/terratest/modules/retry"
13+
"sigs.k8s.io/controller-runtime/pkg/client"
1014

1115
. "github.com/onsi/ginkgo/v2"
1216
. "github.com/onsi/gomega"
17+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
1318
)
1419

1520
var gatewayClassName = "api7"
@@ -24,15 +29,89 @@ spec:
2429
controllerName: %s
2530
`, gatewayClassName, controllerName)
2631

32+
var gatewayProxyYaml = `
33+
apiVersion: gateway.apisix.io/v1alpha1
34+
kind: GatewayProxy
35+
metadata:
36+
name: conformance-gateway-proxy
37+
namespace: %s
38+
spec:
39+
statusAddress:
40+
- %s
41+
provider:
42+
type: ControlPlane
43+
controlPlane:
44+
endpoints:
45+
- %s
46+
auth:
47+
type: AdminKey
48+
adminKey:
49+
value: %s
50+
`
51+
52+
type GatewayProxyOpts struct {
53+
StatusAddress string
54+
AdminKey string
55+
AdminEndpoint string
56+
}
57+
58+
var defaultGatewayProxyOpts GatewayProxyOpts
59+
60+
func deleteNamespace(kubectl *k8s.KubectlOptions) {
61+
// gateway api conformance test namespaces
62+
namespacesToDelete := []string{
63+
"gateway-conformance-infra",
64+
"gateway-conformance-web-backend",
65+
"gateway-conformance-app-backend",
66+
}
67+
68+
for _, ns := range namespacesToDelete {
69+
_, err := k8s.GetNamespaceE(GinkgoT(), kubectl, ns)
70+
if err == nil {
71+
// Namespace exists, delete it
72+
GinkgoT().Logf("Deleting existing namespace: %s", ns)
73+
err := k8s.DeleteNamespaceE(GinkgoT(), kubectl, ns)
74+
if err != nil {
75+
GinkgoT().Logf("Error deleting namespace %s: %v", ns, err)
76+
continue
77+
}
78+
79+
// Wait for deletion to complete by checking until GetNamespaceE returns an error
80+
_, err = retry.DoWithRetryE(
81+
GinkgoT(),
82+
fmt.Sprintf("Waiting for namespace %s to be deleted", ns),
83+
30,
84+
5*time.Second,
85+
func() (string, error) {
86+
_, err := k8s.GetNamespaceE(GinkgoT(), kubectl, ns)
87+
if err != nil {
88+
// Namespace is gone, which is what we want
89+
return "Namespace deleted", nil
90+
}
91+
return "", fmt.Errorf("namespace %s still exists", ns)
92+
},
93+
)
94+
95+
if err != nil {
96+
GinkgoT().Logf("Error waiting for namespace %s to be deleted: %v", ns, err)
97+
}
98+
} else {
99+
GinkgoT().Logf("Namespace %s does not exist or cannot be accessed", ns)
100+
}
101+
}
102+
}
103+
27104
func TestMain(m *testing.M) {
28105
RegisterFailHandler(Fail)
29106
f := framework.NewFramework()
30107

31108
f.BeforeSuite()
32109

33-
namespace := "api7ee-conformance-test"
34-
110+
// Check and delete specific namespaces if they exist
35111
kubectl := k8s.NewKubectlOptions("", "", "default")
112+
deleteNamespace(kubectl)
113+
114+
namespace := "api7ee-conformance-test"
36115

37116
k8s.KubectlApplyFromString(GinkgoT(), kubectl, gatewayClass)
38117
defer k8s.KubectlDeleteFromString(GinkgoT(), kubectl, gatewayClass)
@@ -71,9 +150,94 @@ func TestMain(m *testing.M) {
71150
StatusAddress: address,
72151
})
73152

153+
defaultGatewayProxyOpts = GatewayProxyOpts{
154+
StatusAddress: address,
155+
AdminKey: adminKey,
156+
AdminEndpoint: framework.DashboardTLSEndpoint,
157+
}
158+
159+
patchGatewaysForConformanceTest(context.Background(), f.K8sClient)
160+
74161
code := m.Run()
75162

76163
f.AfterSuite()
77164

78165
os.Exit(code)
79166
}
167+
168+
func patchGatewaysForConformanceTest(ctx context.Context, k8sClient client.Client) {
169+
var gatewayProxyMap = make(map[string]bool)
170+
171+
// list all gateways and patch them
172+
patchGateway := func(ctx context.Context, k8sClient client.Client) bool {
173+
gatewayList := &gatewayv1.GatewayList{}
174+
if err := k8sClient.List(ctx, gatewayList); err != nil {
175+
return false
176+
}
177+
178+
patched := false
179+
for i := range gatewayList.Items {
180+
gateway := &gatewayList.Items[i]
181+
182+
// check if the gateway already has infrastructure.parametersRef
183+
if gateway.Spec.Infrastructure != nil &&
184+
gateway.Spec.Infrastructure.ParametersRef != nil {
185+
continue
186+
}
187+
188+
GinkgoT().Logf("Patching Gateway %s", gateway.Name)
189+
// check if the gateway proxy has been created, if not, create it
190+
if !gatewayProxyMap[gateway.Namespace] {
191+
gatewayProxy := fmt.Sprintf(gatewayProxyYaml,
192+
gateway.Namespace,
193+
defaultGatewayProxyOpts.StatusAddress,
194+
defaultGatewayProxyOpts.AdminEndpoint,
195+
defaultGatewayProxyOpts.AdminKey)
196+
kubectl := k8s.NewKubectlOptions("", "", gateway.Namespace)
197+
k8s.KubectlApplyFromString(GinkgoT(), kubectl, gatewayProxy)
198+
199+
// Mark this namespace as having a GatewayProxy
200+
gatewayProxyMap[gateway.Namespace] = true
201+
}
202+
203+
// add infrastructure.parametersRef
204+
gateway.Spec.Infrastructure = &gatewayv1.GatewayInfrastructure{
205+
ParametersRef: &gatewayv1.LocalParametersReference{
206+
Group: "gateway.apisix.io",
207+
Kind: "GatewayProxy",
208+
Name: "conformance-gateway-proxy",
209+
},
210+
}
211+
212+
if err := k8sClient.Update(ctx, gateway); err != nil {
213+
GinkgoT().Logf("Failed to patch Gateway %s: %v", gateway.Name, err)
214+
continue
215+
}
216+
217+
patched = true
218+
GinkgoT().Logf("Successfully patched Gateway %s with GatewayProxy reference", gateway.Name)
219+
}
220+
221+
return patched
222+
}
223+
224+
// continuously monitor and patch gateway resources
225+
go func() {
226+
ticker := time.NewTicker(2 * time.Second)
227+
defer ticker.Stop()
228+
229+
for {
230+
select {
231+
case <-ctx.Done():
232+
// clean up the gateway proxy
233+
for namespace := range gatewayProxyMap {
234+
kubectl := k8s.NewKubectlOptions("", "", namespace)
235+
_ = k8s.RunKubectlE(GinkgoT(), kubectl, "delete", "gatewayproxy", "conformance-gateway-proxy")
236+
}
237+
return
238+
case <-ticker.C:
239+
patchGateway(ctx, k8sClient)
240+
}
241+
}
242+
}()
243+
}

test/e2e/framework/framework.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
k8serrors "k8s.io/apimachinery/pkg/api/errors"
1818
"k8s.io/client-go/kubernetes"
1919
"k8s.io/client-go/rest"
20+
"sigs.k8s.io/controller-runtime/pkg/client"
2021
)
2122

2223
var (
@@ -44,6 +45,7 @@ type Framework struct {
4445
kubectlOpts *k8s.KubectlOptions
4546
clientset *kubernetes.Clientset
4647
restConfig *rest.Config
48+
K8sClient client.Client
4749

4850
DB *gorm.DB
4951
RawETCD *clientv3.Client
@@ -83,6 +85,10 @@ func NewFramework() *Framework {
8385
f.GomegaT.Expect(err).ShouldNot(HaveOccurred(), "creating Kubernetes clientset")
8486
f.clientset = clientset
8587

88+
k8sClient, err := client.New(restCfg, client.Options{})
89+
f.GomegaT.Expect(err).ShouldNot(HaveOccurred(), "creating controller-runtime client")
90+
f.K8sClient = k8sClient
91+
8692
_framework = f
8793

8894
// BeforeSuite(f.BeforeSuite)

0 commit comments

Comments
 (0)