nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/protocol/xrespondent/xrespondent_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 xrespondent
    16  
    17  import (
    18  	"encoding/binary"
    19  	"nanomsg.org/go/mangos/v2"
    20  	"nanomsg.org/go/mangos/v2/protocol"
    21  	"nanomsg.org/go/mangos/v2/protocol/surveyor"
    22  	"nanomsg.org/go/mangos/v2/protocol/xsurveyor"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  
    27  	. "nanomsg.org/go/mangos/v2/internal/test"
    28  	. "nanomsg.org/go/mangos/v2/protocol"
    29  	_ "nanomsg.org/go/mangos/v2/transport/inproc"
    30  )
    31  
    32  func TestXRespondentIdentity(t *testing.T) {
    33  	id := MustGetInfo(t, NewSocket)
    34  	MustBeTrue(t, id.Peer == ProtoSurveyor)
    35  	MustBeTrue(t, id.PeerName == "surveyor")
    36  	MustBeTrue(t, id.Self == ProtoRespondent)
    37  	MustBeTrue(t, id.SelfName == "respondent")
    38  }
    39  
    40  func TestXRespondentRaw(t *testing.T) {
    41  	VerifyRaw(t, NewSocket)
    42  }
    43  
    44  func TestXRespondentClosed(t *testing.T) {
    45  	VerifyClosedRecv(t, NewSocket)
    46  	VerifyClosedSend(t, NewSocket)
    47  	VerifyClosedClose(t, NewSocket)
    48  	VerifyClosedDial(t, NewSocket)
    49  	VerifyClosedListen(t, NewSocket)
    50  	VerifyClosedAddPipe(t, NewSocket)
    51  }
    52  
    53  func TestXRespondentNoHeader(t *testing.T) {
    54  	s := GetSocket(t, NewSocket)
    55  	defer MustClose(t, s)
    56  	m := mangos.NewMessage(0)
    57  
    58  	MustSucceed(t, s.SendMsg(m))
    59  }
    60  
    61  func TestXRespondentMismatchHeader(t *testing.T) {
    62  	s, err := NewSocket()
    63  	MustSucceed(t, err)
    64  
    65  	m := mangos.NewMessage(0)
    66  	m.Header = append(m.Header, []byte{1, 1, 1, 1}...)
    67  
    68  	MustSucceed(t, s.SendMsg(m))
    69  	MustSucceed(t, s.Close())
    70  }
    71  
    72  func TestXRespondentRecvTimeout(t *testing.T) {
    73  	s, err := NewSocket()
    74  	MustSucceed(t, err)
    75  
    76  	MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Millisecond))
    77  	m, err := s.RecvMsg()
    78  	MustBeNil(t, m)
    79  	MustFail(t, err)
    80  	MustBeTrue(t, err == protocol.ErrRecvTimeout)
    81  	MustSucceed(t, s.Close())
    82  }
    83  
    84  func TestXRespondentTTLZero(t *testing.T) {
    85  	SetTTLZero(t, NewSocket)
    86  }
    87  
    88  func TestXRespondentTTLNegative(t *testing.T) {
    89  	SetTTLNegative(t, NewSocket)
    90  }
    91  
    92  func TestXRespondentTTLTooBig(t *testing.T) {
    93  	SetTTLTooBig(t, NewSocket)
    94  }
    95  
    96  func TestXRespondentTTLNotInt(t *testing.T) {
    97  	SetTTLNotInt(t, NewSocket)
    98  }
    99  
   100  func TestXRespondentTTLSet(t *testing.T) {
   101  	SetTTL(t, NewSocket)
   102  }
   103  
   104  func TestXRespondentTTLDrop(t *testing.T) {
   105  	TTLDropTest(t, surveyor.NewSocket, NewSocket, xsurveyor.NewSocket, NewSocket)
   106  }
   107  
   108  func TestXRespondentOptions(t *testing.T) {
   109  	VerifyInvalidOption(t, NewSocket)
   110  	VerifyOptionDuration(t, NewSocket, mangos.OptionRecvDeadline)
   111  	VerifyOptionDuration(t, NewSocket, mangos.OptionSendDeadline)
   112  	VerifyOptionQLen(t, NewSocket, mangos.OptionReadQLen)
   113  	VerifyOptionQLen(t, NewSocket, mangos.OptionWriteQLen)
   114  	VerifyOptionInt(t, NewSocket, mangos.OptionTTL)
   115  	VerifyOptionBool(t, NewSocket, mangos.OptionBestEffort)
   116  }
   117  
   118  func TestXRespondentSendTimeout(t *testing.T) {
   119  	timeout := time.Millisecond * 10
   120  
   121  	s, err := NewSocket()
   122  	MustSucceed(t, err)
   123  	MustNotBeNil(t, s)
   124  
   125  	r, err := xsurveyor.NewSocket()
   126  	MustSucceed(t, err)
   127  	MustNotBeNil(t, r)
   128  
   129  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1))
   130  	MustSucceed(t, r.SetOption(mangos.OptionReadQLen, 0))
   131  	MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, timeout))
   132  	MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, timeout))
   133  	MustSucceed(t, r.SetOption(mangos.OptionRecvDeadline, timeout))
   134  
   135  	// We need to setup a connection so that we can get a meaningful
   136  	// pipe ID.  We get this by receiving a message.
   137  	a := AddrTestInp()
   138  	MustSucceed(t, s.Listen(a))
   139  	MustSucceed(t, r.Dial(a))
   140  
   141  	time.Sleep(time.Millisecond * 20)
   142  	MustSucceed(t, r.Send([]byte{0x80, 0, 0, 1})) // Request ID #1
   143  	m, e := s.RecvMsg()
   144  	MustSucceed(t, e)
   145  	MustBeTrue(t, len(m.Header) >= 8) // request ID and pipe ID
   146  
   147  	// Because of vagaries in the queuing, we slam messages until we
   148  	// hit a timeout.  We expect to do so after only a modest number
   149  	// of messages, as we have no reader on the other side.
   150  	for i := 0; i < 100; i++ {
   151  		e = s.SendMsg(m.Dup())
   152  		if e != nil {
   153  			break
   154  		}
   155  	}
   156  	MustBeError(t, s.SendMsg(m.Dup()), mangos.ErrSendTimeout)
   157  	MustSucceed(t, s.Close())
   158  	MustSucceed(t, r.Close())
   159  }
   160  
   161  func TestXRespondentBestEffort(t *testing.T) {
   162  	timeout := time.Millisecond * 10
   163  
   164  	s, err := NewSocket()
   165  	MustSucceed(t, err)
   166  	MustNotBeNil(t, s)
   167  
   168  	r, err := xsurveyor.NewSocket()
   169  	MustSucceed(t, err)
   170  	MustNotBeNil(t, r)
   171  
   172  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1))
   173  	MustSucceed(t, r.SetOption(mangos.OptionReadQLen, 0))
   174  	MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, timeout))
   175  	MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, timeout))
   176  	MustSucceed(t, r.SetOption(mangos.OptionRecvDeadline, timeout))
   177  
   178  	// We need to setup a connection so that we can get a meaningful
   179  	// pipe ID.  We get this by receiving a message.
   180  	a := AddrTestInp()
   181  	MustSucceed(t, s.Listen(a))
   182  	MustSucceed(t, r.Dial(a))
   183  
   184  	time.Sleep(time.Millisecond * 20)
   185  	MustSucceed(t, r.Send([]byte{0x80, 0, 0, 1})) // Request ID #1
   186  	m, e := s.RecvMsg()
   187  	MustSucceed(t, e)
   188  	MustBeTrue(t, len(m.Header) >= 8) // request ID and pipe ID
   189  	MustSucceed(t, s.SetOption(mangos.OptionBestEffort, true))
   190  
   191  	// Because of vagaries in the queuing, we slam messages until we
   192  	// hit a timeout.  We expect to do so after only a modest number
   193  	// of messages, as we have no reader on the other side.
   194  	for i := 0; i < 100; i++ {
   195  		e = s.SendMsg(m.Dup())
   196  		if e != nil {
   197  			break
   198  		}
   199  	}
   200  	MustSucceed(t, e)
   201  	MustSucceed(t, s.Close())
   202  	MustSucceed(t, r.Close())
   203  }
   204  
   205  func TestXRespondentRecvNoHeader(t *testing.T) {
   206  	self := GetSocket(t, NewSocket)
   207  	mock, _ := MockConnect(t, self)
   208  
   209  	MustSucceed(t, self.SetOption(mangos.OptionReadQLen, 2))
   210  	MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Millisecond*50))
   211  	MockMustSend(t, mock, []byte{}, time.Millisecond*5)
   212  	MustNotRecv(t, self, mangos.ErrRecvTimeout)
   213  	MustSucceed(t, self.Close())
   214  }
   215  
   216  func TestXRespondentRecvJunk(t *testing.T) {
   217  	self := GetSocket(t, NewSocket)
   218  	MustSucceed(t, self.SetOption(OptionReadQLen, 20))
   219  	MustSucceed(t, self.SetOption(OptionRecvDeadline, time.Millisecond*10))
   220  
   221  	mp, _ := MockConnect(t, self)
   222  	MockMustSend(t, mp, []byte{}, time.Second)
   223  	MockMustSend(t, mp, []byte{0, 1}, time.Second)
   224  	MockMustSend(t, mp, []byte{0, 1, 2, 3}, time.Second)
   225  	MockMustSend(t, mp, []byte{0, 1, 2, 3, 0x80}, time.Second)
   226  
   227  	MustNotRecv(t, self, ErrRecvTimeout)
   228  	MustClose(t, self)
   229  }
   230  
   231  func newRequest(id uint32, content string) *mangos.Message {
   232  	m := mangos.NewMessage(len(content) + 8)
   233  	b := make([]byte, 4)
   234  	binary.BigEndian.PutUint32(b[:4], id|0x80000000)
   235  	// Requests (coming in) will be entirely on the body.
   236  	m.Body = append(m.Body, b...)
   237  	m.Body = append(m.Body, []byte(content)...)
   238  	return m
   239  }
   240  
   241  func newReply(id uint32, p mangos.Pipe, content string) *mangos.Message {
   242  	m := mangos.NewMessage(len(content))
   243  	b := make([]byte, 8)
   244  	binary.BigEndian.PutUint32(b, p.ID())            // outgoing pipe ID
   245  	binary.BigEndian.PutUint32(b[4:], id|0x80000000) // request ID
   246  	m.Header = append(m.Header, b...)
   247  	m.Body = append(m.Body, []byte(content)...)
   248  	return m
   249  }
   250  
   251  func TestXRespondentPipeCloseSendAbort(t *testing.T) {
   252  	self := GetSocket(t, NewSocket)
   253  	defer MustClose(t, self)
   254  
   255  	MustSucceed(t, self.SetOption(OptionWriteQLen, 0))
   256  	MustSucceed(t, self.SetOption(OptionSendDeadline, time.Second))
   257  
   258  	_, p := MockConnect(t, self)
   259  	var wg sync.WaitGroup
   260  	wg.Add(1)
   261  	pass := false
   262  	finishQ := make(chan struct{})
   263  	go func() {
   264  		defer wg.Done()
   265  		i := uint32(0)
   266  		for {
   267  			i++
   268  			m := newReply(i, p, "")
   269  			MustSendMsg(t, self, m)
   270  			select {
   271  			case <-finishQ:
   272  				pass = true
   273  				return
   274  			default:
   275  			}
   276  		}
   277  	}()
   278  	time.Sleep(time.Millisecond * 50)
   279  	_ = p.Close()
   280  	time.Sleep(time.Millisecond * 50)
   281  	close(finishQ)
   282  	wg.Wait()
   283  	MustBeTrue(t, pass)
   284  
   285  }
   286  
   287  func TestXRespondentPipeCloseRecvAbort(t *testing.T) {
   288  	self := GetSocket(t, NewSocket)
   289  	defer MustClose(t, self)
   290  
   291  	MustSucceed(t, self.SetOption(OptionReadQLen, 1))
   292  	MustSucceed(t, self.SetOption(OptionSendDeadline, time.Second))
   293  
   294  	mock, p := MockConnect(t, self)
   295  	var wg sync.WaitGroup
   296  	wg.Add(1)
   297  	pass := false
   298  	go func() {
   299  		defer wg.Done()
   300  		i := uint32(0)
   301  		for {
   302  			i++
   303  			m := newRequest(i, "")
   304  			e := mock.MockSendMsg(m, time.Second)
   305  			if e != nil {
   306  				MustBeError(t, e, ErrClosed)
   307  				pass = true
   308  				return
   309  			}
   310  			MustSucceed(t, e)
   311  		}
   312  	}()
   313  	time.Sleep(time.Millisecond * 50)
   314  	_ = p.Close()
   315  	time.Sleep(time.Millisecond * 50)
   316  	_ = mock.Close()
   317  
   318  	wg.Wait()
   319  	MustBeTrue(t, pass)
   320  
   321  }
   322  
   323  func TestXRespondentRecv1(t *testing.T) {
   324  	self := GetSocket(t, NewSocket)
   325  	mp, _ := MockConnect(t, self)
   326  	MustSucceed(t, self.SetOption(OptionReadQLen, 0))
   327  	MustSucceed(t, self.SetOption(OptionRecvDeadline, time.Millisecond))
   328  	MockMustSendMsg(t, mp, newRequest(1, "hello"), time.Second)
   329  
   330  	time.Sleep(time.Millisecond * 50)
   331  	MustSucceed(t, self.SetOption(OptionReadQLen, 2))
   332  	MustNotRecv(t, self, ErrRecvTimeout)
   333  	MustClose(t, self)
   334  }
   335  
   336  func TestXRespondentResizeRecv2(t *testing.T) {
   337  	self := GetSocket(t, NewSocket)
   338  	mp, _ := MockConnect(t, self)
   339  	MustSucceed(t, self.SetOption(OptionReadQLen, 1))
   340  	MustSucceed(t, self.SetOption(OptionRecvDeadline, time.Second))
   341  
   342  	time.AfterFunc(time.Millisecond*50, func() {
   343  		MustSucceed(t, self.SetOption(OptionReadQLen, 2))
   344  		time.Sleep(time.Millisecond * 50)
   345  		MockMustSendMsg(t, mp, newRequest(1, "hello"), time.Second)
   346  	})
   347  	MustRecvString(t, self, "hello")
   348  	MustClose(t, self)
   349  }