aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/google.golang.org/grpc/interop/http2/negative_http2_client.go
blob: b8c1d522009e71e3c49f086421296cd64b11adde (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
 *
 * Copyright 2016 gRPC 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.
 *
 */

// Binary http2 is used to test http2 error edge cases like GOAWAYs and
// RST_STREAMs
//
// Documentation:
// https://github.com/grpc/grpc/blob/master/doc/negative-http2-interop-test-descriptions.md
package main

import (
	"context"
	"flag"
	"net"
	"strconv"
	"sync"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/grpclog"
	"google.golang.org/grpc/interop"
	"google.golang.org/grpc/status"

	testgrpc "google.golang.org/grpc/interop/grpc_testing"
	testpb "google.golang.org/grpc/interop/grpc_testing"
)

var (
	serverHost = flag.String("server_host", "localhost", "The server host name")
	serverPort = flag.Int("server_port", 8080, "The server port number")
	testCase   = flag.String("test_case", "goaway",
		`Configure different test cases. Valid options are:
        goaway : client sends two requests, the server will send a goaway in between;
        rst_after_header : server will send rst_stream after it sends headers;
        rst_during_data : server will send rst_stream while sending data;
        rst_after_data : server will send rst_stream after sending data;
        ping : server will send pings between each http2 frame;
        max_streams : server will ensure that the max_concurrent_streams limit is upheld;`)
	largeReqSize  = 271828
	largeRespSize = 314159

	logger = grpclog.Component("interop")
)

func largeSimpleRequest() *testpb.SimpleRequest {
	pl := interop.ClientNewPayload(testpb.PayloadType_COMPRESSABLE, largeReqSize)
	return &testpb.SimpleRequest{
		ResponseType: testpb.PayloadType_COMPRESSABLE,
		ResponseSize: int32(largeRespSize),
		Payload:      pl,
	}
}

// sends two unary calls. The server asserts that the calls use different connections.
func goaway(tc testgrpc.TestServiceClient) {
	interop.DoLargeUnaryCall(tc)
	// sleep to ensure that the client has time to recv the GOAWAY.
	// TODO(ncteisen): make this less hacky.
	time.Sleep(1 * time.Second)
	interop.DoLargeUnaryCall(tc)
}

func rstAfterHeader(tc testgrpc.TestServiceClient) {
	req := largeSimpleRequest()
	reply, err := tc.UnaryCall(context.Background(), req)
	if reply != nil {
		logger.Fatal("Client received reply despite server sending rst stream after header")
	}
	if status.Code(err) != codes.Internal {
		logger.Fatalf("%v.UnaryCall() = _, %v, want _, %v", tc, status.Code(err), codes.Internal)
	}
}

func rstDuringData(tc testgrpc.TestServiceClient) {
	req := largeSimpleRequest()
	reply, err := tc.UnaryCall(context.Background(), req)
	if reply != nil {
		logger.Fatal("Client received reply despite server sending rst stream during data")
	}
	if status.Code(err) != codes.Unknown {
		logger.Fatalf("%v.UnaryCall() = _, %v, want _, %v", tc, status.Code(err), codes.Unknown)
	}
}

func rstAfterData(tc testgrpc.TestServiceClient) {
	req := largeSimpleRequest()
	reply, err := tc.UnaryCall(context.Background(), req)
	if reply != nil {
		logger.Fatal("Client received reply despite server sending rst stream after data")
	}
	if status.Code(err) != codes.Internal {
		logger.Fatalf("%v.UnaryCall() = _, %v, want _, %v", tc, status.Code(err), codes.Internal)
	}
}

func ping(tc testgrpc.TestServiceClient) {
	// The server will assert that every ping it sends was ACK-ed by the client.
	interop.DoLargeUnaryCall(tc)
}

func maxStreams(tc testgrpc.TestServiceClient) {
	interop.DoLargeUnaryCall(tc)
	var wg sync.WaitGroup
	for i := 0; i < 15; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			interop.DoLargeUnaryCall(tc)
		}()
	}
	wg.Wait()
}

func main() {
	flag.Parse()
	serverAddr := net.JoinHostPort(*serverHost, strconv.Itoa(*serverPort))
	var opts []grpc.DialOption
	opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
	conn, err := grpc.Dial(serverAddr, opts...)
	if err != nil {
		logger.Fatalf("Fail to dial: %v", err)
	}
	defer conn.Close()
	tc := testgrpc.NewTestServiceClient(conn)
	switch *testCase {
	case "goaway":
		goaway(tc)
		logger.Infoln("goaway done")
	case "rst_after_header":
		rstAfterHeader(tc)
		logger.Infoln("rst_after_header done")
	case "rst_during_data":
		rstDuringData(tc)
		logger.Infoln("rst_during_data done")
	case "rst_after_data":
		rstAfterData(tc)
		logger.Infoln("rst_after_data done")
	case "ping":
		ping(tc)
		logger.Infoln("ping done")
	case "max_streams":
		maxStreams(tc)
		logger.Infoln("max_streams done")
	default:
		logger.Fatal("Unsupported test case: ", *testCase)
	}
}