Skip to content

Commit 4256f32

Browse files
ivanmatmatioktalz
authored andcommitted
TEST: add CORS e2e tests
1 parent 3ad3409 commit 4256f32

File tree

6 files changed

+334
-0
lines changed

6 files changed

+334
-0
lines changed

deploy/tests/e2e/client.go

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ func (c *Client) Do() (res *http.Response, close func() error, err error) {
121121
}
122122
}
123123
c.Req.Host = c.Host
124+
c.Req.Header["Origin"] = []string{c.Req.URL.Scheme + "://" + c.Host}
124125
c.Req.URL.Host = c.Host
125126
c.Req.URL.Path = c.Path
126127
res, err = client.Do(c.Req)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
kind: Deployment
3+
apiVersion: apps/v1
4+
metadata:
5+
name: http-echo
6+
spec:
7+
replicas: 1
8+
selector:
9+
matchLabels:
10+
app: http-echo
11+
template:
12+
metadata:
13+
labels:
14+
app: http-echo
15+
spec:
16+
containers:
17+
- name: http-echo
18+
image: haproxytech/http-echo:latest
19+
imagePullPolicy: Never
20+
args:
21+
- --default-response=hostname
22+
ports:
23+
- name: http
24+
containerPort: 8888
25+
protocol: TCP
26+
- name: https
27+
containerPort: 8443
28+
protocol: TCP
29+
---
30+
kind: Service
31+
apiVersion: v1
32+
metadata:
33+
name: http-echo
34+
spec:
35+
ports:
36+
- name: http
37+
protocol: TCP
38+
port: 80
39+
targetPort: http
40+
- name: https
41+
protocol: TCP
42+
port: 443
43+
targetPort: https
44+
selector:
45+
app: http-echo
46+
---
47+
kind: Ingress
48+
apiVersion: networking.k8s.io/v1beta1
49+
metadata:
50+
name: http-echo
51+
annotations:
52+
ingress.class: haproxy
53+
{{range .IngAnnotations}}
54+
{{ .Key }}: {{ .Value }}
55+
{{end}}
56+
spec:
57+
rules:
58+
- host: {{ .Host }}
59+
http:
60+
paths:
61+
- path: /
62+
backend:
63+
serviceName: http-echo
64+
servicePort: http
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: patternfiles
5+
namespace: haproxy-controller
6+
data:
7+
cors-allow-credentials: 'false'
8+
cors-allow-headers: >-
9+
x-api-key
10+
cors-allow-methods: GET, POST
11+
cors-allow-origin: >-
12+
^https://configmap.com?$
13+
cors-enable: 'true'
14+
cors-max-age: 100s
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: patternfiles
5+
namespace: haproxy-controller
6+
data: {}

deploy/tests/e2e/cors/cors_test.go

