Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Vanadium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 5 | package manager |
| 6 | |
| 7 | import ( |
| 8 | "bytes" |
| 9 | "fmt" |
| 10 | "io" |
| 11 | "net" |
Cosmos Nicolaou | 920db00 | 2014-10-23 16:57:32 -0700 | [diff] [blame] | 12 | "os" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 13 | "reflect" |
| 14 | "runtime" |
Suharsh Sivakumar | ad1d419 | 2015-03-09 16:48:10 -0700 | [diff] [blame] | 15 | "sort" |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 16 | "strconv" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 17 | "strings" |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 18 | "syscall" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 19 | "testing" |
Cosmos Nicolaou | 920db00 | 2014-10-23 16:57:32 -0700 | [diff] [blame] | 20 | "time" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 21 | |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 22 | "v.io/x/lib/vlog" |
| 23 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 24 | "v.io/v23/naming" |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 25 | "v.io/v23/rpc" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 26 | "v.io/v23/security" |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 27 | |
Suharsh Sivakumar | dcc11d7 | 2015-05-11 12:19:20 -0700 | [diff] [blame^] | 28 | inaming "v.io/x/ref/runtime/internal/naming" |
| 29 | _ "v.io/x/ref/runtime/internal/rpc/protocols/tcp" |
| 30 | _ "v.io/x/ref/runtime/internal/rpc/protocols/ws" |
| 31 | "v.io/x/ref/runtime/internal/rpc/stream" |
| 32 | "v.io/x/ref/runtime/internal/rpc/stream/vc" |
| 33 | "v.io/x/ref/runtime/internal/rpc/stream/vif" |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 34 | "v.io/x/ref/test" |
| 35 | "v.io/x/ref/test/expect" |
| 36 | "v.io/x/ref/test/modules" |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 37 | "v.io/x/ref/test/testutil" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 38 | ) |
| 39 | |
| 40 | func init() { |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 41 | modules.RegisterChild("runServer", "", runServer) |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 42 | modules.RegisterChild("runRLimitedServer", "", runRLimitedServer) |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | // We write our own TestMain here instead of relying on v23 test generate because |
| 46 | // we need to set runtime.GOMAXPROCS. |
| 47 | func TestMain(m *testing.M) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 48 | test.Init() |
Asim Shankar | c920db3 | 2014-10-16 19:18:21 -0700 | [diff] [blame] | 49 | // testutil.Init sets GOMAXPROCS to NumCPU. We want to force |
| 50 | // GOMAXPROCS to remain at 1, in order to trigger a particular race |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 51 | // condition that occurs when closing the server; also, using 1 cpu |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 52 | // introduces less variance in the behavior of the test. |
| 53 | runtime.GOMAXPROCS(1) |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 54 | if modules.IsModulesChildProcess() { |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 55 | if err := modules.Dispatch(); err != nil { |
| 56 | fmt.Fprintf(os.Stderr, "modules.Dispatch failed: %v\n", err) |
| 57 | os.Exit(1) |
| 58 | } |
| 59 | return |
| 60 | } |
| 61 | os.Exit(m.Run()) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 62 | } |
| 63 | |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 64 | func testSimpleFlow(t *testing.T, protocol string) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 65 | server := InternalNew(naming.FixedRoutingID(0x55555555)) |
| 66 | client := InternalNew(naming.FixedRoutingID(0xcccccccc)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 67 | pclient := testutil.NewPrincipal("client") |
| 68 | pserver := testutil.NewPrincipal("server") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 69 | |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 70 | ln, ep, err := server.Listen(protocol, "127.0.0.1:0", pserver, pserver.BlessingStore().Default()) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 71 | if err != nil { |
| 72 | t.Fatal(err) |
| 73 | } |
| 74 | |
| 75 | data := "the dark knight rises" |
| 76 | var clientVC stream.VC |
| 77 | var clientF1 stream.Flow |
| 78 | go func() { |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 79 | if clientVC, err = client.Dial(ep, pclient); err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 80 | t.Errorf("Dial(%q) failed: %v", ep, err) |
| 81 | return |
| 82 | } |
| 83 | if clientF1, err = clientVC.Connect(); err != nil { |
| 84 | t.Errorf("Connect() failed: %v", err) |
| 85 | return |
| 86 | } |
| 87 | if err := writeLine(clientF1, data); err != nil { |
| 88 | t.Error(err) |
| 89 | } |
| 90 | }() |
| 91 | serverF, err := ln.Accept() |
| 92 | if err != nil { |
| 93 | t.Fatalf("Accept failed: %v", err) |
| 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 | // By this point, the goroutine has passed the write call (or exited |
| 99 | // early) since the read has gotten through. Check if the goroutine |
| 100 | // encountered any errors in creating the VC or flow and abort. |
| 101 | if t.Failed() { |
| 102 | return |
| 103 | } |
| 104 | defer clientF1.Close() |
| 105 | |
| 106 | ln.Close() |
| 107 | |
| 108 | // Writes on flows opened before the server listener was closed should |
| 109 | // still succeed. |
| 110 | data = "the dark knight goes to bed" |
| 111 | go func() { |
| 112 | if err := writeLine(clientF1, data); err != nil { |
| 113 | t.Error(err) |
| 114 | } |
| 115 | }() |
| 116 | if got, err := readLine(serverF); got != data || err != nil { |
| 117 | t.Errorf("Got (%q, %v), want (%q, nil)", got, err, data) |
| 118 | } |
| 119 | |
| 120 | // Opening a new flow on an existing VC will succeed initially, but |
| 121 | // writes on the client end will eventually fail once the server has |
| 122 | // stopped listening. |
| 123 | // |
| 124 | // It will require a round-trip to the server to notice the failure, |
| 125 | // hence the client should write enough data to ensure that the Write |
| 126 | // call will not return before a round-trip. |
| 127 | // |
| 128 | // The length of the data is taken to exceed the queue buffer size |
| 129 | // (DefaultBytesBufferedPerFlow), the shared counters (MaxSharedBytes) |
| 130 | // and the per-flow counters (DefaultBytesBufferedPerFlow) that are |
| 131 | // given when the flow gets established. |
| 132 | // |
| 133 | // TODO(caprita): separate the constants for the queue buffer size and |
| 134 | // the default number of counters to avoid confusion. |
| 135 | lotsOfData := string(make([]byte, vc.DefaultBytesBufferedPerFlow*2+vc.MaxSharedBytes+1)) |
| 136 | clientF2, err := clientVC.Connect() |
| 137 | if err != nil { |
| 138 | t.Fatalf("Connect() failed: %v", err) |
| 139 | } |
| 140 | defer clientF2.Close() |
| 141 | if err := writeLine(clientF2, lotsOfData); err == nil { |
| 142 | t.Errorf("Should not be able to Dial or Write after the Listener is closed") |
| 143 | } |
| 144 | // Opening a new VC should fail fast. |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 145 | if _, err := client.Dial(ep, pclient); err == nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 146 | t.Errorf("Should not be able to Dial after listener is closed") |
| 147 | } |
| 148 | } |
| 149 | |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 150 | func TestSimpleFlow(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 151 | testSimpleFlow(t, "tcp") |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | func TestSimpleFlowWS(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 155 | testSimpleFlow(t, "ws") |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 156 | } |
| 157 | |
Cosmos Nicolaou | 9388ae4 | 2014-11-10 10:57:15 -0800 | [diff] [blame] | 158 | func TestConnectionTimeout(t *testing.T) { |
| 159 | client := InternalNew(naming.FixedRoutingID(0xcccccccc)) |
| 160 | |
| 161 | ch := make(chan error) |
| 162 | go func() { |
| 163 | // 203.0.113.0 is TEST-NET-3 from RFC5737 |
| 164 | ep, _ := inaming.NewEndpoint(naming.FormatEndpoint("tcp", "203.0.113.10:80")) |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 165 | _, err := client.Dial(ep, testutil.NewPrincipal("client"), DialTimeout(time.Second)) |
Cosmos Nicolaou | 9388ae4 | 2014-11-10 10:57:15 -0800 | [diff] [blame] | 166 | ch <- err |
| 167 | }() |
| 168 | |
| 169 | select { |
| 170 | case err := <-ch: |
| 171 | if err == nil { |
| 172 | t.Fatalf("expected an error") |
| 173 | } |
| 174 | case <-time.After(time.Minute): |
| 175 | t.Fatalf("timedout") |
| 176 | } |
| 177 | } |
| 178 | |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 179 | func testAuthenticatedByDefault(t *testing.T, protocol string) { |
Asim Shankar | 6b0510a | 2014-10-01 12:05:06 -0700 | [diff] [blame] | 180 | var ( |
| 181 | server = InternalNew(naming.FixedRoutingID(0x55555555)) |
| 182 | client = InternalNew(naming.FixedRoutingID(0xcccccccc)) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 183 | |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 184 | clientPrincipal = testutil.NewPrincipal("client") |
| 185 | serverPrincipal = testutil.NewPrincipal("server") |
Suharsh Sivakumar | 59c423c | 2015-03-11 14:06:03 -0700 | [diff] [blame] | 186 | clientKey = clientPrincipal.PublicKey() |
| 187 | serverBlessings = serverPrincipal.BlessingStore().Default() |
Asim Shankar | 6b0510a | 2014-10-01 12:05:06 -0700 | [diff] [blame] | 188 | ) |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 189 | ln, ep, err := server.Listen(protocol, "127.0.0.1:0", serverPrincipal, serverPrincipal.BlessingStore().Default()) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 190 | if err != nil { |
| 191 | t.Fatal(err) |
| 192 | } |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 193 | // And the server blessing should be in the endpoint. |
| 194 | if got, want := ep.BlessingNames(), []string{"server"}; !reflect.DeepEqual(got, want) { |
| 195 | t.Errorf("Got blessings %v from endpoint, want %v", got, want) |
| 196 | } |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 197 | |
| 198 | errs := make(chan error) |
| 199 | |
Ankur | 50a5f39 | 2015-02-27 18:46:30 -0800 | [diff] [blame] | 200 | testAuth := func(tag string, flow stream.Flow, wantServer security.Blessings, wantClientKey security.PublicKey) { |
| 201 | // Since the client's blessing is expected to be self-signed we only test |
| 202 | // its public key |
| 203 | gotServer := flow.RemoteBlessings() |
| 204 | gotClientKey := flow.LocalBlessings().PublicKey() |
| 205 | if tag == "server" { |
| 206 | gotServer = flow.LocalBlessings() |
| 207 | gotClientKey = flow.RemoteBlessings().PublicKey() |
| 208 | } |
| 209 | if !reflect.DeepEqual(gotServer, wantServer) || !reflect.DeepEqual(gotClientKey, wantClientKey) { |
| 210 | errs <- fmt.Errorf("%s: Server: Got Blessings %q, want %q. Server: Got Blessings %q, want %q", tag, gotServer, wantServer, gotClientKey, wantClientKey) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 211 | return |
| 212 | } |
| 213 | errs <- nil |
| 214 | } |
| 215 | |
| 216 | go func() { |
| 217 | flow, err := ln.Accept() |
| 218 | if err != nil { |
| 219 | errs <- err |
| 220 | return |
| 221 | } |
| 222 | defer flow.Close() |
Ankur | 50a5f39 | 2015-02-27 18:46:30 -0800 | [diff] [blame] | 223 | testAuth("server", flow, serverBlessings, clientKey) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 224 | }() |
| 225 | |
| 226 | go func() { |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 227 | vc, err := client.Dial(ep, clientPrincipal) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 228 | if err != nil { |
| 229 | errs <- err |
| 230 | return |
| 231 | } |
| 232 | flow, err := vc.Connect() |
| 233 | if err != nil { |
| 234 | errs <- err |
| 235 | return |
| 236 | } |
| 237 | defer flow.Close() |
Ankur | 50a5f39 | 2015-02-27 18:46:30 -0800 | [diff] [blame] | 238 | testAuth("client", flow, serverBlessings, clientKey) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 239 | }() |
| 240 | |
| 241 | if err := <-errs; err != nil { |
| 242 | t.Error(err) |
| 243 | } |
| 244 | if err := <-errs; err != nil { |
| 245 | t.Error(err) |
| 246 | } |
| 247 | } |
| 248 | |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 249 | func TestAuthenticatedByDefault(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 250 | testAuthenticatedByDefault(t, "tcp") |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 251 | } |
| 252 | |
| 253 | func TestAuthenticatedByDefaultWS(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 254 | testAuthenticatedByDefault(t, "ws") |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 255 | } |
| 256 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 257 | func numListeners(m stream.Manager) int { return len(m.(*manager).listeners) } |
| 258 | func debugString(m stream.Manager) string { return m.(*manager).DebugString() } |
| 259 | func numVIFs(m stream.Manager) int { return len(m.(*manager).vifs.List()) } |
| 260 | |
| 261 | func TestListenEndpoints(t *testing.T) { |
| 262 | server := InternalNew(naming.FixedRoutingID(0xcafe)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 263 | principal := testutil.NewPrincipal("test") |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 264 | blessings := principal.BlessingStore().Default() |
| 265 | ln1, ep1, err1 := server.Listen("tcp", "127.0.0.1:0", principal, blessings) |
| 266 | ln2, ep2, err2 := server.Listen("tcp", "127.0.0.1:0", principal, blessings) |
Adam Sadovsky | 5181bdb | 2014-08-13 10:29:11 -0700 | [diff] [blame] | 267 | // Since "127.0.0.1:0" was used as the network address, a random port will be |
| 268 | // assigned in each case. The endpoint should include that random port. |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 269 | if err1 != nil { |
| 270 | t.Error(err1) |
| 271 | } |
| 272 | if err2 != nil { |
| 273 | t.Error(err2) |
| 274 | } |
| 275 | if ep1.String() == ep2.String() { |
| 276 | t.Errorf("Both listeners got the same endpoint: %q", ep1) |
| 277 | } |
| 278 | if n, expect := numListeners(server), 2; n != expect { |
| 279 | t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server)) |
| 280 | } |
| 281 | ln1.Close() |
| 282 | if n, expect := numListeners(server), 1; n != expect { |
| 283 | t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server)) |
| 284 | } |
| 285 | ln2.Close() |
| 286 | if n, expect := numListeners(server), 0; n != expect { |
| 287 | t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server)) |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | func acceptLoop(ln stream.Listener) { |
| 292 | for { |
| 293 | f, err := ln.Accept() |
| 294 | if err != nil { |
| 295 | return |
| 296 | } |
| 297 | f.Close() |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | func TestCloseListener(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 302 | testCloseListener(t, "tcp") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 303 | } |
| 304 | |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 305 | func TestCloseListenerWS(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 306 | testCloseListener(t, "ws") |
| 307 | } |
| 308 | |
| 309 | func testCloseListener(t *testing.T, protocol string) { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 310 | server := InternalNew(naming.FixedRoutingID(0x5e97e9)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 311 | pclient := testutil.NewPrincipal("client") |
| 312 | pserver := testutil.NewPrincipal("server") |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 313 | blessings := pserver.BlessingStore().Default() |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 314 | |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 315 | ln, ep, err := server.Listen(protocol, "127.0.0.1:0", pserver, blessings) |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 316 | if err != nil { |
| 317 | t.Fatal(err) |
| 318 | } |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 319 | // Server will just listen for flows and close them. |
| 320 | go acceptLoop(ln) |
| 321 | client := InternalNew(naming.FixedRoutingID(0xc1e41)) |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 322 | if _, err = client.Dial(ep, pclient); err != nil { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 323 | t.Fatal(err) |
| 324 | } |
| 325 | ln.Close() |
| 326 | client = InternalNew(naming.FixedRoutingID(0xc1e42)) |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 327 | if _, err := client.Dial(ep, pclient); err == nil { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 328 | t.Errorf("client.Dial(%q) should have failed", ep) |
| 329 | } |
| 330 | } |
| 331 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 332 | func TestShutdown(t *testing.T) { |
| 333 | server := InternalNew(naming.FixedRoutingID(0x5e97e9)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 334 | principal := testutil.NewPrincipal("test") |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 335 | blessings := principal.BlessingStore().Default() |
| 336 | ln, _, err := server.Listen("tcp", "127.0.0.1:0", principal, blessings) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 337 | if err != nil { |
| 338 | t.Fatal(err) |
| 339 | } |
| 340 | // Server will just listen for flows and close them. |
| 341 | go acceptLoop(ln) |
| 342 | if n, expect := numListeners(server), 1; n != expect { |
| 343 | t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server)) |
| 344 | } |
| 345 | server.Shutdown() |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 346 | if _, _, err := server.Listen("tcp", "127.0.0.1:0", principal, blessings); err == nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 347 | t.Error("server should have shut down") |
| 348 | } |
| 349 | if n, expect := numListeners(server), 0; n != expect { |
| 350 | t.Errorf("expecting %d listeners, got %d for %s", n, expect, debugString(server)) |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | func TestShutdownEndpoint(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 355 | testShutdownEndpoint(t, "tcp") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 356 | } |
| 357 | |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 358 | func TestShutdownEndpointWS(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 359 | testShutdownEndpoint(t, "ws") |
| 360 | } |
| 361 | |
| 362 | func testShutdownEndpoint(t *testing.T, protocol string) { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 363 | server := InternalNew(naming.FixedRoutingID(0x55555555)) |
| 364 | client := InternalNew(naming.FixedRoutingID(0xcccccccc)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 365 | principal := testutil.NewPrincipal("test") |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 366 | |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 367 | ln, ep, err := server.Listen(protocol, "127.0.0.1:0", principal, principal.BlessingStore().Default()) |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 368 | if err != nil { |
| 369 | t.Fatal(err) |
| 370 | } |
| 371 | |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 372 | // Server will just listen for flows and close them. |
| 373 | go acceptLoop(ln) |
| 374 | |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 375 | vc, err := client.Dial(ep, testutil.NewPrincipal("client")) |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 376 | if err != nil { |
| 377 | t.Fatal(err) |
| 378 | } |
| 379 | if f, err := vc.Connect(); f == nil || err != nil { |
| 380 | t.Errorf("vc.Connect failed: (%v, %v)", f, err) |
| 381 | } |
| 382 | client.ShutdownEndpoint(ep) |
| 383 | if f, err := vc.Connect(); f != nil || err == nil { |
| 384 | t.Errorf("vc.Connect unexpectedly succeeded: (%v, %v)", f, err) |
| 385 | } |
| 386 | } |
| 387 | |
Jungho Ahn | 6ab655f | 2015-04-14 18:27:09 -0700 | [diff] [blame] | 388 | func TestStartTimeout(t *testing.T) { |
| 389 | const ( |
| 390 | startTime = 5 * time.Millisecond |
Jungho Ahn | 6ab655f | 2015-04-14 18:27:09 -0700 | [diff] [blame] | 391 | ) |
| 392 | |
| 393 | var ( |
| 394 | server = InternalNew(naming.FixedRoutingID(0x55555555)) |
| 395 | pserver = testutil.NewPrincipal("server") |
| 396 | lopts = []stream.ListenerOpt{vc.StartTimeout{startTime}} |
| 397 | ) |
| 398 | |
| 399 | // Pause the start timers. |
| 400 | triggerTimers := vif.SetFakeTimers() |
| 401 | |
| 402 | ln, ep, err := server.Listen("tcp", "127.0.0.1:0", pserver, pserver.BlessingStore().Default(), lopts...) |
| 403 | if err != nil { |
| 404 | t.Fatal(err) |
| 405 | } |
| 406 | go func() { |
| 407 | for { |
| 408 | _, err := ln.Accept() |
| 409 | if err != nil { |
| 410 | return |
| 411 | } |
| 412 | } |
| 413 | }() |
| 414 | |
| 415 | _, err = net.Dial(ep.Addr().Network(), ep.Addr().String()) |
| 416 | if err != nil { |
| 417 | t.Fatalf("net.Dial failed: %v", err) |
| 418 | } |
| 419 | |
| 420 | // Trigger the start timers. |
| 421 | triggerTimers() |
| 422 | |
| 423 | // No VC is opened. The VIF should be closed after start timeout. |
Jungho Ahn | cc9d572 | 2015-04-22 10:13:04 -0700 | [diff] [blame] | 424 | for range time.Tick(startTime) { |
| 425 | if numVIFs(server) == 0 { |
| 426 | break |
Jungho Ahn | 6ab655f | 2015-04-14 18:27:09 -0700 | [diff] [blame] | 427 | } |
| 428 | } |
Jungho Ahn | 6ab655f | 2015-04-14 18:27:09 -0700 | [diff] [blame] | 429 | } |
| 430 | |
Jungho Ahn | cd175b8 | 2015-03-27 14:29:40 -0700 | [diff] [blame] | 431 | func testIdleTimeout(t *testing.T, testServer bool) { |
| 432 | const ( |
| 433 | idleTime = 10 * time.Millisecond |
| 434 | // We use a long wait time here since it takes some time to handle VC close |
| 435 | // especially in race testing. |
| 436 | waitTime = 150 * time.Millisecond |
| 437 | ) |
| 438 | |
| 439 | var ( |
| 440 | server = InternalNew(naming.FixedRoutingID(0x55555555)) |
| 441 | client = InternalNew(naming.FixedRoutingID(0xcccccccc)) |
| 442 | pclient = testutil.NewPrincipal("client") |
| 443 | pserver = testutil.NewPrincipal("server") |
| 444 | |
| 445 | opts []stream.VCOpt |
| 446 | lopts []stream.ListenerOpt |
| 447 | ) |
| 448 | if testServer { |
| 449 | lopts = []stream.ListenerOpt{vc.IdleTimeout{idleTime}} |
| 450 | } else { |
| 451 | opts = []stream.VCOpt{vc.IdleTimeout{idleTime}} |
| 452 | } |
| 453 | |
| 454 | // Pause the idle timers. |
| 455 | triggerTimers := vif.SetFakeTimers() |
| 456 | |
| 457 | ln, ep, err := server.Listen("tcp", "127.0.0.1:0", pserver, pserver.BlessingStore().Default(), lopts...) |
| 458 | if err != nil { |
| 459 | t.Fatal(err) |
| 460 | } |
| 461 | go func() { |
| 462 | for { |
| 463 | _, err := ln.Accept() |
| 464 | if err != nil { |
| 465 | return |
| 466 | } |
| 467 | } |
| 468 | }() |
| 469 | |
| 470 | vc, err := client.Dial(ep, pclient, opts...) |
| 471 | if err != nil { |
| 472 | t.Fatalf("client.Dial(%q) failed: %v", ep, err) |
| 473 | } |
| 474 | f, err := vc.Connect() |
| 475 | if f == nil || err != nil { |
| 476 | t.Fatalf("vc.Connect failed: (%v, %v)", f, err) |
| 477 | } |
| 478 | |
| 479 | // Trigger the idle timers. |
| 480 | triggerTimers() |
| 481 | |
| 482 | // One active flow. The VIF should be kept open. |
| 483 | time.Sleep(waitTime) |
| 484 | if n := numVIFs(client); n != 1 { |
| 485 | t.Errorf("Client has %d VIFs; want 1\n%v", n, debugString(client)) |
| 486 | } |
| 487 | if n := numVIFs(server); n != 1 { |
| 488 | t.Errorf("Server has %d VIFs; want 1\n%v", n, debugString(server)) |
| 489 | } |
| 490 | |
| 491 | f.Close() |
| 492 | |
| 493 | // The flow has been closed. The VIF should be closed after idle timeout. |
Jungho Ahn | cc9d572 | 2015-04-22 10:13:04 -0700 | [diff] [blame] | 494 | for range time.Tick(idleTime) { |
| 495 | if numVIFs(client) == 0 && numVIFs(server) == 0 { |
| 496 | break |
Jungho Ahn | cd175b8 | 2015-03-27 14:29:40 -0700 | [diff] [blame] | 497 | } |
| 498 | } |
Jungho Ahn | cd175b8 | 2015-03-27 14:29:40 -0700 | [diff] [blame] | 499 | } |
| 500 | |
| 501 | func TestIdleTimeout(t *testing.T) { testIdleTimeout(t, false) } |
| 502 | func TestIdleTimeoutServer(t *testing.T) { testIdleTimeout(t, true) } |
| 503 | |
Andres Erbsen | ffa4574 | 2014-08-13 10:13:11 -0700 | [diff] [blame] | 504 | /* TLS + resumption + channel bindings is broken: <https://secure-resumption.com/#channelbindings>. |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 505 | func TestSessionTicketCache(t *testing.T) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 506 | server := InternalNew(naming.FixedRoutingID(0x55555555)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 507 | _, ep, err := server.Listen("tcp", "127.0.0.1:0", testutil.NewPrincipal("server")) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 508 | if err != nil { |
| 509 | t.Fatal(err) |
| 510 | } |
| 511 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 512 | client := InternalNew(naming.FixedRoutingID(0xcccccccc)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 513 | if _, err = client.Dial(ep, testutil.NewPrincipal("TestSessionTicketCacheClient")); err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 514 | t.Fatalf("Dial(%q) failed: %v", ep, err) |
| 515 | } |
| 516 | |
| 517 | if _, ok := client.(*manager).sessionCache.Get(ep.String()); !ok { |
| 518 | t.Fatalf("SessionTicket from TLS handshake not cached") |
| 519 | } |
| 520 | } |
Andres Erbsen | ffa4574 | 2014-08-13 10:13:11 -0700 | [diff] [blame] | 521 | */ |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 522 | |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 523 | func testMultipleVCs(t *testing.T, protocol string) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 524 | server := InternalNew(naming.FixedRoutingID(0x55555555)) |
| 525 | client := InternalNew(naming.FixedRoutingID(0xcccccccc)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 526 | principal := testutil.NewPrincipal("test") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 527 | |
| 528 | const nVCs = 2 |
| 529 | const data = "bugs bunny" |
| 530 | |
| 531 | // Have the server read from each flow and write to rchan. |
| 532 | rchan := make(chan string) |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 533 | ln, ep, err := server.Listen(protocol, "127.0.0.1:0", principal, principal.BlessingStore().Default()) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 534 | if err != nil { |
| 535 | t.Fatal(err) |
| 536 | } |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 537 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 538 | read := func(flow stream.Flow, c chan string) { |
| 539 | var buf bytes.Buffer |
| 540 | var tmp [1024]byte |
| 541 | for { |
| 542 | n, err := flow.Read(tmp[:]) |
| 543 | buf.Write(tmp[:n]) |
| 544 | if err == io.EOF { |
| 545 | c <- buf.String() |
| 546 | return |
| 547 | } |
| 548 | if err != nil { |
| 549 | t.Error(err) |
| 550 | return |
| 551 | } |
| 552 | } |
| 553 | } |
| 554 | go func() { |
| 555 | for i := 0; i < nVCs; i++ { |
| 556 | flow, err := ln.Accept() |
| 557 | if err != nil { |
| 558 | t.Error(err) |
| 559 | rchan <- "" |
| 560 | continue |
| 561 | } |
| 562 | go read(flow, rchan) |
| 563 | } |
| 564 | }() |
| 565 | |
| 566 | // Have the client establish nVCs and a flow on each. |
| 567 | var vcs [nVCs]stream.VC |
| 568 | for i := 0; i < nVCs; i++ { |
| 569 | var err error |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 570 | vcs[i], err = client.Dial(ep, testutil.NewPrincipal("client")) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 571 | if err != nil { |
| 572 | t.Fatal(err) |
| 573 | } |
| 574 | } |
| 575 | write := func(vc stream.VC) { |
| 576 | if err != nil { |
| 577 | ln.Close() |
| 578 | t.Error(err) |
| 579 | return |
| 580 | } |
| 581 | flow, err := vc.Connect() |
| 582 | if err != nil { |
| 583 | ln.Close() |
| 584 | t.Error(err) |
| 585 | return |
| 586 | } |
| 587 | defer flow.Close() |
| 588 | if _, err := flow.Write([]byte(data)); err != nil { |
| 589 | ln.Close() |
| 590 | t.Error(err) |
| 591 | return |
| 592 | } |
| 593 | } |
| 594 | for _, vc := range vcs { |
| 595 | go write(vc) |
| 596 | } |
| 597 | for i := 0; i < nVCs; i++ { |
| 598 | if got := <-rchan; got != data { |
| 599 | t.Errorf("Got %q want %q", got, data) |
| 600 | } |
| 601 | } |
| 602 | } |
| 603 | |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 604 | func TestMultipleVCs(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 605 | testMultipleVCs(t, "tcp") |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 606 | } |
| 607 | |
| 608 | func TestMultipleVCsWS(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 609 | testMultipleVCs(t, "ws") |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 610 | } |
| 611 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 612 | func TestAddressResolution(t *testing.T) { |
| 613 | server := InternalNew(naming.FixedRoutingID(0x55555555)) |
| 614 | client := InternalNew(naming.FixedRoutingID(0xcccccccc)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 615 | principal := testutil.NewPrincipal("test") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 616 | |
Adam Sadovsky | 5181bdb | 2014-08-13 10:29:11 -0700 | [diff] [blame] | 617 | // Using "tcp4" instead of "tcp" because the latter can end up with IPv6 |
| 618 | // addresses and our Google Compute Engine integration test machines cannot |
| 619 | // resolve IPv6 addresses. |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 620 | // As of April 2014, https://developers.google.com/compute/docs/networking |
| 621 | // said that IPv6 is not yet supported. |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 622 | ln, ep, err := server.Listen("tcp4", "127.0.0.1:0", principal, principal.BlessingStore().Default()) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 623 | if err != nil { |
| 624 | t.Fatal(err) |
| 625 | } |
| 626 | go acceptLoop(ln) |
| 627 | |
Adam Sadovsky | 5181bdb | 2014-08-13 10:29:11 -0700 | [diff] [blame] | 628 | // We'd like an endpoint that contains an address that's different than the |
| 629 | // one used for the connection. In practice this is awkward to achieve since |
| 630 | // we don't want to listen on ":0" since that will annoy firewalls. Instead we |
Suharsh Sivakumar | 7e93ce5 | 2015-05-07 17:46:13 -0700 | [diff] [blame] | 631 | // create a endpoint with "localhost", which will result in an endpoint that |
| 632 | // doesn't contain 127.0.0.1. |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 633 | _, port, _ := net.SplitHostPort(ep.Addr().String()) |
Matt Rosencrantz | c16339c | 2015-04-23 10:47:06 -0700 | [diff] [blame] | 634 | nep := &inaming.Endpoint{ |
| 635 | Protocol: ep.Addr().Network(), |
Suharsh Sivakumar | 7e93ce5 | 2015-05-07 17:46:13 -0700 | [diff] [blame] | 636 | Address: net.JoinHostPort("localhost", port), |
Matt Rosencrantz | c16339c | 2015-04-23 10:47:06 -0700 | [diff] [blame] | 637 | RID: ep.RoutingID(), |
| 638 | } |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 639 | |
| 640 | // Dial multiple VCs |
| 641 | for i := 0; i < 2; i++ { |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 642 | if _, err = client.Dial(nep, testutil.NewPrincipal("client")); err != nil { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 643 | t.Fatalf("Dial #%d failed: %v", i, err) |
| 644 | } |
| 645 | } |
| 646 | // They should all be on the same VIF. |
| 647 | if n := numVIFs(client); n != 1 { |
| 648 | t.Errorf("Client has %d VIFs, want 1\n%v", n, debugString(client)) |
| 649 | } |
| 650 | // TODO(ashankar): While a VIF can be re-used to Dial from the server |
| 651 | // to the client, currently there is no way to have the client "listen" |
| 652 | // on the same VIF. It can listen on a VC for new flows, but it cannot |
| 653 | // listen on an established VIF for new VCs. Figure this out? |
| 654 | } |
| 655 | |
| 656 | func TestServerRestartDuringClientLifetime(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 657 | testServerRestartDuringClientLifetime(t, "tcp") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 658 | } |
| 659 | |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 660 | func TestServerRestartDuringClientLifetimeWS(t *testing.T) { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 661 | testServerRestartDuringClientLifetime(t, "ws") |
| 662 | } |
| 663 | |
| 664 | func testServerRestartDuringClientLifetime(t *testing.T, protocol string) { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 665 | client := InternalNew(naming.FixedRoutingID(0xcccccccc)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 666 | pclient := testutil.NewPrincipal("client") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 667 | sh, err := modules.NewShell(nil, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 668 | if err != nil { |
| 669 | t.Fatalf("unexpected error: %s", err) |
| 670 | } |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 671 | defer sh.Cleanup(nil, nil) |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 672 | h, err := sh.Start("runServer", nil, protocol, "127.0.0.1:0") |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 673 | if err != nil { |
| 674 | t.Fatalf("unexpected error: %s", err) |
| 675 | } |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 676 | epstr := expect.NewSession(t, h.Stdout(), time.Minute).ExpectVar("ENDPOINT") |
| 677 | ep, err := inaming.NewEndpoint(epstr) |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 678 | if err != nil { |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 679 | t.Fatalf("inaming.NewEndpoint(%q): %v", epstr, err) |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 680 | } |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 681 | if _, err := client.Dial(ep, pclient); err != nil { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 682 | t.Fatal(err) |
| 683 | } |
| 684 | h.Shutdown(nil, os.Stderr) |
| 685 | |
| 686 | // A new VC cannot be created since the server is dead |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 687 | if _, err := client.Dial(ep, pclient); err == nil { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 688 | t.Fatal("Expected client.Dial to fail since server is dead") |
| 689 | } |
| 690 | |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 691 | h, err = sh.Start("runServer", nil, protocol, ep.Addr().String()) |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 692 | if err != nil { |
| 693 | t.Fatalf("unexpected error: %s", err) |
| 694 | } |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 695 | // Restarting the server, listening on the same address as before |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 696 | ep2, err := inaming.NewEndpoint(expect.NewSession(t, h.Stdout(), time.Minute).ExpectVar("ENDPOINT")) |
| 697 | if err != nil { |
| 698 | t.Fatal(err) |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 699 | } |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 700 | if got, want := ep.Addr().String(), ep2.Addr().String(); got != want { |
| 701 | t.Fatalf("Got %q, want %q", got, want) |
| 702 | } |
| 703 | if _, err := client.Dial(ep2, pclient); err != nil { |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 704 | t.Fatal(err) |
| 705 | } |
| 706 | } |
| 707 | |
Cosmos Nicolaou | 920db00 | 2014-10-23 16:57:32 -0700 | [diff] [blame] | 708 | func runServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 709 | server := InternalNew(naming.FixedRoutingID(0x55555555)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 710 | principal := testutil.NewPrincipal("test") |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 711 | _, ep, err := server.Listen(args[0], args[1], principal, principal.BlessingStore().Default()) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 712 | if err != nil { |
Cosmos Nicolaou | 920db00 | 2014-10-23 16:57:32 -0700 | [diff] [blame] | 713 | fmt.Fprintln(stderr, err) |
| 714 | return err |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 715 | } |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 716 | fmt.Fprintf(stdout, "ENDPOINT=%v\n", ep) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 717 | // Live forever (till the process is explicitly killed) |
Cosmos Nicolaou | 920db00 | 2014-10-23 16:57:32 -0700 | [diff] [blame] | 718 | modules.WaitForEOF(stdin) |
| 719 | return nil |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 720 | } |
| 721 | |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 722 | func runRLimitedServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error { |
| 723 | var rlimit syscall.Rlimit |
| 724 | if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil { |
| 725 | fmt.Fprintln(stderr, err) |
| 726 | return err |
| 727 | } |
| 728 | rlimit.Cur = 9 |
| 729 | if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil { |
| 730 | fmt.Fprintln(stderr, err) |
| 731 | return err |
| 732 | } |
| 733 | fmt.Fprintf(stdout, "RLIMIT_NOFILE=%d\n", rlimit.Cur) |
| 734 | return runServer(stdin, stdout, stderr, env, args...) |
| 735 | } |
| 736 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 737 | func readLine(f stream.Flow) (string, error) { |
| 738 | var result bytes.Buffer |
| 739 | var buf [5]byte |
| 740 | for { |
| 741 | n, err := f.Read(buf[:]) |
| 742 | result.Write(buf[:n]) |
| 743 | if err == io.EOF || buf[n-1] == '\n' { |
| 744 | return strings.TrimRight(result.String(), "\n"), nil |
| 745 | } |
| 746 | if err != nil { |
| 747 | return "", fmt.Errorf("Read returned (%d, %v)", n, err) |
| 748 | } |
| 749 | } |
| 750 | } |
| 751 | |
| 752 | func writeLine(f stream.Flow, data string) error { |
| 753 | data = data + "\n" |
| 754 | vlog.VI(1).Infof("write sending %d bytes", len(data)) |
| 755 | if n, err := f.Write([]byte(data)); err != nil { |
| 756 | return fmt.Errorf("Write returned (%d, %v)", n, err) |
| 757 | } |
| 758 | return nil |
| 759 | } |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 760 | |
| 761 | func TestRegistration(t *testing.T) { |
| 762 | server := InternalNew(naming.FixedRoutingID(0x55555555)) |
| 763 | client := InternalNew(naming.FixedRoutingID(0xcccccccc)) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 764 | principal := testutil.NewPrincipal("server") |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 765 | blessings := principal.BlessingStore().Default() |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 766 | |
Cosmos Nicolaou | 87c0a55 | 2014-12-02 23:05:49 -0800 | [diff] [blame] | 767 | dialer := func(_, _ string, _ time.Duration) (net.Conn, error) { |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 768 | return nil, fmt.Errorf("tn.Dial") |
| 769 | } |
Suharsh Sivakumar | 7e93ce5 | 2015-05-07 17:46:13 -0700 | [diff] [blame] | 770 | resolver := func(_, _ string) (string, string, error) { |
| 771 | return "", "", fmt.Errorf("tn.Resolve") |
| 772 | } |
Cosmos Nicolaou | 87c0a55 | 2014-12-02 23:05:49 -0800 | [diff] [blame] | 773 | listener := func(_, _ string) (net.Listener, error) { |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 774 | return nil, fmt.Errorf("tn.Listen") |
| 775 | } |
Suharsh Sivakumar | 7e93ce5 | 2015-05-07 17:46:13 -0700 | [diff] [blame] | 776 | rpc.RegisterProtocol("tn", dialer, resolver, listener) |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 777 | |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 778 | _, _, err := server.Listen("tnx", "127.0.0.1:0", principal, blessings) |
Cosmos Nicolaou | 07a736d | 2015-04-06 11:55:26 -0700 | [diff] [blame] | 779 | if err == nil || !strings.Contains(err.Error(), "unknown network: tnx") { |
| 780 | t.Fatalf("expected error is missing (%v)", err) |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 781 | } |
| 782 | |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 783 | _, _, err = server.Listen("tn", "127.0.0.1:0", principal, blessings) |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 784 | if err == nil || !strings.Contains(err.Error(), "tn.Listen") { |
Cosmos Nicolaou | 07a736d | 2015-04-06 11:55:26 -0700 | [diff] [blame] | 785 | t.Fatalf("expected error is missing (%v)", err) |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 786 | } |
| 787 | |
| 788 | // Need a functional listener to test Dial. |
Cosmos Nicolaou | 87c0a55 | 2014-12-02 23:05:49 -0800 | [diff] [blame] | 789 | listener = func(_, addr string) (net.Listener, error) { |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 790 | return net.Listen("tcp", addr) |
| 791 | } |
| 792 | |
Suharsh Sivakumar | 7e93ce5 | 2015-05-07 17:46:13 -0700 | [diff] [blame] | 793 | if got, want := rpc.RegisterProtocol("tn", dialer, resolver, listener), true; got != want { |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 794 | t.Errorf("got %t, want %t", got, want) |
| 795 | } |
| 796 | |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 797 | _, ep, err := server.Listen("tn", "127.0.0.1:0", principal, blessings) |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 798 | if err != nil { |
| 799 | t.Errorf("unexpected error %s", err) |
| 800 | } |
| 801 | |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 802 | _, err = client.Dial(ep, testutil.NewPrincipal("client")) |
Suharsh Sivakumar | 7e93ce5 | 2015-05-07 17:46:13 -0700 | [diff] [blame] | 803 | if err == nil || !strings.Contains(err.Error(), "tn.Resolve") { |
| 804 | t.Fatalf("expected error is missing (%v)", err) |
Cosmos Nicolaou | 5129fcb | 2014-08-22 11:52:25 -0700 | [diff] [blame] | 805 | } |
| 806 | } |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 807 | |
| 808 | func TestBlessingNamesInEndpoint(t *testing.T) { |
| 809 | var ( |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 810 | p = testutil.NewPrincipal("default") |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 811 | b, _ = p.BlessSelf("dev.v.io/users/foo@bar.com/devices/desktop/app/myapp") |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 812 | |
| 813 | server = InternalNew(naming.FixedRoutingID(0x1)) |
| 814 | |
| 815 | tests = []struct { |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 816 | principal security.Principal |
| 817 | blessings security.Blessings |
| 818 | blessingNames []string |
| 819 | err bool |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 820 | }{ |
| 821 | { |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 822 | // provided blessings should match returned output. |
| 823 | principal: p, |
| 824 | blessings: b, |
| 825 | blessingNames: []string{"dev.v.io/users/foo@bar.com/devices/desktop/app/myapp"}, |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 826 | }, |
| 827 | { |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 828 | // It is an error to provide a principal without providing blessings. |
Suharsh Sivakumar | 59c423c | 2015-03-11 14:06:03 -0700 | [diff] [blame] | 829 | principal: p, |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 830 | blessings: security.Blessings{}, |
Suharsh Sivakumar | 59c423c | 2015-03-11 14:06:03 -0700 | [diff] [blame] | 831 | err: true, |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 832 | }, |
| 833 | { |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 834 | // It is an error to provide inconsistent blessings and principal |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 835 | principal: testutil.NewPrincipal("random"), |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 836 | blessings: b, |
Suharsh Sivakumar | 59c423c | 2015-03-11 14:06:03 -0700 | [diff] [blame] | 837 | err: true, |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 838 | }, |
| 839 | } |
| 840 | ) |
| 841 | // p must recognize its own blessings! |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 842 | p.AddToRoots(b) |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 843 | for idx, test := range tests { |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 844 | ln, ep, err := server.Listen("tcp", "127.0.0.1:0", test.principal, test.blessings) |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 845 | if (err != nil) != test.err { |
| 846 | t.Errorf("test #%d: Got error %v, wanted error: %v", idx, err, test.err) |
| 847 | } |
| 848 | if err != nil { |
| 849 | continue |
| 850 | } |
| 851 | ln.Close() |
Suharsh Sivakumar | e5e5dcc | 2015-03-18 14:29:31 -0700 | [diff] [blame] | 852 | got, want := ep.BlessingNames(), test.blessingNames |
Suharsh Sivakumar | ad1d419 | 2015-03-09 16:48:10 -0700 | [diff] [blame] | 853 | sort.Strings(got) |
| 854 | sort.Strings(want) |
| 855 | if !reflect.DeepEqual(got, want) { |
Asim Shankar | 7171a25 | 2015-03-07 14:41:40 -0800 | [diff] [blame] | 856 | t.Errorf("test #%d: Got %v, want %v", idx, got, want) |
| 857 | } |
| 858 | } |
| 859 | } |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 860 | |
| 861 | func TestVIFCleanupWhenFDLimitIsReached(t *testing.T) { |
| 862 | sh, err := modules.NewShell(nil, nil, testing.Verbose(), t) |
| 863 | if err != nil { |
| 864 | t.Fatal(err) |
| 865 | } |
| 866 | defer sh.Cleanup(nil, nil) |
| 867 | h, err := sh.Start("runRLimitedServer", nil, "--logtostderr=true", "tcp", "127.0.0.1:0") |
| 868 | if err != nil { |
| 869 | t.Fatal(err) |
| 870 | } |
| 871 | defer h.CloseStdin() |
| 872 | stdout := expect.NewSession(t, h.Stdout(), time.Minute) |
| 873 | nfiles, err := strconv.Atoi(stdout.ExpectVar("RLIMIT_NOFILE")) |
| 874 | if stdout.Error() != nil { |
| 875 | t.Fatal(stdout.Error()) |
| 876 | } |
| 877 | if err != nil { |
| 878 | t.Fatal(err) |
| 879 | } |
| 880 | epstr := stdout.ExpectVar("ENDPOINT") |
| 881 | if stdout.Error() != nil { |
| 882 | t.Fatal(stdout.Error()) |
| 883 | } |
| 884 | ep, err := inaming.NewEndpoint(epstr) |
| 885 | if err != nil { |
| 886 | t.Fatal(err) |
| 887 | } |
| 888 | // Different client processes (represented by different stream managers |
| 889 | // in this test) should be able to make progress, even if the server |
| 890 | // has reached its file descriptor limit. |
| 891 | nattempts := 0 |
| 892 | for i := 0; i < 2*nfiles; i++ { |
| 893 | client := InternalNew(naming.FixedRoutingID(uint64(i))) |
| 894 | defer client.Shutdown() |
| 895 | principal := testutil.NewPrincipal(fmt.Sprintf("client%d", i)) |
| 896 | connected := false |
| 897 | for !connected { |
| 898 | nattempts++ |
| 899 | // If the client connection reached the server when it |
| 900 | // was at its limit, it might fail. However, this |
| 901 | // failure will trigger the "kill connections" logic at |
| 902 | // the server and eventually the client should succeed. |
| 903 | vc, err := client.Dial(ep, principal) |
| 904 | if err != nil { |
| 905 | continue |
| 906 | } |
| 907 | // Establish a flow to prevent the VC (and thus the |
| 908 | // underlying VIF) from being garbage collected as an |
| 909 | // "inactive" connection. |
| 910 | flow, err := vc.Connect() |
| 911 | if err != nil { |
| 912 | continue |
| 913 | } |
| 914 | defer flow.Close() |
| 915 | connected = true |
| 916 | } |
| 917 | } |
| 918 | var stderr bytes.Buffer |
| 919 | if err := h.Shutdown(nil, &stderr); err != nil { |
| 920 | t.Fatal(err) |
| 921 | } |
Matt Rosencrantz | a40f12a | 2015-04-24 11:07:55 -0700 | [diff] [blame] | 922 | if log := expect.NewSession(t, bytes.NewReader(stderr.Bytes()), time.Minute).ExpectSetEventuallyRE("listener.go.*Killing [1-9][0-9]* Conns"); len(log) == 0 { |
| 923 | t.Errorf("Failed to find log message talking about killing Conns in:\n%v", stderr.String()) |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 924 | } |
| 925 | t.Logf("Server FD limit:%d", nfiles) |
| 926 | t.Logf("Client connection attempts: %d", nattempts) |
| 927 | } |
Suharsh Sivakumar | 859ea0f | 2015-04-29 23:51:39 -0700 | [diff] [blame] | 928 | |
| 929 | func TestConcurrentDials(t *testing.T) { |
| 930 | // Concurrent Dials to the same network, address should only result in one VIF. |
| 931 | server := InternalNew(naming.FixedRoutingID(0x55555555)) |
| 932 | client := InternalNew(naming.FixedRoutingID(0xcccccccc)) |
| 933 | principal := testutil.NewPrincipal("test") |
| 934 | |
| 935 | // Using "tcp4" instead of "tcp" because the latter can end up with IPv6 |
| 936 | // addresses and our Google Compute Engine integration test machines cannot |
| 937 | // resolve IPv6 addresses. |
| 938 | // As of April 2014, https://developers.google.com/compute/docs/networking |
| 939 | // said that IPv6 is not yet supported. |
| 940 | ln, ep, err := server.Listen("tcp4", "127.0.0.1:0", principal, principal.BlessingStore().Default()) |
| 941 | if err != nil { |
| 942 | t.Fatal(err) |
| 943 | } |
| 944 | go acceptLoop(ln) |
| 945 | |
Suharsh Sivakumar | 859ea0f | 2015-04-29 23:51:39 -0700 | [diff] [blame] | 946 | nep := &inaming.Endpoint{ |
| 947 | Protocol: ep.Addr().Network(), |
Suharsh Sivakumar | 7e93ce5 | 2015-05-07 17:46:13 -0700 | [diff] [blame] | 948 | Address: ep.Addr().String(), |
Suharsh Sivakumar | 859ea0f | 2015-04-29 23:51:39 -0700 | [diff] [blame] | 949 | RID: ep.RoutingID(), |
| 950 | } |
| 951 | |
| 952 | // Dial multiple VCs |
| 953 | errCh := make(chan error, 10) |
| 954 | for i := 0; i < 10; i++ { |
| 955 | go func() { |
| 956 | _, err = client.Dial(nep, testutil.NewPrincipal("client")) |
| 957 | errCh <- err |
| 958 | }() |
| 959 | } |
| 960 | for i := 0; i < 10; i++ { |
| 961 | if err = <-errCh; err != nil { |
| 962 | t.Fatal(err) |
| 963 | } |
| 964 | } |
| 965 | // They should all be on the same VIF. |
| 966 | if n := numVIFs(client); n != 1 { |
| 967 | t.Errorf("Client has %d VIFs, want 1\n%v", n, debugString(client)) |
| 968 | } |
| 969 | } |