blob: a98eca719baa2d336785396328887a123aa2e94f [file] [log] [blame]
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -08001package ipc_test
2
3import (
4 "fmt"
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -08005 "io"
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -08006 "os"
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -08007 "path/filepath"
8 "reflect"
9 "runtime"
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080010 "testing"
11 "time"
12
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080013 "veyron.io/veyron/veyron2"
14 "veyron.io/veyron/veyron2/ipc"
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080015 "veyron.io/veyron/veyron2/naming"
16 "veyron.io/veyron/veyron2/rt"
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080017 old_verror "veyron.io/veyron/veyron2/verror"
18 verror "veyron.io/veyron/veyron2/verror2"
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080019 "veyron.io/veyron/veyron2/vlog"
20
21 "veyron.io/veyron/veyron/lib/expect"
22 "veyron.io/veyron/veyron/lib/flags/consts"
23 "veyron.io/veyron/veyron/lib/modules"
24 "veyron.io/veyron/veyron/lib/modules/core"
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080025 "veyron.io/veyron/veyron/profiles"
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080026)
27
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080028var r veyron2.Runtime
29
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080030func init() {
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080031 modules.RegisterChild("ping", "<name>", childPing)
Matt Rosencrantzc13446b2014-12-03 10:37:00 -080032 var err error
33 if r, err = rt.New(); err != nil {
34 panic(err)
35 }
36
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080037 r.Namespace().CacheCtl(naming.DisableCache(true))
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080038}
39
40func testArgs(args ...string) []string {
41 var targs = []string{"--", "--veyron.tcp.address=127.0.0.1:0"}
42 return append(targs, args...)
43}
44
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080045func runMountTable(t *testing.T, r veyron2.Runtime) (*modules.Shell, func()) {
46 sh, err := modules.NewShell(r.Principal())
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -080047 if err != nil {
48 t.Fatalf("unexpected error: %s", err)
49 }
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080050 root, err := sh.Start(core.RootMTCommand, nil, testArgs()...)
51 if err != nil {
52 t.Fatalf("unexpected error for root mt: %s", err)
53 }
54 sh.Forget(root)
55
56 rootSession := expect.NewSession(t, root.Stdout(), time.Minute)
57 rootName := rootSession.ExpectVar("MT_NAME")
58 if t.Failed() {
59 t.Fatalf("%s", rootSession.Error())
60 }
61 sh.SetVar(consts.NamespaceRootPrefix, rootName)
Matt Rosencrantzc13446b2014-12-03 10:37:00 -080062 if err = r.Namespace().SetRoots(rootName); err != nil {
63 t.Fatalf("unexpected error setting namespace roots: %s", err)
64 }
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080065
66 deferFn := func() {
67 if testing.Verbose() {
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080068 vlog.Infof("------ shell cleanup ------")
69 sh.Cleanup(os.Stderr, os.Stderr)
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080070 vlog.Infof("------ root shutdown ------")
71 root.Shutdown(os.Stderr, os.Stderr)
72 } else {
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080073 sh.Cleanup(nil, nil)
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080074 root.Shutdown(nil, nil)
75 }
76 }
77 return sh, deferFn
78}
79
80func runClient(t *testing.T, sh *modules.Shell) error {
81 clt, err := sh.Start(core.EchoClientCommand, nil, "echoServer", "a message")
82 if err != nil {
83 t.Fatalf("unexpected error: %s", err)
84 }
85 s := expect.NewSession(t, clt.Stdout(), 30*time.Second)
86 s.Expect("echoServer: a message")
87 if s.Failed() {
88 return s.Error()
89 }
90 return nil
91}
92
Matt Rosencrantzc13446b2014-12-03 10:37:00 -080093func numServers(t *testing.T, name string) int {
94 servers, err := r.Namespace().Resolve(r.NewContext(), name)
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080095 if err != nil {
Matt Rosencrantzc13446b2014-12-03 10:37:00 -080096 return 0
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -080097 }
Matt Rosencrantzc13446b2014-12-03 10:37:00 -080098 return len(servers)
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -080099}
100
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -0800101// TODO(cnicolaou): figure out how to test and see what the internals
102// of tryCall are doing - e.g. using stats counters.
103func TestMultipleEndpoints(t *testing.T) {
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800104 sh, fn := runMountTable(t, r)
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -0800105 defer fn()
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800106 srv, err := sh.Start(core.EchoServerCommand, nil, testArgs("echoServer", "echoServer")...)
107 if err != nil {
108 t.Fatalf("unexpected error: %s", err)
109 }
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -0800110 s := expect.NewSession(t, srv.Stdout(), time.Minute)
111 s.ExpectVar("NAME")
112
113 runClient(t, sh)
114
115 // Create a fake set of 100 entries in the mount table
Matt Rosencrantzc13446b2014-12-03 10:37:00 -0800116 ctx := r.NewContext()
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -0800117 for i := 0; i < 100; i++ {
118 // 203.0.113.0 is TEST-NET-3 from RFC5737
119 ep := naming.FormatEndpoint("tcp", fmt.Sprintf("203.0.113.%d:443", i))
120 n := naming.JoinAddressName(ep, "")
Matt Rosencrantzc13446b2014-12-03 10:37:00 -0800121 if err := r.Namespace().Mount(ctx, "echoServer", n, time.Hour); err != nil {
122 t.Fatalf("unexpected error: %s", err)
123 }
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -0800124 }
125
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800126 // Verify that there are 102 entries for echoServer in the mount table.
Matt Rosencrantzc13446b2014-12-03 10:37:00 -0800127 if got, want := numServers(t, "echoServer"), 102; got != want {
128 t.Fatalf("got: %d, want: %d", got, want)
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -0800129 }
130
131 // TODO(cnicolaou): ok, so it works, but I'm not sure how
132 // long it should take or if the parallel connection code
133 // really works. Use counters to inspect it for example.
134 if err := runClient(t, sh); err != nil {
135 t.Fatalf("unexpected error: %s", err)
136 }
137
138 srv.CloseStdin()
139 srv.Shutdown(nil, nil)
140
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -0800141 // Verify that there are 100 entries for echoServer in the mount table.
Matt Rosencrantzc13446b2014-12-03 10:37:00 -0800142 if got, want := numServers(t, "echoServer"), 100; got != want {
143 t.Fatalf("got: %d, want: %d", got, want)
Cosmos Nicolaou00a0f802014-11-16 22:44:55 -0800144 }
145}
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800146
147func TestTimeoutCall(t *testing.T) {
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800148 client := r.Client()
149 ctx, _ := r.NewContext().WithTimeout(100 * time.Millisecond)
150 name := naming.JoinAddressName(naming.FormatEndpoint("tcp", "203.0.113.10:443"), "")
151 _, err := client.StartCall(ctx, name, "echo", []interface{}{"args don't matter"})
152 if !verror.Is(err, verror.Timeout.ID) {
153 t.Fatalf("wrong error: %s", err)
154 }
155}
156
157type sleeper struct {
158 done <-chan struct{}
159}
160
161func (s *sleeper) Sleep(call ipc.ServerContext) error {
162 select {
163 case <-s.done:
164 case <-time.After(time.Hour):
165 }
166 return nil
167}
168
169func (s *sleeper) Ping(call ipc.ServerContext) (string, error) {
170 return "pong", nil
171}
172
173func (s *sleeper) Source(call ipc.ServerCall, start int) error {
174 i := start
175 backoff := 25 * time.Millisecond
176 for {
177 select {
178 case <-s.done:
179 return nil
180 case <-time.After(backoff):
181 call.Send(i)
182 i++
183 }
184 backoff *= 2
185 }
186}
187
188func (s *sleeper) Sink(call ipc.ServerCall) (int, error) {
189 i := 0
190 for {
191 if err := call.Recv(&i); err != nil {
192 return i, err
193 }
194 }
195}
196
197func childPing(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
198 name := args[1]
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800199 call, err := r.Client().StartCall(r.NewContext(), name, "Ping", nil)
200 if err != nil {
201 fmt.Errorf("unexpected error: %s", err)
202 }
203 got := ""
204 verr := call.Finish(&got, &err)
205 if verr != nil {
206 fmt.Errorf("unexpected error: %s", verr)
207 }
208 if err != nil {
209 fmt.Errorf("unexpected error: %s", err)
210 }
211 fmt.Fprintf(stdout, "RESULT=%s\n", got)
212 return nil
213}
214
215func initServer(t *testing.T, r veyron2.Runtime) (string, ipc.Server, func()) {
216 server, err := r.NewServer()
217 if err != nil {
218 t.Fatalf("unexpected error: %s", err)
219 }
220 done := make(chan struct{})
221 deferFn := func() { close(done); server.Stop() }
222
223 ep, err := server.Listen(profiles.LocalListenSpec)
224 if err != nil {
225 t.Fatalf("unexpected error: %s", err)
226 }
227 server.Serve("", &sleeper{done}, nil)
228 name := naming.JoinAddressName(ep.String(), "")
229 return name, server, deferFn
230}
231
232func testForVerror(t *testing.T, err error, verr ...verror.IDAction) {
233 _, file, line, _ := runtime.Caller(1)
234 loc := fmt.Sprintf("%s:%d", filepath.Base(file), line)
235 found := false
236 for _, v := range verr {
237 if verror.Is(err, v.ID) {
238 found = true
239 break
240 }
241 }
242 if !found {
243 if _, ok := err.(verror.E); !ok {
244 t.Fatalf("%s: err %v not a verror", loc, err)
245 }
246 stack := ""
247 if err != nil {
248 stack = err.(verror.E).Stack().String()
249 }
250 t.Fatalf("%s: expecting one of: %v, got: %v: stack: %s", loc, verr, err, stack)
251 }
252}
253
254func TestTimeoutResponse(t *testing.T) {
255 name, _, fn := initServer(t, r)
256 defer fn()
257 ctx, _ := r.NewContext().WithTimeout(100 * time.Millisecond)
258 call, err := r.Client().StartCall(ctx, name, "Sleep", nil)
259 if err != nil {
260 testForVerror(t, err, verror.Timeout)
261 return
262 }
263 verr := call.Finish(&err)
264 // TODO(cnicolaou): this should be Timeout only.
265 testForVerror(t, verr, verror.Timeout, verror.BadProtocol)
266}
267
268func TestArgsAndResponses(t *testing.T) {
269 name, _, fn := initServer(t, r)
270 defer fn()
271
272 call, err := r.Client().StartCall(r.NewContext(), name, "Sleep", []interface{}{"too many args"})
273 if err != nil {
274 t.Fatalf("unexpected error: %s", err)
275 }
276 verr := call.Finish(&err)
277 testForVerror(t, verr, verror.BadProtocol)
278
279 call, err = r.Client().StartCall(r.NewContext(), name, "Ping", nil)
280 if err != nil {
281 t.Fatalf("unexpected error: %s", err)
282 }
283 pong := ""
284 dummy := ""
285 verr = call.Finish(&pong, &dummy, &err)
286 testForVerror(t, verr, verror.BadProtocol)
287}
288
289func TestAccessDenied(t *testing.T) {
290 r1, _ := rt.New()
291 r2, _ := rt.New()
292
293 // The server and client use different runtimes and hence different
294 // principals and without any shared blessings the server will deny
295 // access to the client
296 name, _, fn := initServer(t, r1)
297 defer fn()
298
299 client := r2.Client()
300 call, err := client.StartCall(r2.NewContext(), name, "Sleep", nil)
301 if err != nil {
302 t.Fatalf("unexpected error: %s", err)
303 }
304 verr := call.Finish(&err)
305 testForVerror(t, verr, verror.NoAccess)
306}
307
308func TestCancelledBeforeFinish(t *testing.T) {
309 name, _, fn := initServer(t, r)
310 defer fn()
311
312 ctx, cancel := r.NewContext().WithCancel()
313 call, err := r.Client().StartCall(ctx, name, "Sleep", nil)
314 if err != nil {
315 t.Fatalf("unexpected error: %s", err)
316 }
317 // Cancel before we call finish.
318 cancel()
319 verr := call.Finish(&err)
320 // TOO(cnicolaou): this should be Cancelled only.
321 testForVerror(t, verr, verror.Cancelled, verror.BadProtocol)
322}
323
324func TestCancelledDuringFinish(t *testing.T) {
325 name, _, fn := initServer(t, r)
326 defer fn()
327
328 ctx, cancel := r.NewContext().WithCancel()
329 call, err := r.Client().StartCall(ctx, name, "Sleep", nil)
330 if err != nil {
331 t.Fatalf("unexpected error: %s", err)
332 }
333 // Cancel whilst the RPC is running.
334 go func() {
335 time.Sleep(100 * time.Millisecond)
336 cancel()
337 }()
338 verr := call.Finish(&err)
339 // TOO(cnicolaou): this should be Cancelled only.
340 testForVerror(t, verr, verror.Cancelled, verror.BadProtocol)
341}
342
343func TestRendezvous(t *testing.T) {
344 sh, fn := runMountTable(t, r)
345 defer fn()
346
347 name := "echoServer"
348
349 // We start the client before we start the server, StartCall will reresolve
350 // the name until it finds an entry or timesout after an exponential
351 // backoff of some minutes.
352 startServer := func() {
353 time.Sleep(10 * time.Millisecond)
354 srv, _ := sh.Start(core.EchoServerCommand, nil, testArgs("message", name)...)
355 s := expect.NewSession(t, srv.Stdout(), time.Minute)
356 s.ExpectVar("NAME")
357 }
358 go startServer()
359
360 call, err := r.Client().StartCall(r.NewContext(), name, "Echo", []interface{}{"hello"})
361 if err != nil {
362 t.Fatalf("unexpected error: %s", err)
363 }
364
365 response := ""
366 verr := call.Finish(&response, &err)
367 if verr != nil {
368 testForVerror(t, verr, verror.Cancelled)
369 return
370 }
371 if got, want := response, "message: hello\n"; got != want {
372 t.Errorf("got %q, want %q", got, want)
373 }
374}
375
376func TestCallback(t *testing.T) {
377 sh, fn := runMountTable(t, r)
378 defer fn()
379
380 name, _, fn := initServer(t, r)
381 defer fn()
382
383 srv, err := sh.Start("ping", nil, name)
384 if err != nil {
385 t.Fatalf("unexpected error: %s", err)
386 }
387 s := expect.NewSession(t, srv.Stdout(), time.Minute)
388 if got, want := s.ExpectVar("RESULT"), "pong"; got != want {
389 t.Errorf("got %q, want %q", got, want)
390 }
391}
392
393func TestStreamTimeout(t *testing.T) {
394 name, _, fn := initServer(t, r)
395 defer fn()
396
397 want := 10
398 ctx, _ := r.NewContext().WithTimeout(300 * time.Millisecond)
399 call, err := r.Client().StartCall(ctx, name, "Source", []interface{}{want})
400 if err != nil {
401 if !verror.Is(err, verror.Timeout.ID) && !verror.Is(err, verror.BadProtocol.ID) {
402 t.Fatalf("verror should be a timeout or badprotocol, not %s: stack %s",
403 err, err.(verror.E).Stack())
404 }
405 return
406 }
407
408 for {
409 got := 0
410 err := call.Recv(&got)
411 if err == nil {
412 if got != want {
413 t.Fatalf("got %d, want %d", got, want)
414 }
415 want++
416 continue
417 }
418 // TOO(cnicolaou): this should be Timeout only.
419 testForVerror(t, err, verror.Timeout, verror.BadProtocol)
420 break
421 }
422 verr := call.Finish(&err)
423 testForVerror(t, verr, verror.Timeout, verror.BadProtocol)
424}
425
426func TestStreamAbort(t *testing.T) {
427 name, _, fn := initServer(t, r)
428 defer fn()
429
430 ctx := r.NewContext()
431 call, err := r.Client().StartCall(ctx, name, "Sink", nil)
432 if err != nil {
433 t.Fatalf("unexpected error: %s", err)
434 }
435
436 want := 10
437 for i := 0; i <= want; i++ {
438 if err := call.Send(i); err != nil {
439 t.Fatalf("unexpected error: %s", err)
440 }
441 }
442 call.CloseSend()
443 verr := call.Send(100)
444 testForVerror(t, verr, verror.Aborted)
445
446 result := 0
447 verr = call.Finish(&result, &err)
448 if verr != nil {
449 t.Fatalf("unexpected error: %s", verr)
450 }
451 if got, want := err, (old_verror.Standard{Msg: "EOF"}); !reflect.DeepEqual(got, want) {
452 t.Fatalf("got %v, want %v", got, want)
453 }
454 if got := result; got != want {
455 t.Errorf("got %d, want %d", got, want)
456 }
457}
458
459func TestNoServersAvailable(t *testing.T) {
460 _, fn := runMountTable(t, r)
461 defer fn()
462 name := "noservers"
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800463 ctx, _ := r.NewContext().WithTimeout(300 * time.Millisecond)
464 call, verr := r.Client().StartCall(ctx, name, "Sleep", nil)
465 if verr != nil {
Jungho Ahn6366dde2014-12-02 20:41:44 -0800466 testForVerror(t, verr, verror.Timeout, verror.BadProtocol, verror.NoExist)
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800467 return
468 }
Jungho Ahn6366dde2014-12-02 20:41:44 -0800469 // The local namespace client may return the 'current' name when it encounters
470 // a timeout or other networking error, which means we may end up invoking an
471 // RPC on that entry - which in our case means we end up invoking:
472 // <mount table endpoint>/noservers.Sleep(). This RPC will fail immediately
473 // since we've already reached our timeout, but we can't see that error
474 // until we call Finish.
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800475 err := call.Finish(&verr)
Jungho Ahn6366dde2014-12-02 20:41:44 -0800476 testForVerror(t, err, verror.Timeout, verror.BadProtocol)
Cosmos Nicolaou5a8a1252014-12-01 14:14:25 -0800477}
478
479func TestNoMountTable(t *testing.T) {
480 r.Namespace().SetRoots()
481 name := "a_mount_table_entry"
482
483 // If there is no mount table, then we'll get a NoServers error message.
484 ctx, _ := r.NewContext().WithTimeout(300 * time.Millisecond)
485 _, verr := r.Client().StartCall(ctx, name, "Sleep", nil)
486 testForVerror(t, verr, verror.NoServers)
487}
488
489// TODO(cnicolaou:) tests for:
490// -- Test for bad discharges error and correct invalidation, client.go:870..880