+192
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// Copyright 2019 HAProxy Technologies LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//go:build e2e_sequential
16+
17+
package cors
18+
19+
import (
20+
"net/http"
21+
22+
"github.com/haproxytech/kubernetes-ingress/deploy/tests/e2e"
23+
)
24+
25+
const (
26+
AccessControlAllowOrigin = "Access-Control-Allow-Origin"
27+
AccessControlAllowMethods = "Access-Control-Allow-Methods"
28+
AccessControlAllowHeaders = "Access-Control-Allow-Headers"
29+
AccessControlMaxAge = "Access-Control-Max-Age"
30+
AccessControlAllowCredential = "Access-Control-Allow-Credentials"
31+
AnnotationCorsEnable = "cors-enable"
32+
AnnotationCorsOrigin = "cors-allow-origin"
33+
AnnotationCorsMethods = "cors-allow-methods"
34+
AnnotationCorsHeaders = "cors-allow-headers"
35+
AnnotationCorsAge = "cors-max-age"
36+
AnnotationCorsCredential = "cors-allow-credentials"
37+
Star = "*"
38+
)
39+
40+
func (suite *CorsSuite) Test_Ingress_Alone() {
41+
suite.Run("Default", func() {
42+
expectedHeaders := http.Header{
43+
AccessControlAllowOrigin: {Star},
44+
AccessControlAllowMethods: {Star},
45+
AccessControlAllowHeaders: {Star},
46+
AccessControlMaxAge: {"5"},
47+
}
48+
suite.tmplData.IngAnnotations = []struct{ Key, Value string }{
49+
{AnnotationCorsEnable, q("true")},
50+
}
51+
52+
suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData))
53+
54+
suite.eventuallyReturns(expectedHeaders, http.Header{})
55+
})
56+
57+
suite.Run("CorsOriginAlone", func() {
58+
expectedHeaders := http.Header{
59+
AccessControlAllowOrigin: {"http://" + suite.tmplData.Host},
60+
AccessControlAllowMethods: {Star},
61+
AccessControlAllowHeaders: {Star},
62+
AccessControlMaxAge: {"5"},
63+
}
64+
suite.tmplData.IngAnnotations = []struct{ Key, Value string }{
65+
{AnnotationCorsEnable, q("true")},
66+
{AnnotationCorsOrigin, q("http://" + suite.tmplData.Host)},
67+
}
68+
69+
suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData))
70+
71+
suite.eventuallyReturns(expectedHeaders, http.Header{})
72+
})
73+
74+
suite.Run("CorsMethodsAlone", func() {
75+
expectedHeaders := http.Header{
76+
AccessControlAllowOrigin: {Star},
77+
AccessControlAllowMethods: {"GET"},
78+
AccessControlAllowHeaders: {Star},
79+
AccessControlMaxAge: {"5"},
80+
}
81+
suite.tmplData.IngAnnotations = []struct{ Key, Value string }{
82+
{AnnotationCorsEnable, q("true")},
83+
{AnnotationCorsMethods, q("GET")},
84+
}
85+
86+
suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData))
87+
88+
suite.eventuallyReturns(expectedHeaders, http.Header{})
89+
})
90+
91+
suite.Run("CorsMethodsHeaders", func() {
92+
expectedHeaders := http.Header{
93+
AccessControlAllowOrigin: {Star},
94+
AccessControlAllowMethods: {Star},
95+
AccessControlAllowHeaders: {"Accept"},
96+
AccessControlMaxAge: {"5"},
97+
}
98+
suite.tmplData.IngAnnotations = []struct{ Key, Value string }{
99+
{AnnotationCorsEnable, q("true")},
100+
{AnnotationCorsHeaders, q("Accept")},
101+
}
102+
103+
suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData))
104+
105+
suite.eventuallyReturns(expectedHeaders, http.Header{})
106+
})
107+
108+
suite.Run("CorsMethodsAge", func() {
109+
expectedHeaders := http.Header{
110+
AccessControlAllowOrigin: {Star},
111+
AccessControlAllowMethods: {Star},
112+
AccessControlAllowHeaders: {Star},
113+
AccessControlMaxAge: {"500"},
114+
}
115+
suite.tmplData.IngAnnotations = []struct{ Key, Value string }{
116+
{AnnotationCorsEnable, q("true")},
117+
{AnnotationCorsAge, q("500s")},
118+
}
119+
120+
suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData))
121+
122+
suite.eventuallyReturns(expectedHeaders, http.Header{})
123+
})
124+
125+
suite.Run("CorsMethodsCredential", func() {
126+
expectedHeaders := http.Header{
127+
AccessControlAllowOrigin: {Star},
128+
AccessControlAllowMethods: {Star},
129+
AccessControlAllowHeaders: {Star},
130+
AccessControlAllowCredential: {"true"},
131+
AccessControlMaxAge: {"5"},
132+
}
133+
suite.tmplData.IngAnnotations = []struct{ Key, Value string }{
134+
{AnnotationCorsEnable, q("true")},
135+
{AnnotationCorsCredential, q("true")},
136+
}
137+
138+
suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData))
139+
140+
suite.eventuallyReturns(expectedHeaders, http.Header{})
141+
})
142+
143+
suite.Run("CorsDisable", func() {
144+
unexpectedHeaders := http.Header{
145+
AccessControlAllowOrigin: {},
146+
AccessControlAllowMethods: {},
147+
AccessControlAllowHeaders: {},
148+
AccessControlMaxAge: {},
149+
AccessControlAllowCredential: {},
150+
}
151+
152+
suite.tmplData.IngAnnotations = []struct{ Key, Value string }{
153+
{AnnotationCorsEnable, q("false")},
154+
{AnnotationCorsOrigin, q("http://wrong.com")},
155+
{AnnotationCorsCredential, q("true")},
156+
{AnnotationCorsMethods, q("GET")},
157+
{AnnotationCorsHeaders, q("Accept")},
158+
}
159+
160+
suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData))
161+
162+
suite.eventuallyReturns(http.Header{}, unexpectedHeaders)
163+
})
164+
}
165+
166+
func (suite *CorsSuite) eventuallyReturns(expecedHeaders, unexpectedHeaders http.Header) {
167+
suite.Eventually(func() bool {
168+
res, cls, err := suite.client.Do()
169+
if err != nil {
170+
suite.T().Logf("Connection ERROR: %s", err.Error())
171+
return false
172+
}
173+
defer cls()
174+
for expectedHeader, expectedValues := range expecedHeaders {
175+
values, ok := res.Header[expectedHeader]
176+
if !ok || len(values) != 1 || values[0] != expectedValues[0] {
177+
return false
178+
}
179+
180+
}
181+
for unexpectedHeader := range unexpectedHeaders {
182+
if _, ok := res.Header[unexpectedHeader]; ok {
183+
return false
184+
}
185+
}
186+
return true
187+
}, e2e.WaitDuration, e2e.TickDuration)
188+
}
189+
190+
func q(value string) string {
191+
return "\"" + value + "\""
192+
}

deploy/tests/e2e/cors/suite_test.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2019 HAProxy Technologies LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//go:build e2e_sequential
16+
17+
package cors
18+
19+
import (
20+
"testing"
21+
22+
"github.com/stretchr/testify/suite"
23+
24+
"github.com/haproxytech/kubernetes-ingress/deploy/tests/e2e"
25+
)
26+
27+
type CorsSuite struct {
28+
suite.Suite
29+
test e2e.Test
30+
client *e2e.Client
31+
tmplData tmplData
32+
}
33+
34+
type tmplData struct {
35+
IngAnnotations []struct{ Key, Value string }
36+
Host string
37+
}
38+
39+
func (suite *CorsSuite) SetupSuite() {
40+
var err error
41+
suite.test, err = e2e.NewTest()
42+
suite.NoError(err)
43+
suite.tmplData = tmplData{Host: suite.test.GetNS() + ".test"}
44+
suite.client, err = e2e.NewHTTPClient(suite.tmplData.Host)
45+
suite.NoError(err)
46+
47+
suite.NoError(suite.test.Apply("config/patternfile-empty.yml", "", nil))
48+
}
49+
50+
func (suite *CorsSuite) TearDownSuite() {
51+
suite.test.Apply("config/patternfile-empty.yml", "", nil)
52+
suite.test.TearDown()
53+
}
54+
55+
func TestCorsSuite(t *testing.T) {
56+
suite.Run(t, new(CorsSuite))
57+
}

0 commit comments

Comments
 (0)