Skip to content

Commit c698f24

Browse files
Add mesh conformance tests for httproute path host and status redirect (#3777)
* add redirect-port and redirect scheme mesh tests * mesh tests for path host and status redirect
1 parent 344f8de commit c698f24

10 files changed

+682
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package meshtests
18+
19+
import (
20+
"testing"
21+
22+
"sigs.k8s.io/gateway-api/conformance/utils/echo"
23+
"sigs.k8s.io/gateway-api/conformance/utils/http"
24+
"sigs.k8s.io/gateway-api/conformance/utils/roundtripper"
25+
"sigs.k8s.io/gateway-api/conformance/utils/suite"
26+
"sigs.k8s.io/gateway-api/pkg/features"
27+
)
28+
29+
func init() {
30+
MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteRedirectHostAndStatus)
31+
}
32+
33+
var MeshHTTPRouteRedirectHostAndStatus = suite.ConformanceTest{
34+
ShortName: "MeshHTTPRouteRedirectHostAndStatus",
35+
Description: "An HTTPRoute with hostname and statusCode redirect filters",
36+
Features: []features.FeatureName{
37+
features.SupportMesh,
38+
features.SupportHTTPRoute,
39+
},
40+
Manifests: []string{"tests/mesh/httproute-redirect-host-and-status.yaml"},
41+
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
42+
ns := "gateway-conformance-mesh"
43+
client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1)
44+
45+
testCases := []http.ExpectedResponse{
46+
{
47+
Request: http.Request{
48+
Host: "echo",
49+
Path: "/hostname-redirect",
50+
UnfollowRedirect: true,
51+
},
52+
Response: http.Response{
53+
StatusCode: 302,
54+
},
55+
RedirectRequest: &roundtripper.RedirectRequest{
56+
Host: "example.org",
57+
},
58+
Namespace: ns,
59+
}, {
60+
Request: http.Request{
61+
Host: "echo",
62+
Path: "/host-and-status",
63+
UnfollowRedirect: true,
64+
},
65+
Response: http.Response{
66+
StatusCode: 301,
67+
},
68+
RedirectRequest: &roundtripper.RedirectRequest{
69+
Host: "example.org",
70+
},
71+
Namespace: ns,
72+
},
73+
}
74+
for i := range testCases {
75+
// Declare tc here to avoid loop variable
76+
// reuse issues across parallel tests.
77+
tc := testCases[i]
78+
t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
79+
t.Parallel()
80+
client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
81+
})
82+
}
83+
},
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
apiVersion: gateway.networking.k8s.io/v1
2+
kind: HTTPRoute
3+
metadata:
4+
name: mesh-redirect-host-and-status
5+
namespace: gateway-conformance-mesh
6+
spec:
7+
parentRefs:
8+
- group: ""
9+
kind: Service
10+
name: echo
11+
port: 80
12+
rules:
13+
- matches:
14+
- path:
15+
type: PathPrefix
16+
value: /hostname-redirect
17+
filters:
18+
- type: RequestRedirect
19+
requestRedirect:
20+
hostname: example.org
21+
- matches:
22+
- path:
23+
type: PathPrefix
24+
value: /host-and-status
25+
filters:
26+
- type: RequestRedirect
27+
requestRedirect:
28+
statusCode: 301
29+
hostname: example.org
30+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package meshtests
18+
19+
import (
20+
"testing"
21+
22+
"sigs.k8s.io/gateway-api/conformance/utils/echo"
23+
"sigs.k8s.io/gateway-api/conformance/utils/http"
24+
"sigs.k8s.io/gateway-api/conformance/utils/roundtripper"
25+
"sigs.k8s.io/gateway-api/conformance/utils/suite"
26+
"sigs.k8s.io/gateway-api/pkg/features"
27+
)
28+
29+
func init() {
30+
MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteRedirectPath)
31+
}
32+
33+
var MeshHTTPRouteRedirectPath = suite.ConformanceTest{
34+
ShortName: "MeshHTTPRouteRedirectPath",
35+
Description: "An HTTPRoute with scheme redirect filter",
36+
Manifests: []string{"tests/mesh/httproute-redirect-path.yaml"},
37+
Features: []features.FeatureName{
38+
features.SupportMesh,
39+
features.SupportHTTPRoute,
40+
features.SupportMeshHTTPRouteRedirectPath,
41+
},
42+
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
43+
ns := "gateway-conformance-mesh"
44+
client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1)
45+
46+
testCases := []http.ExpectedResponse{
47+
{
48+
Request: http.Request{
49+
Host: "echo",
50+
Path: "/original-prefix/lemon",
51+
UnfollowRedirect: true,
52+
},
53+
Response: http.Response{
54+
StatusCode: 302,
55+
},
56+
RedirectRequest: &roundtripper.RedirectRequest{
57+
Path: "/replacement-prefix/lemon",
58+
},
59+
Namespace: ns,
60+
}, {
61+
Request: http.Request{
62+
Host: "echo",
63+
Path: "/full/path/original",
64+
UnfollowRedirect: true,
65+
},
66+
Response: http.Response{
67+
StatusCode: 302,
68+
},
69+
RedirectRequest: &roundtripper.RedirectRequest{
70+
Path: "/full-path-replacement",
71+
},
72+
Namespace: ns,
73+
}, {
74+
Request: http.Request{
75+
Host: "echo",
76+
Path: "/path-and-host",
77+
UnfollowRedirect: true,
78+
},
79+
Response: http.Response{
80+
StatusCode: 302,
81+
},
82+
RedirectRequest: &roundtripper.RedirectRequest{
83+
Host: "example.org",
84+
Path: "/replacement-prefix",
85+
},
86+
Namespace: ns,
87+
}, {
88+
Request: http.Request{
89+
Host: "echo",
90+
Path: "/path-and-status",
91+
UnfollowRedirect: true,
92+
},
93+
Response: http.Response{
94+
StatusCode: 301,
95+
},
96+
RedirectRequest: &roundtripper.RedirectRequest{
97+
Path: "/replacement-prefix",
98+
},
99+
Namespace: ns,
100+
}, {
101+
Request: http.Request{
102+
Host: "echo",
103+
Path: "/full-path-and-host",
104+
UnfollowRedirect: true,
105+
},
106+
Response: http.Response{
107+
StatusCode: 302,
108+
},
109+
RedirectRequest: &roundtripper.RedirectRequest{
110+
Host: "example.org",
111+
Path: "/replacement-full",
112+
},
113+
Namespace: ns,
114+
}, {
115+
Request: http.Request{
116+
Host: "echo",
117+
Path: "/full-path-and-status",
118+
UnfollowRedirect: true,
119+
},
120+
Response: http.Response{
121+
StatusCode: 301,
122+
},
123+
RedirectRequest: &roundtripper.RedirectRequest{
124+
Path: "/replacement-full",
125+
},
126+
Namespace: ns,
127+
},
128+
}
129+
for i := range testCases {
130+
// Declare tc here to avoid loop variable
131+
// reuse issues across parallel tests.
132+
tc := testCases[i]
133+
t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
134+
t.Parallel()
135+
client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
136+
})
137+
}
138+
},
139+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
apiVersion: gateway.networking.k8s.io/v1
2+
kind: HTTPRoute
3+
metadata:
4+
name: mesh-redirect-path
5+
namespace: gateway-conformance-mesh
6+
spec:
7+
parentRefs:
8+
- group: ""
9+
kind: Service
10+
name: echo
11+
port: 80
12+
rules:
13+
- matches:
14+
- path:
15+
type: PathPrefix
16+
value: /original-prefix
17+
filters:
18+
- type: RequestRedirect
19+
requestRedirect:
20+
path:
21+
type: ReplacePrefixMatch
22+
replacePrefixMatch: /replacement-prefix
23+
- matches:
24+
- path:
25+
type: PathPrefix
26+
value: /full
27+
filters:
28+
- type: RequestRedirect
29+
requestRedirect:
30+
path:
31+
type: ReplaceFullPath
32+
replaceFullPath: /full-path-replacement
33+
- matches:
34+
- path:
35+
type: PathPrefix
36+
value: /path-and-host
37+
filters:
38+
- type: RequestRedirect
39+
requestRedirect:
40+
hostname: example.org
41+
path:
42+
type: ReplacePrefixMatch
43+
replacePrefixMatch: /replacement-prefix
44+
- matches:
45+
- path:
46+
type: PathPrefix
47+
value: /path-and-status
48+
filters:
49+
- type: RequestRedirect
50+
requestRedirect:
51+
path:
52+
type: ReplacePrefixMatch
53+
replacePrefixMatch: /replacement-prefix
54+
statusCode: 301
55+
- matches:
56+
- path:
57+
type: PathPrefix
58+
value: /full-path-and-host
59+
filters:
60+
- type: RequestRedirect
61+
requestRedirect:
62+
hostname: example.org
63+
path:
64+
type: ReplaceFullPath
65+
replaceFullPath: /replacement-full
66+
- matches:
67+
- path:
68+
type: PathPrefix
69+
value: /full-path-and-status
70+
filters:
71+
- type: RequestRedirect
72+
requestRedirect:
73+
path:
74+
type: ReplaceFullPath
75+
replaceFullPath: /replacement-full
76+
statusCode: 301

0 commit comments

Comments
 (0)