Skip to content

Add CEL validation tests for NginxProxy #3701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Aug 13, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9631d54
Add tests for kubernetes validation
shaun-nx Aug 7, 2025
8455a14
Add tests for rewriteClientIP
shaun-nx Aug 7, 2025
8404b7d
Move validation function to common.go
shaun-nx Aug 7, 2025
0ba4b7c
Add comment to `validateCrd` function
shaun-nx Aug 7, 2025
8032352
Merge branch 'main' into tests/cel-nginxproxy
shaun-nx Aug 7, 2025
82f84a1
Merge branch 'main' into tests/cel-nginxproxy
shaun-nx Aug 11, 2025
b1da498
Move expected error strings to common.go
shaun-nx Aug 11, 2025
80e121a
Add tests for autoscaling validation
shaun-nx Aug 11, 2025
9bbe4cd
Refactor tests
shaun-nx Aug 11, 2025
8612c21
Change name of `testResourceName` const
shaun-nx Aug 11, 2025
45302dc
Group expexted error consts
shaun-nx Aug 11, 2025
9bb4bdb
Ensure gateway CRDs are installed when running `test-cel-validation`
shaun-nx Aug 11, 2025
531850d
Undo changes to `install-gateway-crds` command
shaun-nx Aug 11, 2025
d742467
Change `policyName` to `resourceName`
shaun-nx Aug 11, 2025
216406c
Add test for when `minReplicas` is nil
shaun-nx Aug 12, 2025
702ccb5
Merge branch 'main' into tests/cel-nginxproxy
shaun-nx Aug 12, 2025
960db80
Have `k8sClient.Delete` use same context and `k8sClient.Create`
shaun-nx Aug 12, 2025
38e20ee
Add spacing
shaun-nx Aug 12, 2025
aba710a
Add additional comments
shaun-nx Aug 12, 2025
14ee3f7
Ensure installed resources are only delete if an error is NOT expected
shaun-nx Aug 12, 2025
ac12bab
Expected k8sClient.Delete to succeed
shaun-nx Aug 12, 2025
55d4fe1
Merge branch 'main' into tests/cel-nginxproxy
shaun-nx Aug 13, 2025
51d49f8
Add additional comments
shaun-nx Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 30 additions & 45 deletions tests/cel/clientsettingspolicy_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package cel

import (
"context"
"testing"

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

ngfAPIv1alpha1 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha1"
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/helpers"
"github.com/nginx/nginx-gateway-fabric/v2/tests/framework"
)

func TestClientSettingsPoliciesTargetRefKind(t *testing.T) {
Expand Down Expand Up @@ -78,7 +75,16 @@ func TestClientSettingsPoliciesTargetRefKind(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
validateClientSettingsPolicy(t, tt, g, k8sClient)
policySpec := tt.policySpec
policySpec.TargetRef.Name = gatewayv1alpha2.ObjectName(uniqueResourceName(testTargetRefName))
clientSettingsPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
ObjectMeta: controllerruntime.ObjectMeta{
Name: uniqueResourceName(testPolicyName),
Namespace: defaultNamespace,
},
Spec: policySpec,
}
validateCrd(t, tt.wantErrors, g, clientSettingsPolicy, k8sClient)
})
}
}
Expand Down Expand Up @@ -129,7 +135,16 @@ func TestClientSettingsPoliciesTargetRefGroup(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
validateClientSettingsPolicy(t, tt, g, k8sClient)
policySpec := tt.policySpec
policySpec.TargetRef.Name = gatewayv1alpha2.ObjectName(uniqueResourceName(testTargetRefName))
clientSettingsPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
ObjectMeta: controllerruntime.ObjectMeta{
Name: uniqueResourceName(testPolicyName),
Namespace: defaultNamespace,
},
Spec: policySpec,
}
validateCrd(t, tt.wantErrors, g, clientSettingsPolicy, k8sClient)
})
}
}
Expand Down Expand Up @@ -191,46 +206,16 @@ func TestClientSettingsPoliciesKeepAliveTimeout(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
validateClientSettingsPolicy(t, tt, g, k8sClient)
policySpec := tt.policySpec
policySpec.TargetRef.Name = gatewayv1alpha2.ObjectName(uniqueResourceName(testTargetRefName))
clientSettingsPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
ObjectMeta: controllerruntime.ObjectMeta{
Name: uniqueResourceName(testPolicyName),
Namespace: defaultNamespace,
},
Spec: policySpec,
}
validateCrd(t, tt.wantErrors, g, clientSettingsPolicy, k8sClient)
})
}
}

func validateClientSettingsPolicy(t *testing.T, tt struct {
policySpec ngfAPIv1alpha1.ClientSettingsPolicySpec
name string
wantErrors []string
}, g *WithT, k8sClient client.Client,
) {
t.Helper()

policySpec := tt.policySpec
policySpec.TargetRef.Name = gatewayv1alpha2.ObjectName(uniqueResourceName(testTargetRefName))
policyName := uniqueResourceName(testPolicyName)

clientSettingsPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
ObjectMeta: controllerruntime.ObjectMeta{
Name: policyName,
Namespace: defaultNamespace,
},
Spec: policySpec,
}
timeoutConfig := framework.DefaultTimeoutConfig()
ctx, cancel := context.WithTimeout(context.Background(), timeoutConfig.KubernetesClientTimeout)
err := k8sClient.Create(ctx, clientSettingsPolicy)
defer cancel()

// Clean up after test
defer func() {
_ = k8sClient.Delete(context.Background(), clientSettingsPolicy)
}()

