Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
65fb552
Add k8s clients
johananl Jan 8, 2026
7098cb9
Add logger interface
johananl Jan 8, 2026
ae94714
Add CRD helpers
johananl Jan 8, 2026
7e76c00
Add Helm helpers
johananl Jan 8, 2026
0385bd2
Add namespace helpers
johananl Jan 8, 2026
f4cfe5f
Add dummy app helpers
johananl Jan 8, 2026
b5b6838
Add helper for installing Istio
johananl Jan 8, 2026
a7ad561
Add helpers for Kong
johananl Jan 8, 2026
6740ba4
Add GWAPI helpers
johananl Jan 8, 2026
2d48d39
Add port forwarding helpers
johananl Jan 8, 2026
126c0a6
Add ingress-nginx helpers
johananl Jan 8, 2026
665eaa9
Add helper for creating ingresses
johananl Jan 8, 2026
395fded
Add resource manager
johananl Jan 8, 2026
9f95c22
Add verifier interface and httpGetVerifier implementation
johananl Jan 8, 2026
4f693fa
Add main test logic
johananl Jan 8, 2026
f63093e
Add some initial test cases
johananl Jan 8, 2026
88ed612
Add Make targets for e2e
johananl Jan 8, 2026
d5c28ed
Add README for e2e tests
johananl Jan 8, 2026
7aa6b5f
Install kind to ./bin
johananl Jan 12, 2026
ad1c425
Use builder pattern for ingresses in test cases
johananl Jan 14, 2026
04b9b26
Centralize retry logic
johananl Jan 15, 2026
3221ffb
Use ingress2gateway binary
johananl Jan 21, 2026
c3e0aa8
Canary tests
Stevenjin8 Jan 30, 2026
6df4abc
Merge remote-tracking branch 'up/main' into test/canary
Stevenjin8 Jan 30, 2026
72043b7
Path rewrite
Stevenjin8 Jan 30, 2026
ae822a8
Verify TLS Ingresses and TLS redirects
Stevenjin8 Feb 2, 2026
5b2790c
Merge remote-tracking branch 'up/main' into test/canary
Stevenjin8 Feb 2, 2026
04180bf
Merge branch 'test/canary' into tests/e2e-tls
Stevenjin8 Feb 2, 2026
8a6932c
touchup
Stevenjin8 Feb 2, 2026
1d9549c
touchup
Stevenjin8 Feb 2, 2026
28f32fa
lint
Stevenjin8 Feb 2, 2026
90526b1
lint
Stevenjin8 Feb 2, 2026
9cf777d
use regex body verifier
Stevenjin8 Feb 4, 2026
c01ca8a
Merge branch 'test/canary' into tests/e2e-tls
Stevenjin8 Feb 4, 2026
4bc978e
random canary host
Stevenjin8 Feb 5, 2026
cd108f1
Merge remote-tracking branch 'up/main' into tests/e2e-tls
Stevenjin8 Feb 5, 2026
1727e84
CORS tests
Stevenjin8 Feb 5, 2026
3c23866
move to module
Stevenjin8 Feb 10, 2026
24e310f
Merge branch 'main' into tests/e2e-tls
Stevenjin8 Feb 10, 2026
aec685e
Use monthly CRD and move packages
Stevenjin8 Feb 10, 2026
0ff86f7
Review
Stevenjin8 Feb 12, 2026
c2a2d25
lints
Stevenjin8 Feb 12, 2026
47ddeee
review
Stevenjin8 Feb 13, 2026
7a82725
lint
Stevenjin8 Feb 13, 2026
6bb967b
remove unecessary host
Stevenjin8 Feb 13, 2026
4f1c9cf
comments
Stevenjin8 Feb 13, 2026
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
5 changes: 3 additions & 2 deletions e2e/crd.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ import (
)

const (
gatewayAPIVersion = "v1.4.1"
gatewayAPIInstallURL = "https://github.com/kubernetes-sigs/gateway-api/releases/download/" + gatewayAPIVersion + "/standard-install.yaml"
// gatewayAPIVersion = "v1.4.1"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to clean up?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not really. I think we want to target gwapi 1.5, which isn't released yet (rc coming this week) because we really want support for status code 308 in ReqestRedirects. Since 308 isn't available in 1.4, but is in 1.5, I figured I'd use a monthly release and just update it to 1.5/1.5-rc whenever that comes out.

// gatewayAPIInstallURL = "https://github.com/kubernetes-sigs/gateway-api/releases/download/" + gatewayAPIVersion + "/experimental-install.yaml"
gatewayAPIInstallURL = "https://github.com/kubernetes-sigs/gateway-api/releases/download/monthly-2026.01/monthly-2026.01-install.yaml"
)

