go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xbus/xbus_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 xbus 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "sync" 21 "testing" 22 "time" 23 24 "go.nanomsg.org/mangos/v3" 25 . "go.nanomsg.org/mangos/v3/internal/test" 26 . "go.nanomsg.org/mangos/v3/protocol" 27 _ "go.nanomsg.org/mangos/v3/transport/inproc" 28 ) 29 30 func TestXBusIdentity(t *testing.T) { 31 id := MustGetInfo(t, NewSocket) 32 MustBeTrue(t, id.Self == ProtoBus) 33 MustBeTrue(t, id.SelfName == "bus") 34 MustBeTrue(t, id.Peer == ProtoBus) 35 MustBeTrue(t, id.PeerName == "bus") 36 } 37 38 func TestXBusRaw(t *testing.T) { 39 VerifyRaw(t, NewSocket) 40 } 41 42 func TestXBusClosed(t *testing.T) { 43 VerifyClosedRecv(t, NewSocket) 44 VerifyClosedSend(t, NewSocket) 45 VerifyClosedClose(t, NewSocket) 46 VerifyClosedDial(t, NewSocket) 47 VerifyClosedListen(t, NewSocket) 48 VerifyClosedAddPipe(t, NewSocket) 49 } 50 51 func TestXBusOptions(t *testing.T) { 52 VerifyInvalidOption(t, NewSocket) 53 VerifyOptionDuration(t, NewSocket, OptionRecvDeadline) 54 VerifyOptionInt(t, NewSocket, OptionReadQLen) 55 VerifyOptionInt(t, NewSocket, OptionWriteQLen) 56 } 57 58 func TestXBusRecvDeadline(t *testing.T) { 59 self := GetSocket(t, NewSocket) 60 MustSucceed(t, self.SetOption(OptionRecvDeadline, time.Millisecond)) 61 MustNotRecv(t, self, ErrRecvTimeout) 62 MustClose(t, self) 63 } 64 65 // This ensures we get our pipe ID on receive as the sole header. 66 func TestXBusRecvHeader(t *testing.T) { 67 self := GetSocket(t, NewSocket) 68 mock, _ := MockConnect(t, self) 69 70 MockMustSendStr(t, mock, "abc", time.Second) 71 recv := MustRecvMsg(t, self) 72 MustBeTrue(t, string(recv.Body) == "abc") 73 MustBeTrue(t, len(recv.Header) == 4) 74 MustBeTrue(t, recv.Pipe.ID() == binary.BigEndian.Uint32(recv.Header)) 75 MustClose(t, self) 76 } 77 78 // This ensures that on send the header is discarded. 79 func TestXBusSendRecvHeader(t *testing.T) { 80 self := GetSocket(t, NewSocket) 81 peer := GetSocket(t, NewSocket) 82 83 data := []byte{'a', 'b', 'c'} 84 send := mangos.NewMessage(0) 85 send.Body = append(send.Body, data...) 86 send.Header = append(send.Header, 1, 2, 3, 4) 87 ConnectPair(t, self, peer) 88 MustSucceed(t, peer.SendMsg(send)) 89 recv := MustRecvMsg(t, self) 90 MustBeTrue(t, bytes.Equal(data, recv.Body)) 91 MustBeTrue(t, len(recv.Header) == 4) 92 MustBeTrue(t, recv.Pipe.ID() == binary.BigEndian.Uint32(recv.Header)) 93 MustSucceed(t, self.Close()) 94 MustSucceed(t, peer.Close()) 95 } 96 97 // This tests that if we send down a message with a header matching a peer, 98 // it won't go back out to where it came from. 99 func TestXBusNoLoop(t *testing.T) { 100 self := GetSocket(t, NewSocket) 101 peer := GetSocket(t, NewSocket) 102 103 data := []byte{'a', 'b', 'c'} 104 send := mangos.NewMessage(0) 105 send.Body = append(send.Body, data...) 106 send.Header = append(send.Header, 1, 2, 3, 4) 107 MustSucceed(t, self.SetOption(OptionRecvDeadline, time.Millisecond*5)) 108 MustSucceed(t, peer.SetOption(OptionRecvDeadline, time.Millisecond*5)) 109 ConnectPair(t, self, peer) 110 MustSendMsg(t, peer, send) 111 recv := MustRecvMsg(t, self) 112 MustBeTrue(t, bytes.Equal(data, recv.Body)) 113 MustBeTrue(t, len(recv.Header) == 4) 114 MustBeTrue(t, recv.Pipe.ID() == binary.BigEndian.Uint32(recv.Header)) 115 116 MustSucceed(t, self.SendMsg(recv)) 117 MustNotRecv(t, peer, ErrRecvTimeout) 118 MustClose(t, self) 119 MustClose(t, peer) 120 } 121 122 func TestXBusNonBlock(t *testing.T) { 123 124 self := GetSocket(t, NewSocket) 125 MustSucceed(t, self.SetOption(OptionWriteQLen, 1)) 126 for i := 0; i < 100; i++ { 127 MustSendString(t, self, "abc") 128 } 129 MustSucceed(t, self.Close()) 130 } 131 132 func TestXBusSendDrop(t *testing.T) { 133 self := GetSocket(t, NewSocket) 134 MustSucceed(t, self.SetOption(OptionWriteQLen, 1)) 135 l, ml := GetMockListener(t, self) 136 MustSucceed(t, l.Listen()) 137 mp := ml.NewPipe(self.Info().Peer) 138 MustSucceed(t, ml.AddPipe(mp)) 139 140 for i := 0; i < 100; i++ { 141 MustSucceed(t, self.Send([]byte{byte(i)})) 142 } 143 time.Sleep(time.Millisecond * 10) 144 MustSucceed(t, self.Close()) 145 } 146 147 func TestXBusResizeRecv(t *testing.T) { 148 self := GetSocket(t, NewSocket) 149 peer := GetSocket(t, NewSocket) 150 MustSucceed(t, peer.SetOption(OptionWriteQLen, 20)) 151 MustSucceed(t, self.SetOption(OptionReadQLen, 20)) 152 MustSucceed(t, self.SetOption(OptionRecvDeadline, time.Minute)) 153 ConnectPair(t, self, peer) 154 155 time.AfterFunc(time.Millisecond*20, func() { 156 MustSucceed(t, self.SetOption(OptionReadQLen, 10)) 157 MustSendString(t, peer, "wakeup") 158 }) 159 160 MustRecvString(t, self, "wakeup") 161 MustClose(t, self) 162 } 163 164 func TestXBusResize(t *testing.T) { 165 self := GetSocket(t, NewSocket) 166 peer := GetSocket(t, NewSocket) 167 MustSucceed(t, peer.SetOption(mangos.OptionWriteQLen, 10)) 168 MustSucceed(t, self.SetOption(mangos.OptionReadQLen, 2)) 169 MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Millisecond)) 170 ConnectPair(t, self, peer) 171 172 // Over-fill the pipe -- this gets the reader stuck in the right place. 173 for i := 0; i < 10; i++ { 174 // These all will work, but the back-pressure will go all the 175 // way to the sender. 176 MustSendString(t, peer, "fill me up") 177 } 178 179 time.Sleep(time.Millisecond * 200) 180 MustSucceed(t, self.SetOption(OptionReadQLen, 10)) 181 // Sleep so the resize filler finishes 182 time.Sleep(time.Millisecond * 20) 183 184 MustNotRecv(t, self, ErrRecvTimeout) 185 MustSucceed(t, self.Close()) 186 } 187 188 func TestXBusBackPressure(t *testing.T) { 189 self := GetSocket(t, NewSocket) 190 MustSucceed(t, self.SetOption(OptionWriteQLen, 5)) 191 MockConnect(t, self) 192 MockConnect(t, self) 193 // We don't read at all from it. 194 for i := 0; i < 100; i++ { 195 MustSendString(t, self, "") 196 } 197 time.Sleep(time.Millisecond * 100) 198 MustClose(t, self) 199 } 200 201 func TestXBusRecvPipeAbort(t *testing.T) { 202 self := GetSocket(t, NewSocket) 203 mp, p := MockConnect(t, self) 204 205 wg := sync.WaitGroup{} 206 wg.Add(1) 207 208 closeQ := make(chan struct{}) 209 210 go func() { 211 defer wg.Done() 212 for { 213 m := mangos.NewMessage(0) 214 select { 215 case mp.RecvQ() <- m: 216 case <-closeQ: 217 return 218 } 219 } 220 }() 221 222 time.Sleep(time.Millisecond * 20) 223 MustSucceed(t, p.Close()) 224 time.Sleep(time.Millisecond * 20) 225 MustSucceed(t, self.Close()) 226 227 close(closeQ) 228 wg.Wait() 229 } 230 231 func TestXBusRecvSockAbort(t *testing.T) { 232 self := GetSocket(t, NewSocket) 233 l, mc := GetMockListener(t, self) 234 235 MustSucceed(t, l.Listen()) 236 mp := mc.NewPipe(self.Info().Peer) 237 mp.DeferClose(true) 238 MockAddPipe(t, self, mc, mp) 239 240 wg := sync.WaitGroup{} 241 wg.Add(1) 242 243 closeQ := make(chan struct{}) 244 245 go func() { 246 defer wg.Done() 247 for { 248 m := mangos.NewMessage(0) 249 select { 250 case mp.RecvQ() <- m: 251 case <-closeQ: 252 return 253 } 254 } 255 }() 256 257 time.Sleep(time.Millisecond * 20) 258 MustSucceed(t, self.Close()) 259 mp.DeferClose(true) 260 close(closeQ) 261 wg.Wait() 262 }