Skip to content

Commit d308a00

Browse files
authored
Add NginxGateway functional test (#2486)
Add a functional test for the NginxGateway resource. Problem: We would like a functional test for the NginxGateway resource to ensure its working correctly. Solution: Add the functional test.
1 parent 2544818 commit d308a00

File tree

5 files changed

+356
-35
lines changed

5 files changed

+356
-35
lines changed

tests/framework/ngf.go

-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ func InstallNGF(cfg InstallationConfig, extraArgs ...string) ([]byte, error) {
6767
"--namespace", cfg.Namespace,
6868
"--wait",
6969
"--set", "nginxGateway.productTelemetry.enable=false",
70-
"--set", "nginxGateway.config.logging.level=debug",
7170
}
7271
if cfg.ChartVersion != "" {
7372
args = append(args, "--version", cfg.ChartVersion)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: gateway.nginx.org/v1alpha1
2+
kind: NginxGateway
3+
metadata:
4+
name: ngf-test-config
5+
namespace: nginx-gateway
6+
spec:
7+
logging:
8+
level: debug

tests/suite/nginxgateway_test.go

+298
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"strings"
8+
"time"
9+
10+
. "github.com/onsi/ginkgo/v2"
11+
. "github.com/onsi/gomega"
12+
core "k8s.io/api/core/v1"
13+
"k8s.io/apimachinery/pkg/types"
14+
15+
ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
16+
"github.com/nginxinc/nginx-gateway-fabric/tests/framework"
17+
)
18+
19+
var _ = Describe("NginxGateway", Ordered, Label("functional", "nginxGateway"), func() {
20+
var (
21+
ngfPodName string
22+
23+
namespace = "nginx-gateway"
24+
nginxGatewayNsname = types.NamespacedName{Name: releaseName + "-config", Namespace: namespace}
25+
26+
files = []string{
27+
"nginxgateway/nginx-gateway.yaml",
28+
}
29+
)
30+
31+
getNginxGateway := func(nsname types.NamespacedName) (ngfAPI.NginxGateway, error) {
32+
ctx, cancel := context.WithTimeout(context.Background(), timeoutConfig.GetTimeout)
33+
defer cancel()
34+
35+
var nginxGateway ngfAPI.NginxGateway
36+
37+
if err := k8sClient.Get(ctx, nsname, &nginxGateway); err != nil {
38+
return nginxGateway, fmt.Errorf("failed to get nginxGateway: %w", err)
39+
}
40+
41+
return nginxGateway, nil
42+
}
43+
44+
verifyNginxGatewayConditions := func(ng ngfAPI.NginxGateway) error {
45+
if ng.Status.Conditions == nil {
46+
return errors.New("nginxGateway has no conditions")
47+
}
48+
49+
if len(ng.Status.Conditions) != 1 {
50+
return fmt.Errorf(
51+
"expected nginxGateway to have only one condition, instead has %d conditions",
52+
len(ng.Status.Conditions),
53+
)
54+
}
55+
56+
return nil
57+
}
58+
59+
getNginxGatewayCurrentObservedGeneration := func(ng ngfAPI.NginxGateway) (int64, error) {
60+
if err := verifyNginxGatewayConditions(ng); err != nil {
61+
return 0, err
62+
}
63+
64+
return ng.Status.Conditions[0].ObservedGeneration, nil
65+
}
66+
67+
verifyNginxGatewayStatus := func(ng ngfAPI.NginxGateway, expObservedGen int64) error {
68+
if err := verifyNginxGatewayConditions(ng); err != nil {
69+
return err
70+
}
71+
72+
condition := ng.Status.Conditions[0]
73+
74+
if condition.Type != "Valid" {
75+
return fmt.Errorf(
76+
"expected nginxGateway condition type to be Valid, instead has type %s",
77+
condition.Type,
78+
)
79+
}
80+
81+
if condition.Reason != "Valid" {
82+
return fmt.Errorf("expected nginxGateway reason to be Valid, instead is %s", condition.Reason)
83+
}
84+
85+
if condition.ObservedGeneration != expObservedGen {
86+
return fmt.Errorf(
87+
"expected nginxGateway observed generation to be %d, instead is %d",
88+
expObservedGen,
89+
condition.ObservedGeneration,
90+
)
91+
}
92+
93+
return nil
94+
}
95+
96+
getNGFPodName := func() (string, error) {
97+
podNames, err := framework.GetReadyNGFPodNames(
98+
k8sClient,
99+
ngfNamespace,
100+
releaseName,
101+
timeoutConfig.GetTimeout,
102+
)
103+
if err != nil {
104+
return "", err
105+
}
106+
107+
if len(podNames) != 1 {
108+
return "", fmt.Errorf("expected 1 pod name, got %d", len(podNames))
109+
}
110+
111+
return podNames[0], nil
112+
}
113+
114+
AfterAll(func() {
115+
// re-apply NginxGateway crd to restore NGF instance for following functional tests
116+
Expect(resourceManager.ApplyFromFiles(files, namespace)).To(Succeed())
117+
118+
Eventually(
119+
func() bool {
120+
ng, err := getNginxGateway(nginxGatewayNsname)
121+
if err != nil {
122+
return false
123+
}
124+
125+
return verifyNginxGatewayStatus(ng, int64(1)) == nil
126+
}).WithTimeout(timeoutConfig.UpdateTimeout).
127+
WithPolling(500 * time.Millisecond).
128+
Should(BeTrue())
129+
})
130+
131+
When("testing NGF on startup", func() {
132+
When("log level is set to debug", func() {
133+
It("outputs debug logs and the status is valid", func() {
134+
ngfPodName, err := getNGFPodName()
135+
Expect(err).ToNot(HaveOccurred())
136+
137+
ng, err := getNginxGateway(nginxGatewayNsname)
138+
Expect(err).ToNot(HaveOccurred())
139+
140+
Expect(verifyNginxGatewayStatus(ng, int64(1))).To(Succeed())
141+
142+
Eventually(
143+
func() bool {
144+
logs, err := resourceManager.GetPodLogs(ngfNamespace, ngfPodName, &core.PodLogOptions{
145+
Container: "nginx-gateway",
146+
})
147+
if err != nil {
148+
return false
149+
}
150+
151+
return strings.Contains(logs, "\"level\":\"debug\"")
152+
}).WithTimeout(timeoutConfig.GetTimeout).
153+
WithPolling(500 * time.Millisecond).
154+
Should(BeTrue())
155+
})
156+
})
157+
158+
When("default log level is used", func() {
159+
It("only outputs info logs and the status is valid", func() {
160+
teardown(releaseName)
161+
162+
cfg := getDefaultSetupCfg()
163+
cfg.debugLogLevel = false
164+
setup(cfg)
165+
166+
ngfPodName, err := getNGFPodName()
167+
Expect(err).ToNot(HaveOccurred())
168+
169+
Eventually(
170+
func() bool {
171+
ng, err := getNginxGateway(nginxGatewayNsname)
172+
if err != nil {
173+
return false
174+
}
175+
176+
return verifyNginxGatewayStatus(ng, int64(1)) == nil
177+
}).WithTimeout(timeoutConfig.UpdateTimeout).
178+
WithPolling(500 * time.Millisecond).
179+
Should(BeTrue())
180+
181+
Consistently(
182+
func() bool {
183+
logs, err := resourceManager.GetPodLogs(ngfNamespace, ngfPodName, &core.PodLogOptions{
184+
Container: "nginx-gateway",
185+
})
186+
if err != nil {
187+
return false
188+
}
189+
190+
return !strings.Contains(logs, "\"level\":\"debug\"")
191+
}).WithTimeout(timeoutConfig.GetTimeout).
192+
WithPolling(500 * time.Millisecond).
193+
Should(BeTrue())
194+
})
195+
})
196+
})
197+
198+
When("testing on an existing NGF instance", Ordered, func() {
199+
BeforeAll(func() {
200+
var err error
201+
ngfPodName, err = getNGFPodName()
202+
Expect(err).ToNot(HaveOccurred())
203+
})
204+
205+
When("NginxGateway is updated", func() {
206+
It("captures the change, the status is valid, and the observed generation is incremented", func() {
207+
// previous test has left the log level at info, this test will change the log level to debug
208+
ng, err := getNginxGateway(nginxGatewayNsname)
209+
Expect(err).ToNot(HaveOccurred())
210+
211+
gen, err := getNginxGatewayCurrentObservedGeneration(ng)
212+
Expect(err).ToNot(HaveOccurred())
213+
214+
Expect(verifyNginxGatewayStatus(ng, gen)).To(Succeed())
215+
216+
logs, err := resourceManager.GetPodLogs(ngfNamespace, ngfPodName, &core.PodLogOptions{
217+
Container: "nginx-gateway",
218+
})
219+
Expect(err).ToNot(HaveOccurred())
220+
221+
Expect(logs).ToNot(ContainSubstring("\"level\":\"debug\""))
222+
223+
Expect(resourceManager.ApplyFromFiles(files, namespace)).To(Succeed())
224+
225+
Eventually(
226+
func() bool {
227+
ng, err := getNginxGateway(nginxGatewayNsname)
228+
if err != nil {
229+
return false
230+
}
231+
232+
return verifyNginxGatewayStatus(ng, gen+1) == nil
233+
}).WithTimeout(timeoutConfig.UpdateTimeout).
234+
WithPolling(500 * time.Millisecond).
235+
Should(BeTrue())
236+
237+
Eventually(
238+
func() bool {
239+
logs, err := resourceManager.GetPodLogs(ngfNamespace, ngfPodName, &core.PodLogOptions{
240+
Container: "nginx-gateway",
241+
})
242+
if err != nil {
243+
return false
244+
}
245+
246+
return strings.Contains(
247+
logs,
248+
"\"current\":\"debug\",\"msg\":\"Log level changed\",\"prev\":\"info\"",
249+
)
250+
}).WithTimeout(timeoutConfig.GetTimeout).
251+
WithPolling(500 * time.Millisecond).
252+
Should(BeTrue())
253+
})
254+
})
255+
256+
When("NginxGateway is deleted", func() {
257+
It("captures the deletion and default values are used", func() {
258+
Expect(resourceManager.DeleteFromFiles(files, namespace)).To(Succeed())
259+
260+
Eventually(
261+
func() error {
262+
_, err := getNginxGateway(nginxGatewayNsname)
263+
return err
264+
}).WithTimeout(timeoutConfig.DeleteTimeout).
265+
WithPolling(500 * time.Millisecond).
266+
Should(MatchError(ContainSubstring("failed to get nginxGateway")))
267+
268+
Eventually(
269+
func() bool {
270+
logs, err := resourceManager.GetPodLogs(ngfNamespace, ngfPodName, &core.PodLogOptions{
271+
Container: "nginx-gateway",
272+
})
273+
if err != nil {
274+
return false
275+
}
276+
277+
return strings.Contains(logs, "NginxGateway configuration was deleted; using defaults")
278+
}).WithTimeout(timeoutConfig.GetTimeout).
279+
WithPolling(500 * time.Millisecond).
280+
Should(BeTrue())
281+
282+
events, err := resourceManager.GetEvents(namespace)
283+
Expect(err).ToNot(HaveOccurred())
284+
285+
var foundNginxGatewayDeletionEvent bool
286+
for _, item := range events.Items {
287+
if item.Message == "NginxGateway configuration was deleted; using defaults" &&
288+
item.Type == "Warning" &&
289+
item.Reason == "ResourceDeleted" {
290+
foundNginxGatewayDeletionEvent = true
291+
break
292+
}
293+
}
294+
Expect(foundNginxGatewayDeletionEvent).To(BeTrue())
295+
})
296+
})
297+
})
298+
})

0 commit comments

Comments
 (0)