Skip to content

Commit 346e951

Browse files
authored
Basic GRPCRoute Conformance Tests (#2745)
* Build gRPC conformance server image * Add initial grpc conformance test server unit test * Add test for header echoing * Parameterize Echo and EchoTwo * Go fmt * First passing conformance test * Re-add tests * Add cross-platform codegen * Merge gRPC echo server into echo-basic binary and docker image * Review comments * Fix file inclusion * Skip boilerplate check for protobuf generated codee * Please the linter * Remove dangling grpc-echo unit test invocation * Add debug prints * Ensure GOPATH/bin is on the PATH * Remove debug prints * Account for #2829 * golint
1 parent 09f17e0 commit 346e951

27 files changed

+2553
-42
lines changed

conformance/base/manifests.yaml

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,3 +507,150 @@ spec:
507507
resources:
508508
requests:
509509
cpu: 10m
510+
---
511+
apiVersion: v1
512+
kind: Service
513+
metadata:
514+
name: grpc-infra-backend-v1
515+
namespace: gateway-conformance-infra
516+
spec:
517+
selector:
518+
app: grpc-infra-backend-v1
519+
ports:
520+
- protocol: TCP
521+
port: 8080
522+
targetPort: 3000
523+
---
524+
apiVersion: apps/v1
525+
kind: Deployment
526+
metadata:
527+
name: grpc-infra-backend-v1
528+
namespace: gateway-conformance-infra
529+
labels:
530+
app: grpc-infra-backend-v1
531+
spec:
532+
replicas: 2
533+
selector:
534+
matchLabels:
535+
app: grpc-infra-backend-v1
536+
template:
537+
metadata:
538+
labels:
539+
app: grpc-infra-backend-v1
540+
spec:
541+
containers:
542+
- name: grpc-infra-backend-v1
543+
# TODO: Migrate to gcr.io/k8s-staging-gateway-api once possible
544+
image: us-docker.pkg.dev/grpc-testing/testing-images-public/gateway-api/echo-basic:alpha1
545+
env:
546+
- name: POD_NAME
547+
valueFrom:
548+
fieldRef:
549+
fieldPath: metadata.name
550+
- name: NAMESPACE
551+
valueFrom:
552+
fieldRef:
553+
fieldPath: metadata.namespace
554+
- name: GRPC_ECHO_SERVER
555+
value: "1"
556+
resources:
557+
requests:
558+
cpu: 10m
559+
---
560+
apiVersion: v1
561+
kind: Service
562+
metadata:
563+
name: grpc-infra-backend-v2
564+
namespace: gateway-conformance-infra
565+
spec:
566+
selector:
567+
app: grpc-infra-backend-v2
568+
ports:
569+
- protocol: TCP
570+
port: 8080
571+
targetPort: 3000
572+
---
573+
apiVersion: apps/v1
574+
kind: Deployment
575+
metadata:
576+
name: grpc-infra-backend-v2
577+
namespace: gateway-conformance-infra
578+
labels:
579+
app: grpc-infra-backend-v2
580+
spec:
581+
replicas: 2
582+
selector:
583+
matchLabels:
584+
app: grpc-infra-backend-v2
585+
template:
586+
metadata:
587+
labels:
588+
app: grpc-infra-backend-v2
589+
spec:
590+
containers:
591+
- name: grpc-infra-backend-v2
592+
# TODO: Migrate to gcr.io/k8s-staging-gateway-api once possible
593+
image: us-docker.pkg.dev/grpc-testing/testing-images-public/gateway-api/echo-basic:alpha1
594+
env:
595+
- name: POD_NAME
596+
valueFrom:
597+
fieldRef:
598+
fieldPath: metadata.name
599+
- name: NAMESPACE
600+
valueFrom:
601+
fieldRef:
602+
fieldPath: metadata.namespace
603+
- name: GRPC_ECHO_SERVER
604+
value: "1"
605+
resources:
606+
requests:
607+
cpu: 10m
608+
---
609+
apiVersion: v1
610+
kind: Service
611+
metadata:
612+
name: grpc-infra-backend-v3
613+
namespace: gateway-conformance-infra
614+
spec:
615+
selector:
616+
app: grpc-infra-backend-v3
617+
ports:
618+
- protocol: TCP
619+
port: 8080
620+
targetPort: 3000
621+
---
622+
apiVersion: apps/v1
623+
kind: Deployment
624+
metadata:
625+
name: grpc-infra-backend-v3
626+
namespace: gateway-conformance-infra
627+
labels:
628+
app: grpc-infra-backend-v3
629+
spec:
630+
replicas: 2
631+
selector:
632+
matchLabels:
633+
app: grpc-infra-backend-v3
634+
template:
635+
metadata:
636+
labels:
637+
app: grpc-infra-backend-v3
638+
spec:
639+
containers:
640+
- name: grpc-infra-backend-v3
641+
# TODO: Migrate to gcr.io/k8s-staging-gateway-api once possible
642+
image: us-docker.pkg.dev/grpc-testing/testing-images-public/gateway-api/echo-basic:alpha1
643+
env:
644+
- name: POD_NAME
645+
valueFrom:
646+
fieldRef:
647+
fieldPath: metadata.name
648+
- name: NAMESPACE
649+
valueFrom:
650+
fieldRef:
651+
fieldPath: metadata.namespace
652+
- name: GRPC_ECHO_SERVER
653+
value: "1"
654+
resources:
655+
requests:
656+
cpu: 10m

conformance/echo-basic/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
echo-basic

conformance/echo-basic/.go.mod

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module sigs.k8s.io/gateway-api/conformance/echo-basic
2+
3+
go 1.21
4+
5+
require (
6+
golang.org/x/net v0.21.0
7+
google.golang.org/grpc v1.53.0
8+
google.golang.org/protobuf v1.28.1
9+
)
10+
11+
require (
12+
github.com/golang/protobuf v1.5.2 // indirect
13+
golang.org/x/sys v0.17.0 // indirect
14+
golang.org/x/text v0.14.0 // indirect
15+
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
16+
)

conformance/echo-basic/.go.sum

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
2+
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
3+
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
4+
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
5+
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
6+
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
7+
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
8+
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
9+
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
10+
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
11+
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
12+
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
13+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
14+
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
15+
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
16+
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
17+
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
18+
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
19+
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
20+
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
21+
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=

conformance/echo-basic/echo-basic.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import (
3333
"golang.org/x/net/http2"
3434
"golang.org/x/net/http2/h2c"
3535
"golang.org/x/net/websocket"
36+
37+
g "sigs.k8s.io/gateway-api/conformance/echo-basic/grpc"
3638
)
3739

3840
// RequestAssertions contains information about the request and the Ingress
@@ -62,7 +64,7 @@ type preserveSlashes struct {
6264
}
6365

6466
func (s *preserveSlashes) ServeHTTP(w http.ResponseWriter, r *http.Request) {
65-
r.URL.Path = strings.Replace(r.URL.Path, "//", "/", -1)
67+
r.URL.Path = strings.ReplaceAll(r.URL.Path, "//", "/")
6668
s.mux.ServeHTTP(w, r)
6769
}
6870

@@ -77,6 +79,11 @@ type Context struct {
7779
var context Context
7880

7981
func main() {
82+
if os.Getenv("GRPC_ECHO_SERVER") != "" {
83+
g.Main()
84+
return
85+
}
86+
8087
httpPort := os.Getenv("HTTP_PORT")
8188
if httpPort == "" {
8289
httpPort = "3000"
@@ -109,7 +116,7 @@ func main() {
109116

110117
go func() {
111118
fmt.Printf("Starting server, listening on port %s (http)\n", httpPort)
112-
err := http.ListenAndServe(fmt.Sprintf(":%s", httpPort), httpHandler)
119+
err := http.ListenAndServe(fmt.Sprintf(":%s", httpPort), httpHandler) //nolint:gosec
113120
if err != nil {
114121
errchan <- err
115122
}
@@ -137,12 +144,12 @@ func wsHandler(ws *websocket.Conn) {
137144
fmt.Println("established websocket connection", ws.RemoteAddr())
138145
// Echo websocket frames from the connection back to the client
139146
// until io.EOF
140-
io.Copy(ws, ws)
147+
_, _ = io.Copy(ws, ws)
141148
}
142149

143-
func healthHandler(w http.ResponseWriter, r *http.Request) {
150+
func healthHandler(w http.ResponseWriter, r *http.Request) { //nolint:revive
144151
w.WriteHeader(200)
145-
w.Write([]byte(`OK`))
152+
_, _ = w.Write([]byte(`OK`))
146153
}
147154

148155
func statusHandler(w http.ResponseWriter, r *http.Request) {
@@ -224,7 +231,7 @@ func echoHandler(w http.ResponseWriter, r *http.Request) {
224231
writeEchoResponseHeaders(w, r.Header)
225232
w.Header().Set("Content-Type", "application/json")
226233
w.Header().Set("X-Content-Type-Options", "nosniff")
227-
w.Write(js)
234+
_, _ = w.Write(js)
228235
}
229236

230237
func writeEchoResponseHeaders(w http.ResponseWriter, headers http.Header) {
@@ -242,7 +249,7 @@ func writeEchoResponseHeaders(w http.ResponseWriter, headers http.Header) {
242249
}
243250
}
244251

245-
func processError(w http.ResponseWriter, err error, code int) {
252+
func processError(w http.ResponseWriter, err error, code int) { //nolint:unparam
246253
w.Header().Set("Content-Type", "application/json")
247254
w.Header().Set("X-Content-Type-Options", "nosniff")
248255
body, err := json.Marshal(struct {
@@ -257,7 +264,7 @@ func processError(w http.ResponseWriter, err error, code int) {
257264
}
258265

259266
w.WriteHeader(code)
260-
w.Write(body)
267+
_, _ = w.Write(body)
261268
}
262269

263270
func listenAndServeTLS(addr string, serverCert string, serverPrivKey string, clientCA string, handler http.Handler) error {
@@ -280,7 +287,7 @@ func listenAndServeTLS(addr string, serverCert string, serverPrivKey string, cli
280287
config.ClientCAs = certPool
281288
}
282289

283-
srv := &http.Server{
290+
srv := &http.Server{ //nolint:gosec
284291
Addr: addr,
285292
Handler: handler,
286293
TLSConfig: &config,
@@ -311,11 +318,15 @@ func tlsStateToAssertions(connectionState *tls.ConnectionState) *TLSAssertions {
311318
// Convert peer certificates to PEM blocks.
312319
for _, c := range connectionState.PeerCertificates {
313320
var out strings.Builder
314-
pem.Encode(&out, &pem.Block{
321+
err := pem.Encode(&out, &pem.Block{
315322
Type: "CERTIFICATE",
316323
Bytes: c.Raw,
317324
})
318-
state.PeerCertificates = append(state.PeerCertificates, out.String())
325+
if err != nil {
326+
fmt.Printf("failed to encode certificate: %v\n", err)
327+
} else {
328+
state.PeerCertificates = append(state.PeerCertificates, out.String())
329+
}
319330
}
320331

321332
return &state

conformance/echo-basic/echo-basic_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929

3030
func TestHealthHandler(t *testing.T) {
3131
// Test a valid health check
32-
req, err := http.NewRequest("GET", "/health", nil)
32+
req, err := http.NewRequest("GET", "/health", nil) //nolint:noctx
3333
if err != nil {
3434
t.Fatal(err)
3535
}
@@ -50,7 +50,7 @@ func TestHealthHandler(t *testing.T) {
5050

5151
func TestDelayResponse(t *testing.T) {
5252
// Test with a valid delay integer value
53-
req, err := http.NewRequest("GET", "/?delay=1s", nil)
53+
req, err := http.NewRequest("GET", "/?delay=1s", nil) //nolint:noctx
5454
if err != nil {
5555
t.Fatal(err)
5656
}
@@ -61,7 +61,7 @@ func TestDelayResponse(t *testing.T) {
6161
}
6262

6363
// Test with a valid delay decimal value
64-
req, err = http.NewRequest("GET", "/?delay=0.1s", nil)
64+
req, err = http.NewRequest("GET", "/?delay=0.1s", nil) //nolint:noctx
6565
if err != nil {
6666
t.Fatal(err)
6767
}
@@ -72,7 +72,7 @@ func TestDelayResponse(t *testing.T) {
7272
}
7373

7474
// Test with an invalid delay value
75-
req, err = http.NewRequest("GET", "/?delay=invalid", nil)
75+
req, err = http.NewRequest("GET", "/?delay=invalid", nil) //nolint:noctx
7676
if err != nil {
7777
t.Fatal(err)
7878
}

conformance/echo-basic/go.mod

Lines changed: 0 additions & 7 deletions
This file was deleted.

conformance/echo-basic/go.sum

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)