go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xsurveyor/xsurveyor_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 xsurveyor
    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/respondent"
    27  	_ "go.nanomsg.org/mangos/v3/transport/inproc"
    28  )
    29  
    30  func TestXSurveyorIdentity(t *testing.T) {
    31  	self := GetSocket(t, NewSocket)
    32  	id := self.Info()
    33  	MustBeTrue(t, id.Self == mangos.ProtoSurveyor)
    34  	MustBeTrue(t, id.SelfName == "surveyor")
    35  	MustBeTrue(t, id.Peer == mangos.ProtoRespondent)
    36  	MustBeTrue(t, id.PeerName == "respondent")
    37  	MustSucceed(t, self.Close())
    38  }
    39  
    40  func TestXSurveyorRaw(t *testing.T) {
    41  	VerifyRaw(t, NewSocket)
    42  }
    43  
    44  func TestXSurveyorClosed(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 makeSurveyMsg(id uint32, s string) *mangos.Message {
    54  	m := mangos.NewMessage(0)
    55  	m.Header = append(m.Header, make([]byte, 4)...)
    56  	binary.BigEndian.PutUint32(m.Header, id|0x80000000)
    57  	m.Body = append(m.Body, []byte(s)...)
    58  	return m
    59  }
    60  
    61  func TestXSurveyorNoHeader(t *testing.T) {
    62  	self := GetSocket(t, NewSocket)
    63  
    64  	m := mangos.NewMessage(0)
    65  
    66  	MustSucceed(t, self.SendMsg(m))
    67  	MustSucceed(t, self.Close())
    68  }
    69  
    70  // We can send even with no pipes
    71  func TestXSurveyorNonBlock1(t *testing.T) {
    72  	self := GetSocket(t, NewSocket)
    73  	for i := 0; i < 100; i++ {
    74  		m := makeSurveyMsg(uint32(i), "ping")
    75  		MustSucceed(t, self.SendMsg(m))
    76  	}
    77  	time.Sleep(time.Millisecond * 10)
    78  	MustSucceed(t, self.Close())
    79  }
    80  
    81  // We can send even if we have a pipe that is blocked
    82  func TestXSurveyorNonBlock2(t *testing.T) {
    83  	self := GetSocket(t, NewSocket)
    84  	MustSucceed(t, self.SetOption(mangos.OptionWriteQLen, 1))
    85  	_, _ = MockConnect(t, self)
    86  
    87  	for i := 0; i < 100; i++ {
    88  		m := makeSurveyMsg(uint32(i), "ping")
    89  		MustSucceed(t, self.SendMsg(m))
    90  	}
    91  	time.Sleep(time.Millisecond * 50)
    92  	MustSucceed(t, self.Close())
    93  }
    94  
    95  func TestXSurveyorRecvTimeout(t *testing.T) {
    96  	s, err := NewSocket()
    97  	MustSucceed(t, err)
    98  
    99  	MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Millisecond))
   100  	m, err := s.RecvMsg()
   101  	MustBeNil(t, m)
   102  	MustBeError(t, err, protocol.ErrRecvTimeout)
   103  	MustSucceed(t, s.Close())
   104  }
   105  
   106  // XSurveyor needs a surveyor ID or it will discard.
   107  func TestXSurveyorRecvJunk(t *testing.T) {
   108  	self := GetSocket(t, NewSocket)
   109  	mock, _ := MockConnect(t, self)
   110  
   111  	MockMustSendStr(t, mock, "", time.Second)
   112  	time.Sleep(time.Millisecond * 10)
   113  	MustSucceed(t, self.Close())
   114  }
   115  
   116  func TestXSurveyorOptions(t *testing.T) {
   117  	VerifyInvalidOption(t, NewSocket)
   118  	VerifyOptionDuration(t, NewSocket, mangos.OptionRecvDeadline)
   119  	VerifyOptionQLen(t, NewSocket, mangos.OptionReadQLen)
   120  	VerifyOptionQLen(t, NewSocket, mangos.OptionWriteQLen)
   121  }
   122  
   123  func TestXSurveyorRecvQLenResizeDiscard(t *testing.T) {
   124  	self := GetSocket(t, NewSocket)
   125  	peer := GetSocket(t, respondent.NewSocket)
   126  
   127  	MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Second))
   128  	MustSucceed(t, self.SetOption(mangos.OptionReadQLen, 3))
   129  	MustSucceed(t, peer.SetOption(mangos.OptionWriteQLen, 100))
   130  	ConnectPair(t, self, peer)
   131  
   132  	// Now do some exchanges, but don't collect the answers -- let our
   133  	// receive queue fill up.
   134  	for i := uint32(0); i < 100; i++ {
   135  		MustSucceed(t, self.SendMsg(makeSurveyMsg(i, "")))
   136  		_ = MustRecvMsg(t, peer)
   137  		MustSendString(t, peer, "reply")
   138  	}
   139  
   140  	time.Sleep(time.Millisecond * 50)
   141  	// Shrink it
   142  	MustSucceed(t, self.SetOption(mangos.OptionReadQLen, 2))
   143  	// This can fail or succeed -- depending on how much back-pressure we
   144  	// have applied; it usually succeeds.
   145  	time.Sleep(time.Millisecond * 50)
   146  	_, _ = self.RecvMsg()
   147  	time.Sleep(time.Millisecond * 10)
   148  	MustSucceed(t, peer.Close())
   149  	MustSucceed(t, self.Close())
   150  }
   151  
   152  func TestXSurveyorRecvClosePipeDiscard(t *testing.T) {
   153  	self := GetSocket(t, NewSocket)
   154  	peer := GetSocket(t, respondent.NewSocket)
   155  
   156  	MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Second))
   157  	MustSucceed(t, self.SetOption(mangos.OptionReadQLen, 3))
   158  	MustSucceed(t, peer.SetOption(mangos.OptionWriteQLen, 100))
   159  	ConnectPair(t, self, peer)
   160  
   161  	// One exchange to get the pipe ID to close
   162  	MustSucceed(t, self.SendMsg(makeSurveyMsg(0, "")))
   163  	_ = MustRecvMsg(t, peer)
   164  	MustSendString(t, peer, "junk")
   165  	r, e := self.RecvMsg()
   166  	MustSucceed(t, e)
   167  	pipe := r.Pipe
   168  
   169  	// Now do some exchanges, but don't collect the answers -- let our
   170  	// receive queue fill up.
   171  	for i := uint32(0); i < 100; i++ {
   172  		MustSucceed(t, self.SendMsg(makeSurveyMsg(i, "")))
   173  		_ = MustRecvMsg(t, peer)
   174  		MustSendString(t, peer, "reply")
   175  	}
   176  
   177  	MustSucceed(t, pipe.Close())
   178  	time.Sleep(time.Millisecond * 20)
   179  	MustSucceed(t, self.Close())
   180  	MustSucceed(t, peer.Close())
   181  
   182  }
   183  
   184  // This ensures that the upper RecvMsg sees the new queue after a resize
   185  func TestXSurveyorResizeRecv(t *testing.T) {
   186  	self := GetSocket(t, NewSocket)
   187  	peer := GetSocket(t, respondent.NewSocket)
   188  	MustSucceed(t, peer.SetOption(mangos.OptionWriteQLen, 20))
   189  	MustSucceed(t, self.SetOption(mangos.OptionReadQLen, 20))
   190  	MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Minute))
   191  	ConnectPair(t, self, peer)
   192  
   193  	m := makeSurveyMsg(1, "hello")
   194  	MustSucceed(t, self.SendMsg(m))
   195  	MustRecvString(t, peer, "hello")
   196  
   197  	time.AfterFunc(time.Millisecond*20, func() {
   198  		MustSucceed(t, self.SetOption(mangos.OptionReadQLen, 10))
   199  		time.Sleep(time.Millisecond)
   200  		MustSendString(t, peer, "world")
   201  	})
   202  
   203  	r, e := self.RecvMsg()
   204  	MustSucceed(t, e)
   205  	MustBeTrue(t, binary.BigEndian.Uint32(r.Header) == 0x80000001)
   206  	MustBeTrue(t, string(r.Body) == "world")
   207  
   208  	MustSucceed(t, self.Close())
   209  }
   210  
   211  func TestXSurveyorBroadcast(t *testing.T) {
   212  	s, err := NewSocket()
   213  	MustSucceed(t, err)
   214  	MustNotBeNil(t, s)
   215  
   216  	s1, err := respondent.NewSocket()
   217  	MustSucceed(t, err)
   218  	MustNotBeNil(t, s1)
   219  
   220  	s2, err := respondent.NewSocket()
   221  	MustSucceed(t, err)
   222  	MustNotBeNil(t, s2)
   223  
   224  	a := AddrTestInp()
   225  	MustSucceed(t, s.Listen(a))
   226  	MustSucceed(t, s1.Dial(a))
   227  	MustSucceed(t, s2.Dial(a))
   228  
   229  	time.Sleep(time.Millisecond * 50)
   230  
   231  	MustSucceed(t, s1.SetOption(mangos.OptionRecvDeadline, time.Millisecond*50))
   232  	MustSucceed(t, s2.SetOption(mangos.OptionRecvDeadline, time.Millisecond*50))
   233  
   234  	MustSucceed(t, s.SendMsg(makeSurveyMsg(1, "one")))
   235  	MustSucceed(t, s.SendMsg(makeSurveyMsg(2, "two")))
   236  	MustSucceed(t, s.SendMsg(makeSurveyMsg(3, "three")))
   237  
   238  	var wg sync.WaitGroup
   239  	wg.Add(2)
   240  	pass1 := false
   241  	pass2 := false
   242  
   243  	f := func(s mangos.Socket, pass *bool) {
   244  		defer wg.Done()
   245  		v, e := s.Recv()
   246  		MustSucceed(t, e)
   247  		MustBeTrue(t, string(v) == "one")
   248  
   249  		v, e = s.Recv()
   250  		MustSucceed(t, e)
   251  		MustBeTrue(t, string(v) == "two")
   252  
   253  		v, e = s.Recv()
   254  		MustSucceed(t, e)
   255  		MustBeTrue(t, string(v) == "three")
   256  
   257  		v, e = s.Recv()
   258  		MustBeError(t, e, mangos.ErrRecvTimeout)
   259  		MustBeNil(t, v)
   260  		*pass = true
   261  	}
   262  
   263  	go f(s1, &pass1)
   264  	go f(s2, &pass2)
   265  
   266  	wg.Wait()
   267  
   268  	MustBeTrue(t, pass1)
   269  	MustBeTrue(t, pass2)
   270  
   271  	MustSucceed(t, s.Close())
   272  	MustSucceed(t, s1.Close())
   273  	MustSucceed(t, s2.Close())
   274  }