func deployCRDs(ctx context.Context, l logger, client *apiextensionsclientset.Clientset, skipCleanup bool) (func(), error) {
Expand Down
15 changes: 7 additions & 8 deletions e2e/dummy_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,20 @@ import (
)

const (
name = "dummy-app"
image = "registry.k8s.io/e2e-test-images/agnhost"
version = "2.39"
)

func deployDummyApp(ctx context.Context, l logger, client *kubernetes.Clientset, namespace string, skipCleanup bool) (func(), error) {
if err := createDummyAppDeployment(ctx, l, client, namespace); err != nil {
func deployDummyApp(ctx context.Context, l logger, client *kubernetes.Clientset, name, namespace string, skipCleanup bool) (func(), error) {
if err := createDummyAppDeployment(ctx, l, client, name, namespace); err != nil {
return nil, fmt.Errorf("creating deployment: %w", err)
}

if err := createDummyAppService(ctx, client, namespace); err != nil {
if err := createDummyAppService(ctx, client, name, namespace); err != nil {
return nil, fmt.Errorf("creating service: %w", err)
}

if err := waitForDummyApp(ctx, l, client, namespace); err != nil {
if err := waitForDummyApp(ctx, l, client, name, namespace); err != nil {
return nil, fmt.Errorf("waiting for dummy app: %w", err)
}

Expand All @@ -72,7 +71,7 @@ func deployDummyApp(ctx context.Context, l logger, client *kubernetes.Clientset,
}, nil
}

func createDummyAppDeployment(ctx context.Context, l logger, client *kubernetes.Clientset, namespace string) error {
func createDummyAppDeployment(ctx context.Context, l logger, client *kubernetes.Clientset, name, namespace string) error {
labels := map[string]string{"app": name}

l.Logf("Creating dummy app %s", name)
Expand Down Expand Up @@ -116,7 +115,7 @@ func createDummyAppDeployment(ctx context.Context, l logger, client *kubernetes.
return nil
}

func createDummyAppService(ctx context.Context, client *kubernetes.Clientset, namespace string) error {
func createDummyAppService(ctx context.Context, client *kubernetes.Clientset, name, namespace string) error {
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Expand All @@ -141,7 +140,7 @@ func createDummyAppService(ctx context.Context, client *kubernetes.Clientset, na
return nil
}

func waitForDummyApp(ctx context.Context, l logger, client *kubernetes.Clientset, namespace string) error {
func waitForDummyApp(ctx context.Context, l logger, client *kubernetes.Clientset, name, namespace string) error {
l.Logf("Waiting for dummy app to be ready")
err := wait.PollUntilContextTimeout(ctx, 1*time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) {
dep, err := client.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{})
Expand Down
4 changes: 4 additions & 0 deletions e2e/gwapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"time"

"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
Expand Down Expand Up @@ -169,6 +170,9 @@ func createGatewayClasses(ctx context.Context, l logger, client *gwclientset.Cli
&gc,
metav1.CreateOptions{},
)
if errors.IsAlreadyExists(err) {
_, err = client.GatewayV1().GatewayClasses().Update(ctx, &gc, metav1.UpdateOptions{})
}
if err != nil {
return nil, fmt.Errorf("creating GatewayClass %s: %w", name.String(), err)
}
Expand Down
4 changes: 4 additions & 0 deletions e2e/gwapi_kong.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"time"

"helm.sh/helm/v4/pkg/cli"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
Expand Down Expand Up @@ -92,6 +93,9 @@ func deployGatewayAPIKong(

l.Logf("Creating GatewayClass %s", kongGatewayClass)
_, err := gwClient.GatewayV1().GatewayClasses().Create(ctx, gc, metav1.CreateOptions{})
if errors.IsAlreadyExists(err) {
_, err = gwClient.GatewayV1().GatewayClasses().Update(ctx, gc, metav1.UpdateOptions{})
}
if err != nil {
return nil, fmt.Errorf("creating GatewayClass: %w", err)
}
Expand Down
78 changes: 78 additions & 0 deletions e2e/ingress_nginx_canary_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
Copyright 2026 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package e2e

import (
"fmt"
"regexp"
"testing"

"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/providers/ingressnginx"
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/providers/istio"
"github.com/stretchr/testify/require"
networkingv1 "k8s.io/api/networking/v1"
)

func TestIngressNGINXCanary(t *testing.T) {
t.Parallel()
t.Run("to Istio", func(t *testing.T) {
t.Parallel()
t.Run("base canary", func(t *testing.T) {
suffix, err := randString()
require.NoError(t, err)
host := fmt.Sprintf("canary-%s.com", suffix)
Comment thread
Stevenjin8 marked this conversation as resolved.
runTestCase(t, &testCase{
gatewayImplementation: istio.ProviderName,
providers: []string{ingressnginx.Name},
providerFlags: map[string]map[string]string{
ingressnginx.Name: {
ingressnginx.NginxIngressClassFlag: ingressnginx.NginxIngressClass,
},
},
ingresses: []*networkingv1.Ingress{
basicIngress().
withName("foo1").
withHost(host).
withIngressClass(ingressnginx.NginxIngressClass).
build(),
basicIngress().
withName("foo2").
withHost(host).
withIngressClass(ingressnginx.NginxIngressClass).
withAnnotation("nginx.ingress.kubernetes.io/canary", "true").
withAnnotation("nginx.ingress.kubernetes.io/canary-weight", "20").
withBackend(DummyAppName2).
build(),
},
verifiers: map[string][]verifier{
"foo1": {
&canaryVerifier{
verifier: &httpRequestVerifier{
host: host,
path: "/hostname",
bodyRegex: regexp.MustCompile("^dummy-app2"),
},
runs: 200,
minSuccesses: 0.1,
maxSuccesses: 0.3,
},
},
},
})
})
})
}
Loading