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 }