nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/protocol/surveyor/surveyor_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 surveyor
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/binary"
    20  	"nanomsg.org/go/mangos/v2/protocol/respondent"
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  
    25  	"nanomsg.org/go/mangos/v2"
    26  	. "nanomsg.org/go/mangos/v2/internal/test"
    27  	_ "nanomsg.org/go/mangos/v2/transport/inproc"
    28  )
    29  
    30  func TestSurveyorIdentity(t *testing.T) {
    31  	s, err := NewSocket()
    32  	MustSucceed(t, err)
    33  	id := s.Info()
    34  	MustBeTrue(t, id.Self == mangos.ProtoSurveyor)
    35  	MustBeTrue(t, id.SelfName == "surveyor")
    36  	MustBeTrue(t, id.Peer == mangos.ProtoRespondent)
    37  	MustBeTrue(t, id.PeerName == "respondent")
    38  	MustSucceed(t, s.Close())
    39  }
    40  
    41  func TestSurveyorCooked(t *testing.T) {
    42  	VerifyCooked(t, NewSocket)
    43  }
    44  
    45  func TestSurveyorNonBlock(t *testing.T) {
    46  	maxqlen := 2
    47  
    48  	rp, err := NewSocket()
    49  	MustSucceed(t, err)
    50  	MustNotBeNil(t, rp)
    51  
    52  	MustSucceed(t, rp.SetOption(mangos.OptionWriteQLen, maxqlen))
    53  	MustSucceed(t, rp.Listen(AddrTestInp()))
    54  
    55  	msg := []byte{'A', 'B', 'C'}
    56  	start := time.Now()
    57  	for i := 0; i < maxqlen*10; i++ {
    58  		MustSucceed(t, rp.Send(msg))
    59  	}
    60  	end := time.Now()
    61  	MustBeTrue(t, end.Sub(start) < time.Second/10)
    62  	MustSucceed(t, rp.Close())
    63  }
    64  
    65  func TestSurveyorOptions(t *testing.T) {
    66  	VerifyInvalidOption(t, NewSocket)
    67  	VerifyOptionDuration(t, NewSocket, mangos.OptionRecvDeadline)
    68  	VerifyOptionDuration(t, NewSocket, mangos.OptionSurveyTime)
    69  	VerifyOptionQLen(t, NewSocket, mangos.OptionReadQLen)
    70  	VerifyOptionQLen(t, NewSocket, mangos.OptionWriteQLen)
    71  }
    72  
    73  func TestSurveyorClosed(t *testing.T) {
    74  	VerifyClosedRecv(t, NewSocket)
    75  	VerifyClosedSend(t, NewSocket)
    76  	VerifyClosedClose(t, NewSocket)
    77  	VerifyClosedDial(t, NewSocket)
    78  	VerifyClosedListen(t, NewSocket)
    79  	VerifyClosedAddPipe(t, NewSocket)
    80  }
    81  
    82  func TestSurveyorRecvState(t *testing.T) {
    83  	s, e := NewSocket()
    84  	MustSucceed(t, e)
    85  	v, e := s.Recv()
    86  	MustBeError(t, e, mangos.ErrProtoState)
    87  	MustBeNil(t, v)
    88  	MustSucceed(t, s.Close())
    89  }
    90  
    91  // This test demonstrates that sending a second survey cancels any Rx on the
    92  // earlier outstanding ones.
    93  func TestSurveyorCancel(t *testing.T) {
    94  	self := GetSocket(t, NewSocket)
    95  	MustSucceed(t, self.SetOption(mangos.OptionSurveyTime, time.Second))
    96  	MustSucceed(t, self.Send([]byte("first")))
    97  	var wg sync.WaitGroup
    98  	wg.Add(1)
    99  	pass := false
   100  	go func() {
   101  		MustNotRecv(t, self, mangos.ErrCanceled)
   102  		pass = true
   103  		wg.Done()
   104  	}()
   105  	time.Sleep(time.Millisecond * 50) // to allow go routine to run
   106  	MustSucceed(t, self.Send([]byte("second")))
   107  	wg.Wait()
   108  	MustSucceed(t, self.Close())
   109  	MustBeTrue(t, pass)
   110  }
   111  
   112  // This test demonstrates that sending a second survey discards any received
   113  // messages from the earlier survey.
   114  func TestSurveyorCancelDiscard(t *testing.T) {
   115  	s := GetSocket(t, NewSocket)
   116  	// r1's message will get into the queue, but r2's will be sent
   117  	// after we have canceled -- neither should get through
   118  	r1 := GetSocket(t, respondent.NewSocket)
   119  	r2 := GetSocket(t, respondent.NewSocket)
   120  	a := AddrTestInp()
   121  	MustSucceed(t, s.Listen(a))
   122  	MustSucceed(t, r1.Dial(a))
   123  	MustSucceed(t, r2.Dial(a))
   124  	time.Sleep(time.Millisecond * 20)
   125  	MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Second))
   126  	MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Millisecond*10))
   127  	MustSucceed(t, s.Send([]byte("first")))
   128  	v1, e := r1.Recv()
   129  	MustSucceed(t, e)
   130  	MustBeTrue(t, string(v1) == "first")
   131  	MustSucceed(t, r1.Send([]byte("reply1")))
   132  	v2, e := r2.Recv()
   133  	MustSucceed(t, e)
   134  	MustBeTrue(t, string(v2) == "first")
   135  
   136  	time.Sleep(time.Millisecond * 10)
   137  	MustSucceed(t, s.Send([]byte("second")))
   138  	time.Sleep(time.Millisecond * 10) // to allow async cancel to finish
   139  	MustSucceed(t, r2.Send([]byte("reply2")))
   140  	v, e := s.Recv()
   141  	MustBeError(t, e, mangos.ErrRecvTimeout)
   142  	MustBeNil(t, v)
   143  	MustSucceed(t, s.Close())
   144  	MustSucceed(t, r1.Close())
   145  	MustSucceed(t, r2.Close())
   146  }
   147  
   148  // This test demonstrates that closing the socket aborts outstanding receives.
   149  func TestSurveyorCloseRx(t *testing.T) {
   150  	s := GetSocket(t, NewSocket)
   151  	MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Second))
   152  	MustSucceed(t, s.Send([]byte("first")))
   153  	var wg sync.WaitGroup
   154  	wg.Add(1)
   155  	pass := false
   156  	go func() {
   157  		defer wg.Done()
   158  		v, e := s.Recv()
   159  		MustBeError(t, e, mangos.ErrClosed)
   160  		MustBeNil(t, v)
   161  		pass = true
   162  	}()
   163  	time.Sleep(time.Millisecond * 50) // to allow go routine to run
   164  	MustSucceed(t, s.Close())
   165  	wg.Wait()
   166  	MustBeTrue(t, pass)
   167  }
   168  
   169  // This test demonstrates that surveys expire on their own.
   170  func TestSurveyExpire(t *testing.T) {
   171  	s := GetSocket(t, NewSocket)
   172  	MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Millisecond*10))
   173  	MustSucceed(t, s.Send([]byte("first")))
   174  	v, e := s.Recv()
   175  	MustBeError(t, e, mangos.ErrProtoState)
   176  	MustBeNil(t, v)
   177  	MustSucceed(t, s.Close())
   178  }
   179  
   180  // This test demonstrates that we can keep sending even if the pipes are full.
   181  func TestSurveyorBestEffortSend(t *testing.T) {
   182  	s := GetSocket(t, NewSocket)
   183  	r := GetSocket(t, respondent.NewSocket)
   184  	a := AddrTestInp()
   185  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1))
   186  	MustSucceed(t, s.Listen(a))
   187  	MustSucceed(t, r.Dial(a))
   188  
   189  	MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Second))
   190  
   191  	time.Sleep(time.Millisecond * 10)
   192  	for i := 0; i < 100; i++ {
   193  		MustSucceed(t, s.Send([]byte{byte(i)}))
   194  	}
   195  	MustSucceed(t, s.Close())
   196  }
   197  
   198  // This test demonstrates that if too many responses are received they will
   199  // be dropped.
   200  func TestSurveyorRxDiscard(t *testing.T) {
   201  	a := AddrTestInp()
   202  	s := GetSocket(t, NewSocket)
   203  	MustSucceed(t, s.SetOption(mangos.OptionReadQLen, 2))
   204  	MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Millisecond*10))
   205  	MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Second))
   206  	MustSucceed(t, s.Listen(a))
   207  
   208  	nresp := 100
   209  	var rs []mangos.Socket
   210  	var wg sync.WaitGroup
   211  	wg.Add(nresp)
   212  	for i := 0; i < nresp; i++ {
   213  		r := GetSocket(t, respondent.NewSocket)
   214  		MustSucceed(t, r.Dial(a))
   215  		rs = append(rs, r)
   216  		go func() {
   217  			defer wg.Done()
   218  			m, e := r.RecvMsg()
   219  			MustSucceed(t, e)
   220  			MustSucceed(t, r.SendMsg(m))
   221  		}()
   222  	}
   223  	time.Sleep(time.Millisecond * 10)
   224  	MustSucceed(t, s.Send([]byte{'a'}))
   225  	wg.Wait()
   226  	time.Sleep(time.Millisecond * 10)
   227  	nrecv := 0
   228  	for {
   229  		m, e := s.RecvMsg()
   230  		if e != nil {
   231  			MustBeError(t, e, mangos.ErrRecvTimeout)
   232  			break
   233  		}
   234  		m.Free()
   235  		nrecv++
   236  	}
   237  	MustBeTrue(t, nrecv == 2) // must match the queue length
   238  	for _, r := range rs {
   239  		MustSucceed(t, r.Close())
   240  	}
   241  	MustSucceed(t, s.Close())
   242  }
   243  
   244  // This test demonstrates that we can send surveys to a bunch of peers,
   245  // and collect responses from them all.
   246  func TestSurveyorBroadcast(t *testing.T) {
   247  	a := AddrTestInp()
   248  
   249  	s := GetSocket(t, NewSocket)
   250  	MustSucceed(t, s.Listen(a))
   251  
   252  	// note the total number of messages exchanged will be nresp * repeat
   253  	nresp := 100
   254  	repeat := 300
   255  
   256  	MustSucceed(t, s.SetOption(mangos.OptionReadQLen, nresp))
   257  	r := make([]mangos.Socket, 0, nresp)
   258  	var wg sync.WaitGroup
   259  	wg.Add(nresp)
   260  
   261  	for i := 0; i < nresp; i++ {
   262  		x := GetSocket(t, respondent.NewSocket)
   263  		MustSucceed(t, x.Dial(a))
   264  		r = append(r, x)
   265  
   266  		go func(idx int) {
   267  			defer wg.Done()
   268  
   269  			for num := 0; num < repeat; num++ {
   270  				v, e := x.Recv()
   271  				MustSucceed(t, e)
   272  				MustBeTrue(t, string(v) == "survey")
   273  				body := make([]byte, 8)
   274  				binary.BigEndian.PutUint32(body, uint32(idx))
   275  				binary.BigEndian.PutUint32(body[4:], uint32(num))
   276  				MustSucceed(t, x.Send(body))
   277  			}
   278  		}(i)
   279  	}
   280  
   281  	time.Sleep(time.Millisecond * 100)
   282  
   283  	MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Millisecond*200))
   284  	MustSucceed(t, s.SetOption(mangos.OptionReadQLen, nresp))
   285  	MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Millisecond*500))
   286  
   287  	recv := make([]int, nresp)
   288  
   289  	for num := 0; num < repeat; num++ {
   290  		MustSucceed(t, s.Send([]byte("survey")))
   291  		for i := 0; i < nresp; i++ {
   292  			v, e := s.Recv()
   293  			MustSucceed(t, e)
   294  			MustBeTrue(t, len(v) == 8)
   295  			peer := binary.BigEndian.Uint32(v)
   296  			MustBeTrue(t, peer < uint32(nresp))
   297  			MustBeTrue(t, binary.BigEndian.Uint32(v[4:]) == uint32(num))
   298  			MustBeTrue(t, recv[peer] == num)
   299  			recv[peer]++
   300  		}
   301  
   302  		// We could wait for the survey to timeout, but we don't.
   303  	}
   304  	wg.Wait()
   305  
   306  	MustSucceed(t, s.Close())
   307  	for i := 0; i < nresp; i++ {
   308  		MustSucceed(t, r[i].Close())
   309  	}
   310  }
   311  
   312  func TestSurveyorContextClosed(t *testing.T) {
   313  	s := GetSocket(t, NewSocket)
   314  	c, e := s.OpenContext()
   315  	MustSucceed(t, e)
   316  	MustNotBeNil(t, c)
   317  	MustSucceed(t, c.Close())
   318  	MustBeError(t, c.Close(), mangos.ErrClosed)
   319  
   320  	c, e = s.OpenContext()
   321  	MustSucceed(t, e)
   322  	MustNotBeNil(t, c)
   323  
   324  	MustSucceed(t, s.Close())
   325  
   326  	MustBeError(t, c.Close(), mangos.ErrClosed)
   327  
   328  	_, e = s.OpenContext()
   329  	MustBeError(t, e, mangos.ErrClosed)
   330  }
   331  
   332  func TestSurveyorContextCloseAbort(t *testing.T) {
   333  	s := GetSocket(t, NewSocket)
   334  	defer MustClose(t, s)
   335  
   336  	c, e := s.OpenContext()
   337  	MustSucceed(t, e)
   338  	MustNotBeNil(t, c)
   339  	MustSucceed(t, c.SetOption(mangos.OptionRecvDeadline, time.Second))
   340  
   341  	// To get us an id.
   342  	MustSucceed(t, c.Send([]byte{}))
   343  	var wg sync.WaitGroup
   344  	wg.Add(1)
   345  	go func() {
   346  		defer wg.Done()
   347  		time.Sleep(time.Millisecond * 50)
   348  		MustSucceed(t, c.Close())
   349  	}()
   350  
   351  	_, e = c.Recv()
   352  	MustBeError(t, e, mangos.ErrClosed)
   353  }
   354  
   355  // This sets up a bunch of contexts to run in parallel, and verifies that
   356  // they all seem to run with no mis-deliveries.
   357  func TestSurveyorMultiContexts(t *testing.T) {
   358  	count := 30
   359  	repeat := 20
   360  
   361  	s := GetSocket(t, NewSocket)
   362  	r := GetSocket(t, respondent.NewSocket)
   363  	MustSucceed(t, s.SetOption(mangos.OptionReadQLen, count*repeat))
   364  	MustSucceed(t, r.SetOption(mangos.OptionReadQLen, count*repeat))
   365  	MustSucceed(t, r.SetOption(mangos.OptionWriteQLen, count*repeat))
   366  	MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, count*repeat))
   367  
   368  	a := AddrTestInp()
   369  
   370  	MustSucceed(t, r.Listen(a))
   371  	MustSucceed(t, s.Dial(a))
   372  
   373  	// Make sure we have dialed properly
   374  	time.Sleep(time.Millisecond * 20)
   375  
   376  	recv := make([]int, count)
   377  	ctxs := make([]mangos.Context, 0, count)
   378  	var wg1 sync.WaitGroup
   379  	var wg2 sync.WaitGroup
   380  	wg1.Add(count)
   381  	fn := func(index int) {
   382  		defer wg1.Done()
   383  		c, e := s.OpenContext()
   384  		MustSucceed(t, e)
   385  		MustNotBeNil(t, c)
   386  
   387  		ctxs = append(ctxs, c)
   388  		topic := make([]byte, 4)
   389  		binary.BigEndian.PutUint32(topic, uint32(index))
   390  
   391  		MustSucceed(t, c.SetOption(mangos.OptionRecvDeadline, time.Minute/4))
   392  		MustSucceed(t, c.SetOption(mangos.OptionSurveyTime, time.Minute))
   393  
   394  		for i := 0; i < repeat; i++ {
   395  			MustSucceed(t, c.Send(topic))
   396  			m, e := c.RecvMsg()
   397  			MustSucceed(t, e)
   398  			MustBeTrue(t, len(m.Body) == 4)
   399  			MustBeTrue(t, bytes.Equal(m.Body, topic))
   400  			recv[index]++
   401  		}
   402  	}
   403  
   404  	for i := 0; i < count; i++ {
   405  		go fn(i)
   406  	}
   407  
   408  	wg2.Add(1)
   409  	go func() {
   410  		defer wg2.Done()
   411  		var e error
   412  		var m *mangos.Message
   413  		for {
   414  			if m, e = r.RecvMsg(); e != nil {
   415  				break
   416  			}
   417  			if e = r.SendMsg(m); e != nil {
   418  				break
   419  			}
   420  		}
   421  		MustBeError(t, e, mangos.ErrClosed)
   422  	}()
   423  
   424  	// Give time for everything to be delivered.
   425  	wg1.Wait()
   426  	MustSucceed(t, r.Close())
   427  	wg2.Wait()
   428  	MustSucceed(t, s.Close())
   429  
   430  	for i := 0; i < count; i++ {
   431  		MustBeTrue(t, recv[i] == repeat)
   432  	}
   433  }
   434  
   435  func TestSurveyorRecvGarbage(t *testing.T) {
   436  	self := GetSocket(t, NewSocket)
   437  	mock, _ := MockConnect(t, self)
   438  	expire := time.Millisecond * 20
   439  
   440  	MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, expire))
   441  
   442  	MustSendString(t, self, "")
   443  	MockMustSendStr(t, mock, "abc", expire)
   444  	MustNotRecv(t, self, mangos.ErrRecvTimeout)
   445  
   446  	var msg []byte
   447  	// No header
   448  	MustSendString(t, self, "")
   449  	MockMustSend(t, mock, msg, expire)
   450  	MustNotRecv(t, self, mangos.ErrRecvTimeout)
   451  
   452  	// No request ID
   453  	MustSendString(t, self, "")
   454  	msg = append(msg, 0, 1, 2, 3)
   455  	MockMustSend(t, mock, msg, expire)
   456  	MustNotRecv(t, self, mangos.ErrRecvTimeout)
   457  
   458  	// Also send a bogus header -- no request ID
   459  	MustSendString(t, self, "")
   460  	MockMustSendStr(t, mock, "\001\002\003\004", time.Second)
   461  	MustNotRecv(t, self, mangos.ErrRecvTimeout)
   462  
   463  	MustSucceed(t, self.Close())
   464  }