Skip to content

Commit c0d95e3

Browse files
shaun-nxsalonichf5
authored andcommitted
Add CEL validation tests for NginxProxy (#3701)
1 parent c811790 commit c0d95e3

File tree

4 files changed

+292
-85
lines changed

4 files changed

+292
-85
lines changed

tests/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ uninstall-ngf: ## Uninstall NGF on configured kind cluster
191191
# Run CEL validation integration tests against a real cluster
192192
.PHONY: test-cel-validation
193193
test-cel-validation:
194+
-make install-crds || true;
194195
@if [ -z "$(CEL_TEST_TARGET)" ]; then \
195196
echo "Running all tests in ./cel"; \
196197
go test -v ./cel; \
Lines changed: 47 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,27 @@
11
package cel
22

33
import (
4-
"context"
54
"testing"
65

7-
. "github.com/onsi/gomega"
86
controllerruntime "sigs.k8s.io/controller-runtime"
9-
"sigs.k8s.io/controller-runtime/pkg/client"
107
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
118

129
ngfAPIv1alpha1 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha1"
1310
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/helpers"
14-
"github.com/nginx/nginx-gateway-fabric/v2/tests/framework"
1511
)
1612

1713
func TestClientSettingsPoliciesTargetRefKind(t *testing.T) {
1814
t.Parallel()
19-
g := NewWithT(t)
20-
21-
k8sClient, err := getKubernetesClient(t)
22-
g.Expect(err).ToNot(HaveOccurred())
15+
k8sClient := getKubernetesClient(t)
2316

2417
tests := []struct {
25-
policySpec ngfAPIv1alpha1.ClientSettingsPolicySpec
18+
spec ngfAPIv1alpha1.ClientSettingsPolicySpec
2619
name string
2720
wantErrors []string
2821
}{
2922
{
3023
name: "Validate TargetRef of kind Gateway is allowed",
31-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
24+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
3225
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
3326
Kind: gatewayKind,
3427
Group: gatewayGroup,
@@ -37,7 +30,7 @@ func TestClientSettingsPoliciesTargetRefKind(t *testing.T) {
3730
},
3831
{
3932
name: "Validate TargetRef of kind HTTPRoute is allowed",
40-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
33+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
4134
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
4235
Kind: httpRouteKind,
4336
Group: gatewayGroup,
@@ -46,7 +39,7 @@ func TestClientSettingsPoliciesTargetRefKind(t *testing.T) {
4639
},
4740
{
4841
name: "Validate TargetRef of kind GRPCRoute is allowed",
49-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
42+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
5043
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
5144
Kind: grpcRouteKind,
5245
Group: gatewayGroup,
@@ -56,7 +49,7 @@ func TestClientSettingsPoliciesTargetRefKind(t *testing.T) {
5649
{
5750
name: "Validate Invalid TargetRef Kind is not allowed",
5851
wantErrors: []string{expectedTargetRefKindError},
59-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
52+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
6053
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
6154
Kind: invalidKind,
6255
Group: gatewayGroup,
@@ -66,7 +59,7 @@ func TestClientSettingsPoliciesTargetRefKind(t *testing.T) {
6659
{
6760
name: "Validate TCPRoute TargetRef Kind is not allowed",
6861
wantErrors: []string{expectedTargetRefKindError},
69-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
62+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
7063
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
7164
Kind: tcpRouteKind,
7265
Group: gatewayGroup,
@@ -78,26 +71,32 @@ func TestClientSettingsPoliciesTargetRefKind(t *testing.T) {
7871
for _, tt := range tests {
7972
t.Run(tt.name, func(t *testing.T) {
8073
t.Parallel()
81-
validateClientSettingsPolicy(t, tt, g, k8sClient)
74+
spec := tt.spec
75+
spec.TargetRef.Name = gatewayv1alpha2.ObjectName(uniqueResourceName(testTargetRefName))
76+
clientSettingsPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
77+
ObjectMeta: controllerruntime.ObjectMeta{
78+
Name: uniqueResourceName(testResourceName),
79+
Namespace: defaultNamespace,
80+
},
81+
Spec: spec,
82+
}
83+
validateCrd(t, tt.wantErrors, clientSettingsPolicy, k8sClient)
8284
})
8385
}
8486
}
8587

8688
func TestClientSettingsPoliciesTargetRefGroup(t *testing.T) {
8789
t.Parallel()
88-
g := NewWithT(t)
89-
90-
k8sClient, err := getKubernetesClient(t)
91-
g.Expect(err).ToNot(HaveOccurred())
90+
k8sClient := getKubernetesClient(t)
9291

9392
tests := []struct {
94-
policySpec ngfAPIv1alpha1.ClientSettingsPolicySpec
93+
spec ngfAPIv1alpha1.ClientSettingsPolicySpec
9594
name string
9695
wantErrors []string
9796
}{
9897
{
9998
name: "Validate gateway.networking.k8s.io TargetRef Group is allowed",
100-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
99+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
101100
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
102101
Kind: gatewayKind,
103102
Group: gatewayGroup,
@@ -107,7 +106,7 @@ func TestClientSettingsPoliciesTargetRefGroup(t *testing.T) {
107106
{
108107
name: "Validate invalid.networking.k8s.io TargetRef Group is not allowed",
109108
wantErrors: []string{expectedTargetRefGroupError},
110-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
109+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
111110
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
112111
Kind: gatewayKind,
113112
Group: invalidGroup,
@@ -117,7 +116,7 @@ func TestClientSettingsPoliciesTargetRefGroup(t *testing.T) {
117116
{
118117
name: "Validate discovery.k8s.io/v1 TargetRef Group is not allowed",
119118
wantErrors: []string{expectedTargetRefGroupError},
120-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
119+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
121120
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
122121
Kind: gatewayKind,
123122
Group: discoveryGroup,
@@ -129,26 +128,32 @@ func TestClientSettingsPoliciesTargetRefGroup(t *testing.T) {
129128
for _, tt := range tests {
130129
t.Run(tt.name, func(t *testing.T) {
131130
t.Parallel()
132-
validateClientSettingsPolicy(t, tt, g, k8sClient)
131+
spec := tt.spec
132+
spec.TargetRef.Name = gatewayv1alpha2.ObjectName(uniqueResourceName(testTargetRefName))
133+
clientSettingsPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
134+
ObjectMeta: controllerruntime.ObjectMeta{
135+
Name: uniqueResourceName(testResourceName),
136+
Namespace: defaultNamespace,
137+
},
138+
Spec: spec,
139+
}
140+
validateCrd(t, tt.wantErrors, clientSettingsPolicy, k8sClient)
133141
})
134142
}
135143
}
136144

137145
func TestClientSettingsPoliciesKeepAliveTimeout(t *testing.T) {
138146
t.Parallel()
139-
g := NewWithT(t)
140-
141-
k8sClient, err := getKubernetesClient(t)
142-
g.Expect(err).ToNot(HaveOccurred())
147+
k8sClient := getKubernetesClient(t)
143148

144149
tests := []struct {
145-
policySpec ngfAPIv1alpha1.ClientSettingsPolicySpec
150+
spec ngfAPIv1alpha1.ClientSettingsPolicySpec
146151
name string
147152
wantErrors []string
148153
}{
149154
{
150155
name: "Validate KeepAliveTimeout is not set",
151-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
156+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
152157
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
153158
Kind: gatewayKind,
154159
Group: gatewayGroup,
@@ -158,7 +163,7 @@ func TestClientSettingsPoliciesKeepAliveTimeout(t *testing.T) {
158163
},
159164
{
160165
name: "Validate KeepAlive is set",
161-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
166+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
162167
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
163168
Kind: gatewayKind,
164169
Group: gatewayGroup,
@@ -174,7 +179,7 @@ func TestClientSettingsPoliciesKeepAliveTimeout(t *testing.T) {
174179
{
175180
name: "Validate Header cannot be set without Server",
176181
wantErrors: []string{expectedHeaderWithoutServerError},
177-
policySpec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
182+
spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
178183
TargetRef: gatewayv1alpha2.LocalPolicyTargetReference{
179184
Kind: gatewayKind,
180185
Group: gatewayGroup,
@@ -191,46 +196,16 @@ func TestClientSettingsPoliciesKeepAliveTimeout(t *testing.T) {
191196
for _, tt := range tests {
192197
t.Run(tt.name, func(t *testing.T) {
193198
t.Parallel()
194-
validateClientSettingsPolicy(t, tt, g, k8sClient)
199+
spec := tt.spec
200+
spec.TargetRef.Name = gatewayv1alpha2.ObjectName(uniqueResourceName(testTargetRefName))
201+
clientSettingsPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
202+
ObjectMeta: controllerruntime.ObjectMeta{
203+
Name: uniqueResourceName(testResourceName),
204+
Namespace: defaultNamespace,
205+
},
206+
Spec: spec,
207+
}
208+
validateCrd(t, tt.wantErrors, clientSettingsPolicy, k8sClient)
195209
})
196210
}
197211
}
198-
199-
func validateClientSettingsPolicy(t *testing.T, tt struct {
200-
policySpec ngfAPIv1alpha1.ClientSettingsPolicySpec
201-
name string
202-
wantErrors []string
203-
}, g *WithT, k8sClient client.Client,
204-
) {
205-
t.Helper()
206-
207-
policySpec := tt.policySpec
208-
policySpec.TargetRef.Name = gatewayv1alpha2.ObjectName(uniqueResourceName(testTargetRefName))
209-
policyName := uniqueResourceName(testPolicyName)
210-
211-
clientSettingsPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
212-
ObjectMeta: controllerruntime.ObjectMeta{
213-
Name: policyName,
214-
Namespace: defaultNamespace,
215-
},
216-
Spec: policySpec,
217-
}
218-
timeoutConfig := framework.DefaultTimeoutConfig()
219-
ctx, cancel := context.WithTimeout(context.Background(), timeoutConfig.KubernetesClientTimeout)
220-
err := k8sClient.Create(ctx, clientSettingsPolicy)
221-
defer cancel()
222-
223-
// Clean up after test
224-
defer func() {
225-
_ = k8sClient.Delete(context.Background(), clientSettingsPolicy)
226-
}()
227-
228-
if len(tt.wantErrors) == 0 {
229-
g.Expect(err).ToNot(HaveOccurred())
230-
} else {
231-
g.Expect(err).To(HaveOccurred())
232-
for _, wantError := range tt.wantErrors {
233-
g.Expect(err.Error()).To(ContainSubstring(wantError), "Expected error '%s' not found in: %s", wantError, err.Error())
234-
}
235-
}
236-
}

tests/cel/common.go

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
package cel
22

33
import (
4+
"context"
45
"crypto/rand"
56
"fmt"
67
"testing"
78

9+
. "github.com/onsi/gomega"
810
"k8s.io/apimachinery/pkg/runtime"
911
controllerruntime "sigs.k8s.io/controller-runtime"
1012
"sigs.k8s.io/controller-runtime/pkg/client"
1113

1214
ngfAPIv1alpha1 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha1"
1315
ngfAPIv1alpha2 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha2"
16+
"github.com/nginx/nginx-gateway-fabric/v2/tests/framework"
1417
)
1518

1619
const (
@@ -27,40 +30,46 @@ const (
2730
discoveryGroup = "discovery.k8s.io/v1"
2831
)
2932

33+
// ClientSettingsPolicy validation errors.
3034
const (
3135
expectedTargetRefKindError = `TargetRef Kind must be one of: Gateway, HTTPRoute, or GRPCRoute`
3236
expectedTargetRefGroupError = `TargetRef Group must be gateway.networking.k8s.io.`
3337
expectedHeaderWithoutServerError = `header can only be specified if server is specified`
3438
)
3539

40+
// NginxProxy validation errors.
41+
const (
42+
expectedOneOfDeploymentOrDaemonSetError = `only one of deployment or daemonSet can be set`
43+
expectedIfModeSetTrustedAddressesError = `if mode is set, trustedAddresses is a required field`
44+
expectedMinReplicasLessThanOrEqualError = `minReplicas must be less than or equal to maxReplicas`
45+
)
46+
3647
const (
3748
defaultNamespace = "default"
3849
)
3950

4051
const (
41-
testPolicyName = "test-policy"
52+
testResourceName = "test-resource"
4253
testTargetRefName = "test-targetRef"
4354
)
4455

4556
// getKubernetesClient returns a client connected to a real Kubernetes cluster.
46-
func getKubernetesClient(t *testing.T) (k8sClient client.Client, err error) {
57+
func getKubernetesClient(t *testing.T) (k8sClient client.Client) {
4758
t.Helper()
59+
g := NewWithT(t)
4860
// Use controller-runtime to get cluster connection
4961
k8sConfig, err := controllerruntime.GetConfig()
50-
if err != nil {
51-
return nil, err
52-
}
62+
g.Expect(err).ToNot(HaveOccurred())
5363

5464
// Set up scheme with NGF types
5565
scheme := runtime.NewScheme()
56-
if err = ngfAPIv1alpha1.AddToScheme(scheme); err != nil {
57-
return nil, err
58-
}
59-
if err = ngfAPIv1alpha2.AddToScheme(scheme); err != nil {
60-
return nil, err
61-
}
62-
// Create a new client with the scheme and return it
63-
return client.New(k8sConfig, client.Options{Scheme: scheme})
66+
g.Expect(ngfAPIv1alpha1.AddToScheme(scheme)).To(Succeed())
67+
g.Expect(ngfAPIv1alpha2.AddToScheme(scheme)).To(Succeed())
68+
69+
k8sClient, err = client.New(k8sConfig, client.Options{Scheme: scheme})
70+
g.Expect(err).ToNot(HaveOccurred())
71+
72+
return k8sClient
6473
}
6574

6675
// randomPrimeNumber generates a random prime number of 64 bits.
@@ -77,3 +86,27 @@ func randomPrimeNumber() int64 {
7786
func uniqueResourceName(name string) string {
7887
return fmt.Sprintf("%s-%d", name, randomPrimeNumber())
7988
}
89+
90+
// validateCrd creates a k8s resource and validates it against the expected errors.
91+
func validateCrd(t *testing.T, wantErrors []string, crd client.Object, k8sClient client.Client) {
92+
t.Helper()
93+
g := NewWithT(t)
94+
95+
timeoutConfig := framework.DefaultTimeoutConfig()
96+
ctx, cancel := context.WithTimeout(context.Background(), timeoutConfig.KubernetesClientTimeout)
97+
defer cancel()
98+
err := k8sClient.Create(ctx, crd)
99+
100+
// Check for expected errors
101+
if len(wantErrors) == 0 {
102+
g.Expect(err).ToNot(HaveOccurred())
103+
// Clean up after test
104+
// Resources only need to be deleted if they were created successfully
105+
g.Expect(k8sClient.Delete(ctx, crd)).To(Succeed())
106+
} else {
107+
g.Expect(err).To(HaveOccurred())
108+
for _, wantError := range wantErrors {
109+
g.Expect(err.Error()).To(ContainSubstring(wantError), "Expected error '%s' not found in: %s", wantError, err.Error())
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)