nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/internal/test/dialer_test.go (about)

     1  // Copyright 2019 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  	"nanomsg.org/go/mangos/v2"
    19  	"nanomsg.org/go/mangos/v2/protocol/pair"
    20  	_ "nanomsg.org/go/mangos/v2/transport/inproc"
    21  	"reflect"
    22  	"sync"
    23  	"testing"
    24  	"time"
    25  )
    26  
    27  func TestDialerBadScheme(t *testing.T) {
    28  	self := GetMockSocket()
    29  	defer MustClose(t, self)
    30  
    31  	d, e := self.NewDialer("bad://nothere", nil)
    32  	MustBeError(t, e, mangos.ErrBadTran)
    33  	MustBeTrue(t, d == nil)
    34  
    35  	// Malformed, needs :// bit
    36  	d, e = self.NewDialer("inproc:nothere", nil)
    37  	MustBeError(t, e, mangos.ErrBadTran)
    38  	MustBeTrue(t, d == nil)
    39  }
    40  
    41  func TestDialerAddress(t *testing.T) {
    42  	AddMockTransport()
    43  	self := GetMockSocket()
    44  	defer MustClose(t, self)
    45  
    46  	d, e := self.NewDialer(AddrMock(), nil)
    47  	MustSucceed(t, e)
    48  	MustBeTrue(t, d.Address() == AddrMock())
    49  }
    50  
    51  func TestDialerSocketOptions(t *testing.T) {
    52  	AddMockTransport()
    53  
    54  	VerifyOptionDuration(t, NewMockSocket, mangos.OptionReconnectTime)
    55  	VerifyOptionDuration(t, NewMockSocket, mangos.OptionMaxReconnectTime)
    56  	VerifyOptionBool(t, NewMockSocket, mangos.OptionDialAsynch)
    57  	VerifyOptionInt(t, NewMockSocket, mangos.OptionMaxRecvSize)
    58  }
    59  
    60  func TestDialerOptions(t *testing.T) {
    61  	AddMockTransport()
    62  	sock := GetMockSocket()
    63  	defer MustClose(t, sock)
    64  
    65  	d, e := sock.NewDialer(AddrMock(), nil)
    66  	MustSucceed(t, e)
    67  	MustBeTrue(t, d != nil)
    68  
    69  	MustBeError(t, d.SetOption("bogus", nil), mangos.ErrBadOption)
    70  	_, e = d.GetOption("bogus")
    71  	MustBeError(t, e, mangos.ErrBadOption)
    72  
    73  	val, e := d.GetOption(mangos.OptionReconnectTime)
    74  	MustSucceed(t, e)
    75  	MustBeTrue(t, reflect.TypeOf(val) == reflect.TypeOf(time.Duration(0)))
    76  
    77  	val, e = d.GetOption(mangos.OptionMaxReconnectTime)
    78  	MustSucceed(t, e)
    79  	MustBeTrue(t, reflect.TypeOf(val) == reflect.TypeOf(time.Duration(0)))
    80  
    81  	val, e = d.GetOption(mangos.OptionDialAsynch)
    82  	MustSucceed(t, e)
    83  	MustBeTrue(t, reflect.TypeOf(val) == reflect.TypeOf(true))
    84  
    85  	val, e = d.GetOption("mockError")
    86  	MustBeError(t, e, mangos.ErrProtoState)
    87  	MustBeTrue(t, val == nil)
    88  
    89  	MustBeError(t, d.SetOption(mangos.OptionDialAsynch, 1), mangos.ErrBadValue)
    90  	MustBeError(t, d.SetOption(mangos.OptionReconnectTime, 1), mangos.ErrBadValue)
    91  	MustBeError(t, d.SetOption(mangos.OptionReconnectTime, -time.Second), mangos.ErrBadValue)
    92  	MustBeError(t, d.SetOption(mangos.OptionMaxReconnectTime, 1), mangos.ErrBadValue)
    93  	MustBeError(t, d.SetOption(mangos.OptionMaxReconnectTime, -time.Second), mangos.ErrBadValue)
    94  	MustBeError(t, d.SetOption(mangos.OptionMaxRecvSize, -100), mangos.ErrBadValue)
    95  	MustBeError(t, d.SetOption(mangos.OptionMaxRecvSize, "a"), mangos.ErrBadValue)
    96  	MustBeError(t, d.SetOption("mockError", mangos.ErrCanceled), mangos.ErrCanceled)
    97  
    98  	MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, false))
    99  	MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Duration(0)))
   100  	MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Second))
   101  	MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Duration(0)))
   102  	MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, 5*time.Second))
   103  	MustSucceed(t, d.SetOption(mangos.OptionMaxRecvSize, 1024))
   104  
   105  	MustSucceed(t, d.SetOption(mangos.OptionMaxRecvSize, 1024))
   106  	val, e = d.GetOption(mangos.OptionMaxRecvSize)
   107  	MustSucceed(t, e)
   108  	sz, ok := val.(int)
   109  	MustBeTrue(t, ok)
   110  	MustBeTrue(t, sz == 1024)
   111  }
   112  
   113  func TestDialerOptionsMap(t *testing.T) {
   114  	AddMockTransport()
   115  	sock := GetMockSocket()
   116  	defer MustClose(t, sock)
   117  	addr := AddrMock()
   118  
   119  	opts := make(map[string]interface{})
   120  	opts[mangos.OptionMaxRecvSize] = "garbage"
   121  	d, e := sock.NewDialer(addr, opts)
   122  	MustBeError(t, e, mangos.ErrBadValue)
   123  	MustBeTrue(t, d == nil)
   124  
   125  	opts = make(map[string]interface{})
   126  	opts[mangos.OptionMaxRecvSize] = -1
   127  	d, e = sock.NewDialer(addr, opts)
   128  	MustBeError(t, e, mangos.ErrBadValue)
   129  	MustBeTrue(t, d == nil)
   130  
   131  	opts = make(map[string]interface{})
   132  	opts[mangos.OptionMaxRecvSize] = 1001
   133  	d, e = sock.NewDialer(addr, opts)
   134  	MustBeError(t, e, mangos.ErrBadValue)
   135  	MustBeTrue(t, d == nil)
   136  
   137  	opts = make(map[string]interface{})
   138  	opts[mangos.OptionMaxRecvSize] = 1002
   139  	d, e = sock.NewDialer(addr, opts)
   140  	MustBeError(t, e, mangos.ErrBadOption)
   141  	MustBeTrue(t, d == nil)
   142  
   143  	opts = make(map[string]interface{})
   144  	opts[mangos.OptionDialAsynch] = -1
   145  	d, e = sock.NewDialer(addr, opts)
   146  	MustBeError(t, e, mangos.ErrBadValue)
   147  	MustBeTrue(t, d == nil)
   148  
   149  	opts = make(map[string]interface{})
   150  	opts["JUNKOPT"] = "yes"
   151  	d, e = sock.NewDialer(addr, opts)
   152  	MustBeError(t, e, mangos.ErrBadOption)
   153  	MustBeTrue(t, d == nil)
   154  
   155  	opts = make(map[string]interface{})
   156  	opts["mockError"] = mangos.ErrCanceled
   157  	d, e = sock.NewDialer(addr, opts)
   158  	MustBeError(t, e, mangos.ErrCanceled)
   159  	MustBeTrue(t, d == nil)
   160  
   161  	// Now good options
   162  	opts = make(map[string]interface{})
   163  	opts[mangos.OptionMaxRecvSize] = 3172
   164  	opts[mangos.OptionReconnectTime] = time.Second
   165  	opts[mangos.OptionMaxReconnectTime] = time.Second * 2
   166  	opts[mangos.OptionDialAsynch] = false
   167  	d, e = sock.NewDialer(addr, opts)
   168  	MustSucceed(t, e)
   169  	MustBeTrue(t, d != nil)
   170  	v, e := d.GetOption(mangos.OptionMaxRecvSize)
   171  	MustSucceed(t, e)
   172  	sz, ok := v.(int)
   173  	MustBeTrue(t, ok)
   174  	MustBeTrue(t, sz == 3172)
   175  
   176  }
   177  
   178  func TestDialerOptionsInherit(t *testing.T) {
   179  	AddMockTransport()
   180  	sock := GetMockSocket()
   181  	defer MustClose(t, sock)
   182  	addr := AddrMock()
   183  
   184  	// This should force listener not to alloc (bad option value)
   185  	MustSucceed(t, sock.SetOption(mangos.OptionMaxRecvSize, 1001))
   186  	d, e := sock.NewDialer(addr, nil)
   187  	MustBeError(t, e, mangos.ErrBadValue)
   188  	MustBeTrue(t, d == nil)
   189  	MustSucceed(t, sock.SetOption(mangos.OptionMaxRecvSize, 1002))
   190  	d, e = sock.NewDialer(addr, nil)
   191  	MustSucceed(t, e)
   192  	MustBeTrue(t, d != nil)
   193  
   194  	MustSucceed(t, sock.SetOption(mangos.OptionMaxRecvSize, 500))
   195  	v, e := d.GetOption(mangos.OptionMaxRecvSize)
   196  	MustSucceed(t, e)
   197  	MustBeTrue(t, v.(int) == 500)
   198  
   199  }
   200  
   201  func TestDialerPipe(t *testing.T) {
   202  	sock1 := GetMockSocket()
   203  	defer MustClose(t, sock1)
   204  	sock2 := GetMockSocket()
   205  	defer MustClose(t, sock2)
   206  	addr := AddrTestInp()
   207  
   208  	MustSucceed(t, sock1.SetOption(mangos.OptionRecvDeadline, time.Second))
   209  	MustSucceed(t, sock2.SetOption(mangos.OptionSendDeadline, time.Second))
   210  
   211  	d, e := sock1.NewDialer(addr, nil)
   212  	MustSucceed(t, e)
   213  	MustSucceed(t, sock2.Listen(addr))
   214  	MustSucceed(t, d.Dial())
   215  
   216  	MustSendString(t, sock2, "junk")
   217  	m := MustRecvMsg(t, sock1)
   218  
   219  	MustBeTrue(t, m.Pipe.Dialer() == d)
   220  	MustBeTrue(t, m.Pipe.Listener() == nil)
   221  	MustBeTrue(t, m.Pipe.Address() == addr)
   222  	m.Free()
   223  }
   224  
   225  func TestDialerClosed(t *testing.T) {
   226  	AddMockTransport()
   227  	sock := GetMockSocket()
   228  	defer MustClose(t, sock)
   229  
   230  	d, e := sock.NewDialer(AddrMock(), nil)
   231  	MustSucceed(t, e)
   232  	MustBeTrue(t, d != nil)
   233  
   234  	MustSucceed(t, d.Close())
   235  
   236  	MustBeError(t, d.Dial(), mangos.ErrClosed)
   237  	MustBeError(t, d.Close(), mangos.ErrClosed)
   238  }
   239  
   240  func TestDialerCloseAbort(t *testing.T) {
   241  	addr := AddrTestInp()
   242  	sock := GetMockSocket()
   243  	defer MustClose(t, sock)
   244  
   245  	d, e := sock.NewDialer(addr, nil)
   246  	MustSucceed(t, e)
   247  	MustBeTrue(t, d != nil)
   248  	MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, true))
   249  	MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond))
   250  	MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond))
   251  
   252  	MustSucceed(t, d.Dial())
   253  	time.Sleep(time.Millisecond * 50)
   254  	MustSucceed(t, d.Close())
   255  }
   256  
   257  func TestDialerCloseAbort2(t *testing.T) {
   258  	sock := GetMockSocket()
   259  	defer MustClose(t, sock)
   260  
   261  	d, mc := GetMockDialer(t, sock)
   262  	MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, true))
   263  	MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond))
   264  	MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond))
   265  
   266  	var wg sync.WaitGroup
   267  	wg.Add(1)
   268  
   269  	pass := false
   270  	go func() {
   271  		defer wg.Done()
   272  		time.Sleep(time.Millisecond * 20)
   273  		MustSucceed(t, mc.Close())
   274  		pass = true
   275  	}()
   276  
   277  	// We're async, so this is guaranteed to succeed.
   278  	MustSucceed(t, d.Dial())
   279  	time.Sleep(time.Millisecond * 50)
   280  	wg.Wait()
   281  	MustBeTrue(t, pass)
   282  }
   283  
   284  func TestDialerReuse(t *testing.T) {
   285  	AddMockTransport()
   286  	sock := GetMockSocket()
   287  	defer MustClose(t, sock)
   288  
   289  	d, e := sock.NewDialer(AddrMock(), nil)
   290  	MustSucceed(t, e)
   291  	MustBeTrue(t, d != nil)
   292  	MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, true))
   293  
   294  	MustSucceed(t, d.Dial())
   295  	MustBeError(t, d.Dial(), mangos.ErrAddrInUse)
   296  
   297  	MustSucceed(t, d.Close())
   298  }
   299  
   300  func TestDialerReconnect(t *testing.T) {
   301  	// We have to use real protocol and transport for this.
   302  	addr := AddrTestInp()
   303  	sock := GetSocket(t, pair.NewSocket)
   304  	defer MustClose(t, sock)
   305  	peer1 := GetSocket(t, pair.NewSocket)
   306  	peer2 := GetSocket(t, pair.NewSocket)
   307  	defer MustClose(t, peer2)
   308  
   309  	MustSucceed(t, sock.SetOption(mangos.OptionRecvDeadline, time.Second))
   310  	MustSucceed(t, sock.SetOption(mangos.OptionSendDeadline, time.Second))
   311  	MustSucceed(t, peer1.SetOption(mangos.OptionRecvDeadline, time.Second))
   312  	MustSucceed(t, peer1.SetOption(mangos.OptionSendDeadline, time.Second))
   313  	MustSucceed(t, peer2.SetOption(mangos.OptionRecvDeadline, time.Second))
   314  	MustSucceed(t, peer2.SetOption(mangos.OptionSendDeadline, time.Second))
   315  
   316  	d, e := sock.NewDialer(addr, nil)
   317  	MustSucceed(t, e)
   318  	MustBeTrue(t, d != nil)
   319  	MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond))
   320  	MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond))
   321  
   322  	MustSucceed(t, peer1.Listen(addr))
   323  	MustSucceed(t, d.Dial())
   324  	time.Sleep(time.Millisecond * 20)
   325  	MustClose(t, peer1)
   326  	MustSucceed(t, peer2.Listen(addr))
   327  	time.Sleep(time.Millisecond * 20)
   328  	MustSendString(t, sock, "test")
   329  	MustRecvString(t, peer2, "test")
   330  
   331  	MustSucceed(t, d.Close())
   332  }
   333  
   334  func TestDialerConnectLate(t *testing.T) {
   335  	// We have to use real protocol and transport for this.
   336  	addr := AddrTestInp()
   337  	sock := GetSocket(t, pair.NewSocket)
   338  	defer MustClose(t, sock)
   339  	peer := GetSocket(t, pair.NewSocket)
   340  	defer MustClose(t, peer)
   341  
   342  	d, e := sock.NewDialer(addr, nil)
   343  	MustSucceed(t, e)
   344  	MustBeTrue(t, d != nil)
   345  	MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond))
   346  	MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond))
   347  	MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, true))
   348  
   349  	lock := &sync.Mutex{}
   350  	cond := sync.NewCond(lock)
   351  	done := false
   352  
   353  	hook := func(ev mangos.PipeEvent, p mangos.Pipe) {
   354  		if ev == mangos.PipeEventAttached {
   355  			lock.Lock()
   356  			done = true
   357  			cond.Broadcast()
   358  			lock.Unlock()
   359  		}
   360  	}
   361  	_ = sock.SetPipeEventHook(hook)
   362  
   363  	var wg sync.WaitGroup
   364  	wg.Add(1)
   365  
   366  	go func() {
   367  		defer wg.Done()
   368  		time.Sleep(time.Millisecond * 50)
   369  		MustSucceed(t, peer.Listen(addr))
   370  	}()
   371  
   372  	MustSucceed(t, d.Dial())
   373  
   374  	wg.Wait()
   375  	lock.Lock()
   376  	cond.Wait()
   377  	lock.Unlock()
   378  
   379  	MustBeTrue(t, done)
   380  }
   381  
   382  func TestDialerConnectRefused(t *testing.T) {
   383  	// We have to use real protocol and transport for this.
   384  	addr := AddrTestInp()
   385  	sock := GetSocket(t, pair.NewSocket)
   386  	defer MustClose(t, sock)
   387  	peer := GetSocket(t, pair.NewSocket)
   388  	defer MustClose(t, peer)
   389  
   390  	d, e := sock.NewDialer(addr, nil)
   391  	MustSucceed(t, e)
   392  	MustBeTrue(t, d != nil)
   393  	MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond))
   394  	MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond))
   395  
   396  	MustBeError(t, d.Dial(), mangos.ErrConnRefused)
   397  
   398  }