blob: dc2b32dfc8994dc5eb989cb4755180d56d587dae [file] [log] [blame]
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001package manager
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "net"
Cosmos Nicolaou920db002014-10-23 16:57:32 -07008 "os"
Jiri Simsa5293dcb2014-05-10 09:56:38 -07009 "reflect"
10 "runtime"
11 "strings"
12 "testing"
Cosmos Nicolaou920db002014-10-23 16:57:32 -070013 "time"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070014
Jiri Simsa519c5072014-09-17 21:37:57 -070015 "veyron.io/veyron/veyron2/ipc/stream"
16 "veyron.io/veyron/veyron2/naming"
17 "veyron.io/veyron/veyron2/security"
18 "veyron.io/veyron/veyron2/vlog"
Cosmos Nicolaou5129fcb2014-08-22 11:52:25 -070019
Cosmos Nicolaou920db002014-10-23 16:57:32 -070020 "veyron.io/veyron/veyron/lib/expect"
21 "veyron.io/veyron/veyron/lib/modules"
Cosmos Nicolaou87c0a552014-12-02 23:05:49 -080022 _ "veyron.io/veyron/veyron/lib/tcp"
Asim Shankarc920db32014-10-16 19:18:21 -070023 "veyron.io/veyron/veyron/lib/testutil"
Ankure49a86a2014-11-11 18:52:43 -080024 tsecurity "veyron.io/veyron/veyron/lib/testutil/security"
Cosmos Nicolaou87c0a552014-12-02 23:05:49 -080025 _ "veyron.io/veyron/veyron/lib/websocket"
Jiri Simsa519c5072014-09-17 21:37:57 -070026 "veyron.io/veyron/veyron/runtimes/google/ipc/stream/vc"
27 "veyron.io/veyron/veyron/runtimes/google/ipc/version"
28 inaming "veyron.io/veyron/veyron/runtimes/google/naming"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070029)
30
Asim Shankar6b0510a2014-10-01 12:05:06 -070031func newPrincipal(defaultBlessing string) vc.LocalPrincipal {
Ankure49a86a2014-11-11 18:52:43 -080032 return vc.LocalPrincipal{tsecurity.NewPrincipal(defaultBlessing)}
Ankura3c97652014-07-17 20:01:21 -070033}
34
Jiri Simsa5293dcb2014-05-10 09:56:38 -070035func init() {
Asim Shankarc920db32014-10-16 19:18:21 -070036 testutil.Init()
37 // testutil.Init sets GOMAXPROCS to NumCPU. We want to force
38 // GOMAXPROCS to remain at 1, in order to trigger a particular race
39 // condition tht occurs when closing the server; also, using 1 cpu
Jiri Simsa5293dcb2014-05-10 09:56:38 -070040 // introduces less variance in the behavior of the test.
41 runtime.GOMAXPROCS(1)
Cosmos Nicolaou920db002014-10-23 16:57:32 -070042 modules.RegisterChild("runServer", "", runServer)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070043}
44
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -080045func testSimpleFlow(t *testing.T, protocol string) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070046 server := InternalNew(naming.FixedRoutingID(0x55555555))
47 client := InternalNew(naming.FixedRoutingID(0xcccccccc))
48
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -080049 ln, ep, err := server.Listen(protocol, "127.0.0.1:0")
Jiri Simsa5293dcb2014-05-10 09:56:38 -070050 if err != nil {
51 t.Fatal(err)
52 }
53
54 data := "the dark knight rises"
55 var clientVC stream.VC
56 var clientF1 stream.Flow
57 go func() {
58 if clientVC, err = client.Dial(ep); err != nil {
59 t.Errorf("Dial(%q) failed: %v", ep, err)
60 return
61 }
62 if clientF1, err = clientVC.Connect(); err != nil {
63 t.Errorf("Connect() failed: %v", err)
64 return
65 }
66 if err := writeLine(clientF1, data); err != nil {
67 t.Error(err)
68 }
69 }()
70 serverF, err := ln.Accept()
71 if err != nil {
72 t.Fatalf("Accept failed: %v", err)
73 }
74 if got, err := readLine(serverF); got != data || err != nil {
75 t.Errorf("Got (%q, %v), want (%q, nil)", got, err, data)
76 }
77 // By this point, the goroutine has passed the write call (or exited
78 // early) since the read has gotten through. Check if the goroutine
79 // encountered any errors in creating the VC or flow and abort.
80 if t.Failed() {
81 return
82 }
83 defer clientF1.Close()
84
85 ln.Close()
86
87 // Writes on flows opened before the server listener was closed should
88 // still succeed.
89 data = "the dark knight goes to bed"
90 go func() {
91 if err := writeLine(clientF1, data); err != nil {
92 t.Error(err)
93 }
94 }()
95 if got, err := readLine(serverF); got != data || err != nil {
96 t.Errorf("Got (%q, %v), want (%q, nil)", got, err, data)
97 }
98
99 // Opening a new flow on an existing VC will succeed initially, but
100 // writes on the client end will eventually fail once the server has
101 // stopped listening.
102 //
103 // It will require a round-trip to the server to notice the failure,
104 // hence the client should write enough data to ensure that the Write
105 // call will not return before a round-trip.
106 //
107 // The length of the data is taken to exceed the queue buffer size
108 // (DefaultBytesBufferedPerFlow), the shared counters (MaxSharedBytes)
109 // and the per-flow counters (DefaultBytesBufferedPerFlow) that are
110 // given when the flow gets established.
111 //
112 // TODO(caprita): separate the constants for the queue buffer size and
113 // the default number of counters to avoid confusion.
114 lotsOfData := string(make([]byte, vc.DefaultBytesBufferedPerFlow*2+vc.MaxSharedBytes+1))
115 clientF2, err := clientVC.Connect()
116 if err != nil {
117 t.Fatalf("Connect() failed: %v", err)
118 }
119 defer clientF2.Close()
120 if err := writeLine(clientF2, lotsOfData); err == nil {
121 t.Errorf("Should not be able to Dial or Write after the Listener is closed")
122 }
123 // Opening a new VC should fail fast.
124 if _, err := client.Dial(ep); err == nil {
125 t.Errorf("Should not be able to Dial after listener is closed")
126 }
127}
128
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800129func TestSimpleFlow(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800130 testSimpleFlow(t, "tcp")
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800131}
132
133func TestSimpleFlowWS(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800134 testSimpleFlow(t, "ws")
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800135}
136
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -0800137func TestConnectionTimeout(t *testing.T) {
138 client := InternalNew(naming.FixedRoutingID(0xcccccccc))
139
140 ch := make(chan error)
141 go func() {
142 // 203.0.113.0 is TEST-NET-3 from RFC5737
143 ep, _ := inaming.NewEndpoint(naming.FormatEndpoint("tcp", "203.0.113.10:80"))
144 _, err := client.Dial(ep, &DialTimeout{time.Second})
145 ch <- err
146 }()
147
148 select {
149 case err := <-ch:
150 if err == nil {
151 t.Fatalf("expected an error")
152 }
153 case <-time.After(time.Minute):
154 t.Fatalf("timedout")
155 }
156}
157
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800158func testAuthenticatedByDefault(t *testing.T, protocol string) {
Asim Shankar6b0510a2014-10-01 12:05:06 -0700159 var (
160 server = InternalNew(naming.FixedRoutingID(0x55555555))
161 client = InternalNew(naming.FixedRoutingID(0xcccccccc))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700162
Asim Shankar6b0510a2014-10-01 12:05:06 -0700163 clientPrincipal = newPrincipal("client")
164 serverPrincipal = newPrincipal("server")
165 clientBlessings = clientPrincipal.Principal.BlessingStore().Default()
166 serverBlessings = serverPrincipal.Principal.BlessingStore().Default()
167 )
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700168 // VCSecurityLevel is intentionally not provided to Listen - to test
169 // default behavior.
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800170 ln, ep, err := server.Listen(protocol, "127.0.0.1:0", serverPrincipal)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700171 if err != nil {
172 t.Fatal(err)
173 }
174
175 errs := make(chan error)
176
Asim Shankar6b0510a2014-10-01 12:05:06 -0700177 testAuth := func(tag string, flow stream.Flow, local, remote security.Blessings) {
178 l := flow.LocalBlessings()
179 r := flow.RemoteBlessings()
180 if !reflect.DeepEqual(l, local) || !reflect.DeepEqual(r, remote) {
181 errs <- fmt.Errorf("%s: LocalBlessings: Got %q, want %q. RemoteBlessings: Got %q, want %q", tag, l, local, r, remote)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700182 return
183 }
184 errs <- nil
185 }
186
187 go func() {
188 flow, err := ln.Accept()
189 if err != nil {
190 errs <- err
191 return
192 }
193 defer flow.Close()
Asim Shankar6b0510a2014-10-01 12:05:06 -0700194 testAuth("server", flow, serverBlessings, clientBlessings)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700195 }()
196
197 go func() {
198 // VCSecurityLevel is intentionally not provided to Dial - to
199 // test default behavior.
Asim Shankar6b0510a2014-10-01 12:05:06 -0700200 vc, err := client.Dial(ep, clientPrincipal)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700201 if err != nil {
202 errs <- err
203 return
204 }
205 flow, err := vc.Connect()
206 if err != nil {
207 errs <- err
208 return
209 }
210 defer flow.Close()
Asim Shankar6b0510a2014-10-01 12:05:06 -0700211 testAuth("client", flow, clientBlessings, serverBlessings)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700212 }()
213
214 if err := <-errs; err != nil {
215 t.Error(err)
216 }
217 if err := <-errs; err != nil {
218 t.Error(err)
219 }
220}
221
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800222func TestAuthenticatedByDefault(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800223 testAuthenticatedByDefault(t, "tcp")
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800224}
225
226func TestAuthenticatedByDefaultWS(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800227 testAuthenticatedByDefault(t, "ws")
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800228}
229
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700230func numListeners(m stream.Manager) int { return len(m.(*manager).listeners) }
231func debugString(m stream.Manager) string { return m.(*manager).DebugString() }
232func numVIFs(m stream.Manager) int { return len(m.(*manager).vifs.List()) }
233
234func TestListenEndpoints(t *testing.T) {
235 server := InternalNew(naming.FixedRoutingID(0xcafe))
Adam Sadovsky5181bdb2014-08-13 10:29:11 -0700236 ln1, ep1, err1 := server.Listen("tcp", "127.0.0.1:0")
237 ln2, ep2, err2 := server.Listen("tcp", "127.0.0.1:0")
238 // Since "127.0.0.1:0" was used as the network address, a random port will be
239 // assigned in each case. The endpoint should include that random port.
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700240 if err1 != nil {
241 t.Error(err1)
242 }
243 if err2 != nil {
244 t.Error(err2)
245 }
246 if ep1.String() == ep2.String() {
247 t.Errorf("Both listeners got the same endpoint: %q", ep1)
248 }
249 if n, expect := numListeners(server), 2; n != expect {
250 t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server))
251 }
252 ln1.Close()
253 if n, expect := numListeners(server), 1; n != expect {
254 t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server))
255 }
256 ln2.Close()
257 if n, expect := numListeners(server), 0; n != expect {
258 t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server))
259 }
260}
261
262func acceptLoop(ln stream.Listener) {
263 for {
264 f, err := ln.Accept()
265 if err != nil {
266 return
267 }
268 f.Close()
269 }
270}
271
272func TestCloseListener(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800273 testCloseListener(t, "tcp")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700274}
275
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800276func TestCloseListenerWS(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800277 testCloseListener(t, "ws")
278}
279
280func testCloseListener(t *testing.T, protocol string) {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800281 server := InternalNew(naming.FixedRoutingID(0x5e97e9))
282
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800283 ln, ep, err := server.Listen(protocol, "127.0.0.1:0")
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800284 if err != nil {
285 t.Fatal(err)
286 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800287 // Server will just listen for flows and close them.
288 go acceptLoop(ln)
289 client := InternalNew(naming.FixedRoutingID(0xc1e41))
290 if _, err = client.Dial(ep); err != nil {
291 t.Fatal(err)
292 }
293 ln.Close()
294 client = InternalNew(naming.FixedRoutingID(0xc1e42))
295 if _, err := client.Dial(ep); err == nil {
296 t.Errorf("client.Dial(%q) should have failed", ep)
297 }
298}
299
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700300func TestShutdown(t *testing.T) {
301 server := InternalNew(naming.FixedRoutingID(0x5e97e9))
Adam Sadovsky5181bdb2014-08-13 10:29:11 -0700302 ln, _, err := server.Listen("tcp", "127.0.0.1:0")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700303 if err != nil {
304 t.Fatal(err)
305 }
306 // Server will just listen for flows and close them.
307 go acceptLoop(ln)
308 if n, expect := numListeners(server), 1; n != expect {
309 t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server))
310 }
311 server.Shutdown()
Adam Sadovsky5181bdb2014-08-13 10:29:11 -0700312 if _, _, err := server.Listen("tcp", "127.0.0.1:0"); err == nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700313 t.Error("server should have shut down")
314 }
315 if n, expect := numListeners(server), 0; n != expect {
316 t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server))
317 }
318}
319
320func TestShutdownEndpoint(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800321 testShutdownEndpoint(t, "tcp")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700322}
323
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800324func TestShutdownEndpointWS(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800325 testShutdownEndpoint(t, "ws")
326}
327
328func testShutdownEndpoint(t *testing.T, protocol string) {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800329 server := InternalNew(naming.FixedRoutingID(0x55555555))
330 client := InternalNew(naming.FixedRoutingID(0xcccccccc))
331
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800332 ln, ep, err := server.Listen(protocol, "127.0.0.1:0")
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800333 if err != nil {
334 t.Fatal(err)
335 }
336
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800337 // Server will just listen for flows and close them.
338 go acceptLoop(ln)
339
340 vc, err := client.Dial(ep)
341 if err != nil {
342 t.Fatal(err)
343 }
344 if f, err := vc.Connect(); f == nil || err != nil {
345 t.Errorf("vc.Connect failed: (%v, %v)", f, err)
346 }
347 client.ShutdownEndpoint(ep)
348 if f, err := vc.Connect(); f != nil || err == nil {
349 t.Errorf("vc.Connect unexpectedly succeeded: (%v, %v)", f, err)
350 }
351}
352
Andres Erbsenffa45742014-08-13 10:13:11 -0700353/* TLS + resumption + channel bindings is broken: <https://secure-resumption.com/#channelbindings>.
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700354func TestSessionTicketCache(t *testing.T) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700355 server := InternalNew(naming.FixedRoutingID(0x55555555))
Asim Shankar6b0510a2014-10-01 12:05:06 -0700356 _, ep, err := server.Listen("tcp", "127.0.0.1:0", newPrincipal("server"))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700357 if err != nil {
358 t.Fatal(err)
359 }
360
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700361 client := InternalNew(naming.FixedRoutingID(0xcccccccc))
Asim Shankar6b0510a2014-10-01 12:05:06 -0700362 if _, err = client.Dial(ep, newPrincipal("TestSessionTicketCacheClient")); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700363 t.Fatalf("Dial(%q) failed: %v", ep, err)
364 }
365
366 if _, ok := client.(*manager).sessionCache.Get(ep.String()); !ok {
367 t.Fatalf("SessionTicket from TLS handshake not cached")
368 }
369}
Andres Erbsenffa45742014-08-13 10:13:11 -0700370*/
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700371
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800372func testMultipleVCs(t *testing.T, protocol string) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700373 server := InternalNew(naming.FixedRoutingID(0x55555555))
374 client := InternalNew(naming.FixedRoutingID(0xcccccccc))
375
376 const nVCs = 2
377 const data = "bugs bunny"
378
379 // Have the server read from each flow and write to rchan.
380 rchan := make(chan string)
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800381 ln, ep, err := server.Listen(protocol, "127.0.0.1:0")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700382 if err != nil {
383 t.Fatal(err)
384 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800385
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700386 read := func(flow stream.Flow, c chan string) {
387 var buf bytes.Buffer
388 var tmp [1024]byte
389 for {
390 n, err := flow.Read(tmp[:])
391 buf.Write(tmp[:n])
392 if err == io.EOF {
393 c <- buf.String()
394 return
395 }
396 if err != nil {
397 t.Error(err)
398 return
399 }
400 }
401 }
402 go func() {
403 for i := 0; i < nVCs; i++ {
404 flow, err := ln.Accept()
405 if err != nil {
406 t.Error(err)
407 rchan <- ""
408 continue
409 }
410 go read(flow, rchan)
411 }
412 }()
413
414 // Have the client establish nVCs and a flow on each.
415 var vcs [nVCs]stream.VC
416 for i := 0; i < nVCs; i++ {
417 var err error
Asim Shankar7cf29002014-10-09 00:38:37 -0700418 vcs[i], err = client.Dial(ep)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700419 if err != nil {
420 t.Fatal(err)
421 }
422 }
423 write := func(vc stream.VC) {
424 if err != nil {
425 ln.Close()
426 t.Error(err)
427 return
428 }
429 flow, err := vc.Connect()
430 if err != nil {
431 ln.Close()
432 t.Error(err)
433 return
434 }
435 defer flow.Close()
436 if _, err := flow.Write([]byte(data)); err != nil {
437 ln.Close()
438 t.Error(err)
439 return
440 }
441 }
442 for _, vc := range vcs {
443 go write(vc)
444 }
445 for i := 0; i < nVCs; i++ {
446 if got := <-rchan; got != data {
447 t.Errorf("Got %q want %q", got, data)
448 }
449 }
450}
451
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800452func TestMultipleVCs(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800453 testMultipleVCs(t, "tcp")
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800454}
455
456func TestMultipleVCsWS(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800457 testMultipleVCs(t, "ws")
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800458}
459
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700460func TestAddressResolution(t *testing.T) {
461 server := InternalNew(naming.FixedRoutingID(0x55555555))
462 client := InternalNew(naming.FixedRoutingID(0xcccccccc))
463
Adam Sadovsky5181bdb2014-08-13 10:29:11 -0700464 // Using "tcp4" instead of "tcp" because the latter can end up with IPv6
465 // addresses and our Google Compute Engine integration test machines cannot
466 // resolve IPv6 addresses.
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700467 // As of April 2014, https://developers.google.com/compute/docs/networking
468 // said that IPv6 is not yet supported.
469 ln, ep, err := server.Listen("tcp4", "127.0.0.1:0")
470 if err != nil {
471 t.Fatal(err)
472 }
473 go acceptLoop(ln)
474
Adam Sadovsky5181bdb2014-08-13 10:29:11 -0700475 // We'd like an endpoint that contains an address that's different than the
476 // one used for the connection. In practice this is awkward to achieve since
477 // we don't want to listen on ":0" since that will annoy firewalls. Instead we
478 // listen on 127.0.0.1 and we fabricate an endpoint that doesn't contain
479 // 127.0.0.1 by using ":0" to create it. This leads to an endpoint such that
480 // the address encoded in the endpoint (e.g. "0.0.0.0:55324") is different
481 // from the address of the connection (e.g. "127.0.0.1:55324").
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700482 _, port, _ := net.SplitHostPort(ep.Addr().String())
483 nep := version.Endpoint(ep.Addr().Network(), net.JoinHostPort("", port), ep.RoutingID())
484
485 // Dial multiple VCs
486 for i := 0; i < 2; i++ {
487 if _, err = client.Dial(nep); err != nil {
488 t.Fatalf("Dial #%d failed: %v", i, err)
489 }
490 }
491 // They should all be on the same VIF.
492 if n := numVIFs(client); n != 1 {
493 t.Errorf("Client has %d VIFs, want 1\n%v", n, debugString(client))
494 }
495 // TODO(ashankar): While a VIF can be re-used to Dial from the server
496 // to the client, currently there is no way to have the client "listen"
497 // on the same VIF. It can listen on a VC for new flows, but it cannot
498 // listen on an established VIF for new VCs. Figure this out?
499}
500
501func TestServerRestartDuringClientLifetime(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800502 testServerRestartDuringClientLifetime(t, "tcp")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700503}
504
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800505func TestServerRestartDuringClientLifetimeWS(t *testing.T) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800506 testServerRestartDuringClientLifetime(t, "ws")
507}
508
509func testServerRestartDuringClientLifetime(t *testing.T, protocol string) {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800510 client := InternalNew(naming.FixedRoutingID(0xcccccccc))
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800511 sh, err := modules.NewShell(nil)
512 if err != nil {
513 t.Fatalf("unexpected error: %s", err)
514 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800515 defer sh.Cleanup(nil, nil)
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800516 h, err := sh.Start("runServer", nil, protocol, "127.0.0.1:0")
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800517 if err != nil {
518 t.Fatalf("unexpected error: %s", err)
519 }
520 s := expect.NewSession(t, h.Stdout(), time.Minute)
521 addr := s.ReadLine()
522
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800523 ep, err := inaming.NewEndpoint(naming.FormatEndpoint(protocol, addr))
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800524 if err != nil {
525 t.Fatalf("inaming.NewEndpoint(%q): %v", addr, err)
526 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800527 if _, err := client.Dial(ep); err != nil {
528 t.Fatal(err)
529 }
530 h.Shutdown(nil, os.Stderr)
531
532 // A new VC cannot be created since the server is dead
533 if _, err := client.Dial(ep); err == nil {
534 t.Fatal("Expected client.Dial to fail since server is dead")
535 }
536
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800537 h, err = sh.Start("runServer", nil, protocol, addr)
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800538 if err != nil {
539 t.Fatalf("unexpected error: %s", err)
540 }
541 s = expect.NewSession(t, h.Stdout(), time.Minute)
542 // Restarting the server, listening on the same address as before
543 if addr2 := s.ReadLine(); addr2 != addr || err != nil {
544 t.Fatalf("Got (%q, %v) want (%q, nil)", addr2, err, addr)
545 }
546 if _, err := client.Dial(ep); err != nil {
547 t.Fatal(err)
548 }
549}
550
Cosmos Nicolaou9388ae42014-11-10 10:57:15 -0800551// Needed by modules framework
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700552func TestHelperProcess(t *testing.T) {
Cosmos Nicolaou920db002014-10-23 16:57:32 -0700553 modules.DispatchInTest()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700554}
555
Cosmos Nicolaou920db002014-10-23 16:57:32 -0700556func runServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700557 server := InternalNew(naming.FixedRoutingID(0x55555555))
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800558 _, ep, err := server.Listen(args[1], args[2])
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700559 if err != nil {
Cosmos Nicolaou920db002014-10-23 16:57:32 -0700560 fmt.Fprintln(stderr, err)
561 return err
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700562 }
Cosmos Nicolaou920db002014-10-23 16:57:32 -0700563 fmt.Fprintln(stdout, ep.Addr())
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700564 // Live forever (till the process is explicitly killed)
Cosmos Nicolaou920db002014-10-23 16:57:32 -0700565 modules.WaitForEOF(stdin)
566 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700567}
568
569func readLine(f stream.Flow) (string, error) {
570 var result bytes.Buffer
571 var buf [5]byte
572 for {
573 n, err := f.Read(buf[:])
574 result.Write(buf[:n])
575 if err == io.EOF || buf[n-1] == '\n' {
576 return strings.TrimRight(result.String(), "\n"), nil
577 }
578 if err != nil {
579 return "", fmt.Errorf("Read returned (%d, %v)", n, err)
580 }
581 }
582}
583
584func writeLine(f stream.Flow, data string) error {
585 data = data + "\n"
586 vlog.VI(1).Infof("write sending %d bytes", len(data))
587 if n, err := f.Write([]byte(data)); err != nil {
588 return fmt.Errorf("Write returned (%d, %v)", n, err)
589 }
590 return nil
591}
Cosmos Nicolaou5129fcb2014-08-22 11:52:25 -0700592
593func TestRegistration(t *testing.T) {
594 server := InternalNew(naming.FixedRoutingID(0x55555555))
595 client := InternalNew(naming.FixedRoutingID(0xcccccccc))
596
Cosmos Nicolaou87c0a552014-12-02 23:05:49 -0800597 dialer := func(_, _ string, _ time.Duration) (net.Conn, error) {
Cosmos Nicolaou5129fcb2014-08-22 11:52:25 -0700598 return nil, fmt.Errorf("tn.Dial")
599 }
Cosmos Nicolaou87c0a552014-12-02 23:05:49 -0800600 listener := func(_, _ string) (net.Listener, error) {
Cosmos Nicolaou5129fcb2014-08-22 11:52:25 -0700601 return nil, fmt.Errorf("tn.Listen")
602 }
603 stream.RegisterProtocol("tn", dialer, listener)
604
605 _, _, err := server.Listen("tnx", "127.0.0.1:0")
606 if err == nil || !strings.Contains(err.Error(), "unknown network tnx") {
607 t.Fatal("expected error is missing (%v)", err)
608 }
609
610 _, _, err = server.Listen("tn", "127.0.0.1:0")
611 if err == nil || !strings.Contains(err.Error(), "tn.Listen") {
612 t.Fatal("expected error is missing (%v)", err)
613 }
614
615 // Need a functional listener to test Dial.
Cosmos Nicolaou87c0a552014-12-02 23:05:49 -0800616 listener = func(_, addr string) (net.Listener, error) {
Cosmos Nicolaou5129fcb2014-08-22 11:52:25 -0700617 return net.Listen("tcp", addr)
618 }
619
620 if got, want := stream.RegisterProtocol("tn", dialer, listener), true; got != want {
621 t.Errorf("got %t, want %t", got, want)
622 }
623
624 _, ep, err := server.Listen("tn", "127.0.0.1:0")
625 if err != nil {
626 t.Errorf("unexpected error %s", err)
627 }
628
629 _, err = client.Dial(ep)
630 if err == nil || !strings.Contains(err.Error(), "tn.Dial") {
631 t.Fatal("expected error is missing (%v)", err)
632 }
633}