go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xpush/xpush_test.go (about) 1 // Copyright 2021 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 "sync" 19 "testing" 20 "time" 21 22 "go.nanomsg.org/mangos/v3" 23 . "go.nanomsg.org/mangos/v3/internal/test" 24 "go.nanomsg.org/mangos/v3/protocol/pull" 25 _ "go.nanomsg.org/mangos/v3/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 VerifyOptionBool(t, NewSocket, mangos.OptionFailNoPeers) 46 VerifyOptionDuration(t, NewSocket, mangos.OptionSendDeadline) 47 VerifyOptionQLen(t, NewSocket, mangos.OptionWriteQLen) 48 } 49 50 func TestXPushNoRecv(t *testing.T) { 51 CannotRecv(t, NewSocket) 52 } 53 54 func TestXPushClosed(t *testing.T) { 55 VerifyClosedListen(t, NewSocket) 56 VerifyClosedDial(t, NewSocket) 57 VerifyClosedClose(t, NewSocket) 58 VerifyClosedSend(t, NewSocket) 59 VerifyClosedAddPipe(t, NewSocket) 60 } 61 62 func TestXPushSendBestEffort(t *testing.T) { 63 s := GetSocket(t, NewSocket) 64 MustSucceed(t, s.SetOption(mangos.OptionBestEffort, true)) 65 MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1)) 66 for i := 0; i < 20; i++ { 67 MustSucceed(t, s.Send([]byte{})) 68 } 69 MustSucceed(t, s.Close()) 70 } 71 72 func TestXPushSendTimeout(t *testing.T) { 73 s := GetSocket(t, NewSocket) 74 MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Millisecond)) 75 MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1)) 76 pass := false 77 for i := 0; i < 20; i++ { 78 if e := s.Send([]byte{}); e != nil { 79 MustBeError(t, e, mangos.ErrSendTimeout) 80 pass = true 81 break 82 } 83 } 84 MustBeTrue(t, pass) 85 MustSucceed(t, s.Close()) 86 } 87 88 func TestXPushSendResize(t *testing.T) { 89 s := GetSocket(t, NewSocket) 90 p := GetSocket(t, pull.NewSocket) 91 MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Millisecond)) 92 MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 20)) 93 MustSucceed(t, p.SetOption(mangos.OptionRecvDeadline, time.Millisecond*20)) 94 for i := 0; i < 10; i++ { 95 MustSucceed(t, s.Send([]byte{byte(i)})) 96 } 97 98 MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 3)) 99 100 // Now connect them so they can drain -- we should only have 3 messages 101 // that arrive at the peer. 102 ConnectPair(t, s, p) 103 104 for i := 0; i < 3; i++ { 105 m, e := p.Recv() 106 MustSucceed(t, e) 107 MustNotBeNil(t, m) 108 } 109 _, e := p.Recv() 110 MustBeError(t, e, mangos.ErrRecvTimeout) 111 MustSucceed(t, s.Close()) 112 MustSucceed(t, p.Close()) 113 } 114 115 func TestXPushCloseAbort(t *testing.T) { 116 s := GetSocket(t, NewSocket) 117 MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Minute)) 118 MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1)) 119 pass := false 120 time.AfterFunc(time.Millisecond*10, func() { 121 MustSucceed(t, s.Close()) 122 }) 123 for i := 0; i < 20; i++ { 124 if e := s.Send([]byte{}); e != nil { 125 MustBeError(t, e, mangos.ErrClosed) 126 pass = true 127 break 128 } 129 } 130 MustBeTrue(t, pass) 131 } 132 133 // This tests that with nPeers, the load sharing will be "fair". It can't 134 // verify ordering, because goroutines that return peers to the readyq can 135 // race against each other. 136 func TestXPushFairShare(t *testing.T) { 137 count := 20 138 nPeer := 5 139 peers := make([]mangos.Socket, nPeer) 140 s := GetSocket(t, NewSocket) 141 142 for i := 0; i < nPeer; i++ { 143 p := GetSocket(t, pull.NewSocket) 144 MustSucceed(t, p.SetOption(mangos.OptionRecvDeadline, time.Second)) 145 MustSucceed(t, p.SetOption(mangos.OptionReadQLen, 0)) 146 ConnectPair(t, s, p) 147 peers[i] = p 148 } 149 MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, count*nPeer)) 150 151 for i := 0; i < count; i++ { 152 for j := 0; j < nPeer; j++ { 153 MustSucceed(t, s.Send([]byte{byte(j)})) 154 } 155 } 156 157 for i := 0; i < count; i++ { 158 for j := 0; j < nPeer; j++ { 159 p := peers[j] 160 m, e := p.Recv() 161 MustSucceed(t, e) 162 MustBeTrue(t, len(m) == 1) 163 // We have to sleep a bit to let the go routine 164 // that returns the readyq complete 165 time.Sleep(time.Millisecond) 166 } 167 } 168 for i := 0; i < nPeer; i++ { 169 MustSucceed(t, peers[i].Close()) 170 } 171 MustSucceed(t, s.Close()) 172 } 173 174 func TestXPushRecvDiscard(t *testing.T) { 175 s := GetSocket(t, NewSocket) 176 l, mc := GetMockListener(t, s) 177 mp := mc.NewPipe(s.Info().Peer) 178 MustSucceed(t, l.Listen()) 179 MustSucceed(t, mc.AddPipe(mp)) 180 181 pass := true 182 outer: 183 for i := 0; i < 10; i++ { 184 m := mangos.NewMessage(0) 185 m.Body = append(m.Body, 'a', 'b', 'c') 186 select { 187 case <-time.After(time.Second): 188 pass = false 189 break outer 190 case mp.RecvQ() <- m: 191 } 192 } 193 MustBeTrue(t, pass) 194 MustSucceed(t, s.Close()) 195 } 196 197 func TestXPushSendFail(t *testing.T) { 198 s := GetSocket(t, NewSocket) 199 l, mc := GetMockListener(t, s) 200 mp := mc.NewPipe(s.Info().Peer) 201 MustSucceed(t, l.Listen()) 202 nAdd := uint32(0) 203 nRem := uint32(0) 204 wg := sync.WaitGroup{} 205 wg.Add(1) 206 hook := func(ev mangos.PipeEvent, p mangos.Pipe) { 207 switch ev { 208 case mangos.PipeEventAttached: 209 nAdd++ 210 case mangos.PipeEventDetached: 211 nRem++ 212 wg.Done() 213 } 214 } 215 s.SetPipeEventHook(hook) 216 217 MustSucceed(t, mc.AddPipe(mp)) 218 mp.InjectSendError(mangos.ErrBadHeader) 219 MustSucceed(t, s.Send([]byte{})) 220 wg.Wait() 221 MustSucceed(t, s.Close()) 222 MustBeTrue(t, nAdd == 1) 223 MustBeTrue(t, nRem == 1) 224 MustBeTrue(t, len(mp.SendQ()) == 0) 225 } 226 227 func TestXPushFastFailNoPeerDisconnect(t *testing.T) { 228 VerifyOptionBool(t, NewSocket, mangos.OptionFailNoPeers) 229 230 s := GetSocket(t, NewSocket) 231 p := GetSocket(t, pull.NewSocket) 232 MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Second)) 233 234 MustSucceed(t, s.SetOption(mangos.OptionFailNoPeers, true)) 235 MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 0)) 236 MustSucceed(t, p.SetOption(mangos.OptionReadQLen, 0)) 237 238 // Now connect them so they can drain -- we should only have 3 messages 239 // that arrive at the peer. 240 ConnectPair(t, s, p) 241 242 go func() { 243 time.Sleep(time.Millisecond*20) 244 MustSucceed(t, p.Close()) 245 }() 246 247 MustBeError(t ,s.Send([]byte("three")), mangos.ErrNoPeers) 248 MustSucceed(t, s.Close()) 249 }