if len(tt.wantErrors) == 0 {
g.Expect(err).ToNot(HaveOccurred())
} else {
g.Expect(err).To(HaveOccurred())
for _, wantError := range tt.wantErrors {
g.Expect(err.Error()).To(ContainSubstring(wantError), "Expected error '%s' not found in: %s", wantError, err.Error())
}
}
}
26 changes: 26 additions & 0 deletions tests/cel/common.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package cel

import (
"context"
"crypto/rand"
"fmt"
"testing"

. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/runtime"
controllerruntime "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

ngfAPIv1alpha1 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha1"
ngfAPIv1alpha2 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha2"
"github.com/nginx/nginx-gateway-fabric/v2/tests/framework"
)

const (
Expand Down Expand Up @@ -77,3 +80,26 @@ func randomPrimeNumber() int64 {
func uniqueResourceName(name string) string {
return fmt.Sprintf("%s-%d", name, randomPrimeNumber())
}

func validateCrd(t *testing.T, wantErrors []string, g *WithT, crd client.Object, k8sClient client.Client) {
t.Helper()

timeoutConfig := framework.DefaultTimeoutConfig()
ctx, cancel := context.WithTimeout(context.Background(), timeoutConfig.KubernetesClientTimeout)
err := k8sClient.Create(ctx, crd)
defer cancel()

// Clean up after test
defer func() {
_ = k8sClient.Delete(context.Background(), crd)
}()

if len(wantErrors) == 0 {
g.Expect(err).ToNot(HaveOccurred())
} else {
g.Expect(err).To(HaveOccurred())
for _, wantError := range wantErrors {
g.Expect(err.Error()).To(ContainSubstring(wantError), "Expected error '%s' not found in: %s", wantError, err.Error())
}
}
}
128 changes: 128 additions & 0 deletions tests/cel/nginxproxy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package cel

import (
"testing"

. "github.com/onsi/gomega"
controllerruntime "sigs.k8s.io/controller-runtime"

ngfAPIv1alpha2 "github.com/nginx/nginx-gateway-fabric/v2/apis/v1alpha2"
"github.com/nginx/nginx-gateway-fabric/v2/internal/framework/helpers"
)

func TestNginxProxyKubernetes(t *testing.T) {
t.Parallel()
g := NewWithT(t)

k8sClient, err := getKubernetesClient(t)
g.Expect(err).ToNot(HaveOccurred())

tests := []struct {
policySpec ngfAPIv1alpha2.NginxProxySpec
name string
wantErrors []string
}{
{
name: "Validate NginxProxy with both Deployment and DaemonSet is invalid",
wantErrors: []string{"only one of deployment or daemonSet can be set"},
policySpec: ngfAPIv1alpha2.NginxProxySpec{
Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{
Deployment: &ngfAPIv1alpha2.DeploymentSpec{
Replicas: helpers.GetPointer[int32](3),
},
DaemonSet: &ngfAPIv1alpha2.DaemonSetSpec{},
},
},
},
{
name: "Validate NginxProxy with Deployment only is valid",
policySpec: ngfAPIv1alpha2.NginxProxySpec{
Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{
Deployment: &ngfAPIv1alpha2.DeploymentSpec{
Replicas: helpers.GetPointer[int32](3),
},
},
},
},
{
name: "Validate NginxProxy with DaemonSet only is valid",
policySpec: ngfAPIv1alpha2.NginxProxySpec{
Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{
DaemonSet: &ngfAPIv1alpha2.DaemonSetSpec{},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
policySpec := tt.policySpec
policyName := uniqueResourceName(testPolicyName)

nginxProxy := &ngfAPIv1alpha2.NginxProxy{
ObjectMeta: controllerruntime.ObjectMeta{
Name: policyName,
Namespace: defaultNamespace,
},
Spec: policySpec,
}
validateCrd(t, tt.wantErrors, g, nginxProxy, k8sClient)
})
}
}

func TestNginxProxyRewriteClientIP(t *testing.T) {
t.Parallel()
g := NewWithT(t)

k8sClient, err := getKubernetesClient(t)
g.Expect(err).ToNot(HaveOccurred())

tests := []struct {
policySpec ngfAPIv1alpha2.NginxProxySpec
name string
wantErrors []string
}{
{
name: "Validate NginxProxy is invalid when trustedAddresses is not set and mode is set",
wantErrors: []string{"if mode is set, trustedAddresses is a required field"},
policySpec: ngfAPIv1alpha2.NginxProxySpec{
RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
Mode: helpers.GetPointer[ngfAPIv1alpha2.RewriteClientIPModeType]("XForwardedFor"),
},
},
},
{
name: "Validate NginxProxy is valid when both mode and trustedAddresses are set",
policySpec: ngfAPIv1alpha2.NginxProxySpec{
RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
Mode: helpers.GetPointer[ngfAPIv1alpha2.RewriteClientIPModeType]("XForwardedFor"),
TrustedAddresses: []ngfAPIv1alpha2.RewriteClientIPAddress{
{
Type: ngfAPIv1alpha2.RewriteClientIPAddressType("CIDR"),
Value: "10.0.0.0/8",
},
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
policySpec := tt.policySpec
policyName := uniqueResourceName(testPolicyName)

nginxProxy := &ngfAPIv1alpha2.NginxProxy{
ObjectMeta: controllerruntime.ObjectMeta{
Name: policyName,
Namespace: defaultNamespace,
},
Spec: policySpec,
}
validateCrd(t, tt.wantErrors, g, nginxProxy, k8sClient)
})
}
}
Loading