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

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

Issue 1605363002: common/prpc, tools/cmd/cproto: prpc client (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-go@master
Patch Set: addressed comments Created 4 years, 11 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
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/logging"
23 "github.com/luci/luci-go/common/logging/memlogger"
24 "github.com/luci/luci-go/common/retry"
25
26 . "github.com/luci/luci-go/common/testing/assertions"
27 . "github.com/smartystreets/goconvey/convey"
28 )
29
30 func sayHello(c C) http.HandlerFunc {
31 return func(w http.ResponseWriter, r *http.Request) {
32 c.So(r.Method, ShouldEqual, "POST")
33 c.So(r.URL.Path, ShouldEqual, "/prpc/prpc.Greeter/SayHello")
34 c.So(r.Header.Get("Accept"), ShouldEqual, "application/prpc")
35 c.So(r.Header.Get("Content-Type"), ShouldEqual, "application/prp c")
36 c.So(r.Header.Get("User-Agent"), ShouldEqual, "prpc-test")
37
38 reqBody, err := ioutil.ReadAll(r.Body)
39 c.So(err, ShouldBeNil)
40
41 var req HelloRequest
42 err = proto.Unmarshal(reqBody, &req)
43 c.So(err, ShouldBeNil)
44
45 res := HelloReply{"Hello " + req.Name}
46 buf, err := proto.Marshal(&res)
47 c.So(err, ShouldBeNil)
48
49 _, err = w.Write(buf)
50 c.So(err, ShouldBeNil)
51 }
52 }
53
54 func transientErrors(count int, then http.Handler) http.HandlerFunc {
55 return func(w http.ResponseWriter, r *http.Request) {
56 if count > 0 {
57 count--
58 w.WriteHeader(http.StatusInternalServerError)
59 fmt.Fprintln(w, "Server misbehaved")
60 return
61 }
62 then.ServeHTTP(w, r)
63 }
64 }
65
66 func shouldHaveMessagesLike(actual interface{}, expected ...interface{}) string {
67 log := actual.(*memlogger.MemLogger)
68 msgs := log.Messages()
69
70 So(msgs, ShouldHaveLength, len(expected))
71 for i, actual := range msgs {
72 expected := expected[i].(memlogger.LogEntry)
73 So(actual.Level, ShouldEqual, expected.Level)
74 So(actual.Msg, ShouldContainSubstring, expected.Msg)
75 }
76 return ""
77 }
78
79 func TestClient(t *testing.T) {
80 t.Parallel()
81
82 Convey("Client", t, func() {
83 setUp := func(h http.HandlerFunc) (*Client, *httptest.Server) {
84 server := httptest.NewServer(h)
85 client := &Client{
86 Host: strings.TrimPrefix(server.URL, "http://"),
87 Options: &Options{
88 Retry: func() retry.Iterator {
89 return &retry.ExponentialBackoff {
90 Limited: retry.Limited{
91 Retries: 3,
92 Delay: time.Mi llisecond,
93 },
94 }
95 },
96 Insecure: true,
97 UserAgent: "prpc-test",
98 },
99 }
100 return client, server
101 }
102
103 ctx := memlogger.Use(context.Background())
104 log := logging.Get(ctx).(*memlogger.MemLogger)
105 expectedCallLogEntry := func(c *Client) memlogger.LogEntry {
106 return memlogger.LogEntry{
107 Level: logging.Debug,
108 Msg: fmt.Sprintf("RPC %s/prpc.Greeter.SayHello ", c.Host),
109 }
110 }
111
112 req := &HelloRequest{"John"}
113 res := &HelloReply{}
114
115 Convey("Call", func() {
116 Convey("Works", func(c C) {
117 client, server := setUp(sayHello(c))
118 defer server.Close()
119
120 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
121 So(err, ShouldBeNil)
122 So(res.Message, ShouldEqual, "Hello John")
123
124 So(log, shouldHaveMessagesLike, expectedCallLogE ntry(client))
125 })
126
127 Convey("HTTP 500 x2", func(c C) {
128 client, server := setUp(transientErrors(2, sayHe llo(c)))
129 defer server.Close()
130
131 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
132 So(err, ShouldBeNil)
133 So(res.Message, ShouldEqual, "Hello John")
134
135 So(log, shouldHaveMessagesLike,
136 expectedCallLogEntry(client),
137 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 1ms"},
138
139 expectedCallLogEntry(client),
140 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 2ms"},
141
142 expectedCallLogEntry(client),
143 )
144 })
145
146 Convey("HTTP 500 many", func(c C) {
147 client, server := setUp(transientErrors(10, sayH ello(c)))
148 defer server.Close()
149
150 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
151 So(err, ShouldErrLike, "HTTP 500 Internal Server Error: Server misbehaved")
152 So(grpc.Code(err), ShouldEqual, codes.Internal)
153
154 So(log, shouldHaveMessagesLike,
155 expectedCallLogEntry(client),
156 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 1ms"},
157
158 expectedCallLogEntry(client),
159 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 2ms"},
160
161 expectedCallLogEntry(client),
162 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed transiently. Will retry in 4ms"},
163
164 expectedCallLogEntry(client),
165 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed permanently"},
166 )
167 })
168
169 Convey("HTTP 403 x10", func(c C) {
170 client, server := setUp(func(w http.ResponseWrit er, r *http.Request) {
171 w.WriteHeader(http.StatusForbidden)
172 })
173 defer server.Close()
174
175 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
176 So(err, ShouldErrLike, "HTTP 403")
177 So(grpc.Code(err), ShouldEqual, codes.Permission Denied)
178
179 So(log, shouldHaveMessagesLike,
180 expectedCallLogEntry(client),
181 memlogger.LogEntry{Level: logging.Warnin g, Msg: "RPC failed permanently"},
182 )
183 })
184
185 Convey(HeaderGrpcCode, func(c C) {
186 client, server := setUp(func(w http.ResponseWrit er, r *http.Request) {
187 w.Header().Set(HeaderGrpcCode, strconv.I toa(int(codes.Canceled)))
188 w.WriteHeader(http.StatusBadRequest)
189 })
190 defer server.Close()
191
192 err := client.Call(ctx, "prpc.Greeter", "SayHell o", req, res)
193 So(grpc.Code(err), ShouldEqual, codes.Canceled)
194 })
195 })
196 })
197 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698