go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/internal/test/dialer_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 test 16 17 import ( 18 "reflect" 19 "sync" 20 "testing" 21 "time" 22 23 "go.nanomsg.org/mangos/v3" 24 "go.nanomsg.org/mangos/v3/protocol/pair" 25 _ "go.nanomsg.org/mangos/v3/transport/inproc" 26 ) 27 28 func TestDialerBadScheme(t *testing.T) { 29 self := GetMockSocket() 30 defer MustClose(t, self) 31 32 d, e := self.NewDialer("bad://nothere", nil) 33 MustBeError(t, e, mangos.ErrBadTran) 34 MustBeTrue(t, d == nil) 35 36 // Malformed, needs :// bit 37 d, e = self.NewDialer("inproc:nothere", nil) 38 MustBeError(t, e, mangos.ErrBadTran) 39 MustBeTrue(t, d == nil) 40 } 41 42 func TestDialerAddress(t *testing.T) { 43 AddMockTransport() 44 self := GetMockSocket() 45 defer MustClose(t, self) 46 47 d, e := self.NewDialer(AddrMock(), nil) 48 MustSucceed(t, e) 49 MustBeTrue(t, d.Address() == AddrMock()) 50 } 51 52 func TestDialerSocketOptions(t *testing.T) { 53 AddMockTransport() 54 55 VerifyOptionDuration(t, NewMockSocket, mangos.OptionReconnectTime) 56 VerifyOptionDuration(t, NewMockSocket, mangos.OptionMaxReconnectTime) 57 VerifyOptionBool(t, NewMockSocket, mangos.OptionDialAsynch) 58 VerifyOptionInt(t, NewMockSocket, mangos.OptionMaxRecvSize) 59 } 60 61 func TestDialerOptions(t *testing.T) { 62 AddMockTransport() 63 sock := GetMockSocket() 64 defer MustClose(t, sock) 65 66 d, e := sock.NewDialer(AddrMock(), nil) 67 MustSucceed(t, e) 68 MustBeTrue(t, d != nil) 69 70 MustBeError(t, d.SetOption("bogus", nil), mangos.ErrBadOption) 71 _, e = d.GetOption("bogus") 72 MustBeError(t, e, mangos.ErrBadOption) 73 74 val, e := d.GetOption(mangos.OptionReconnectTime) 75 MustSucceed(t, e) 76 MustBeTrue(t, reflect.TypeOf(val) == reflect.TypeOf(time.Duration(0))) 77 78 val, e = d.GetOption(mangos.OptionMaxReconnectTime) 79 MustSucceed(t, e) 80 MustBeTrue(t, reflect.TypeOf(val) == reflect.TypeOf(time.Duration(0))) 81 82 val, e = d.GetOption(mangos.OptionDialAsynch) 83 MustSucceed(t, e) 84 MustBeTrue(t, reflect.TypeOf(val) == reflect.TypeOf(true)) 85 86 val, e = d.GetOption("mockError") 87 MustBeError(t, e, mangos.ErrProtoState) 88 MustBeTrue(t, val == nil) 89 90 MustBeError(t, d.SetOption(mangos.OptionDialAsynch, 1), mangos.ErrBadValue) 91 MustBeError(t, d.SetOption(mangos.OptionReconnectTime, 1), mangos.ErrBadValue) 92 MustBeError(t, d.SetOption(mangos.OptionReconnectTime, -time.Second), mangos.ErrBadValue) 93 MustBeError(t, d.SetOption(mangos.OptionMaxReconnectTime, 1), mangos.ErrBadValue) 94 MustBeError(t, d.SetOption(mangos.OptionMaxReconnectTime, -time.Second), mangos.ErrBadValue) 95 MustBeError(t, d.SetOption(mangos.OptionMaxRecvSize, -100), mangos.ErrBadValue) 96 MustBeError(t, d.SetOption(mangos.OptionMaxRecvSize, "a"), mangos.ErrBadValue) 97 MustBeError(t, d.SetOption("mockError", mangos.ErrCanceled), mangos.ErrCanceled) 98 99 MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, false)) 100 MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Duration(0))) 101 MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Second)) 102 MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Duration(0))) 103 MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, 5*time.Second)) 104 MustSucceed(t, d.SetOption(mangos.OptionMaxRecvSize, 1024)) 105 106 MustSucceed(t, d.SetOption(mangos.OptionMaxRecvSize, 1024)) 107 val, e = d.GetOption(mangos.OptionMaxRecvSize) 108 MustSucceed(t, e) 109 sz, ok := val.(int) 110 MustBeTrue(t, ok) 111 MustBeTrue(t, sz == 1024) 112 } 113 114 func TestDialerOptionsMap(t *testing.T) { 115 AddMockTransport() 116 sock := GetMockSocket() 117 defer MustClose(t, sock) 118 addr := AddrMock() 119 120 opts := make(map[string]interface{}) 121 opts[mangos.OptionMaxRecvSize] = "garbage" 122 d, e := sock.NewDialer(addr, opts) 123 MustBeError(t, e, mangos.ErrBadValue) 124 MustBeTrue(t, d == nil) 125 126 opts = make(map[string]interface{}) 127 opts[mangos.OptionMaxRecvSize] = -1 128 d, e = sock.NewDialer(addr, opts) 129 MustBeError(t, e, mangos.ErrBadValue) 130 MustBeTrue(t, d == nil) 131 132 opts = make(map[string]interface{}) 133 opts[mangos.OptionMaxRecvSize] = 1001 134 d, e = sock.NewDialer(addr, opts) 135 MustBeError(t, e, mangos.ErrBadValue) 136 MustBeTrue(t, d == nil) 137 138 opts = make(map[string]interface{}) 139 opts[mangos.OptionMaxRecvSize] = 1002 140 d, e = sock.NewDialer(addr, opts) 141 MustBeError(t, e, mangos.ErrBadOption) 142 MustBeTrue(t, d == nil) 143 144 opts = make(map[string]interface{}) 145 opts[mangos.OptionDialAsynch] = -1 146 d, e = sock.NewDialer(addr, opts) 147 MustBeError(t, e, mangos.ErrBadValue) 148 MustBeTrue(t, d == nil) 149 150 opts = make(map[string]interface{}) 151 opts["JUNKOPT"] = "yes" 152 d, e = sock.NewDialer(addr, opts) 153 MustBeError(t, e, mangos.ErrBadOption) 154 MustBeTrue(t, d == nil) 155 156 opts = make(map[string]interface{}) 157 opts["mockError"] = mangos.ErrCanceled 158 d, e = sock.NewDialer(addr, opts) 159 MustBeError(t, e, mangos.ErrCanceled) 160 MustBeTrue(t, d == nil) 161 162 // Now good options 163 opts = make(map[string]interface{}) 164 opts[mangos.OptionMaxRecvSize] = 3172 165 opts[mangos.OptionReconnectTime] = time.Second 166 opts[mangos.OptionMaxReconnectTime] = time.Second * 2 167 opts[mangos.OptionDialAsynch] = false 168 d, e = sock.NewDialer(addr, opts) 169 MustSucceed(t, e) 170 MustBeTrue(t, d != nil) 171 v, e := d.GetOption(mangos.OptionMaxRecvSize) 172 MustSucceed(t, e) 173 sz, ok := v.(int) 174 MustBeTrue(t, ok) 175 MustBeTrue(t, sz == 3172) 176 177 } 178 179 func TestDialerOptionsInherit(t *testing.T) { 180 AddMockTransport() 181 sock := GetMockSocket() 182 defer MustClose(t, sock) 183 addr := AddrMock() 184 185 // This should force listener not to alloc (bad option value) 186 MustSucceed(t, sock.SetOption(mangos.OptionMaxRecvSize, 1001)) 187 d, e := sock.NewDialer(addr, nil) 188 MustBeError(t, e, mangos.ErrBadValue) 189 MustBeTrue(t, d == nil) 190 MustSucceed(t, sock.SetOption(mangos.OptionMaxRecvSize, 1002)) 191 d, e = sock.NewDialer(addr, nil) 192 MustSucceed(t, e) 193 MustBeTrue(t, d != nil) 194 195 MustSucceed(t, sock.SetOption(mangos.OptionMaxRecvSize, 500)) 196 v, e := d.GetOption(mangos.OptionMaxRecvSize) 197 MustSucceed(t, e) 198 MustBeTrue(t, v.(int) == 500) 199 200 } 201 202 func TestDialerPipe(t *testing.T) { 203 sock1 := GetMockSocket() 204 defer MustClose(t, sock1) 205 sock2 := GetMockSocket() 206 defer MustClose(t, sock2) 207 addr := AddrTestInp() 208 209 MustSucceed(t, sock1.SetOption(mangos.OptionRecvDeadline, time.Second)) 210 MustSucceed(t, sock2.SetOption(mangos.OptionSendDeadline, time.Second)) 211 212 d, e := sock1.NewDialer(addr, nil) 213 MustSucceed(t, e) 214 MustSucceed(t, sock2.Listen(addr)) 215 MustSucceed(t, d.Dial()) 216 217 MustSendString(t, sock2, "junk") 218 m := MustRecvMsg(t, sock1) 219 220 MustBeTrue(t, m.Pipe.Dialer() == d) 221 MustBeTrue(t, m.Pipe.Listener() == nil) 222 MustBeTrue(t, m.Pipe.Address() == addr) 223 m.Free() 224 } 225 226 func TestDialerClosed(t *testing.T) { 227 AddMockTransport() 228 sock := GetMockSocket() 229 defer MustClose(t, sock) 230 231 d, e := sock.NewDialer(AddrMock(), nil) 232 MustSucceed(t, e) 233 MustBeTrue(t, d != nil) 234 235 MustSucceed(t, d.Close()) 236 237 MustBeError(t, d.Dial(), mangos.ErrClosed) 238 MustBeError(t, d.Close(), mangos.ErrClosed) 239 } 240 241 func TestDialerCloseAbort(t *testing.T) { 242 addr := AddrTestInp() 243 sock := GetMockSocket() 244 defer MustClose(t, sock) 245 246 d, e := sock.NewDialer(addr, nil) 247 MustSucceed(t, e) 248 MustBeTrue(t, d != nil) 249 MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, true)) 250 MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond)) 251 MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond)) 252 253 MustSucceed(t, d.Dial()) 254 time.Sleep(time.Millisecond * 50) 255 MustSucceed(t, d.Close()) 256 } 257 258 func TestDialerCloseAbort2(t *testing.T) { 259 sock := GetMockSocket() 260 defer MustClose(t, sock) 261 262 d, mc := GetMockDialer(t, sock) 263 MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, true)) 264 MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond)) 265 MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond)) 266 267 var wg sync.WaitGroup 268 wg.Add(1) 269 270 pass := false 271 go func() { 272 defer wg.Done() 273 time.Sleep(time.Millisecond * 20) 274 MustSucceed(t, mc.Close()) 275 pass = true 276 }() 277 278 // We're async, so this is guaranteed to succeed. 279 MustSucceed(t, d.Dial()) 280 time.Sleep(time.Millisecond * 50) 281 wg.Wait() 282 MustBeTrue(t, pass) 283 } 284 285 func TestDialerReuse(t *testing.T) { 286 AddMockTransport() 287 sock := GetMockSocket() 288 defer MustClose(t, sock) 289 290 d, e := sock.NewDialer(AddrMock(), nil) 291 MustSucceed(t, e) 292 MustBeTrue(t, d != nil) 293 MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, true)) 294 295 MustSucceed(t, d.Dial()) 296 MustBeError(t, d.Dial(), mangos.ErrAddrInUse) 297 298 MustSucceed(t, d.Close()) 299 } 300 301 func TestDialerReconnect(t *testing.T) { 302 // We have to use real protocol and transport for this. 303 addr := AddrTestInp() 304 sock := GetSocket(t, pair.NewSocket) 305 defer MustClose(t, sock) 306 peer1 := GetSocket(t, pair.NewSocket) 307 peer2 := GetSocket(t, pair.NewSocket) 308 defer MustClose(t, peer2) 309 310 MustSucceed(t, sock.SetOption(mangos.OptionRecvDeadline, time.Second)) 311 MustSucceed(t, sock.SetOption(mangos.OptionSendDeadline, time.Second)) 312 MustSucceed(t, peer1.SetOption(mangos.OptionRecvDeadline, time.Second)) 313 MustSucceed(t, peer1.SetOption(mangos.OptionSendDeadline, time.Second)) 314 MustSucceed(t, peer2.SetOption(mangos.OptionRecvDeadline, time.Second)) 315 MustSucceed(t, peer2.SetOption(mangos.OptionSendDeadline, time.Second)) 316 317 d, e := sock.NewDialer(addr, nil) 318 MustSucceed(t, e) 319 MustBeTrue(t, d != nil) 320 MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond)) 321 MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond)) 322 323 MustSucceed(t, peer1.Listen(addr)) 324 MustSucceed(t, d.Dial()) 325 time.Sleep(time.Millisecond * 20) 326 MustClose(t, peer1) 327 MustSucceed(t, peer2.Listen(addr)) 328 time.Sleep(time.Millisecond * 20) 329 MustSendString(t, sock, "test") 330 MustRecvString(t, peer2, "test") 331 332 MustSucceed(t, d.Close()) 333 } 334 335 func TestDialerConnectLate(t *testing.T) { 336 // We have to use real protocol and transport for this. 337 addr := AddrTestInp() 338 sock := GetSocket(t, pair.NewSocket) 339 defer MustClose(t, sock) 340 peer := GetSocket(t, pair.NewSocket) 341 defer MustClose(t, peer) 342 343 d, e := sock.NewDialer(addr, nil) 344 MustSucceed(t, e) 345 MustBeTrue(t, d != nil) 346 MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond)) 347 MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond)) 348 MustSucceed(t, d.SetOption(mangos.OptionDialAsynch, true)) 349 350 lock := &sync.Mutex{} 351 cond := sync.NewCond(lock) 352 done := false 353 354 hook := func(ev mangos.PipeEvent, p mangos.Pipe) { 355 if ev == mangos.PipeEventAttached { 356 lock.Lock() 357 done = true 358 cond.Broadcast() 359 lock.Unlock() 360 } 361 } 362 _ = sock.SetPipeEventHook(hook) 363 364 var wg sync.WaitGroup 365 wg.Add(1) 366 367 go func() { 368 defer wg.Done() 369 time.Sleep(time.Millisecond * 50) 370 MustSucceed(t, peer.Listen(addr)) 371 }() 372 373 MustSucceed(t, d.Dial()) 374 375 wg.Wait() 376 lock.Lock() 377 cond.Wait() 378 lock.Unlock() 379 380 MustBeTrue(t, done) 381 } 382 383 func TestDialerConnectRefused(t *testing.T) { 384 // We have to use real protocol and transport for this. 385 addr := AddrTestInp() 386 sock := GetSocket(t, pair.NewSocket) 387 defer MustClose(t, sock) 388 peer := GetSocket(t, pair.NewSocket) 389 defer MustClose(t, peer) 390 391 d, e := sock.NewDialer(addr, nil) 392 MustSucceed(t, e) 393 MustBeTrue(t, d != nil) 394 MustSucceed(t, d.SetOption(mangos.OptionReconnectTime, time.Millisecond)) 395 MustSucceed(t, d.SetOption(mangos.OptionMaxReconnectTime, time.Millisecond)) 396 397 MustBeError(t, d.Dial(), mangos.ErrConnRefused) 398 399 }