1206.2.1
by Martin Packman
Add copyright statement at the top of all go files bar thirdparty |
1 |
// Copyright 2012, 2013 Canonical Ltd.
|
2 |
// Licensed under the AGPLv3, see LICENCE file for details.
|
|
3 |
||
766.2.1
by Roger Peppe
rpc: initial commit |
4 |
package rpc_test |
766.2.3
by Roger Peppe
rpc: more tests; updated docs |
5 |
|
766.2.1
by Roger Peppe
rpc: initial commit |
6 |
import ( |
766.2.24
by Roger Peppe
gofmt |
7 |
"encoding/json"
|
766.2.3
by Roger Peppe
rpc: more tests; updated docs |
8 |
"fmt"
|
1408.1.1
by John Arbash Meinel
Start changing the imports of the middle level files. |
9 |
"net"
|
10 |
"reflect"
|
|
11 |
"sync"
|
|
12 |
stdtesting "testing" |
|
13 |
"time"
|
|
14 |
||
1657.1.7
by Roger Peppe
gocheck imports - e-r |
15 |
gc "launchpad.net/gocheck" |
1408.1.1
by John Arbash Meinel
Start changing the imports of the middle level files. |
16 |
|
766.3.1
by Roger Peppe
rpc: concurrent requests |
17 |
"launchpad.net/juju-core/log"
|
766.2.1
by Roger Peppe
rpc: initial commit |
18 |
"launchpad.net/juju-core/rpc"
|
1863.2.4
by Roger Peppe
rpc/rpcreflect: rename Methods to Type |
19 |
"launchpad.net/juju-core/rpc/jsoncodec"
|
1847.1.5
by Tim Penhey
add the import |
20 |
"launchpad.net/juju-core/testing/testbase"
|
766.2.1
by Roger Peppe
rpc: initial commit |
21 |
)
|
22 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
23 |
type rpcSuite struct { |
1847.1.3
by Tim Penhey
More changes |
24 |
testbase.LoggingSuite |
766.3.1
by Roger Peppe
rpc: concurrent requests |
25 |
}
|
26 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
27 |
var _ = gc.Suite(&rpcSuite{}) |
766.3.1
by Roger Peppe
rpc: concurrent requests |
28 |
|
29 |
func TestAll(t *stdtesting.T) { |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
30 |
gc.TestingT(t) |
766.2.25
by Roger Peppe
rpc: first tests pass |
31 |
}
|
32 |
||
766.2.23
by Roger Peppe
rpc: revamp |
33 |
type callInfo struct { |
766.2.24
by Roger Peppe
gofmt |
34 |
rcvr interface{} |
766.2.23
by Roger Peppe
rpc: revamp |
35 |
method string |
766.2.24
by Roger Peppe
gofmt |
36 |
arg interface{} |
766.2.23
by Roger Peppe
rpc: revamp |
37 |
}
|
38 |
||
39 |
type callError callInfo |
|
40 |
||
41 |
func (e *callError) Error() string { |
|
42 |
return fmt.Sprintf("error calling %s", e.method) |
|
766.2.19
by Roger Peppe
rpc: http client codec tests |
43 |
}
|
44 |
||
766.2.25
by Roger Peppe
rpc: first tests pass |
45 |
type stringVal struct { |
46 |
Val string |
|
766.2.1
by Roger Peppe
rpc: initial commit |
47 |
}
|
48 |
||
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
49 |
type Root struct { |
766.3.8
by Roger Peppe
rpc: add error path testing |
50 |
mu sync.Mutex |
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
51 |
conn *rpc.Conn |
766.3.8
by Roger Peppe
rpc: add error path testing |
52 |
calls []*callInfo |
53 |
returnErr bool |
|
54 |
simple map[string]*SimpleMethods |
|
55 |
delayed map[string]*DelayedMethods |
|
892.2.2
by Roger Peppe
rpc: error code test |
56 |
errorInst *ErrorMethods |
766.3.8
by Roger Peppe
rpc: add error path testing |
57 |
}
|
58 |
||
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
59 |
func (r *Root) callError(rcvr interface{}, name string, arg interface{}) error { |
766.3.8
by Roger Peppe
rpc: add error path testing |
60 |
if r.returnErr { |
61 |
return &callError{rcvr, name, arg} |
|
62 |
}
|
|
63 |
return nil |
|
766.3.5
by Roger Peppe
rpc: concurrent tests |
64 |
}
|
65 |
||
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
66 |
func (r *Root) SimpleMethods(id string) (*SimpleMethods, error) { |
766.3.5
by Roger Peppe
rpc: concurrent tests |
67 |
r.mu.Lock() |
68 |
defer r.mu.Unlock() |
|
69 |
if a := r.simple[id]; a != nil { |
|
70 |
return a, nil |
|
71 |
}
|
|
72 |
return nil, fmt.Errorf("unknown SimpleMethods id") |
|
73 |
}
|
|
74 |
||
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
75 |
func (r *Root) DelayedMethods(id string) (*DelayedMethods, error) { |
766.3.5
by Roger Peppe
rpc: concurrent tests |
76 |
r.mu.Lock() |
77 |
defer r.mu.Unlock() |
|
78 |
if a := r.delayed[id]; a != nil { |
|
79 |
return a, nil |
|
80 |
}
|
|
81 |
return nil, fmt.Errorf("unknown DelayedMethods id") |
|
82 |
}
|
|
83 |
||
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
84 |
func (r *Root) ErrorMethods(id string) (*ErrorMethods, error) { |
894.5.9
by Roger Peppe
rpc: fix error transforms on obtainer methods |
85 |
if r.errorInst == nil { |
86 |
return nil, fmt.Errorf("no error methods") |
|
87 |
}
|
|
892.2.2
by Roger Peppe
rpc: error code test |
88 |
return r.errorInst, nil |
89 |
}
|
|
90 |
||
1863.2.2
by Roger Peppe
rpc: add introspection test |
91 |
func (r *Root) Discard1() {} |
92 |
||
93 |
func (r *Root) Discard2(id string) error { return nil } |
|
94 |
||
95 |
func (r *Root) Discard3(id string) int { return 0 } |
|
96 |
||
1214.1.11
by Roger Peppe
rpc: add bidirectional test |
97 |
func (r *Root) CallbackMethods(string) (*CallbackMethods, error) { |
98 |
return &CallbackMethods{r}, nil |
|
99 |
}
|
|
100 |
||
1809.1.1
by Roger Peppe
rpc: allow interface types |
101 |
func (r *Root) InterfaceMethods(id string) (InterfaceMethods, error) { |
102 |
log.Infof("interface methods called") |
|
103 |
m, err := r.SimpleMethods(id) |
|
104 |
if err != nil { |
|
105 |
return nil, err |
|
106 |
}
|
|
107 |
return m, nil |
|
108 |
}
|
|
109 |
||
110 |
type InterfaceMethods interface { |
|
111 |
Call1r1e(s stringVal) (stringVal, error) |
|
112 |
}
|
|
113 |
||
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
114 |
type ChangeAPIMethods struct { |
115 |
r *Root |
|
116 |
}
|
|
117 |
||
118 |
func (r *Root) ChangeAPIMethods(string) (*ChangeAPIMethods, error) { |
|
119 |
return &ChangeAPIMethods{r}, nil |
|
120 |
}
|
|
121 |
||
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
122 |
func (t *Root) called(rcvr interface{}, method string, arg interface{}) { |
766.3.5
by Roger Peppe
rpc: concurrent tests |
123 |
t.mu.Lock() |
124 |
t.calls = append(t.calls, &callInfo{rcvr, method, arg}) |
|
125 |
t.mu.Unlock() |
|
126 |
}
|
|
127 |
||
128 |
type SimpleMethods struct { |
|
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
129 |
root *Root |
766.3.5
by Roger Peppe
rpc: concurrent tests |
130 |
id string |
766.2.23
by Roger Peppe
rpc: revamp |
131 |
}
|
132 |
||
766.2.36
by Roger Peppe
rpc: add comments |
133 |
// Each Call method is named in this standard form:
|
134 |
//
|
|
135 |
// Call<narg>r<nret><e>
|
|
136 |
//
|
|
137 |
// where narg is the number of arguments, nret is the number of returned
|
|
138 |
// values (not including the error) and e is the letter 'e' if the
|
|
139 |
// method returns an error.
|
|
140 |
||
766.3.5
by Roger Peppe
rpc: concurrent tests |
141 |
func (a *SimpleMethods) Call0r0() { |
142 |
a.root.called(a, "Call0r0", nil) |
|
766.2.23
by Roger Peppe
rpc: revamp |
143 |
}
|
144 |
||
766.3.5
by Roger Peppe
rpc: concurrent tests |
145 |
func (a *SimpleMethods) Call0r1() stringVal { |
146 |
a.root.called(a, "Call0r1", nil) |
|
766.2.25
by Roger Peppe
rpc: first tests pass |
147 |
return stringVal{"Call0r1 ret"} |
766.2.23
by Roger Peppe
rpc: revamp |
148 |
}
|
149 |
||
766.3.5
by Roger Peppe
rpc: concurrent tests |
150 |
func (a *SimpleMethods) Call0r1e() (stringVal, error) { |
151 |
a.root.called(a, "Call0r1e", nil) |
|
766.3.8
by Roger Peppe
rpc: add error path testing |
152 |
return stringVal{"Call0r1e ret"}, a.root.callError(a, "Call0r1e", nil) |
766.2.23
by Roger Peppe
rpc: revamp |
153 |
}
|
154 |
||
766.3.5
by Roger Peppe
rpc: concurrent tests |
155 |
func (a *SimpleMethods) Call0r0e() error { |
156 |
a.root.called(a, "Call0r0e", nil) |
|
766.3.8
by Roger Peppe
rpc: add error path testing |
157 |
return a.root.callError(a, "Call0r0e", nil) |
766.2.23
by Roger Peppe
rpc: revamp |
158 |
}
|
159 |
||
766.3.5
by Roger Peppe
rpc: concurrent tests |
160 |
func (a *SimpleMethods) Call1r0(s stringVal) { |
161 |
a.root.called(a, "Call1r0", s) |
|
766.2.23
by Roger Peppe
rpc: revamp |
162 |
}
|
163 |
||
766.3.5
by Roger Peppe
rpc: concurrent tests |
164 |
func (a *SimpleMethods) Call1r1(s stringVal) stringVal { |
165 |
a.root.called(a, "Call1r1", s) |
|
766.2.25
by Roger Peppe
rpc: first tests pass |
166 |
return stringVal{"Call1r1 ret"} |
766.2.23
by Roger Peppe
rpc: revamp |
167 |
}
|
168 |
||
766.3.5
by Roger Peppe
rpc: concurrent tests |
169 |
func (a *SimpleMethods) Call1r1e(s stringVal) (stringVal, error) { |
170 |
a.root.called(a, "Call1r1e", s) |
|
766.3.8
by Roger Peppe
rpc: add error path testing |
171 |
return stringVal{"Call1r1e ret"}, a.root.callError(a, "Call1r1e", s) |
766.2.23
by Roger Peppe
rpc: revamp |
172 |
}
|
173 |
||
766.3.5
by Roger Peppe
rpc: concurrent tests |
174 |
func (a *SimpleMethods) Call1r0e(s stringVal) error { |
175 |
a.root.called(a, "Call1r0e", s) |
|
766.3.8
by Roger Peppe
rpc: add error path testing |
176 |
return a.root.callError(a, "Call1r0e", s) |
766.2.23
by Roger Peppe
rpc: revamp |
177 |
}
|
178 |
||
1068.4.2
by Roger Peppe
rpc: continue after read body error (tests) |
179 |
func (a *SimpleMethods) SliceArg(struct{ X []string }) stringVal { |
180 |
return stringVal{"SliceArg ret"} |
|
181 |
}
|
|
182 |
||
1863.2.2
by Roger Peppe
rpc: add introspection test |
183 |
func (a *SimpleMethods) Discard1(int) {} |
184 |
||
185 |
func (a *SimpleMethods) Discard2(struct{}, struct{}) {} |
|
186 |
||
187 |
func (a *SimpleMethods) Discard3() int { return 0 } |
|
188 |
||
189 |
func (a *SimpleMethods) Discard4() (_, _ struct{}) { return } |
|
190 |
||
766.3.5
by Roger Peppe
rpc: concurrent tests |
191 |
type DelayedMethods struct { |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
192 |
ready chan struct{} |
193 |
done chan string |
|
194 |
doneError chan error |
|
766.3.5
by Roger Peppe
rpc: concurrent tests |
195 |
}
|
196 |
||
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
197 |
func (a *DelayedMethods) Delay() (stringVal, error) { |
766.3.5
by Roger Peppe
rpc: concurrent tests |
198 |
if a.ready != nil { |
199 |
a.ready <- struct{}{} |
|
766.2.23
by Roger Peppe
rpc: revamp |
200 |
}
|
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
201 |
select { |
202 |
case s := <-a.done: |
|
203 |
return stringVal{s}, nil |
|
204 |
case err := <-a.doneError: |
|
205 |
return stringVal{}, err |
|
206 |
}
|
|
766.2.23
by Roger Peppe
rpc: revamp |
207 |
}
|
208 |
||
892.2.2
by Roger Peppe
rpc: error code test |
209 |
type ErrorMethods struct { |
210 |
err error |
|
211 |
}
|
|
212 |
||
213 |
func (e *ErrorMethods) Call() error { |
|
214 |
return e.err |
|
215 |
}
|
|
216 |
||
1214.1.11
by Roger Peppe
rpc: add bidirectional test |
217 |
type CallbackMethods struct { |
218 |
root *Root |
|
219 |
}
|
|
220 |
||
221 |
type int64val struct { |
|
222 |
I int64 |
|
223 |
}
|
|
224 |
||
225 |
func (a *CallbackMethods) Factorial(x int64val) (int64val, error) { |
|
226 |
if x.I <= 1 { |
|
227 |
return int64val{1}, nil |
|
228 |
}
|
|
229 |
var r int64val |
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
230 |
err := a.root.conn.Call("CallbackMethods", "", "Factorial", int64val{x.I - 1}, &r) |
1214.1.11
by Roger Peppe
rpc: add bidirectional test |
231 |
if err != nil { |
232 |
return int64val{}, err |
|
233 |
}
|
|
234 |
return int64val{x.I * r.I}, nil |
|
235 |
}
|
|
236 |
||
1863.2.1
by Roger Peppe
rpc: allow introspection of methods |
237 |
func (a *ChangeAPIMethods) ChangeAPI() { |
238 |
a.r.conn.Serve(&changedAPIRoot{}, nil) |
|
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
239 |
}
|
240 |
||
1863.2.1
by Roger Peppe
rpc: allow introspection of methods |
241 |
func (a *ChangeAPIMethods) RemoveAPI() { |
242 |
a.r.conn.Serve(nil, nil) |
|
1260.2.4
by Roger Peppe
rpc: add TestChangeAPIToNil |
243 |
}
|
244 |
||
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
245 |
type changedAPIRoot struct{} |
246 |
||
247 |
func (r *changedAPIRoot) NewlyAvailable(string) (newlyAvailableMethods, error) { |
|
248 |
return newlyAvailableMethods{}, nil |
|
249 |
}
|
|
250 |
||
251 |
type newlyAvailableMethods struct{} |
|
252 |
||
253 |
func (newlyAvailableMethods) NewMethod() stringVal { |
|
254 |
return stringVal{"new method result"} |
|
255 |
}
|
|
256 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
257 |
func (*rpcSuite) TestRPC(c *gc.C) { |
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
258 |
root := &Root{ |
766.3.5
by Roger Peppe
rpc: concurrent tests |
259 |
simple: make(map[string]*SimpleMethods), |
260 |
}
|
|
261 |
root.simple["a99"] = &SimpleMethods{root: root, id: "a99"} |
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
262 |
client, srvDone := newRPCClientServer(c, root, nil, false) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
263 |
defer closeClient(c, client, srvDone) |
766.3.3
by Roger Peppe
rpc: factor out newRPCClientServer in tests |
264 |
for narg := 0; narg < 2; narg++ { |
265 |
for nret := 0; nret < 2; nret++ { |
|
266 |
for nerr := 0; nerr < 2; nerr++ { |
|
766.3.8
by Roger Peppe
rpc: add error path testing |
267 |
retErr := nerr != 0 |
1809.1.1
by Roger Peppe
rpc: allow interface types |
268 |
root.testCall(c, client, "SimpleMethods", narg, nret, retErr, false) |
766.3.8
by Roger Peppe
rpc: add error path testing |
269 |
if retErr { |
1809.1.1
by Roger Peppe
rpc: allow interface types |
270 |
root.testCall(c, client, "SimpleMethods", narg, nret, retErr, true) |
766.3.8
by Roger Peppe
rpc: add error path testing |
271 |
}
|
766.3.3
by Roger Peppe
rpc: factor out newRPCClientServer in tests |
272 |
}
|
273 |
}
|
|
274 |
}
|
|
275 |
}
|
|
276 |
||
1863.2.2
by Roger Peppe
rpc: add introspection test |
277 |
func callName(narg, nret int, retErr bool) string { |
278 |
e := "" |
|
279 |
if retErr { |
|
280 |
e = "e" |
|
281 |
}
|
|
282 |
return fmt.Sprintf("Call%dr%d%s", narg, nret, e) |
|
283 |
}
|
|
284 |
||
1809.1.1
by Roger Peppe
rpc: allow interface types |
285 |
func (root *Root) testCall(c *gc.C, conn *rpc.Conn, entry string, narg, nret int, retErr, testErr bool) { |
766.3.8
by Roger Peppe
rpc: add error path testing |
286 |
root.calls = nil |
287 |
root.returnErr = testErr |
|
1863.2.2
by Roger Peppe
rpc: add introspection test |
288 |
method := callName(narg, nret, retErr) |
766.3.5
by Roger Peppe
rpc: concurrent tests |
289 |
c.Logf("test call %s", method) |
290 |
var r stringVal |
|
1809.1.1
by Roger Peppe
rpc: allow interface types |
291 |
err := conn.Call(entry, "a99", method, stringVal{"arg"}, &r) |
766.3.5
by Roger Peppe
rpc: concurrent tests |
292 |
root.mu.Lock() |
293 |
defer root.mu.Unlock() |
|
294 |
expectCall := callInfo{ |
|
295 |
rcvr: root.simple["a99"], |
|
296 |
method: method, |
|
297 |
}
|
|
298 |
if narg > 0 { |
|
299 |
expectCall.arg = stringVal{"arg"} |
|
300 |
}
|
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
301 |
c.Assert(root.calls, gc.HasLen, 1) |
302 |
c.Assert(*root.calls[0], gc.Equals, expectCall) |
|
766.3.5
by Roger Peppe
rpc: concurrent tests |
303 |
switch { |
766.3.8
by Roger Peppe
rpc: add error path testing |
304 |
case retErr && testErr: |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
305 |
c.Assert(err, gc.DeepEquals, &rpc.RequestError{ |
892.2.1
by Roger Peppe
rpc: add error codes |
306 |
Message: fmt.Sprintf("error calling %s", method), |
766.3.5
by Roger Peppe
rpc: concurrent tests |
307 |
})
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
308 |
c.Assert(r, gc.Equals, stringVal{}) |
766.3.5
by Roger Peppe
rpc: concurrent tests |
309 |
case nret > 0: |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
310 |
c.Assert(r, gc.Equals, stringVal{method + " ret"}) |
766.3.5
by Roger Peppe
rpc: concurrent tests |
311 |
}
|
312 |
}
|
|
766.3.4
by Roger Peppe
rpc: make test context thread-safe |
313 |
|
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
314 |
func (*rpcSuite) TestInterfaceMethods(c *gc.C) { |
1809.1.1
by Roger Peppe
rpc: allow interface types |
315 |
root := &Root{ |
316 |
simple: make(map[string]*SimpleMethods), |
|
317 |
}
|
|
318 |
root.simple["a99"] = &SimpleMethods{root: root, id: "a99"} |
|
319 |
client, srvDone := newRPCClientServer(c, root, nil, false) |
|
320 |
defer closeClient(c, client, srvDone) |
|
321 |
root.testCall(c, client, "InterfaceMethods", 1, 1, true, false) |
|
322 |
root.testCall(c, client, "InterfaceMethods", 1, 1, true, true) |
|
323 |
}
|
|
324 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
325 |
func (*rpcSuite) TestConcurrentCalls(c *gc.C) { |
766.3.5
by Roger Peppe
rpc: concurrent tests |
326 |
start1 := make(chan string) |
327 |
start2 := make(chan string) |
|
766.3.6
by Roger Peppe
rpc: slightly simpler test |
328 |
ready1 := make(chan struct{}) |
329 |
ready2 := make(chan struct{}) |
|
330 |
||
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
331 |
root := &Root{ |
766.3.5
by Roger Peppe
rpc: concurrent tests |
332 |
delayed: map[string]*DelayedMethods{ |
766.3.6
by Roger Peppe
rpc: slightly simpler test |
333 |
"1": {ready: ready1, done: start1}, |
334 |
"2": {ready: ready2, done: start2}, |
|
766.3.5
by Roger Peppe
rpc: concurrent tests |
335 |
},
|
336 |
}
|
|
337 |
||
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
338 |
client, srvDone := newRPCClientServer(c, root, nil, false) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
339 |
defer closeClient(c, client, srvDone) |
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
340 |
call := func(id string, done chan<- struct{}) { |
766.3.5
by Roger Peppe
rpc: concurrent tests |
341 |
var r stringVal |
342 |
err := client.Call("DelayedMethods", id, "Delay", nil, &r) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
343 |
c.Check(err, gc.IsNil) |
344 |
c.Check(r.Val, gc.Equals, "return "+id) |
|
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
345 |
done <- struct{}{} |
766.3.5
by Roger Peppe
rpc: concurrent tests |
346 |
}
|
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
347 |
done1 := make(chan struct{}) |
348 |
done2 := make(chan struct{}) |
|
766.3.5
by Roger Peppe
rpc: concurrent tests |
349 |
go call("1", done1) |
350 |
go call("2", done2) |
|
351 |
||
766.3.6
by Roger Peppe
rpc: slightly simpler test |
352 |
// Check that both calls are running concurrently.
|
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
353 |
chanRead(c, ready1, "method 1 ready") |
354 |
chanRead(c, ready2, "method 2 ready") |
|
766.3.6
by Roger Peppe
rpc: slightly simpler test |
355 |
|
356 |
// Let the requests complete.
|
|
766.3.5
by Roger Peppe
rpc: concurrent tests |
357 |
start1 <- "return 1" |
358 |
start2 <- "return 2" |
|
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
359 |
chanRead(c, done1, "method 1 done") |
360 |
chanRead(c, done2, "method 2 done") |
|
766.3.5
by Roger Peppe
rpc: concurrent tests |
361 |
}
|
362 |
||
892.2.2
by Roger Peppe
rpc: error code test |
363 |
type codedError struct { |
892.2.3
by Roger Peppe
gofmt |
364 |
m string |
892.2.2
by Roger Peppe
rpc: error code test |
365 |
code string |
366 |
}
|
|
367 |
||
368 |
func (e *codedError) Error() string { |
|
369 |
return e.m |
|
370 |
}
|
|
371 |
||
372 |
func (e *codedError) ErrorCode() string { |
|
373 |
return e.code |
|
374 |
}
|
|
375 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
376 |
func (*rpcSuite) TestErrorCode(c *gc.C) { |
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
377 |
root := &Root{ |
892.2.2
by Roger Peppe
rpc: error code test |
378 |
errorInst: &ErrorMethods{&codedError{"message", "code"}}, |
379 |
}
|
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
380 |
client, srvDone := newRPCClientServer(c, root, nil, false) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
381 |
defer closeClient(c, client, srvDone) |
892.2.2
by Roger Peppe
rpc: error code test |
382 |
err := client.Call("ErrorMethods", "", "Call", nil, nil) |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
383 |
c.Assert(err, gc.ErrorMatches, `request error: message \(code\)`) |
384 |
c.Assert(err.(rpc.ErrorCoder).ErrorCode(), gc.Equals, "code") |
|
892.2.2
by Roger Peppe
rpc: error code test |
385 |
}
|
386 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
387 |
func (*rpcSuite) TestTransformErrors(c *gc.C) { |
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
388 |
root := &Root{ |
894.5.4
by Roger Peppe
rpc: add error transform test |
389 |
errorInst: &ErrorMethods{&codedError{"message", "code"}}, |
390 |
}
|
|
391 |
tfErr := func(err error) error { |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
392 |
c.Check(err, gc.NotNil) |
894.5.9
by Roger Peppe
rpc: fix error transforms on obtainer methods |
393 |
if e, ok := err.(*codedError); ok { |
394 |
return &codedError{ |
|
894.5.11
by Roger Peppe
state/api: errors codes now work |
395 |
m: "transformed: " + e.m, |
894.5.9
by Roger Peppe
rpc: fix error transforms on obtainer methods |
396 |
code: "transformed: " + e.code, |
397 |
}
|
|
894.5.4
by Roger Peppe
rpc: add error transform test |
398 |
}
|
894.5.9
by Roger Peppe
rpc: fix error transforms on obtainer methods |
399 |
return fmt.Errorf("transformed: %v", err) |
894.5.4
by Roger Peppe
rpc: add error transform test |
400 |
}
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
401 |
client, srvDone := newRPCClientServer(c, root, tfErr, false) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
402 |
defer closeClient(c, client, srvDone) |
894.5.4
by Roger Peppe
rpc: add error transform test |
403 |
err := client.Call("ErrorMethods", "", "Call", nil, nil) |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
404 |
c.Assert(err, gc.DeepEquals, &rpc.RequestError{ |
894.5.9
by Roger Peppe
rpc: fix error transforms on obtainer methods |
405 |
Message: "transformed: message", |
894.5.11
by Roger Peppe
state/api: errors codes now work |
406 |
Code: "transformed: code", |
894.5.4
by Roger Peppe
rpc: add error transform test |
407 |
})
|
408 |
||
409 |
root.errorInst.err = nil |
|
410 |
err = client.Call("ErrorMethods", "", "Call", nil, nil) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
411 |
c.Assert(err, gc.IsNil) |
894.5.4
by Roger Peppe
rpc: add error transform test |
412 |
|
894.5.9
by Roger Peppe
rpc: fix error transforms on obtainer methods |
413 |
root.errorInst = nil |
414 |
err = client.Call("ErrorMethods", "", "Call", nil, nil) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
415 |
c.Assert(err, gc.DeepEquals, &rpc.RequestError{ |
894.5.9
by Roger Peppe
rpc: fix error transforms on obtainer methods |
416 |
Message: "transformed: no error methods", |
417 |
})
|
|
418 |
||
894.5.4
by Roger Peppe
rpc: add error transform test |
419 |
}
|
420 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
421 |
func (*rpcSuite) TestServerWaitsForOutstandingCalls(c *gc.C) { |
766.3.5
by Roger Peppe
rpc: concurrent tests |
422 |
ready := make(chan struct{}) |
423 |
start := make(chan string) |
|
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
424 |
root := &Root{ |
766.3.5
by Roger Peppe
rpc: concurrent tests |
425 |
delayed: map[string]*DelayedMethods{ |
426 |
"1": { |
|
427 |
ready: ready, |
|
428 |
done: start, |
|
429 |
},
|
|
430 |
},
|
|
431 |
}
|
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
432 |
client, srvDone := newRPCClientServer(c, root, nil, false) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
433 |
defer closeClient(c, client, srvDone) |
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
434 |
done := make(chan struct{}) |
766.3.5
by Roger Peppe
rpc: concurrent tests |
435 |
go func() { |
436 |
var r stringVal |
|
437 |
err := client.Call("DelayedMethods", "1", "Delay", nil, &r) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
438 |
c.Check(err, gc.Equals, rpc.ErrShutdown) |
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
439 |
done <- struct{}{} |
766.3.5
by Roger Peppe
rpc: concurrent tests |
440 |
}()
|
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
441 |
chanRead(c, ready, "DelayedMethods.Delay ready") |
766.3.5
by Roger Peppe
rpc: concurrent tests |
442 |
client.Close() |
443 |
select { |
|
444 |
case err := <-srvDone: |
|
445 |
c.Fatalf("server returned while outstanding operation in progress: %v", err) |
|
446 |
<-done |
|
447 |
case <-time.After(25 * time.Millisecond): |
|
448 |
}
|
|
449 |
start <- "xxx" |
|
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
450 |
}
|
451 |
||
1657.1.7
by Roger Peppe
gocheck imports - e-r |
452 |
func chanRead(c *gc.C, ch <-chan struct{}, what string) { |
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
453 |
select { |
454 |
case <-ch: |
|
455 |
return
|
|
456 |
case <-time.After(3 * time.Second): |
|
457 |
c.Fatalf("timeout on channel read %s", what) |
|
458 |
}
|
|
459 |
}
|
|
460 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
461 |
func (*rpcSuite) TestCompatibility(c *gc.C) { |
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
462 |
root := &Root{ |
885.2.2
by Roger Peppe
rpc: extra tests |
463 |
simple: make(map[string]*SimpleMethods), |
464 |
}
|
|
465 |
a0 := &SimpleMethods{root: root, id: "a0"} |
|
466 |
root.simple["a0"] = a0 |
|
467 |
||
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
468 |
client, srvDone := newRPCClientServer(c, root, nil, false) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
469 |
defer closeClient(c, client, srvDone) |
885.2.2
by Roger Peppe
rpc: extra tests |
470 |
call := func(method string, arg, ret interface{}) (passedArg interface{}) { |
471 |
root.calls = nil |
|
472 |
err := client.Call("SimpleMethods", "a0", method, arg, ret) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
473 |
c.Assert(err, gc.IsNil) |
474 |
c.Assert(root.calls, gc.HasLen, 1) |
|
885.2.2
by Roger Peppe
rpc: extra tests |
475 |
info := root.calls[0] |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
476 |
c.Assert(info.rcvr, gc.Equals, a0) |
477 |
c.Assert(info.method, gc.Equals, method) |
|
885.2.2
by Roger Peppe
rpc: extra tests |
478 |
return info.arg |
479 |
}
|
|
480 |
type extra struct { |
|
885.2.6
by Roger Peppe
rpc: more struct fixes + tests |
481 |
Val string |
885.2.2
by Roger Peppe
rpc: extra tests |
482 |
Extra string |
483 |
}
|
|
484 |
// Extra fields in request and response.
|
|
485 |
var r extra |
|
486 |
arg := call("Call1r1", extra{"x", "y"}, &r) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
487 |
c.Assert(arg, gc.Equals, stringVal{"x"}) |
885.2.2
by Roger Peppe
rpc: extra tests |
488 |
|
489 |
// Nil argument as request.
|
|
490 |
r = extra{} |
|
491 |
arg = call("Call1r1", nil, &r) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
492 |
c.Assert(arg, gc.Equals, stringVal{}) |
885.2.2
by Roger Peppe
rpc: extra tests |
493 |
|
494 |
// Nil argument as response.
|
|
495 |
arg = call("Call1r1", stringVal{"x"}, nil) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
496 |
c.Assert(arg, gc.Equals, stringVal{"x"}) |
885.2.2
by Roger Peppe
rpc: extra tests |
497 |
|
498 |
// Non-nil argument for no response.
|
|
499 |
r = extra{} |
|
500 |
arg = call("Call1r0", stringVal{"x"}, &r) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
501 |
c.Assert(arg, gc.Equals, stringVal{"x"}) |
502 |
c.Assert(r, gc.Equals, extra{}) |
|
885.2.2
by Roger Peppe
rpc: extra tests |
503 |
}
|
504 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
505 |
func (*rpcSuite) TestBadCall(c *gc.C) { |
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
506 |
root := &Root{ |
885.2.10
by Roger Peppe
rpc: add log messages |
507 |
simple: make(map[string]*SimpleMethods), |
508 |
}
|
|
509 |
a0 := &SimpleMethods{root: root, id: "a0"} |
|
510 |
root.simple["a0"] = a0 |
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
511 |
client, srvDone := newRPCClientServer(c, root, nil, false) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
512 |
defer closeClient(c, client, srvDone) |
885.2.10
by Roger Peppe
rpc: add log messages |
513 |
|
514 |
err := client.Call("BadSomething", "a0", "No", nil, nil) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
515 |
c.Assert(err, gc.ErrorMatches, `request error: unknown object type "BadSomething"`) |
885.2.10
by Roger Peppe
rpc: add log messages |
516 |
|
517 |
err = client.Call("SimpleMethods", "xx", "No", nil, nil) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
518 |
c.Assert(err, gc.ErrorMatches, `request error: no such request "No" on SimpleMethods`) |
885.2.10
by Roger Peppe
rpc: add log messages |
519 |
|
520 |
err = client.Call("SimpleMethods", "xx", "Call0r0", nil, nil) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
521 |
c.Assert(err, gc.ErrorMatches, "request error: unknown SimpleMethods id") |
1068.4.2
by Roger Peppe
rpc: continue after read body error (tests) |
522 |
}
|
523 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
524 |
func (*rpcSuite) TestContinueAfterReadBodyError(c *gc.C) { |
1068.4.2
by Roger Peppe
rpc: continue after read body error (tests) |
525 |
root := &Root{ |
526 |
simple: make(map[string]*SimpleMethods), |
|
527 |
}
|
|
528 |
a0 := &SimpleMethods{root: root, id: "a0"} |
|
529 |
root.simple["a0"] = a0 |
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
530 |
client, srvDone := newRPCClientServer(c, root, nil, false) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
531 |
defer closeClient(c, client, srvDone) |
1068.4.2
by Roger Peppe
rpc: continue after read body error (tests) |
532 |
|
533 |
var ret stringVal |
|
534 |
arg0 := struct { |
|
535 |
X map[string]int |
|
536 |
}{
|
|
537 |
X: map[string]int{"hello": 65}, |
|
538 |
}
|
|
539 |
err := client.Call("SimpleMethods", "a0", "SliceArg", arg0, &ret) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
540 |
c.Assert(err, gc.ErrorMatches, `request error: json: cannot unmarshal object into Go value of type \[\]string`) |
1068.4.2
by Roger Peppe
rpc: continue after read body error (tests) |
541 |
|
542 |
err = client.Call("SimpleMethods", "a0", "SliceArg", arg0, &ret) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
543 |
c.Assert(err, gc.ErrorMatches, `request error: json: cannot unmarshal object into Go value of type \[\]string`) |
1068.4.2
by Roger Peppe
rpc: continue after read body error (tests) |
544 |
|
545 |
arg1 := struct { |
|
546 |
X []string |
|
547 |
}{
|
|
548 |
X: []string{"one"}, |
|
549 |
}
|
|
550 |
err = client.Call("SimpleMethods", "a0", "SliceArg", arg1, &ret) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
551 |
c.Assert(err, gc.IsNil) |
552 |
c.Assert(ret.Val, gc.Equals, "SliceArg ret") |
|
885.2.10
by Roger Peppe
rpc: add log messages |
553 |
}
|
554 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
555 |
func (*rpcSuite) TestErrorAfterClientClose(c *gc.C) { |
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
556 |
client, srvDone := newRPCClientServer(c, &Root{}, nil, false) |
894.3.1
by Roger Peppe
rpc, state/api: more consistent error messages |
557 |
err := client.Close() |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
558 |
c.Assert(err, gc.IsNil) |
894.3.1
by Roger Peppe
rpc, state/api: more consistent error messages |
559 |
err = client.Call("Foo", "", "Bar", nil, nil) |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
560 |
c.Assert(err, gc.Equals, rpc.ErrShutdown) |
894.3.1
by Roger Peppe
rpc, state/api: more consistent error messages |
561 |
err = chanReadError(c, srvDone, "server done") |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
562 |
c.Assert(err, gc.IsNil) |
894.3.1
by Roger Peppe
rpc, state/api: more consistent error messages |
563 |
}
|
564 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
565 |
func (*rpcSuite) TestClientCloseIdempotent(c *gc.C) { |
1712.2.3
by John Arbash Meinel
Add some direct tests that calling Close multiple times is ok. |
566 |
client, _ := newRPCClientServer(c, &Root{}, nil, false) |
567 |
err := client.Close() |
|
568 |
c.Assert(err, gc.IsNil) |
|
569 |
err = client.Close() |
|
570 |
c.Assert(err, gc.IsNil) |
|
571 |
err = client.Close() |
|
572 |
c.Assert(err, gc.IsNil) |
|
573 |
}
|
|
574 |
||
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
575 |
type KillerRoot struct { |
932.1.1
by Roger Peppe
rpc: kill root before returning |
576 |
killed bool |
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
577 |
Root
|
932.1.1
by Roger Peppe
rpc: kill root before returning |
578 |
}
|
579 |
||
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
580 |
func (r *KillerRoot) Kill() { |
932.1.1
by Roger Peppe
rpc: kill root before returning |
581 |
r.killed = true |
582 |
}
|
|
583 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
584 |
func (*rpcSuite) TestRootIsKilled(c *gc.C) { |
932.1.4
by Roger Peppe
rpc: rename TRoot to Root in tests |
585 |
root := &KillerRoot{} |
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
586 |
client, srvDone := newRPCClientServer(c, root, nil, false) |
932.1.1
by Roger Peppe
rpc: kill root before returning |
587 |
err := client.Close() |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
588 |
c.Assert(err, gc.IsNil) |
932.1.1
by Roger Peppe
rpc: kill root before returning |
589 |
err = chanReadError(c, srvDone, "server done") |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
590 |
c.Assert(err, gc.IsNil) |
591 |
c.Assert(root.killed, gc.Equals, true) |
|
932.1.1
by Roger Peppe
rpc: kill root before returning |
592 |
}
|
593 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
594 |
func (*rpcSuite) TestBidirectional(c *gc.C) { |
1214.1.11
by Roger Peppe
rpc: add bidirectional test |
595 |
srvRoot := &Root{} |
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
596 |
client, srvDone := newRPCClientServer(c, srvRoot, nil, true) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
597 |
defer closeClient(c, client, srvDone) |
1214.1.11
by Roger Peppe
rpc: add bidirectional test |
598 |
clientRoot := &Root{conn: client} |
599 |
client.Serve(clientRoot, nil) |
|
600 |
var r int64val |
|
601 |
err := client.Call("CallbackMethods", "", "Factorial", int64val{12}, &r) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
602 |
c.Assert(err, gc.IsNil) |
603 |
c.Assert(r.I, gc.Equals, int64(479001600)) |
|
1214.1.11
by Roger Peppe
rpc: add bidirectional test |
604 |
}
|
605 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
606 |
func (*rpcSuite) TestServerRequestWhenNotServing(c *gc.C) { |
1260.2.2
by Roger Peppe
rpc: test for unexpected server request |
607 |
srvRoot := &Root{} |
608 |
client, srvDone := newRPCClientServer(c, srvRoot, nil, true) |
|
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
609 |
defer closeClient(c, client, srvDone) |
1260.2.2
by Roger Peppe
rpc: test for unexpected server request |
610 |
var r int64val |
611 |
err := client.Call("CallbackMethods", "", "Factorial", int64val{12}, &r) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
612 |
c.Assert(err, gc.ErrorMatches, "request error: request error: no service") |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
613 |
}
|
614 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
615 |
func (*rpcSuite) TestChangeAPI(c *gc.C) { |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
616 |
srvRoot := &Root{} |
617 |
client, srvDone := newRPCClientServer(c, srvRoot, nil, true) |
|
618 |
defer closeClient(c, client, srvDone) |
|
619 |
var s stringVal |
|
620 |
err := client.Call("NewlyAvailable", "", "NewMethod", nil, &s) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
621 |
c.Assert(err, gc.ErrorMatches, `request error: unknown object type "NewlyAvailable"`) |
622 |
err = client.Call("ChangeAPIMethods", "", "ChangeAPI", nil, nil) |
|
623 |
c.Assert(err, gc.IsNil) |
|
624 |
err = client.Call("ChangeAPIMethods", "", "ChangeAPI", nil, nil) |
|
625 |
c.Assert(err, gc.ErrorMatches, `request error: unknown object type "ChangeAPIMethods"`) |
|
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
626 |
err = client.Call("NewlyAvailable", "", "NewMethod", nil, &s) |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
627 |
c.Assert(err, gc.IsNil) |
628 |
c.Assert(s, gc.Equals, stringVal{"new method result"}) |
|
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
629 |
}
|
630 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
631 |
func (*rpcSuite) TestChangeAPIToNil(c *gc.C) { |
1260.2.4
by Roger Peppe
rpc: add TestChangeAPIToNil |
632 |
srvRoot := &Root{} |
633 |
client, srvDone := newRPCClientServer(c, srvRoot, nil, true) |
|
634 |
defer closeClient(c, client, srvDone) |
|
635 |
||
636 |
err := client.Call("ChangeAPIMethods", "", "RemoveAPI", nil, nil) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
637 |
c.Assert(err, gc.IsNil) |
1260.2.4
by Roger Peppe
rpc: add TestChangeAPIToNil |
638 |
|
639 |
err = client.Call("ChangeAPIMethods", "", "RemoveAPI", nil, nil) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
640 |
c.Assert(err, gc.ErrorMatches, "request error: no service") |
1260.2.4
by Roger Peppe
rpc: add TestChangeAPIToNil |
641 |
}
|
642 |
||
1863.4.5
by Roger Peppe
rpc: split out rpcreflect tests |
643 |
func (*rpcSuite) TestChangeAPIWhileServingRequest(c *gc.C) { |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
644 |
ready := make(chan struct{}) |
645 |
done := make(chan error) |
|
646 |
srvRoot := &Root{ |
|
647 |
delayed: map[string]*DelayedMethods{ |
|
648 |
"1": {ready: ready, doneError: done}, |
|
649 |
},
|
|
650 |
}
|
|
651 |
transform := func(err error) error { |
|
652 |
return fmt.Errorf("transformed: %v", err) |
|
653 |
}
|
|
654 |
client, srvDone := newRPCClientServer(c, srvRoot, transform, true) |
|
655 |
defer closeClient(c, client, srvDone) |
|
656 |
||
657 |
result := make(chan error) |
|
658 |
go func() { |
|
659 |
result <- client.Call("DelayedMethods", "1", "Delay", nil, nil) |
|
660 |
}()
|
|
661 |
chanRead(c, ready, "method ready") |
|
662 |
||
663 |
err := client.Call("ChangeAPIMethods", "", "ChangeAPI", nil, nil) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
664 |
c.Assert(err, gc.IsNil) |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
665 |
|
666 |
// Ensure that not only does the request in progress complete,
|
|
667 |
// but that the original transformErrors function is called.
|
|
668 |
done <- fmt.Errorf("an error") |
|
669 |
select { |
|
670 |
case r := <-result: |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
671 |
c.Assert(r, gc.ErrorMatches, "request error: transformed: an error") |
1260.2.3
by Roger Peppe
rpc: tests for dynamic Serve request |
672 |
case <-time.After(3 * time.Second): |
673 |
c.Fatalf("timeout on channel read") |
|
674 |
}
|
|
1260.2.2
by Roger Peppe
rpc: test for unexpected server request |
675 |
}
|
676 |
||
1657.1.7
by Roger Peppe
gocheck imports - e-r |
677 |
func chanReadError(c *gc.C, ch <-chan error, what string) error { |
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
678 |
select { |
679 |
case e := <-ch: |
|
680 |
return e |
|
681 |
case <-time.After(3 * time.Second): |
|
1585.2.4
by Roger Peppe
another one |
682 |
c.Fatalf("timeout on channel read %s", what) |
885.1.1
by Roger Peppe
rpc: add timeouts to channel reads in tests |
683 |
}
|
1585.2.4
by Roger Peppe
another one |
684 |
panic("unreachable") |
766.3.4
by Roger Peppe
rpc: make test context thread-safe |
685 |
}
|
686 |
||
687 |
// newRPCClientServer starts an RPC server serving a connection from a
|
|
688 |
// single client. When the server has finished serving the connection,
|
|
1025.1.2
by Roger Peppe
rpc: lose named return args on newRPCClientServer |
689 |
// it sends a value on the returned channel.
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
690 |
// If bidir is true, requests can flow in both directions.
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
691 |
func newRPCClientServer(c *gc.C, root interface{}, tfErr func(error) error, bidir bool) (*rpc.Conn, <-chan error) { |
1127.1.1
by Martin Packman
Use ipv4 for loopback connection in rpc tests |
692 |
l, err := net.Listen("tcp", "127.0.0.1:0") |
1657.1.7
by Roger Peppe
gocheck imports - e-r |
693 |
c.Assert(err, gc.IsNil) |
766.2.11
by Roger Peppe
rpc: working connection codec tests |
694 |
|
766.3.3
by Roger Peppe
rpc: factor out newRPCClientServer in tests |
695 |
srvDone := make(chan error, 1) |
766.2.11
by Roger Peppe
rpc: working connection codec tests |
696 |
go func() { |
766.3.3
by Roger Peppe
rpc: factor out newRPCClientServer in tests |
697 |
conn, err := l.Accept() |
698 |
if err != nil { |
|
1863.2.1
by Roger Peppe
rpc: allow introspection of methods |
699 |
srvDone <- nil |
766.3.3
by Roger Peppe
rpc: factor out newRPCClientServer in tests |
700 |
return
|
766.2.26
by Roger Peppe
rpc: simplify a little |
701 |
}
|
1025.1.1
by Roger Peppe
rpc: fix race when closing down test rpc server |
702 |
defer l.Close() |
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
703 |
role := roleServer |
704 |
if bidir { |
|
705 |
role = roleBoth |
|
706 |
}
|
|
707 |
rpcConn := rpc.NewConn(NewJSONCodec(conn, role)) |
|
1863.2.1
by Roger Peppe
rpc: allow introspection of methods |
708 |
rpcConn.Serve(root, tfErr) |
1214.1.11
by Roger Peppe
rpc: add bidirectional test |
709 |
if root, ok := root.(*Root); ok { |
710 |
root.conn = rpcConn |
|
711 |
}
|
|
712 |
rpcConn.Start() |
|
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
713 |
<-rpcConn.Dead() |
714 |
srvDone <- rpcConn.Close() |
|
766.2.11
by Roger Peppe
rpc: working connection codec tests |
715 |
}()
|
716 |
conn, err := net.Dial("tcp", l.Addr().String()) |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
717 |
c.Assert(err, gc.IsNil) |
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
718 |
role := roleClient |
719 |
if bidir { |
|
720 |
role = roleBoth |
|
721 |
}
|
|
722 |
client := rpc.NewConn(NewJSONCodec(conn, role)) |
|
1214.1.11
by Roger Peppe
rpc: add bidirectional test |
723 |
client.Start() |
766.3.3
by Roger Peppe
rpc: factor out newRPCClientServer in tests |
724 |
return client, srvDone |
766.2.11
by Roger Peppe
rpc: working connection codec tests |
725 |
}
|
726 |
||
1657.1.7
by Roger Peppe
gocheck imports - e-r |
727 |
func closeClient(c *gc.C, client *rpc.Conn, srvDone <-chan error) { |
1712.2.3
by John Arbash Meinel
Add some direct tests that calling Close multiple times is ok. |
728 |
err := client.Close() |
729 |
c.Assert(err, gc.IsNil) |
|
730 |
err = chanReadError(c, srvDone, "server done") |
|
1657.1.7
by Roger Peppe
gocheck imports - e-r |
731 |
c.Assert(err, gc.IsNil) |
1068.4.2
by Roger Peppe
rpc: continue after read body error (tests) |
732 |
}
|
733 |
||
766.2.23
by Roger Peppe
rpc: revamp |
734 |
type encoder interface { |
735 |
Encode(e interface{}) error |
|
736 |
}
|
|
737 |
||
738 |
type decoder interface { |
|
739 |
Decode(e interface{}) error |
|
740 |
}
|
|
741 |
||
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
742 |
// testCodec wraps an rpc.Codec with extra error checking code.
|
743 |
type testCodec struct { |
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
744 |
role connRole |
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
745 |
rpc.Codec |
766.2.23
by Roger Peppe
rpc: revamp |
746 |
}
|
747 |
||
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
748 |
func (c *testCodec) WriteMessage(hdr *rpc.Header, x interface{}) error { |
885.2.6
by Roger Peppe
rpc: more struct fixes + tests |
749 |
if reflect.ValueOf(x).Kind() != reflect.Struct { |
750 |
panic(fmt.Errorf("WriteRequest bad param; want struct got %T (%#v)", x, x)) |
|
751 |
}
|
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
752 |
if c.role != roleBoth && hdr.IsRequest() != (c.role == roleClient) { |
753 |
panic(fmt.Errorf("codec role %v; header wrong type %#v", c.role, hdr)) |
|
754 |
}
|
|
755 |
log.Infof("send header: %#v; body: %#v", hdr, x) |
|
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
756 |
return c.Codec.WriteMessage(hdr, x) |
766.2.23
by Roger Peppe
rpc: revamp |
757 |
}
|
758 |
||
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
759 |
func (c *testCodec) ReadHeader(hdr *rpc.Header) error { |
760 |
err := c.Codec.ReadHeader(hdr) |
|
1214.1.1
by Roger Peppe
rpc: refactor to be symmetrical |
761 |
if err != nil { |
762 |
return err |
|
763 |
}
|
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
764 |
log.Infof("got header %#v", hdr) |
765 |
if c.role != roleBoth && hdr.IsRequest() == (c.role == roleClient) { |
|
766 |
panic(fmt.Errorf("codec role %v; read wrong type %#v", c.role, hdr)) |
|
767 |
}
|
|
1214.1.1
by Roger Peppe
rpc: refactor to be symmetrical |
768 |
return nil |
766.2.23
by Roger Peppe
rpc: revamp |
769 |
}
|
770 |
||
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
771 |
func (c *testCodec) ReadBody(r interface{}, isRequest bool) error { |
885.2.6
by Roger Peppe
rpc: more struct fixes + tests |
772 |
if v := reflect.ValueOf(r); v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { |
773 |
panic(fmt.Errorf("ReadResponseBody bad destination; want *struct got %T", r)) |
|
774 |
}
|
|
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
775 |
if c.role != roleBoth && isRequest == (c.role == roleClient) { |
776 |
panic(fmt.Errorf("codec role %v; read wrong body type %#v", c.role, r)) |
|
777 |
}
|
|
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
778 |
// Note: this will need to change if we want to test a non-JSON codec.
|
766.3.1
by Roger Peppe
rpc: concurrent requests |
779 |
var m json.RawMessage |
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
780 |
err := c.Codec.ReadBody(&m, isRequest) |
766.3.1
by Roger Peppe
rpc: concurrent requests |
781 |
if err != nil { |
782 |
return err |
|
783 |
}
|
|
993.5.2
by Ian Booth
Add syslog logging target, rework logging interface |
784 |
log.Infof("got response body: %q", m) |
766.3.1
by Roger Peppe
rpc: concurrent requests |
785 |
err = json.Unmarshal(m, r) |
993.5.2
by Ian Booth
Add syslog logging target, rework logging interface |
786 |
log.Infof("unmarshalled into %#v", r) |
766.3.1
by Roger Peppe
rpc: concurrent requests |
787 |
return err |
766.2.23
by Roger Peppe
rpc: revamp |
788 |
}
|
789 |
||
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
790 |
type connRole string |
791 |
||
792 |
const ( |
|
793 |
roleBoth connRole = "both" |
|
794 |
roleClient connRole = "client" |
|
795 |
roleServer connRole = "server" |
|
796 |
)
|
|
797 |
||
798 |
func NewJSONCodec(c net.Conn, role connRole) rpc.Codec { |
|
1214.1.7
by Roger Peppe
rpc: improve shutdown logic |
799 |
return &testCodec{ |
1214.1.12
by Roger Peppe
rpc/jsoncodec: tests |
800 |
role: role, |
801 |
Codec: jsoncodec.NewNet(c), |
|
766.2.23
by Roger Peppe
rpc: revamp |
802 |
}
|
766.2.4
by Roger Peppe
rpc: implement ServeCodec (single threaded) |
803 |
}
|