xref: /aosp_15_r20/external/pigweed/pw_grpc/integration_test.go (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker// Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker//
3*61c4878aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker// use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker// the License at
6*61c4878aSAndroid Build Coastguard Worker//
7*61c4878aSAndroid Build Coastguard Worker//	https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker//
9*61c4878aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker// License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker// the License.
14*61c4878aSAndroid Build Coastguard Worker//
15*61c4878aSAndroid Build Coastguard Worker// Package integration_test implements a client to exercise the pw_grpc server implementation
16*61c4878aSAndroid Build Coastguard Workerpackage integration_test
17*61c4878aSAndroid Build Coastguard Worker
18*61c4878aSAndroid Build Coastguard Workerimport (
19*61c4878aSAndroid Build Coastguard Worker	"bufio"
20*61c4878aSAndroid Build Coastguard Worker	"context"
21*61c4878aSAndroid Build Coastguard Worker	"fmt"
22*61c4878aSAndroid Build Coastguard Worker	"hash/crc32"
23*61c4878aSAndroid Build Coastguard Worker	"io"
24*61c4878aSAndroid Build Coastguard Worker	"os/exec"
25*61c4878aSAndroid Build Coastguard Worker	"strconv"
26*61c4878aSAndroid Build Coastguard Worker	"strings"
27*61c4878aSAndroid Build Coastguard Worker	"testing"
28*61c4878aSAndroid Build Coastguard Worker	"time"
29*61c4878aSAndroid Build Coastguard Worker
30*61c4878aSAndroid Build Coastguard Worker	"google.golang.org/grpc"
31*61c4878aSAndroid Build Coastguard Worker	"google.golang.org/grpc/codes"
32*61c4878aSAndroid Build Coastguard Worker	"google.golang.org/grpc/credentials/insecure"
33*61c4878aSAndroid Build Coastguard Worker	pb "google.golang.org/grpc/examples/features/proto/echo"
34*61c4878aSAndroid Build Coastguard Worker	"google.golang.org/grpc/status"
35*61c4878aSAndroid Build Coastguard Worker)
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard Workerconst port = "3402"
38*61c4878aSAndroid Build Coastguard Worker
39*61c4878aSAndroid Build Coastguard Workerfunc TestUnaryEcho(t *testing.T) {
40*61c4878aSAndroid Build Coastguard Worker	const num_connections = 1
41*61c4878aSAndroid Build Coastguard Worker	cmd, reader, err := launchServer(t, num_connections)
42*61c4878aSAndroid Build Coastguard Worker	if err != nil {
43*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to launch %v", err)
44*61c4878aSAndroid Build Coastguard Worker	}
45*61c4878aSAndroid Build Coastguard Worker	defer cmd.Wait()
46*61c4878aSAndroid Build Coastguard Worker
47*61c4878aSAndroid Build Coastguard Worker	conn, echo_client, err := connectServer()
48*61c4878aSAndroid Build Coastguard Worker	if err != nil {
49*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to connect %v", err)
50*61c4878aSAndroid Build Coastguard Worker	}
51*61c4878aSAndroid Build Coastguard Worker	defer conn.Close()
52*61c4878aSAndroid Build Coastguard Worker	go logServer(t, reader)
53*61c4878aSAndroid Build Coastguard Worker
54*61c4878aSAndroid Build Coastguard Worker	testRPC(t, func(t *testing.T, ctx context.Context, msg string) {
55*61c4878aSAndroid Build Coastguard Worker		t.Logf("call UnaryEcho(%v)", msg)
56*61c4878aSAndroid Build Coastguard Worker		resp, err := echo_client.UnaryEcho(ctx, &pb.EchoRequest{Message: msg})
57*61c4878aSAndroid Build Coastguard Worker		if err != nil {
58*61c4878aSAndroid Build Coastguard Worker			t.Logf("... failed with error: %v", err.Error())
59*61c4878aSAndroid Build Coastguard Worker			if msg != "quiet" || status.Convert(err).Code() != codes.Canceled {
60*61c4878aSAndroid Build Coastguard Worker				t.Errorf("Error unexpected %v", err)
61*61c4878aSAndroid Build Coastguard Worker			}
62*61c4878aSAndroid Build Coastguard Worker		} else {
63*61c4878aSAndroid Build Coastguard Worker			t.Logf("... Recv %v", resp)
64*61c4878aSAndroid Build Coastguard Worker			if resp.Message != msg {
65*61c4878aSAndroid Build Coastguard Worker				t.Errorf("Unexpected response %v", resp)
66*61c4878aSAndroid Build Coastguard Worker			}
67*61c4878aSAndroid Build Coastguard Worker		}
68*61c4878aSAndroid Build Coastguard Worker	})
69*61c4878aSAndroid Build Coastguard Worker}
70*61c4878aSAndroid Build Coastguard Worker
71*61c4878aSAndroid Build Coastguard Workerfunc TestFragmentedMessage(t *testing.T) {
72*61c4878aSAndroid Build Coastguard Worker	// Test sending successively larger messages, larger than the maximum
73*61c4878aSAndroid Build Coastguard Worker	// HTTP2 data frame size (16384), ensuring messages are fragmented across
74*61c4878aSAndroid Build Coastguard Worker	// frames.
75*61c4878aSAndroid Build Coastguard Worker	const num_connections = 1
76*61c4878aSAndroid Build Coastguard Worker	cmd, reader, err := launchServer(t, num_connections)
77*61c4878aSAndroid Build Coastguard Worker	if err != nil {
78*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to launch %v", err)
79*61c4878aSAndroid Build Coastguard Worker	}
80*61c4878aSAndroid Build Coastguard Worker	defer cmd.Wait()
81*61c4878aSAndroid Build Coastguard Worker
82*61c4878aSAndroid Build Coastguard Worker	conn, echo_client, err := connectServer()
83*61c4878aSAndroid Build Coastguard Worker	if err != nil {
84*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to connect %v", err)
85*61c4878aSAndroid Build Coastguard Worker	}
86*61c4878aSAndroid Build Coastguard Worker	defer conn.Close()
87*61c4878aSAndroid Build Coastguard Worker	go logServer(t, reader)
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard Worker	const num_calls = 4
90*61c4878aSAndroid Build Coastguard Worker	for i := 0; i < num_calls; i++ {
91*61c4878aSAndroid Build Coastguard Worker		t.Run(fmt.Sprintf("%d of %d", i+1, num_calls), func(t *testing.T) {
92*61c4878aSAndroid Build Coastguard Worker			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
93*61c4878aSAndroid Build Coastguard Worker			defer cancel()
94*61c4878aSAndroid Build Coastguard Worker
95*61c4878aSAndroid Build Coastguard Worker			msg := "crc32:" + strings.Repeat("testmessage!", 1500*(i+1))
96*61c4878aSAndroid Build Coastguard Worker			checksum := strconv.FormatUint(uint64(crc32.ChecksumIEEE([]byte(msg))), 10)
97*61c4878aSAndroid Build Coastguard Worker
98*61c4878aSAndroid Build Coastguard Worker			done := make(chan struct{})
99*61c4878aSAndroid Build Coastguard Worker			go func() {
100*61c4878aSAndroid Build Coastguard Worker				t.Logf("call UnaryChecksum")
101*61c4878aSAndroid Build Coastguard Worker				resp, err := echo_client.UnaryEcho(ctx, &pb.EchoRequest{Message: msg})
102*61c4878aSAndroid Build Coastguard Worker				if err != nil {
103*61c4878aSAndroid Build Coastguard Worker					t.Logf("... failed with error: %v", err.Error())
104*61c4878aSAndroid Build Coastguard Worker					if msg != "quiet" || status.Convert(err).Code() != codes.Canceled {
105*61c4878aSAndroid Build Coastguard Worker						t.Errorf("Error unexpected %v", err)
106*61c4878aSAndroid Build Coastguard Worker					}
107*61c4878aSAndroid Build Coastguard Worker				} else {
108*61c4878aSAndroid Build Coastguard Worker					t.Logf("... Recv %v", resp)
109*61c4878aSAndroid Build Coastguard Worker					if resp.Message != checksum {
110*61c4878aSAndroid Build Coastguard Worker						t.Errorf("Unexpected response %v", resp)
111*61c4878aSAndroid Build Coastguard Worker					}
112*61c4878aSAndroid Build Coastguard Worker				}
113*61c4878aSAndroid Build Coastguard Worker				close(done)
114*61c4878aSAndroid Build Coastguard Worker			}()
115*61c4878aSAndroid Build Coastguard Worker			<-done
116*61c4878aSAndroid Build Coastguard Worker		})
117*61c4878aSAndroid Build Coastguard Worker	}
118*61c4878aSAndroid Build Coastguard Worker}
119*61c4878aSAndroid Build Coastguard Worker
120*61c4878aSAndroid Build Coastguard Workerfunc TestMultipleConnections(t *testing.T) {
121*61c4878aSAndroid Build Coastguard Worker	const num_connections = 3
122*61c4878aSAndroid Build Coastguard Worker	cmd, reader, err := launchServer(t, num_connections)
123*61c4878aSAndroid Build Coastguard Worker	if err != nil {
124*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to launch %v", err)
125*61c4878aSAndroid Build Coastguard Worker	}
126*61c4878aSAndroid Build Coastguard Worker	defer cmd.Wait()
127*61c4878aSAndroid Build Coastguard Worker
128*61c4878aSAndroid Build Coastguard Worker	go logServer(t, reader)
129*61c4878aSAndroid Build Coastguard Worker
130*61c4878aSAndroid Build Coastguard Worker	for i := 0; i < num_connections; i++ {
131*61c4878aSAndroid Build Coastguard Worker		t.Run(fmt.Sprintf("connection %d of %d", i+1, num_connections), func(t *testing.T) {
132*61c4878aSAndroid Build Coastguard Worker			conn, echo_client, err := connectServer()
133*61c4878aSAndroid Build Coastguard Worker			if err != nil {
134*61c4878aSAndroid Build Coastguard Worker				t.Errorf("Failed to connect %v", err)
135*61c4878aSAndroid Build Coastguard Worker			}
136*61c4878aSAndroid Build Coastguard Worker
137*61c4878aSAndroid Build Coastguard Worker			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
138*61c4878aSAndroid Build Coastguard Worker			defer cancel()
139*61c4878aSAndroid Build Coastguard Worker
140*61c4878aSAndroid Build Coastguard Worker			resp, err := echo_client.UnaryEcho(ctx, &pb.EchoRequest{Message: "message0"})
141*61c4878aSAndroid Build Coastguard Worker			if err != nil {
142*61c4878aSAndroid Build Coastguard Worker				t.Errorf("... failed with error: %v", err.Error())
143*61c4878aSAndroid Build Coastguard Worker			} else {
144*61c4878aSAndroid Build Coastguard Worker				t.Logf("... Recv %v", resp)
145*61c4878aSAndroid Build Coastguard Worker				if resp.Message != "message0" {
146*61c4878aSAndroid Build Coastguard Worker					t.Errorf("Unexpected response %v", resp)
147*61c4878aSAndroid Build Coastguard Worker				}
148*61c4878aSAndroid Build Coastguard Worker			}
149*61c4878aSAndroid Build Coastguard Worker
150*61c4878aSAndroid Build Coastguard Worker			conn.Close()
151*61c4878aSAndroid Build Coastguard Worker		})
152*61c4878aSAndroid Build Coastguard Worker	}
153*61c4878aSAndroid Build Coastguard Worker}
154*61c4878aSAndroid Build Coastguard Worker
155*61c4878aSAndroid Build Coastguard Workerfunc TestServerStreamingEcho(t *testing.T) {
156*61c4878aSAndroid Build Coastguard Worker	const num_connections = 1
157*61c4878aSAndroid Build Coastguard Worker	cmd, reader, err := launchServer(t, num_connections)
158*61c4878aSAndroid Build Coastguard Worker	if err != nil {
159*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to launch %v", err)
160*61c4878aSAndroid Build Coastguard Worker	}
161*61c4878aSAndroid Build Coastguard Worker	defer cmd.Wait()
162*61c4878aSAndroid Build Coastguard Worker
163*61c4878aSAndroid Build Coastguard Worker	conn, echo_client, err := connectServer()
164*61c4878aSAndroid Build Coastguard Worker	if err != nil {
165*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to connect %v", err)
166*61c4878aSAndroid Build Coastguard Worker	}
167*61c4878aSAndroid Build Coastguard Worker	defer conn.Close()
168*61c4878aSAndroid Build Coastguard Worker	go logServer(t, reader)
169*61c4878aSAndroid Build Coastguard Worker
170*61c4878aSAndroid Build Coastguard Worker	testRPC(t, func(t *testing.T, ctx context.Context, msg string) {
171*61c4878aSAndroid Build Coastguard Worker		t.Logf("call ServerStreamingEcho(%v)", msg)
172*61c4878aSAndroid Build Coastguard Worker		client, err := echo_client.ServerStreamingEcho(ctx, &pb.EchoRequest{Message: msg})
173*61c4878aSAndroid Build Coastguard Worker		if err != nil {
174*61c4878aSAndroid Build Coastguard Worker			t.Errorf("... failed with error: %v", err)
175*61c4878aSAndroid Build Coastguard Worker			return
176*61c4878aSAndroid Build Coastguard Worker		}
177*61c4878aSAndroid Build Coastguard Worker		for {
178*61c4878aSAndroid Build Coastguard Worker			resp, err := client.Recv()
179*61c4878aSAndroid Build Coastguard Worker			if err == io.EOF {
180*61c4878aSAndroid Build Coastguard Worker				t.Logf("... completed")
181*61c4878aSAndroid Build Coastguard Worker				return
182*61c4878aSAndroid Build Coastguard Worker			}
183*61c4878aSAndroid Build Coastguard Worker			if err != nil {
184*61c4878aSAndroid Build Coastguard Worker				t.Logf("... Recv failed with error: %v", err)
185*61c4878aSAndroid Build Coastguard Worker				if msg != "quiet" || status.Convert(err).Code() != codes.Canceled {
186*61c4878aSAndroid Build Coastguard Worker					t.Errorf("Error unexpected %v", err)
187*61c4878aSAndroid Build Coastguard Worker				}
188*61c4878aSAndroid Build Coastguard Worker				return
189*61c4878aSAndroid Build Coastguard Worker			}
190*61c4878aSAndroid Build Coastguard Worker			t.Logf("... Recv %v", resp)
191*61c4878aSAndroid Build Coastguard Worker			if resp.Message != msg && resp.Message != "done" {
192*61c4878aSAndroid Build Coastguard Worker				t.Errorf("Unexpected response %v", resp)
193*61c4878aSAndroid Build Coastguard Worker			}
194*61c4878aSAndroid Build Coastguard Worker		}
195*61c4878aSAndroid Build Coastguard Worker	})
196*61c4878aSAndroid Build Coastguard Worker}
197*61c4878aSAndroid Build Coastguard Worker
198*61c4878aSAndroid Build Coastguard Workerfunc TestClientStreamingEcho(t *testing.T) {
199*61c4878aSAndroid Build Coastguard Worker	const num_connections = 1
200*61c4878aSAndroid Build Coastguard Worker	cmd, reader, err := launchServer(t, num_connections)
201*61c4878aSAndroid Build Coastguard Worker	if err != nil {
202*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to launch %v", err)
203*61c4878aSAndroid Build Coastguard Worker	}
204*61c4878aSAndroid Build Coastguard Worker	defer cmd.Wait()
205*61c4878aSAndroid Build Coastguard Worker
206*61c4878aSAndroid Build Coastguard Worker	conn, echo_client, err := connectServer()
207*61c4878aSAndroid Build Coastguard Worker	if err != nil {
208*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to connect %v", err)
209*61c4878aSAndroid Build Coastguard Worker	}
210*61c4878aSAndroid Build Coastguard Worker	defer conn.Close()
211*61c4878aSAndroid Build Coastguard Worker	go logServer(t, reader)
212*61c4878aSAndroid Build Coastguard Worker
213*61c4878aSAndroid Build Coastguard Worker	testRPC(t, func(t *testing.T, ctx context.Context, msg string) {
214*61c4878aSAndroid Build Coastguard Worker		t.Logf("call ClientStreamingEcho()")
215*61c4878aSAndroid Build Coastguard Worker		client, err := echo_client.ClientStreamingEcho(ctx)
216*61c4878aSAndroid Build Coastguard Worker		if err != nil {
217*61c4878aSAndroid Build Coastguard Worker			t.Errorf("... failed with error: %v", err)
218*61c4878aSAndroid Build Coastguard Worker			return
219*61c4878aSAndroid Build Coastguard Worker		}
220*61c4878aSAndroid Build Coastguard Worker		for i := 0; i < 3; i++ {
221*61c4878aSAndroid Build Coastguard Worker			t.Logf("... Send %v", msg)
222*61c4878aSAndroid Build Coastguard Worker			if err := client.Send(&pb.EchoRequest{Message: msg}); err != nil {
223*61c4878aSAndroid Build Coastguard Worker				t.Errorf("... Send failed with error: %v", err)
224*61c4878aSAndroid Build Coastguard Worker				return
225*61c4878aSAndroid Build Coastguard Worker			}
226*61c4878aSAndroid Build Coastguard Worker		}
227*61c4878aSAndroid Build Coastguard Worker		if err := client.CloseSend(); err != nil {
228*61c4878aSAndroid Build Coastguard Worker			t.Errorf("... CloseSend failed with error: %v", err)
229*61c4878aSAndroid Build Coastguard Worker			return
230*61c4878aSAndroid Build Coastguard Worker		}
231*61c4878aSAndroid Build Coastguard Worker		resp, err := client.CloseAndRecv()
232*61c4878aSAndroid Build Coastguard Worker		if err != nil {
233*61c4878aSAndroid Build Coastguard Worker			t.Logf("... CloseAndRecv failed with error: %v", err)
234*61c4878aSAndroid Build Coastguard Worker			if msg != "quiet" || status.Convert(err).Code() != codes.Canceled {
235*61c4878aSAndroid Build Coastguard Worker				t.Errorf("Error unexpected %v", err)
236*61c4878aSAndroid Build Coastguard Worker			}
237*61c4878aSAndroid Build Coastguard Worker		} else {
238*61c4878aSAndroid Build Coastguard Worker			t.Logf("... CloseAndRecv %v", resp)
239*61c4878aSAndroid Build Coastguard Worker			if resp.Message != "done" {
240*61c4878aSAndroid Build Coastguard Worker				t.Errorf("Unexpected response %v", resp)
241*61c4878aSAndroid Build Coastguard Worker			}
242*61c4878aSAndroid Build Coastguard Worker		}
243*61c4878aSAndroid Build Coastguard Worker	})
244*61c4878aSAndroid Build Coastguard Worker}
245*61c4878aSAndroid Build Coastguard Worker
246*61c4878aSAndroid Build Coastguard Workerfunc TestBidirectionalStreamingEcho(t *testing.T) {
247*61c4878aSAndroid Build Coastguard Worker	const num_connections = 1
248*61c4878aSAndroid Build Coastguard Worker	cmd, reader, err := launchServer(t, num_connections)
249*61c4878aSAndroid Build Coastguard Worker	if err != nil {
250*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to launch %v", err)
251*61c4878aSAndroid Build Coastguard Worker	}
252*61c4878aSAndroid Build Coastguard Worker	defer cmd.Wait()
253*61c4878aSAndroid Build Coastguard Worker
254*61c4878aSAndroid Build Coastguard Worker	conn, echo_client, err := connectServer()
255*61c4878aSAndroid Build Coastguard Worker	if err != nil {
256*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to connect %v", err)
257*61c4878aSAndroid Build Coastguard Worker	}
258*61c4878aSAndroid Build Coastguard Worker	defer conn.Close()
259*61c4878aSAndroid Build Coastguard Worker	go logServer(t, reader)
260*61c4878aSAndroid Build Coastguard Worker
261*61c4878aSAndroid Build Coastguard Worker	testRPC(t, func(t *testing.T, ctx context.Context, msg string) {
262*61c4878aSAndroid Build Coastguard Worker		t.Logf("call BidirectionalStreamingEcho()")
263*61c4878aSAndroid Build Coastguard Worker		client, err := echo_client.BidirectionalStreamingEcho(ctx)
264*61c4878aSAndroid Build Coastguard Worker		if err != nil {
265*61c4878aSAndroid Build Coastguard Worker			t.Logf("... failed with error: %v", err)
266*61c4878aSAndroid Build Coastguard Worker			return
267*61c4878aSAndroid Build Coastguard Worker		}
268*61c4878aSAndroid Build Coastguard Worker		for i := 0; i < 3; i++ {
269*61c4878aSAndroid Build Coastguard Worker			t.Logf("... Send %v", msg)
270*61c4878aSAndroid Build Coastguard Worker			if err := client.Send(&pb.EchoRequest{Message: msg}); err != nil {
271*61c4878aSAndroid Build Coastguard Worker				t.Errorf("... Send failed with error: %v", err)
272*61c4878aSAndroid Build Coastguard Worker				return
273*61c4878aSAndroid Build Coastguard Worker			}
274*61c4878aSAndroid Build Coastguard Worker		}
275*61c4878aSAndroid Build Coastguard Worker		if err := client.CloseSend(); err != nil {
276*61c4878aSAndroid Build Coastguard Worker			t.Logf("... CloseSend failed with error: %v", err)
277*61c4878aSAndroid Build Coastguard Worker			return
278*61c4878aSAndroid Build Coastguard Worker		}
279*61c4878aSAndroid Build Coastguard Worker		for {
280*61c4878aSAndroid Build Coastguard Worker			resp, err := client.Recv()
281*61c4878aSAndroid Build Coastguard Worker			if err == io.EOF {
282*61c4878aSAndroid Build Coastguard Worker				t.Logf("... completed")
283*61c4878aSAndroid Build Coastguard Worker				return
284*61c4878aSAndroid Build Coastguard Worker			}
285*61c4878aSAndroid Build Coastguard Worker			if err != nil {
286*61c4878aSAndroid Build Coastguard Worker				t.Logf("... Recv failed with error: %v", err)
287*61c4878aSAndroid Build Coastguard Worker				if msg != "quiet" || status.Convert(err).Code() != codes.Canceled {
288*61c4878aSAndroid Build Coastguard Worker					t.Errorf("Error unexpected %v", err)
289*61c4878aSAndroid Build Coastguard Worker				}
290*61c4878aSAndroid Build Coastguard Worker				return
291*61c4878aSAndroid Build Coastguard Worker			}
292*61c4878aSAndroid Build Coastguard Worker			t.Logf("... Recv %v", resp)
293*61c4878aSAndroid Build Coastguard Worker			if resp.Message != msg {
294*61c4878aSAndroid Build Coastguard Worker				t.Errorf("Unexpected response %v", resp)
295*61c4878aSAndroid Build Coastguard Worker			}
296*61c4878aSAndroid Build Coastguard Worker		}
297*61c4878aSAndroid Build Coastguard Worker	})
298*61c4878aSAndroid Build Coastguard Worker}
299*61c4878aSAndroid Build Coastguard Worker
300*61c4878aSAndroid Build Coastguard Workerfunc logServer(t *testing.T, reader *bufio.Reader) {
301*61c4878aSAndroid Build Coastguard Worker	for {
302*61c4878aSAndroid Build Coastguard Worker		line, err := reader.ReadString('\n')
303*61c4878aSAndroid Build Coastguard Worker		if err != nil {
304*61c4878aSAndroid Build Coastguard Worker			break
305*61c4878aSAndroid Build Coastguard Worker		}
306*61c4878aSAndroid Build Coastguard Worker		t.Logf("SERVER: %v", line)
307*61c4878aSAndroid Build Coastguard Worker	}
308*61c4878aSAndroid Build Coastguard Worker}
309*61c4878aSAndroid Build Coastguard Worker
310*61c4878aSAndroid Build Coastguard Workerfunc launchServer(t *testing.T, num_connections int) (*exec.Cmd, *bufio.Reader, error) {
311*61c4878aSAndroid Build Coastguard Worker	cmd := exec.Command("./test_pw_rpc_server", port, strconv.Itoa(num_connections))
312*61c4878aSAndroid Build Coastguard Worker
313*61c4878aSAndroid Build Coastguard Worker	output, err := cmd.StdoutPipe()
314*61c4878aSAndroid Build Coastguard Worker	if err != nil {
315*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to get stdout of server %v", err)
316*61c4878aSAndroid Build Coastguard Worker		return nil, nil, err
317*61c4878aSAndroid Build Coastguard Worker	}
318*61c4878aSAndroid Build Coastguard Worker
319*61c4878aSAndroid Build Coastguard Worker	if err := cmd.Start(); err != nil {
320*61c4878aSAndroid Build Coastguard Worker		t.Errorf("Failed to launch server %v", err)
321*61c4878aSAndroid Build Coastguard Worker		return nil, nil, err
322*61c4878aSAndroid Build Coastguard Worker	}
323*61c4878aSAndroid Build Coastguard Worker
324*61c4878aSAndroid Build Coastguard Worker	reader := bufio.NewReader(output)
325*61c4878aSAndroid Build Coastguard Worker	for {
326*61c4878aSAndroid Build Coastguard Worker		line, _ := reader.ReadString('\n')
327*61c4878aSAndroid Build Coastguard Worker		if strings.Contains(line, "Accept") {
328*61c4878aSAndroid Build Coastguard Worker			break
329*61c4878aSAndroid Build Coastguard Worker		}
330*61c4878aSAndroid Build Coastguard Worker	}
331*61c4878aSAndroid Build Coastguard Worker
332*61c4878aSAndroid Build Coastguard Worker	return cmd, reader, nil
333*61c4878aSAndroid Build Coastguard Worker}
334*61c4878aSAndroid Build Coastguard Worker
335*61c4878aSAndroid Build Coastguard Workerfunc connectServer() (*grpc.ClientConn, pb.EchoClient, error) {
336*61c4878aSAndroid Build Coastguard Worker	addr := "localhost:" + port
337*61c4878aSAndroid Build Coastguard Worker
338*61c4878aSAndroid Build Coastguard Worker	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
339*61c4878aSAndroid Build Coastguard Worker	if err != nil {
340*61c4878aSAndroid Build Coastguard Worker		return nil, nil, err
341*61c4878aSAndroid Build Coastguard Worker	}
342*61c4878aSAndroid Build Coastguard Worker
343*61c4878aSAndroid Build Coastguard Worker	echo_client := pb.NewEchoClient(conn)
344*61c4878aSAndroid Build Coastguard Worker	return conn, echo_client, nil
345*61c4878aSAndroid Build Coastguard Worker}
346*61c4878aSAndroid Build Coastguard Worker
347*61c4878aSAndroid Build Coastguard Workerfunc testRPC(t *testing.T, call func(t *testing.T, ctx context.Context, msg string)) {
348*61c4878aSAndroid Build Coastguard Worker	const num_calls = 30
349*61c4878aSAndroid Build Coastguard Worker	for i := 0; i < num_calls; i++ {
350*61c4878aSAndroid Build Coastguard Worker		t.Run(fmt.Sprintf("%d of %d", i+1, num_calls), func(t *testing.T) {
351*61c4878aSAndroid Build Coastguard Worker			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
352*61c4878aSAndroid Build Coastguard Worker			defer cancel()
353*61c4878aSAndroid Build Coastguard Worker
354*61c4878aSAndroid Build Coastguard Worker			msg := fmt.Sprintf("message%d", i)
355*61c4878aSAndroid Build Coastguard Worker			if i == num_calls-1 {
356*61c4878aSAndroid Build Coastguard Worker				msg = "quiet"
357*61c4878aSAndroid Build Coastguard Worker			}
358*61c4878aSAndroid Build Coastguard Worker
359*61c4878aSAndroid Build Coastguard Worker			done := make(chan struct{})
360*61c4878aSAndroid Build Coastguard Worker			go func() {
361*61c4878aSAndroid Build Coastguard Worker				call(t, ctx, msg)
362*61c4878aSAndroid Build Coastguard Worker				close(done)
363*61c4878aSAndroid Build Coastguard Worker			}()
364*61c4878aSAndroid Build Coastguard Worker			// Test cancellation. When we sent "quiet", the server won't echo anything
365*61c4878aSAndroid Build Coastguard Worker			// back and instead will hold onto the request. Sleep a bit to make sure
366*61c4878aSAndroid Build Coastguard Worker			// the server doesn't respond. Then cancel the request, which should
367*61c4878aSAndroid Build Coastguard Worker			// complete the RPC.
368*61c4878aSAndroid Build Coastguard Worker			if msg == "quiet" {
369*61c4878aSAndroid Build Coastguard Worker				time.Sleep(100 * time.Millisecond)
370*61c4878aSAndroid Build Coastguard Worker				cancel()
371*61c4878aSAndroid Build Coastguard Worker			}
372*61c4878aSAndroid Build Coastguard Worker			<-done
373*61c4878aSAndroid Build Coastguard Worker		})
374*61c4878aSAndroid Build Coastguard Worker	}
375*61c4878aSAndroid Build Coastguard Worker}
376