~rogpeppe/juju-core/438-local-instance-Addresses

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
}