Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: common/prpc/client_test.go

Issue 1637193002: common/prpc, tools/cmd/cproto: prpc client (Closed) Base URL: https://github.com/luci/luci-go@prpc-server
Patch Set: Add some content length tests. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « common/prpc/client.go ('k') | common/prpc/codes.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package prpc
6
7 import (
8 "fmt"
9 "io/ioutil"
10 "net/http"
11 "net/http/httptest"
12 "strconv"
13 "strings"
14 "testing"
15 "time"
16
17 "github.com/golang/protobuf/proto"
18 "golang.org/x/net/context"
19 "google.golang.org/grpc"
20 "google.golang.org/grpc/codes"
21
22 "github.com/luci/luci-go/common/clock"
23 "github.com/luci/luci-go/common/clock/testclock"
24 "github.com/luci/luci-go/common/logging"
25 "github.com/luci/luci-go/common/logging/memlogger"
26 "github.com/luci/luci-go/common/retry"
27
28 . "github.com/smartystreets/goconvey/convey"
29 )
30
31 func sayHello(c C) http.HandlerFunc {
32 return func(w http.ResponseWriter, r *http.Request) {
33 c.So(r.Method, ShouldEqual, "POST")
34 c.So(r.URL.Path, ShouldEqual, "/prpc/prpc.Greeter/SayHello")
35 c.So(r.Header.Get("Accept"), ShouldEqual, "application/prpc")
36 c.So(r.Header.Get("Content-Type"), ShouldEqual, "application/prp c")
37 c.So(r.Header.Get("User-Agent"), ShouldEqual, "prpc-test")
38
39 if timeout := r.Header.Get(HeaderTimeout); timeout != "" {
40 c.So(timeout, ShouldEqual, "10000000u")
41 }
42
43 reqBody, err := ioutil.ReadAll(r.Body)
44 c.So(err, ShouldBeNil)
45
46 var req HelloRequest
47 err = proto.Unmarshal(reqBody, &req)
48 c.So(err, ShouldBeNil)
49
50 if req.Name == "TOO BIG" {
51 w.Header().Set("Content-Length", "999999999999")
52 }
53
54 res := HelloReply{"Hello " + req.Name}
55 buf, err := proto.Marshal(&res)
56 c.So(err, ShouldBeNil)
57
58 w.Header().Set(HeaderGRPCCode, strconv.Itoa(int(codes.OK)))
59 _, err = w.Write(buf)
60 c.So(err, ShouldBeNil)
61 }
62 }
63
64 func doPanicHandler(w http.ResponseWriter, r *http.Request) {
65 panic("test panic")
66 }
67
68 func transientErrors(count int, then http.Handler) http.HandlerFunc {
69 return func(w http.ResponseWriter, r *http.Request) {
70 if count > 0 {
71 count--
72 w.Header().Set(HeaderGRPCCode, strconv.Itoa(int(codes.In ternal)))
73 w.WriteHeader(http.StatusInternalServerError)
74 fmt.Fprintln(w, "Server misbehaved")
75 return
76 }
77 then.ServeHTTP(w, r)
78 }
79 }
80
81 func shouldHaveMessagesLike(actual interface{}, expected ...interface{}) string {
82 log := actual.(*memlogger.MemLogger)
83 msgs := log.Messages()
84
85 So(msgs, ShouldHaveLength, len(expected))
86 for i, actual := range msgs {
87 expected := expected[i].(memlogger.LogEntry)
88 So(actual.Level, ShouldEqual, expected.Level)
89 So(actual.Msg, ShouldContainSubstring, expected.Msg)
90 }
91 return ""
92 }
93
94 func TestClient(t *testing.T) {
95 t.Parallel()
96
97 Convey("Client", t, func() {
98 setUp := func(h http.HandlerFunc) (*Client, *httptest.Server) {
99 server := httptest.NewServer(h)
100 client := &Client{
101 Host: strings.TrimPrefix(server.URL, "http://"),
102 Options: &Options{
103 Retry: func() retry.Iterator {
104 return &retry.Limited{
105 Retries: 3,
106 Delay: 0,
107 }
108 },
109 Insecure: true,
110 UserAgent: "prpc-test",
111 },
112 }
113 return client, server
114 }
115
116 ctx, _ := testclock.UseTime(context.Background(), testclock.Test TimeLocal)
117 ctx = memlogger.Use(ctx)
118 log := logging.Get(ctx).(*memlogger.MemLogger)
119 expectedCallLogEntry := func(c *Client) memlogger.LogEntry {
120 return memlogger.LogEntry{
121 Level: logging.Debug,
122 Msg: fmt.Sprintf("RPC %s/prpc.Greeter.SayHello ", c.Host),
123 }
124 }
125
126 req := &HelloRequest{"John"}
127 res := &HelloReply{}
128
129 Convey("Call", func() {
130 Convey("Works", func(c C) {
131 client, server := setUp(sayHello(c))
132 defer server.Close()
133
134 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
135 So(err, ShouldBeNil)
136 So(res.Message, ShouldEqual, "Hello John")
137
138 So(log, shouldHaveMessagesLike, expectedCallLogE ntry(client))
139 })
140
141 Convey("With a deadline <= now, does not execute.", func (c C) {
142 client, server := setUp(doPanicHandler)
143 defer server.Close()
144
145 ctx, _ = context.WithDeadline(ctx, clock.Now(ctx ))
146 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
147 So(err, ShouldEqual, context.DeadlineExceeded)
148 })
149
150 Convey("With a deadline in the future, sets the deadline header.", func(c C) {
151 client, server := setUp(sayHello(c))
152 defer server.Close()
153
154 ctx, _ = clock.WithDeadline(ctx, clock.Now(ctx). Add(10*time.Second))
155 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
156 So(err, ShouldBeNil)
157 So(res.Message, ShouldEqual, "Hello John")
158
159 So(log, shouldHaveMessagesLike, expectedCallLogE ntry(client))
160 })
161
162 Convey(`With a maximum content length smaller than the r esponse, returns "ErrResponseTooBig".`, func(c C) {
163 client, server := setUp(sayHello(c))
164 defer server.Close()
165
166 client.MaxContentLength = 8
167 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
168 So(err, ShouldEqual, ErrResponseTooBig)
169 })
170
171 Convey(`When the response returns a huge Content Length, returns "ErrResponseTooBig".`, func(c C) {
172 client, server := setUp(sayHello(c))
173 defer server.Close()
174
175 req.Name = "TOO BIG"
176 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
177 So(err, ShouldEqual, ErrResponseTooBig)
178 })
179
180 Convey("HTTP 500 x2", func(c C) {
181 client, server := setUp(transientErrors(2, sayHe llo(c)))
182 defer server.Close()
183
184 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
185 So(err, ShouldBeNil)
186 So(res.Message, ShouldEqual, "Hello John")
187
188 So(log, shouldHaveMessagesLike,
189 expectedCallLogEntry(client),
190 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 0"},
191
192 expectedCallLogEntry(client),
193 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 0"},
194
195 expectedCallLogEntry(client),
196 )
197 })
198
199 Convey("HTTP 500 many", func(c C) {
200 client, server := setUp(transientErrors(10, sayH ello(c)))
201 defer server.Close()
202
203 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
204 So(grpc.Code(err), ShouldEqual, codes.Internal)
205 So(grpc.ErrorDesc(err), ShouldEqual, "Server mis behaved")
206
207 So(log, shouldHaveMessagesLike,
208 expectedCallLogEntry(client),
209 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 0"},
210
211 expectedCallLogEntry(client),
212 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 0"},
213
214 expectedCallLogEntry(client),
215 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 0"},
216
217 expectedCallLogEntry(client),
218 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed permanently"},
219 )
220 })
221
222 Convey("Forbidden", func(c C) {
223 client, server := setUp(func(w http.ResponseWrit er, r *http.Request) {
224 w.Header().Set(HeaderGRPCCode, strconv.I toa(int(codes.PermissionDenied)))
225 w.WriteHeader(http.StatusForbidden)
226 fmt.Fprintln(w, "Access denied")
227 })
228 defer server.Close()
229
230 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
231 So(grpc.Code(err), ShouldEqual, codes.Permission Denied)
232 So(grpc.ErrorDesc(err), ShouldEqual, "Access den ied")
233
234 So(log, shouldHaveMessagesLike,
235 expectedCallLogEntry(client),
236 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed permanently"},
237 )
238 })
239
240 Convey(HeaderGRPCCode, func(c C) {
241 client, server := setUp(func(w http.ResponseWrit er, r *http.Request) {
242 w.Header().Set(HeaderGRPCCode, strconv.I toa(int(codes.Canceled)))
243 w.WriteHeader(http.StatusBadRequest)
244 })
245 defer server.Close()
246
247 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
248 So(grpc.Code(err), ShouldEqual, codes.Canceled)
249 })
250 })
251 })
252 }
OLDNEW
« no previous file with comments | « common/prpc/client.go ('k') | common/prpc/codes.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698