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