nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/test/transport.go (about) 1 // Copyright 2018 The Mangos Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use file except in compliance with the License. 5 // You may obtain a copy of the license at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package test 16 17 import ( 18 "bytes" 19 "crypto/tls" 20 "net" 21 "strings" 22 "sync" 23 "testing" 24 "time" 25 26 "nanomsg.org/go/mangos/v2" 27 "nanomsg.org/go/mangos/v2/protocol/rep" 28 "nanomsg.org/go/mangos/v2/protocol/req" 29 ) 30 31 // TranTest provides a common test structure for transports, so that they 32 // can implement a battery of standard tests. 33 type TranTest struct { 34 addr string 35 tran mangos.Transport 36 cliCfg *tls.Config 37 srvCfg *tls.Config 38 sockRep mangos.Socket 39 sockReq mangos.Socket 40 } 41 42 // NewTranTest creates a TranTest. 43 func NewTranTest(tran mangos.Transport, addr string) *TranTest { 44 tt := &TranTest{addr: addr, tran: tran} 45 if strings.HasPrefix(tt.addr, "tls+tcp://") || strings.HasPrefix(tt.addr, "wss://") { 46 tt.cliCfg, _ = GetTLSConfig(false) 47 tt.srvCfg, _ = GetTLSConfig(true) 48 } 49 tt.sockRep, _ = rep.NewSocket() 50 tt.sockReq, _ = req.NewSocket() 51 return tt 52 } 53 54 // TestListenAndAccept tests that we can both listen and accept connections 55 // for the given transport. 56 func (tt *TranTest) TestListenAndAccept(t *testing.T) { 57 t.Logf("Establishing listener for %s", tt.addr) 58 l, err := tt.tran.NewListener(tt.addr, tt.sockRep) 59 if err != nil { 60 t.Errorf("NewListener failed: %v", err) 61 return 62 } 63 defer l.Close() 64 if tt.srvCfg != nil { 65 if err = l.SetOption(mangos.OptionTLSConfig, tt.srvCfg); err != nil { 66 t.Errorf("Failed setting TLS config: %v", err) 67 return 68 } 69 } 70 if err = l.Listen(); err != nil { 71 t.Errorf("Listen failed: %v", err) 72 return 73 } 74 75 var wg sync.WaitGroup 76 77 wg.Add(1) 78 go func() { 79 defer wg.Done() 80 t.Logf("Connecting on %s", tt.addr) 81 d, err := tt.tran.NewDialer(tt.addr, tt.sockReq) 82 if err != nil { 83 t.Errorf("NewDialer failed: %v", err) 84 return 85 } 86 if tt.cliCfg != nil { 87 if err = d.SetOption(mangos.OptionTLSConfig, tt.cliCfg); err != nil { 88 t.Errorf("Failed setting TLS config: %v", err) 89 return 90 } 91 } 92 client, err := d.Dial() 93 if err != nil { 94 t.Errorf("Dial failed: %v", err) 95 return 96 } 97 if v, err := client.GetOption(mangos.OptionLocalAddr); err == nil { 98 addr := v.(net.Addr) 99 t.Logf("Dialed on local net %s addr %s", addr.Network(), addr.String()) 100 } else { 101 t.Logf("err is %v", err.Error()) 102 } 103 if v, err := client.GetOption(mangos.OptionRemoteAddr); err == nil { 104 addr := v.(net.Addr) 105 t.Logf("Dialed remote peer %s addr %s", addr.Network(), addr.String()) 106 } 107 }() 108 109 server, err := l.Accept() 110 if err != nil { 111 t.Errorf("Accept failed: %v", err) 112 return 113 } 114 if v, err := server.GetOption(mangos.OptionLocalAddr); err == nil { 115 addr := v.(net.Addr) 116 t.Logf("Accepted on local net %s addr %s", addr.Network(), addr.String()) 117 } 118 if v, err := server.GetOption(mangos.OptionRemoteAddr); err == nil { 119 addr := v.(net.Addr) 120 t.Logf("Accepted remote peer %s addr %s", addr.Network(), addr.String()) 121 } 122 defer server.Close() 123 124 wg.Wait() 125 } 126 127 // TestDuplicateListen checks to make sure that an attempt to listen 128 // on a second socket, when another listener is already present, properly 129 // fails with ErrAddrInUse. 130 func (tt *TranTest) TestDuplicateListen(t *testing.T) { 131 var err error 132 time.Sleep(100 * time.Millisecond) 133 t.Logf("Testing Duplicate Listen on %s", tt.addr) 134 l1, err := tt.tran.NewListener(tt.addr, tt.sockRep) 135 if err != nil { 136 t.Errorf("NewListener failed: %v", err) 137 return 138 } 139 defer l1.Close() 140 if tt.srvCfg != nil { 141 if err = l1.SetOption(mangos.OptionTLSConfig, tt.srvCfg); err != nil { 142 t.Errorf("Failed setting TLS config: %v", err) 143 return 144 } 145 } 146 if err = l1.Listen(); err != nil { 147 t.Errorf("Listen failed: %v", err) 148 return 149 } 150 151 l2, err := tt.tran.NewListener(tt.addr, tt.sockReq) 152 if err != nil { 153 t.Errorf("NewListener faield: %v", err) 154 return 155 } 156 defer l2.Close() 157 if tt.srvCfg != nil { 158 if err = l2.SetOption(mangos.OptionTLSConfig, tt.srvCfg); err != nil { 159 t.Errorf("Failed setting TLS config: %v", err) 160 return 161 } 162 } 163 if err = l2.Listen(); err == nil { 164 t.Errorf("Duplicate listen should not be permitted!") 165 return 166 } 167 t.Logf("Got expected error: %v", err) 168 } 169 170 // TestConnRefused tests that attempts to dial to an address without a listener 171 // properly fail with EConnRefused. 172 func (tt *TranTest) TestConnRefused(t *testing.T) { 173 d, err := tt.tran.NewDialer(tt.addr, tt.sockReq) 174 if err != nil || d == nil { 175 t.Errorf("New Dialer failed: %v", err) 176 } 177 if tt.cliCfg != nil { 178 if err = d.SetOption(mangos.OptionTLSConfig, tt.cliCfg); err != nil { 179 t.Errorf("Failed setting TLS config: %v", err) 180 return 181 } 182 } 183 c, err := d.Dial() 184 if err == nil || c != nil { 185 t.Errorf("Connection not refused (%s)!", tt.addr) 186 return 187 } 188 t.Logf("Got expected error: %v", err) 189 } 190 191 // TestSendRecv test that the transport can send and receive. It uses the 192 // REQ/REP protocol for messages. 193 func (tt *TranTest) TestSendRecv(t *testing.T) { 194 ping := []byte("REQUEST_MESSAGE") 195 ack := []byte("RESPONSE_MESSAGE") 196 197 ch := make(chan *mangos.Message) 198 199 t.Logf("Establishing REP listener on %s", tt.addr) 200 l, err := tt.tran.NewListener(tt.addr, tt.sockRep) 201 if err != nil { 202 t.Errorf("NewListener failed: %v", err) 203 return 204 } 205 defer l.Close() 206 if tt.srvCfg != nil { 207 if err = l.SetOption(mangos.OptionTLSConfig, tt.srvCfg); err != nil { 208 t.Errorf("Failed setting TLS config: %v", err) 209 return 210 } 211 } 212 if err = l.Listen(); err != nil { 213 t.Errorf("Listen failed: %v", err) 214 return 215 } 216 217 var wg sync.WaitGroup 218 219 wg.Add(1) 220 221 go func() { 222 defer close(ch) 223 defer wg.Done() 224 225 // Client side 226 t.Logf("Connecting REQ on %s", tt.addr) 227 d, err := tt.tran.NewDialer(tt.addr, tt.sockReq) 228 if err != nil { 229 t.Errorf("Failed creating Dialer: %v", err) 230 } 231 if tt.cliCfg != nil { 232 if err = d.SetOption(mangos.OptionTLSConfig, tt.cliCfg); err != nil { 233 t.Errorf("Failed setting TLS config: %v", err) 234 return 235 } 236 } 237 238 client, err := d.Dial() 239 if err != nil { 240 t.Errorf("Dial failed: %v", err) 241 return 242 } 243 t.Logf("Connected client") 244 defer client.Close() 245 246 req := mangos.NewMessage(len(ping)) 247 req.Body = append(req.Body, ping...) 248 249 // Now try to send data 250 t.Logf("Sending %d bytes", len(req.Body)) 251 252 err = client.Send(req) 253 if err != nil { 254 t.Errorf("Client send error: %v", err) 255 return 256 } 257 t.Logf("Client sent") 258 259 rep, err := client.Recv() 260 if err != nil { 261 t.Errorf("Client receive error: %v", err) 262 return 263 } 264 265 if !bytes.Equal(rep.Body, ack) { 266 t.Errorf("Reply mismatch: %v, %v", rep.Body, ack) 267 return 268 } 269 if len(rep.Header) != 0 { 270 t.Errorf("Client reply non-empty header: %v", 271 rep.Header) 272 return 273 } 274 select { 275 case ch <- rep: 276 t.Log("Client reply forwarded") 277 case <-time.After(5 * time.Second): // 5 secs should be plenty 278 t.Error("Client timeout forwarding reply") 279 return 280 } 281 }() 282 283 server, err := l.Accept() 284 if err != nil { 285 t.Errorf("Accept failed: %v", err) 286 return 287 } 288 t.Logf("Connected server") 289 defer server.Close() 290 291 // Now we can try to send and receive 292 req, err := server.Recv() 293 if err != nil { 294 t.Errorf("Server receive error: %v", err) 295 return 296 } 297 t.Logf("Server received %d bytes", len(req.Body)) 298 if !bytes.Equal(req.Body, ping) { 299 t.Errorf("Request mismatch: %v, %v", req.Body, ping) 300 return 301 } 302 303 if len(req.Header) != 0 { 304 t.Errorf("Server request non-empty header: %v", req.Header) 305 return 306 } 307 308 // Now reply 309 rep := mangos.NewMessage(len(ack)) 310 rep.Body = append(rep.Body, ack...) 311 312 t.Logf("Server sending %d bytes", len(rep.Body)) 313 314 err = server.Send(rep) 315 if err != nil { 316 t.Errorf("Server send error: %v", err) 317 return 318 } 319 t.Log("Server reply sent") 320 321 // Wait for client to ack reply over back channel. 322 select { 323 case nrep := <-ch: 324 if !bytes.Equal(nrep.Body, ack) { 325 t.Errorf("Client forward mismatch: %v, %v", ack, rep) 326 return 327 } 328 case <-time.After(5 * time.Second): 329 t.Error("Client timeout?") 330 return 331 } 332 333 wg.Wait() 334 } 335 336 // TestScheme tests the Scheme() entry point on the transport. 337 func (tt *TranTest) TestScheme(t *testing.T) { 338 scheme := tt.tran.Scheme() 339 t.Log("Checking scheme") 340 if !strings.HasPrefix(tt.addr, scheme+"://") { 341 t.Errorf("Wrong scheme: addr %s, scheme %s", tt.addr, scheme) 342 return 343 } 344 t.Log("Scheme match") 345 } 346 347 // TestListenerSetOptionInvalid tests passing invalid options to a listener. 348 func (tt *TranTest) TestListenerSetOptionInvalid(t *testing.T) { 349 t.Log("Trying invalid listener SetOption") 350 l, err := tt.tran.NewListener(tt.addr, tt.sockRep) 351 if err != nil { 352 t.Errorf("Unable to create listener") 353 return 354 } 355 err = l.SetOption("NO-SUCH-OPTION", true) 356 switch err { 357 case mangos.ErrBadOption: 358 t.Log("Got expected err BadOption") 359 case nil: 360 t.Errorf("Got nil err, but expected BadOption!") 361 default: 362 t.Errorf("Got unexpected error %v, expected BadOption", err) 363 } 364 } 365 366 // TestListenerGetOptionInvalid tests trying to get an invalid option on 367 // a listener. 368 func (tt *TranTest) TestListenerGetOptionInvalid(t *testing.T) { 369 t.Log("Trying invalid listener GetOption") 370 l, err := tt.tran.NewListener(tt.addr, tt.sockRep) 371 if err != nil { 372 t.Errorf("Unable to create listener") 373 return 374 } 375 _, err = l.GetOption("NO-SUCH-OPTION") 376 switch err { 377 case mangos.ErrBadOption: 378 t.Log("Got expected err BadOption") 379 case nil: 380 t.Errorf("Got nil err, but expected BadOption!") 381 default: 382 t.Errorf("Got unexpected error %v, expected BadOption", err) 383 } 384 } 385 386 // TestDialerSetOptionInvalid tests trying to set an invalid option on a Dialer. 387 func (tt *TranTest) TestDialerSetOptionInvalid(t *testing.T) { 388 t.Log("Trying invalid dialer SetOption") 389 d, err := tt.tran.NewDialer(tt.addr, tt.sockRep) 390 if err != nil { 391 t.Errorf("Unable to create dialer") 392 return 393 } 394 err = d.SetOption("NO-SUCH-OPTION", true) 395 switch err { 396 case mangos.ErrBadOption: 397 t.Log("Got expected err BadOption") 398 case nil: 399 t.Errorf("Got nil err, but expected BadOption!") 400 default: 401 t.Errorf("Got unexpected error %v, expected BadOption", err) 402 } 403 } 404 405 // TestDialerGetOptionInvalid tests attempting to get an invalid option on 406 // a Dialer. 407 func (tt *TranTest) TestDialerGetOptionInvalid(t *testing.T) { 408 t.Log("Trying invalid listener GetOption") 409 d, err := tt.tran.NewDialer(tt.addr, tt.sockRep) 410 if err != nil { 411 t.Errorf("Unable to create dialer") 412 return 413 } 414 _, err = d.GetOption("NO-SUCH-OPTION") 415 switch err { 416 case mangos.ErrBadOption: 417 t.Log("Got expected err BadOption") 418 case nil: 419 t.Errorf("Got nil err, but expected BadOption!") 420 default: 421 t.Errorf("Got unexpected error %v, expected BadOption", err) 422 } 423 } 424 425 // TestDialerBadScheme tests to makes sure that giving a bogus scheme 426 // to create a dialer fails properly. 427 func (tt *TranTest) TestDialerBadScheme(t *testing.T) { 428 t.Logf("NewDialer with bogus scheme") 429 d, err := tt.tran.NewDialer("bogus://address", tt.sockRep) 430 if err == nil { 431 t.Errorf("Expected error, got nil") 432 } else if d != nil { 433 t.Errorf("Got non-nil error, and non-nil dialer") 434 } else { 435 t.Logf("Got expected error %v", err) 436 } 437 } 438 439 // TestListenerBadScheme tests to makes sure that giving a bogus scheme 440 // to create a listener fails properly. 441 func (tt *TranTest) TestListenerBadScheme(t *testing.T) { 442 t.Logf("NewListener with bogus scheme") 443 d, err := tt.tran.NewListener("bogus://address", tt.sockRep) 444 if err == nil { 445 t.Errorf("Expected error, got nil") 446 } else if d != nil { 447 t.Errorf("Got non-nil error, and non-nil listener") 448 } else { 449 t.Logf("Got expected error %v", err) 450 } 451 } 452 453 // TestAll runs a full battery of standard tests on the transport. 454 func (tt *TranTest) TestAll(t *testing.T) { 455 tt.TestScheme(t) 456 tt.TestListenAndAccept(t) 457 tt.TestConnRefused(t) 458 tt.TestDuplicateListen(t) 459 tt.TestSendRecv(t) 460 tt.TestDialerSetOptionInvalid(t) 461 tt.TestDialerGetOptionInvalid(t) 462 tt.TestListenerSetOptionInvalid(t) 463 tt.TestListenerGetOptionInvalid(t) 464 tt.TestDialerBadScheme(t) 465 tt.TestListenerBadScheme(t) 466 }