1313package framework
1414
1515import (
16+ "bufio"
17+ "bytes"
1618 "context"
19+ "fmt"
1720 "os"
21+ "strings"
22+ "sync"
23+ "time"
1824
1925 "github.com/gruntwork-io/terratest/modules/k8s"
2026 "github.com/gruntwork-io/terratest/modules/logger"
2127 . "github.com/onsi/ginkgo/v2"
28+ "github.com/onsi/gomega"
2229 . "github.com/onsi/gomega"
30+ corev1 "k8s.io/api/core/v1"
31+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
32+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2333 "k8s.io/client-go/kubernetes"
2434 "k8s.io/client-go/rest"
35+ "k8s.io/utils/ptr"
2536 "sigs.k8s.io/controller-runtime/pkg/client"
2637)
2738
@@ -42,6 +53,7 @@ type APISIXFramework struct {
4253 clientset * kubernetes.Clientset
4354 restConfig * rest.Config
4455 K8sClient client.Client
56+ namespace string
4557}
4658
4759// NewAPISIXFramework creates a new APISIX framework
@@ -60,6 +72,8 @@ func NewAPISIXFramework() *APISIXFramework {
6072 namespace = _apisixNamespace
6173 }
6274
75+ f .namespace = namespace
76+
6377 f .kubectlOpts = k8s .NewKubectlOptions ("" , "" , namespace )
6478 restCfg , err := buildRestConfig ("" )
6579 f .GomegaT .Expect (err ).ShouldNot (HaveOccurred (), "building API Server rest config" )
@@ -81,9 +95,17 @@ func NewAPISIXFramework() *APISIXFramework {
8195// BeforeSuite initializes the APISIX test environment
8296func (f * APISIXFramework ) BeforeSuite () {
8397 f .Logf ("Starting APISIX standalone test suite" )
98+ _ = k8s .DeleteNamespaceE (GinkgoT (), f .kubectlOpts , f .namespace )
99+
100+ Eventually (func () error {
101+ _ , err := k8s .GetNamespaceE (GinkgoT (), f .kubectlOpts , f .namespace )
102+ if k8serrors .IsNotFound (err ) {
103+ return nil
104+ }
105+ return fmt .Errorf ("namespace %s still exists" , f .namespace )
106+ }, "1m" , "2s" ).Should (Succeed ())
84107
85- // Create namespace for APISIX standalone tests
86- k8s .CreateNamespace (GinkgoT (), f .kubectlOpts , f .kubectlOpts .Namespace )
108+ k8s .CreateNamespace (GinkgoT (), f .kubectlOpts , f .namespace )
87109
88110 f .Logf ("APISIX standalone test environment initialized" )
89111}
@@ -105,3 +127,80 @@ func GetAPISIXFramework() *APISIXFramework {
105127func (f * APISIXFramework ) Logf (format string , v ... any ) {
106128 f .Logger .Logf (f .GinkgoT , format , v ... )
107129}
130+
131+ func (f * APISIXFramework ) DeployIngress (opts IngressDeployOpts ) {
132+ buf := bytes .NewBuffer (nil )
133+
134+ err := IngressSpecTpl .Execute (buf , opts )
135+ f .GomegaT .Expect (err ).ToNot (HaveOccurred (), "rendering ingress spec" )
136+
137+ kubectlOpts := k8s .NewKubectlOptions ("" , "" , opts .Namespace )
138+
139+ k8s .KubectlApplyFromString (f .GinkgoT , kubectlOpts , buf .String ())
140+
141+ err = WaitPodsAvailable (f .GinkgoT , kubectlOpts , metav1.ListOptions {
142+ LabelSelector : "control-plane=controller-manager" ,
143+ })
144+ f .GomegaT .Expect (err ).ToNot (HaveOccurred (), "waiting for controller-manager pod ready" )
145+ f .WaitControllerManagerLog ("All cache synced successfully" , 0 , time .Minute )
146+ }
147+
148+ func (f * APISIXFramework ) WaitControllerManagerLog (keyword string , sinceSeconds int64 , timeout time.Duration ) {
149+ f .WaitPodsLog ("control-plane=controller-manager" , keyword , sinceSeconds , timeout )
150+ }
151+
152+ func (f * APISIXFramework ) WaitDPLog (keyword string , sinceSeconds int64 , timeout time.Duration ) {
153+ f .WaitPodsLog ("app.kubernetes.io/name=apisix" , keyword , sinceSeconds , timeout )
154+ }
155+
156+ func (f * APISIXFramework ) WaitPodsLog (selector , keyword string , sinceSeconds int64 , timeout time.Duration ) {
157+ pods := f .ListRunningPods (selector )
158+ wg := sync.WaitGroup {}
159+ for _ , p := range pods {
160+ wg .Add (1 )
161+ go func (p corev1.Pod ) {
162+ defer wg .Done ()
163+ opts := corev1.PodLogOptions {Follow : true }
164+ if sinceSeconds > 0 {
165+ opts .SinceSeconds = ptr .To (sinceSeconds )
166+ } else {
167+ opts .TailLines = ptr .To (int64 (0 ))
168+ }
169+ logStream , err := f .clientset .CoreV1 ().Pods (p .Namespace ).GetLogs (p .Name , & opts ).Stream (context .Background ())
170+ f .GomegaT .Expect (err ).Should (gomega .BeNil ())
171+ scanner := bufio .NewScanner (logStream )
172+ scanner .Split (bufio .ScanLines )
173+ for scanner .Scan () {
174+ line := scanner .Text ()
175+ if strings .Contains (line , keyword ) {
176+ return
177+ }
178+ }
179+ }(p )
180+ }
181+ c := make (chan struct {})
182+ go func () {
183+ defer close (c )
184+ wg .Wait ()
185+ }()
186+ select {
187+ case <- c :
188+ return
189+ case <- time .After (timeout ):
190+ f .GinkgoT .Error ("wait log timeout" )
191+ }
192+ }
193+
194+ func (f * APISIXFramework ) ListRunningPods (selector string ) []corev1.Pod {
195+ pods , err := f .clientset .CoreV1 ().Pods (f .namespace ).List (context .TODO (), metav1.ListOptions {
196+ LabelSelector : selector ,
197+ })
198+ f .GomegaT .Expect (err ).ShouldNot (gomega .HaveOccurred (), "list pod: " , selector )
199+ runningPods := make ([]corev1.Pod , 0 )
200+ for _ , p := range pods .Items {
201+ if p .Status .Phase == corev1 .PodRunning && p .DeletionTimestamp == nil {
202+ runningPods = append (runningPods , p )
203+ }
204+ }
205+ return runningPods
206+ }
0 commit comments