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  }