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