nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/protocol/xpush/xpush_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 xpush
    16  
    17  import (
    18  	"nanomsg.org/go/mangos/v2"
    19  	"nanomsg.org/go/mangos/v2/protocol/pull"
    20  	"sync"
    21  	"testing"
    22  	"time"
    23  
    24  	. "nanomsg.org/go/mangos/v2/internal/test"
    25  	_ "nanomsg.org/go/mangos/v2/transport/inproc"
    26  )
    27  
    28  func TestXPushIdentity(t *testing.T) {
    29  	s := GetSocket(t, NewSocket)
    30  	id := s.Info()
    31  	MustBeTrue(t, id.Self == mangos.ProtoPush)
    32  	MustBeTrue(t, id.SelfName == "push")
    33  	MustBeTrue(t, id.Peer == mangos.ProtoPull)
    34  	MustBeTrue(t, id.PeerName == "pull")
    35  	MustSucceed(t, s.Close())
    36  }
    37  
    38  func TestXPushRaw(t *testing.T) {
    39  	VerifyRaw(t, NewSocket)
    40  }
    41  
    42  func TestXPushOptions(t *testing.T) {
    43  	VerifyInvalidOption(t, NewSocket)
    44  	VerifyOptionBool(t, NewSocket, mangos.OptionBestEffort)
    45  	VerifyOptionDuration(t, NewSocket, mangos.OptionSendDeadline)
    46  	VerifyOptionQLen(t, NewSocket, mangos.OptionWriteQLen)
    47  }
    48  
    49  func TestXPushNoRecv(t *testing.T) {
    50  	CannotRecv(t, NewSocket)
    51  }
    52  
    53  func TestXPushClosed(t *testing.T) {
    54  	VerifyClosedListen(t, NewSocket)
    55  	VerifyClosedDial(t, NewSocket)
    56  	VerifyClosedClose(t, NewSocket)
    57  	VerifyClosedSend(t, NewSocket)
    58  	VerifyClosedAddPipe(t, NewSocket)
    59  }
    60  
    61  func TestXPushSendBestEffort(t *testing.T) {
    62  	s := GetSocket(t, NewSocket)
    63  	MustSucceed(t, s.SetOption(mangos.OptionBestEffort, true))
    64  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1))
    65  	for i := 0; i < 20; i++ {
    66  		MustSucceed(t, s.Send([]byte{}))
    67  	}
    68  	MustSucceed(t, s.Close())
    69  }
    70  
    71  func TestXPushSendTimeout(t *testing.T) {
    72  	s := GetSocket(t, NewSocket)
    73  	MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Millisecond))
    74  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1))
    75  	pass := false
    76  	for i := 0; i < 20; i++ {
    77  		if e := s.Send([]byte{}); e != nil {
    78  			MustBeError(t, e, mangos.ErrSendTimeout)
    79  			pass = true
    80  			break
    81  		}
    82  	}
    83  	MustBeTrue(t, pass)
    84  	MustSucceed(t, s.Close())
    85  }
    86  
    87  func TestXPushSendResize(t *testing.T) {
    88  	s := GetSocket(t, NewSocket)
    89  	p := GetSocket(t, pull.NewSocket)
    90  	MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Millisecond))
    91  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 20))
    92  	MustSucceed(t, p.SetOption(mangos.OptionRecvDeadline, time.Millisecond*20))
    93  	for i := 0; i < 10; i++ {
    94  		MustSucceed(t, s.Send([]byte{byte(i)}))
    95  	}
    96  
    97  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 3))
    98  
    99  	// Now connect them so they can drain -- we should only have 3 messages
   100  	// that arrive at the peer.
   101  	ConnectPair(t, s, p)
   102  
   103  	for i := 0; i < 3; i++ {
   104  		m, e := p.Recv()
   105  		MustSucceed(t, e)
   106  		MustNotBeNil(t, m)
   107  	}
   108  	_, e := p.Recv()
   109  	MustBeError(t, e, mangos.ErrRecvTimeout)
   110  	MustSucceed(t, s.Close())
   111  	MustSucceed(t, p.Close())
   112  }
   113  
   114  func TestXPushCloseAbort(t *testing.T) {
   115  	s := GetSocket(t, NewSocket)
   116  	MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Minute))
   117  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1))
   118  	pass := false
   119  	time.AfterFunc(time.Millisecond*10, func() {
   120  		MustSucceed(t, s.Close())
   121  	})
   122  	for i := 0; i < 20; i++ {
   123  		if e := s.Send([]byte{}); e != nil {
   124  			MustBeError(t, e, mangos.ErrClosed)
   125  			pass = true
   126  			break
   127  		}
   128  	}
   129  	MustBeTrue(t, pass)
   130  }
   131  
   132  // This tests that with nPeers, the load sharing will be "fair".  It can't
   133  // verify ordering, because goroutines that return peers to the readyq can
   134  // race against each other.
   135  func TestXPushFairShare(t *testing.T) {
   136  	count := 20
   137  	nPeer := 5
   138  	peers := make([]mangos.Socket, nPeer)
   139  	s := GetSocket(t, NewSocket)
   140  
   141  	for i := 0; i < nPeer; i++ {
   142  		p := GetSocket(t, pull.NewSocket)
   143  		MustSucceed(t, p.SetOption(mangos.OptionRecvDeadline, time.Second))
   144  		MustSucceed(t, p.SetOption(mangos.OptionReadQLen, 0))
   145  		ConnectPair(t, s, p)
   146  		peers[i] = p
   147  	}
   148  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, count*nPeer))
   149  
   150  	for i := 0; i < count; i++ {
   151  		for j := 0; j < nPeer; j++ {
   152  			MustSucceed(t, s.Send([]byte{byte(j)}))
   153  		}
   154  	}
   155  
   156  	for i := 0; i < count; i++ {
   157  		for j := 0; j < nPeer; j++ {
   158  			p := peers[j]
   159  			m, e := p.Recv()
   160  			MustSucceed(t, e)
   161  			MustBeTrue(t, len(m) == 1)
   162  			// We have to sleep a bit to let the go routine
   163  			// that returns the readyq complete
   164  			time.Sleep(time.Millisecond)
   165  		}
   166  	}
   167  	for i := 0; i < nPeer; i++ {
   168  		MustSucceed(t, peers[i].Close())
   169  	}
   170  	MustSucceed(t, s.Close())
   171  }
   172  
   173  func TestXPushRecvDiscard(t *testing.T) {
   174  	s := GetSocket(t, NewSocket)
   175  	l, mc := GetMockListener(t, s)
   176  	mp := mc.NewPipe(s.Info().Peer)
   177  	MustSucceed(t, l.Listen())
   178  	MustSucceed(t, mc.AddPipe(mp))
   179  
   180  	pass := true
   181  outer:
   182  	for i := 0; i < 10; i++ {
   183  		m := mangos.NewMessage(0)
   184  		m.Body = append(m.Body, 'a', 'b', 'c')
   185  		select {
   186  		case <-time.After(time.Second):
   187  			pass = false
   188  			break outer
   189  		case mp.RecvQ() <- m:
   190  		}
   191  	}
   192  	MustBeTrue(t, pass)
   193  	MustSucceed(t, s.Close())
   194  }
   195  
   196  func TestXPushSendFail(t *testing.T) {
   197  	s := GetSocket(t, NewSocket)
   198  	l, mc := GetMockListener(t, s)
   199  	mp := mc.NewPipe(s.Info().Peer)
   200  	MustSucceed(t, l.Listen())
   201  	nAdd := uint32(0)
   202  	nRem := uint32(0)
   203  	wg := sync.WaitGroup{}
   204  	wg.Add(1)
   205  	hook := func(ev mangos.PipeEvent, p mangos.Pipe) {
   206  		switch ev {
   207  		case mangos.PipeEventAttached:
   208  			nAdd++
   209  		case mangos.PipeEventDetached:
   210  			nRem++
   211  			wg.Done()
   212  		}
   213  	}
   214  	s.SetPipeEventHook(hook)
   215  
   216  	MustSucceed(t, mc.AddPipe(mp))
   217  	mp.InjectSendError(mangos.ErrBadHeader)
   218  	MustSucceed(t, s.Send([]byte{}))
   219  	wg.Wait()
   220  	MustSucceed(t, s.Close())
   221  	MustBeTrue(t, nAdd == 1)
   222  	MustBeTrue(t, nRem == 1)
   223  	MustBeTrue(t, len(mp.SendQ()) == 0)
   224  }