go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xstar/xstar_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 xstar 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/transport/inproc" 27 ) 28 29 func TestXStarIdentity(t *testing.T) { 30 id := MustGetInfo(t, NewSocket) 31 MustBeTrue(t, id.Self == ProtoStar) 32 MustBeTrue(t, id.SelfName == "star") 33 MustBeTrue(t, id.Peer == ProtoStar) 34 MustBeTrue(t, id.PeerName == "star") 35 } 36 37 func TestXStarRaw(t *testing.T) { 38 VerifyRaw(t, NewSocket) 39 } 40 41 func TestXStarClosed(t *testing.T) { 42 VerifyClosedRecv(t, NewSocket) 43 VerifyClosedSend(t, NewSocket) 44 VerifyClosedClose(t, NewSocket) 45 VerifyClosedDial(t, NewSocket) 46 VerifyClosedListen(t, NewSocket) 47 VerifyClosedAddPipe(t, NewSocket) 48 } 49 50 func TestXStarOptions(t *testing.T) { 51 VerifyInvalidOption(t, NewSocket) 52 VerifyOptionDuration(t, NewSocket, OptionRecvDeadline) 53 VerifyOptionInt(t, NewSocket, OptionReadQLen) 54 VerifyOptionInt(t, NewSocket, OptionWriteQLen) 55 VerifyOptionInt(t, NewSocket, OptionTTL) 56 } 57 58 func TestXStarRecvDeadline(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 func TestXStarNoHeader(t *testing.T) { 66 s, err := NewSocket() 67 MustSucceed(t, err) 68 defer MustClose(t, s) 69 70 m := mangos.NewMessage(0) 71 72 MustSucceed(t, s.SendMsg(m)) 73 } 74 75 func TestXStarTTL(t *testing.T) { 76 SetTTLZero(t, NewSocket) 77 SetTTLNegative(t, NewSocket) 78 SetTTLTooBig(t, NewSocket) 79 SetTTLNotInt(t, NewSocket) 80 SetTTL(t, NewSocket) 81 } 82 83 func TestXStarNonBlock(t *testing.T) { 84 85 self := GetSocket(t, NewSocket) 86 defer MustClose(t, self) 87 88 MustSucceed(t, self.SetOption(OptionWriteQLen, 2)) 89 MustSucceed(t, self.Listen(AddrTestInp())) 90 91 start := time.Now() 92 for i := 0; i < 100; i++ { 93 MustSendString(t, self, "abc") 94 } 95 end := time.Now() 96 MustBeTrue(t, end.Sub(start) < time.Second/10) 97 } 98 99 func TestXStarSendDrop(t *testing.T) { 100 self := GetSocket(t, NewSocket) 101 MustSucceed(t, self.SetOption(OptionWriteQLen, 1)) 102 l, ml := GetMockListener(t, self) 103 MustSucceed(t, l.Listen()) 104 mp := ml.NewPipe(self.Info().Peer) 105 MustSucceed(t, ml.AddPipe(mp)) 106 107 for i := 0; i < 100; i++ { 108 MustSucceed(t, self.Send([]byte{byte(i)})) 109 } 110 time.Sleep(time.Millisecond * 10) 111 MustSucceed(t, self.Close()) 112 } 113 114 func TestXStarRecvNoHeader(t *testing.T) { 115 self := GetSocket(t, NewSocket) 116 mock, _ := MockConnect(t, self) 117 118 MustSucceed(t, self.SetOption(OptionReadQLen, 2)) 119 MustSucceed(t, self.SetOption(OptionRecvDeadline, time.Millisecond*50)) 120 MockMustSend(t, mock, []byte{}, time.Second) 121 MustNotRecv(t, self, ErrRecvTimeout) 122 MustSucceed(t, self.Close()) 123 } 124 125 func TestXStarRecvHeader(t *testing.T) { 126 self := GetSocket(t, NewSocket) 127 mock, _ := MockConnect(t, self) 128 129 // First byte is non-zero 130 MockMustSendMsg(t, mock, newMessage(0x1000000, "1"), time.Second) 131 // Second byte is non-zero 132 MockMustSendMsg(t, mock, newMessage(0x10000, "2"), time.Second) 133 // Third byte is non-zero 134 MockMustSendMsg(t, mock, newMessage(0x100, "3"), time.Second) 135 // Fourth gets through 136 MockMustSendMsg(t, mock, newMessage(0x1, "4"), time.Second) 137 138 m := MustRecvMsg(t, self) 139 MustBeTrue(t, string(m.Body) == "4") 140 MustBeTrue(t, len(m.Header) == 4) 141 142 // The incoming hop count gets incremented on receive. 143 MustBeTrue(t, binary.BigEndian.Uint32(m.Header) == 2) 144 MustClose(t, self) 145 } 146 147 func TestXStarSendRecv(t *testing.T) { 148 s1 := GetSocket(t, NewSocket) 149 defer MustClose(t, s1) 150 s2 := GetSocket(t, NewSocket) 151 defer MustClose(t, s2) 152 153 ConnectPair(t, s1, s2) 154 155 m := mangos.NewMessage(0) 156 157 // Write an empty hop count to the header 158 m.Header = append(m.Header, 0, 0, 0, 0) 159 m.Body = append(m.Body, []byte("test")...) 160 161 MustSendMsg(t, s1, m) 162 m2 := MustRecvMsg(t, s2) 163 164 MustBeTrue(t, len(m2.Header) == 4) 165 MustBeTrue(t, binary.BigEndian.Uint32(m2.Header) == 1) 166 MustBeTrue(t, string(m2.Body) == "test") 167 } 168 169 func TestXStarRedistribute(t *testing.T) { 170 s1 := GetSocket(t, NewSocket) 171 defer MustClose(t, s1) 172 s2 := GetSocket(t, NewSocket) 173 defer MustClose(t, s2) 174 s3 := GetSocket(t, NewSocket) 175 176 MustSucceed(t, s1.SetOption(OptionRecvDeadline, time.Millisecond*100)) 177 MustSucceed(t, s2.SetOption(OptionRecvDeadline, time.Millisecond*100)) 178 MustSucceed(t, s3.SetOption(OptionRecvDeadline, time.Millisecond*100)) 179 MustSucceed(t, s1.SetOption(OptionReadQLen, 5)) 180 MustSucceed(t, s2.SetOption(OptionReadQLen, 5)) 181 MustSucceed(t, s3.SetOption(OptionReadQLen, 5)) 182 183 ConnectPair(t, s1, s2) 184 ConnectPair(t, s3, s2) 185 186 m := mangos.NewMessage(0) 187 188 // Write an empty hop count to the header 189 m.Header = append(m.Header, 0, 0, 0, 0) 190 m.Body = append(m.Body, []byte("test")...) 191 192 MustSendMsg(t, s1, m) 193 m2 := MustRecvMsg(t, s3) 194 195 MustBeTrue(t, len(m2.Header) == 4) 196 // We go through two hops to get here. 197 MustBeTrue(t, binary.BigEndian.Uint32(m2.Header) == 2) 198 MustBeTrue(t, string(m2.Body) == "test") 199 200 MustNotRecv(t, s1, mangos.ErrRecvTimeout) 201 } 202 203 func TestXStarRedistributeBackPressure(t *testing.T) { 204 s1 := GetSocket(t, NewSocket) 205 defer MustClose(t, s1) 206 s2 := GetSocket(t, NewSocket) 207 defer MustClose(t, s2) 208 s3 := GetSocket(t, NewSocket) 209 210 MustSucceed(t, s1.SetOption(OptionRecvDeadline, time.Millisecond*100)) 211 MustSucceed(t, s2.SetOption(OptionRecvDeadline, time.Millisecond*100)) 212 MustSucceed(t, s3.SetOption(OptionRecvDeadline, time.Millisecond*100)) 213 MustSucceed(t, s1.SetOption(OptionReadQLen, 5)) 214 MustSucceed(t, s2.SetOption(OptionReadQLen, 5)) 215 MustSucceed(t, s3.SetOption(OptionReadQLen, 5)) 216 MustSucceed(t, s1.SetOption(OptionWriteQLen, 2)) 217 MustSucceed(t, s3.SetOption(OptionWriteQLen, 2)) 218 // Make the intermediate queue size too small to force back-pressure. 219 MustSucceed(t, s2.SetOption(OptionWriteQLen, 1)) 220 221 ConnectPair(t, s1, s2) 222 ConnectPair(t, s3, s2) 223 224 for i := 0; i < 10; i++ { 225 m := mangos.NewMessage(0) 226 227 // Write an empty hop count to the header 228 m.Header = append(m.Header, 0, 0, 0, 0) 229 m.Body = append(m.Body, []byte("test")...) 230 231 MustSendMsg(t, s1, m) 232 } 233 234 m2 := MustRecvMsg(t, s3) 235 236 MustBeTrue(t, len(m2.Header) == 4) 237 // We go through two hops to get here. 238 MustBeTrue(t, binary.BigEndian.Uint32(m2.Header) == 2) 239 MustBeTrue(t, string(m2.Body) == "test") 240 241 MustNotRecv(t, s1, ErrRecvTimeout) 242 } 243 244 // newMessage creates a message as it would come from a pipe. The 245 // hops will be part of the body. 246 func newMessage(hops uint32, content string) *mangos.Message { 247 m := mangos.NewMessage(len(content) + 4) 248 b := make([]byte, 4) 249 binary.BigEndian.PutUint32(b[:4], hops) 250 // Requests (coming in) will be entirely on the body. 251 m.Body = append(m.Body, b...) 252 m.Body = append(m.Body, []byte(content)...) 253 return m 254 } 255 256 func TestXStarRecvPipeAbort(t *testing.T) { 257 self := GetSocket(t, NewSocket) 258 mp, p := MockConnect(t, self) 259 260 wg := sync.WaitGroup{} 261 wg.Add(1) 262 263 closeQ := make(chan struct{}) 264 265 go func() { 266 defer wg.Done() 267 for { 268 m := newMessage(1, "") 269 select { 270 case mp.RecvQ() <- m: 271 case <-closeQ: 272 return 273 } 274 } 275 }() 276 277 time.Sleep(time.Millisecond * 20) 278 MustSucceed(t, p.Close()) 279 time.Sleep(time.Millisecond * 20) 280 MustSucceed(t, self.Close()) 281 282 close(closeQ) 283 wg.Wait() 284 } 285 286 func TestXStarRecvSockAbort(t *testing.T) { 287 self := GetSocket(t, NewSocket) 288 l, mc := GetMockListener(t, self) 289 290 MustSucceed(t, l.Listen()) 291 mp := mc.NewPipe(self.Info().Peer) 292 mp.DeferClose(true) 293 MockAddPipe(t, self, mc, mp) 294 295 wg := sync.WaitGroup{} 296 wg.Add(1) 297 298 closeQ := make(chan struct{}) 299 300 go func() { 301 defer wg.Done() 302 for { 303 m := newMessage(1, "") 304 select { 305 case mp.RecvQ() <- m: 306 case <-closeQ: 307 return 308 } 309 } 310 }() 311 312 time.Sleep(time.Millisecond * 20) 313 MustSucceed(t, self.Close()) 314 mp.DeferClose(true) 315 close(closeQ) 316 wg.Wait() 317 } 318 319 func TestXStarBackPressure(t *testing.T) { 320 self := GetSocket(t, NewSocket) 321 MustSucceed(t, self.SetOption(OptionWriteQLen, 5)) 322 MockConnect(t, self) 323 MockConnect(t, self) 324 m := mangos.NewMessage(0) 325 m.Header = append(m.Header, 0, 0, 0, 0) 326 m.Body = append(m.Body, 42) 327 // We don't read at all from it. 328 for i := 0; i < 100; i++ { 329 MustSendMsg(t, self, m.Dup()) 330 } 331 time.Sleep(time.Millisecond * 100) 332 MustClose(t, self) 333 }