get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/test/test.go (about) 1 // Copyright 2012-2019 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package test 15 16 import ( 17 "crypto/rand" 18 "encoding/hex" 19 "encoding/json" 20 "fmt" 21 "io" 22 "net" 23 "os" 24 "regexp" 25 "runtime" 26 "strconv" 27 "strings" 28 "testing" 29 "time" 30 31 "get.pme.sh/pnats/server" 32 ) 33 34 // So we can pass tests and benchmarks.. 35 type tLogger interface { 36 Fatalf(format string, args ...interface{}) 37 Errorf(format string, args ...interface{}) 38 } 39 40 // DefaultTestOptions are default options for the unit tests. 41 var DefaultTestOptions = server.Options{ 42 Host: "127.0.0.1", 43 Port: 4222, 44 NoLog: true, 45 NoSigs: true, 46 MaxControlLine: 4096, 47 DisableShortFirstPing: true, 48 } 49 50 // RunDefaultServer starts a new Go routine based server using the default options 51 func RunDefaultServer() *server.Server { 52 return RunServer(&DefaultTestOptions) 53 } 54 55 func RunRandClientPortServer() *server.Server { 56 opts := DefaultTestOptions 57 opts.Port = -1 58 return RunServer(&opts) 59 } 60 61 // To turn on server tracing and debugging and logging which are 62 // normally suppressed. 63 var ( 64 doLog = false 65 doTrace = false 66 doDebug = false 67 ) 68 69 // RunServer starts a new Go routine based server 70 func RunServer(opts *server.Options) *server.Server { 71 return RunServerCallback(opts, nil) 72 } 73 74 func RunServerCallback(opts *server.Options, callback func(*server.Server)) *server.Server { 75 if opts == nil { 76 opts = &DefaultTestOptions 77 } 78 // Optionally override for individual debugging of tests 79 opts.NoLog = !doLog 80 opts.Trace = doTrace 81 opts.Debug = doDebug 82 // For all tests in the "test" package, we will disable route pooling. 83 opts.Cluster.PoolSize = -1 84 // Also disable compression for "test" package. 85 opts.Cluster.Compression.Mode = server.CompressionOff 86 opts.LeafNode.Compression.Mode = server.CompressionOff 87 88 s, err := server.NewServer(opts) 89 if err != nil || s == nil { 90 panic(fmt.Sprintf("No NATS Server object returned: %v", err)) 91 } 92 93 if doLog { 94 s.ConfigureLogger() 95 } 96 97 if callback != nil { 98 callback(s) 99 } 100 101 // Run server in Go routine. 102 go s.Start() 103 104 // Wait for accept loop(s) to be started 105 if !s.ReadyForConnections(10 * time.Second) { 106 panic("Unable to start NATS Server in Go Routine") 107 } 108 return s 109 } 110 111 // LoadConfig loads a configuration from a filename 112 func LoadConfig(configFile string) *server.Options { 113 opts, err := server.ProcessConfigFile(configFile) 114 if err != nil { 115 panic(fmt.Sprintf("Error processing configuration file: %v", err)) 116 } 117 return opts 118 } 119 120 // RunServerWithConfig starts a new Go routine based server with a configuration file. 121 func RunServerWithConfig(configFile string) (srv *server.Server, opts *server.Options) { 122 opts = LoadConfig(configFile) 123 srv = RunServer(opts) 124 return 125 } 126 127 // RunServerWithConfigOverrides starts a new Go routine based server with a configuration file, 128 // providing a callback to update the options configured. 129 func RunServerWithConfigOverrides(configFile string, optsCallback func(*server.Options), svrCallback func(*server.Server)) (srv *server.Server, opts *server.Options) { 130 opts = LoadConfig(configFile) 131 if optsCallback != nil { 132 optsCallback(opts) 133 } 134 srv = RunServerCallback(opts, svrCallback) 135 return 136 } 137 138 func stackFatalf(t tLogger, f string, args ...interface{}) { 139 lines := make([]string, 0, 32) 140 msg := fmt.Sprintf(f, args...) 141 lines = append(lines, msg) 142 143 // Ignore ourselves 144 _, testFile, _, _ := runtime.Caller(0) 145 146 // Generate the Stack of callers: 147 for i := 0; true; i++ { 148 _, file, line, ok := runtime.Caller(i) 149 if !ok { 150 break 151 } 152 if file == testFile { 153 continue 154 } 155 msg := fmt.Sprintf("%d - %s:%d", i, file, line) 156 lines = append(lines, msg) 157 } 158 159 t.Fatalf("%s", strings.Join(lines, "\n")) 160 } 161 162 func acceptRouteConn(t tLogger, host string, timeout time.Duration) net.Conn { 163 l, e := net.Listen("tcp", host) 164 if e != nil { 165 stackFatalf(t, "Error listening for route connection on %v: %v", host, e) 166 } 167 defer l.Close() 168 169 tl := l.(*net.TCPListener) 170 tl.SetDeadline(time.Now().Add(timeout)) 171 conn, err := l.Accept() 172 tl.SetDeadline(time.Time{}) 173 174 if err != nil { 175 stackFatalf(t, "Did not receive a route connection request: %v", err) 176 } 177 return conn 178 } 179 180 func createRouteConn(t tLogger, host string, port int) net.Conn { 181 return createClientConn(t, host, port) 182 } 183 184 func createClientConn(t tLogger, host string, port int) net.Conn { 185 addr := fmt.Sprintf("%s:%d", host, port) 186 c, err := net.DialTimeout("tcp", addr, 3*time.Second) 187 if err != nil { 188 stackFatalf(t, "Could not connect to server: %v\n", err) 189 } 190 return c 191 } 192 193 func checkSocket(t tLogger, addr string, wait time.Duration) { 194 end := time.Now().Add(wait) 195 for time.Now().Before(end) { 196 conn, err := net.Dial("tcp", addr) 197 if err != nil { 198 // Retry after 50ms 199 time.Sleep(50 * time.Millisecond) 200 continue 201 } 202 conn.Close() 203 // Wait a bit to give a chance to the server to remove this 204 // "client" from its state, which may otherwise interfere with 205 // some tests. 206 time.Sleep(25 * time.Millisecond) 207 return 208 } 209 // We have failed to bind the socket in the time allowed. 210 t.Fatalf("Failed to connect to the socket: %q", addr) 211 } 212 213 func checkInfoMsg(t tLogger, c net.Conn) server.Info { 214 buf := expectResult(t, c, infoRe) 215 js := infoRe.FindAllSubmatch(buf, 1)[0][1] 216 var sinfo server.Info 217 err := json.Unmarshal(js, &sinfo) 218 if err != nil { 219 stackFatalf(t, "Could not unmarshal INFO json: %v\n", err) 220 } 221 return sinfo 222 } 223 224 func doHeadersConnect(t tLogger, c net.Conn, verbose, pedantic, ssl, headers bool) { 225 checkInfoMsg(t, c) 226 cs := fmt.Sprintf("CONNECT {\"verbose\":%v,\"pedantic\":%v,\"tls_required\":%v,\"headers\":%v}\r\n", 227 verbose, pedantic, ssl, headers) 228 sendProto(t, c, cs) 229 } 230 231 func doConnect(t tLogger, c net.Conn, verbose, pedantic, ssl bool) { 232 doHeadersConnect(t, c, verbose, pedantic, ssl, false) 233 } 234 235 func doDefaultHeadersConnect(t tLogger, c net.Conn) { 236 doHeadersConnect(t, c, false, false, false, true) 237 } 238 239 func doDefaultConnect(t tLogger, c net.Conn) { 240 // Basic Connect 241 doConnect(t, c, false, false, false) 242 } 243 244 const routeConnectProto = "CONNECT {\"verbose\":false,\"user\":\"%s\",\"pass\":\"%s\",\"name\":\"%s\",\"cluster\":\"xyz\"}\r\n" 245 246 func doRouteAuthConnect(t tLogger, c net.Conn, user, pass, id string) { 247 cs := fmt.Sprintf(routeConnectProto, user, pass, id) 248 sendProto(t, c, cs) 249 } 250 251 func setupRouteEx(t tLogger, c net.Conn, opts *server.Options, id string) (sendFun, expectFun) { 252 user := opts.Cluster.Username 253 pass := opts.Cluster.Password 254 doRouteAuthConnect(t, c, user, pass, id) 255 return sendCommand(t, c), expectCommand(t, c) 256 } 257 258 func setupRoute(t tLogger, c net.Conn, opts *server.Options) (sendFun, expectFun) { 259 u := make([]byte, 16) 260 io.ReadFull(rand.Reader, u) 261 id := fmt.Sprintf("ROUTER:%s", hex.EncodeToString(u)) 262 return setupRouteEx(t, c, opts, id) 263 } 264 265 func setupHeaderConn(t tLogger, c net.Conn) (sendFun, expectFun) { 266 doDefaultHeadersConnect(t, c) 267 return sendCommand(t, c), expectCommand(t, c) 268 } 269 270 func setupConn(t tLogger, c net.Conn) (sendFun, expectFun) { 271 doDefaultConnect(t, c) 272 return sendCommand(t, c), expectCommand(t, c) 273 } 274 275 func setupConnWithProto(t tLogger, c net.Conn, proto int) (sendFun, expectFun) { 276 checkInfoMsg(t, c) 277 cs := fmt.Sprintf("CONNECT {\"verbose\":%v,\"pedantic\":%v,\"tls_required\":%v,\"protocol\":%d}\r\n", false, false, false, proto) 278 sendProto(t, c, cs) 279 return sendCommand(t, c), expectCommand(t, c) 280 } 281 282 func setupConnWithAccount(t tLogger, s *server.Server, c net.Conn, account string) (sendFun, expectFun) { 283 info := checkInfoMsg(t, c) 284 s.RegisterAccount(account) 285 acc, err := s.LookupAccount(account) 286 if err != nil { 287 t.Fatalf("Unexpected Error: %v", err) 288 } 289 cs := fmt.Sprintf("CONNECT {\"verbose\":%v,\"pedantic\":%v,\"tls_required\":%v}\r\n", false, false, false) 290 sendProto(t, c, cs) 291 292 send, expect := sendCommand(t, c), expectCommand(t, c) 293 send("PING\r\n") 294 expect(pongRe) 295 296 nc := s.GetClient(info.CID) 297 if nc == nil { 298 t.Fatalf("Could not get client for CID:%d", info.CID) 299 } 300 nc.RegisterUser(&server.User{Account: acc}) 301 302 return send, expect 303 } 304 305 func setupConnWithUserPass(t tLogger, c net.Conn, username, password string) (sendFun, expectFun) { 306 checkInfoMsg(t, c) 307 cs := fmt.Sprintf("CONNECT {\"verbose\":%v,\"pedantic\":%v,\"tls_required\":%v,\"protocol\":1,\"user\":%q,\"pass\":%q}\r\n", 308 false, false, false, username, password) 309 sendProto(t, c, cs) 310 return sendCommand(t, c), expectLefMostCommand(t, c) 311 } 312 313 type sendFun func(string) 314 type expectFun func(*regexp.Regexp) []byte 315 316 // Closure version for easier reading 317 func sendCommand(t tLogger, c net.Conn) sendFun { 318 return func(op string) { 319 sendProto(t, c, op) 320 } 321 } 322 323 // Closure version for easier reading 324 func expectCommand(t tLogger, c net.Conn) expectFun { 325 return func(re *regexp.Regexp) []byte { 326 return expectResult(t, c, re) 327 } 328 } 329 330 // Closure version for easier reading 331 func expectLefMostCommand(t tLogger, c net.Conn) expectFun { 332 var buf []byte 333 return func(re *regexp.Regexp) []byte { 334 return expectLeftMostResult(t, c, re, &buf) 335 } 336 } 337 338 // Send the protocol command to the server. 339 func sendProto(t tLogger, c net.Conn, op string) { 340 n, err := c.Write([]byte(op)) 341 if err != nil { 342 stackFatalf(t, "Error writing command to conn: %v\n", err) 343 } 344 if n != len(op) { 345 stackFatalf(t, "Partial write: %d vs %d\n", n, len(op)) 346 } 347 } 348 349 var ( 350 anyRe = regexp.MustCompile(`.*`) 351 infoRe = regexp.MustCompile(`INFO\s+([^\r\n]+)\r\n`) 352 infoStartRe = regexp.MustCompile(`^INFO\s+([^\r\n]+)\r\n`) 353 pingRe = regexp.MustCompile(`^PING\r\n`) 354 pongRe = regexp.MustCompile(`^PONG\r\n`) 355 hmsgRe = regexp.MustCompile(`(?:(?:HMSG\s+([^\s]+)\s+([^\s]+)\s+(([^\s]+)[^\S\r\n]+)?(\d+)\s+(\d+)\s*\r\n([^\\r\\n]*?)\r\n)+?)`) 356 msgRe = regexp.MustCompile(`(?:(?:MSG\s+([^\s]+)\s+([^\s]+)\s+(([^\s]+)[^\S\r\n]+)?(\d+)\s*\r\n([^\\r\\n]*?)\r\n)+?)`) 357 rawMsgRe = regexp.MustCompile(`(?:(?:MSG\s+([^\s]+)\s+([^\s]+)\s+(([^\s]+)[^\S\r\n]+)?(\d+)\s*\r\n(.*?)))`) 358 okRe = regexp.MustCompile(`\A\+OK\r\n`) 359 errRe = regexp.MustCompile(`\A\-ERR\s+([^\r\n]+)\r\n`) 360 connectRe = regexp.MustCompile(`CONNECT\s+([^\r\n]+)\r\n`) 361 rsubRe = regexp.MustCompile(`RS\+\s+([^\s]+)\s+([^\s]+)\s*([^\s]+)?\s*(\d+)?\r\n`) 362 runsubRe = regexp.MustCompile(`RS\-\s+([^\s]+)\s+([^\s]+)\s*([^\s]+)?\r\n`) 363 rmsgRe = regexp.MustCompile(`(?:(?:RMSG\s+([^\s]+)\s+([^\s]+)\s+(?:([|+]\s+([\w\s]+)|[^\s]+)[^\S\r\n]+)?(\d+)\s*\r\n([^\\r\\n]*?)\r\n)+?)`) 364 asubRe = regexp.MustCompile(`A\+\s+([^\r\n]+)\r\n`) 365 aunsubRe = regexp.MustCompile(`A\-\s+([^\r\n]+)\r\n`) 366 lsubRe = regexp.MustCompile(`LS\+\s+([^\s]+)\s*([^\s]+)?\s*(\d+)?\r\n`) 367 lunsubRe = regexp.MustCompile(`LS\-\s+([^\s]+)\s*([^\s]+)?\r\n`) 368 lmsgRe = regexp.MustCompile(`(?:(?:LMSG\s+([^\s]+)\s+(?:([|+]\s+([\w\s]+)|[^\s]+)[^\S\r\n]+)?(\d+)\s*\r\n([^\\r\\n]*?)\r\n)+?)`) 369 rlsubRe = regexp.MustCompile(`LS\+\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s*([^\s]+)?\s*(\d+)?\r\n`) 370 ) 371 372 const ( 373 // Regular Messages 374 subIndex = 1 375 sidIndex = 2 376 replyIndex = 4 377 lenIndex = 5 378 msgIndex = 6 379 // Headers 380 hlenIndex = 5 381 tlenIndex = 6 382 hmsgIndex = 7 383 384 // Routed Messages 385 accIndex = 1 386 rsubIndex = 2 387 replyAndQueueIndex = 3 388 ) 389 390 // Test result from server against regexp and return left most match 391 func expectLeftMostResult(t tLogger, c net.Conn, re *regexp.Regexp, buf *[]byte) []byte { 392 recv := func() []byte { 393 expBuf := make([]byte, 32768) 394 // Wait for commands to be processed and results queued for read 395 c.SetReadDeadline(time.Now().Add(2 * time.Second)) 396 n, err := c.Read(expBuf) 397 c.SetReadDeadline(time.Time{}) 398 399 if n <= 0 && err != nil { 400 stackFatalf(t, "Error reading from conn: %v\n", err) 401 } 402 return expBuf[:n] 403 } 404 if len(*buf) == 0 { 405 *buf = recv() 406 } 407 emptyCnt := 0 408 for { 409 result := re.Find(*buf) 410 if result == nil { 411 emptyCnt++ 412 if emptyCnt > 5 { 413 stackFatalf(t, "Reading empty data too often\n") 414 } 415 *buf = append(*buf, recv()...) 416 } else { 417 cutIdx := strings.Index(string(*buf), string(result)) + len(result) 418 *buf = (*buf)[cutIdx:] 419 return result 420 } 421 } 422 } 423 424 // Test result from server against regexp 425 func expectResult(t tLogger, c net.Conn, re *regexp.Regexp) []byte { 426 expBuf := make([]byte, 32768) 427 // Wait for commands to be processed and results queued for read 428 c.SetReadDeadline(time.Now().Add(2 * time.Second)) 429 n, err := c.Read(expBuf) 430 c.SetReadDeadline(time.Time{}) 431 432 if n <= 0 && err != nil { 433 stackFatalf(t, "Error reading from conn: %v\n", err) 434 } 435 buf := expBuf[:n] 436 if !re.Match(buf) { 437 stackFatalf(t, "Response did not match expected: \n\tReceived:'%q'\n\tExpected:'%s'", buf, re) 438 } 439 return buf 440 } 441 442 func peek(c net.Conn) []byte { 443 expBuf := make([]byte, 32768) 444 c.SetReadDeadline(time.Now().Add(50 * time.Millisecond)) 445 n, err := c.Read(expBuf) 446 c.SetReadDeadline(time.Time{}) 447 if err != nil || n <= 0 { 448 return nil 449 } 450 return expBuf 451 } 452 453 func expectDisconnect(t *testing.T, c net.Conn) { 454 t.Helper() 455 var b [8]byte 456 c.SetReadDeadline(time.Now().Add(200 * time.Millisecond)) 457 _, err := c.Read(b[:]) 458 c.SetReadDeadline(time.Time{}) 459 if err != io.EOF { 460 t.Fatalf("Expected a disconnect") 461 } 462 } 463 464 func expectNothing(t tLogger, c net.Conn) { 465 expectNothingTimeout(t, c, time.Now().Add(100*time.Millisecond)) 466 } 467 468 func expectNothingTimeout(t tLogger, c net.Conn, dl time.Time) { 469 expBuf := make([]byte, 32) 470 c.SetReadDeadline(dl) 471 n, err := c.Read(expBuf) 472 c.SetReadDeadline(time.Time{}) 473 if err == nil && n > 0 { 474 stackFatalf(t, "Expected nothing, received: '%q'\n", expBuf[:n]) 475 } 476 } 477 478 // This will check that we got what we expected from a normal message. 479 func checkMsg(t tLogger, m [][]byte, subject, sid, reply, len, msg string) { 480 if string(m[subIndex]) != subject { 481 stackFatalf(t, "Did not get correct subject: expected '%s' got '%s'\n", subject, m[subIndex]) 482 } 483 if sid != "" && string(m[sidIndex]) != sid { 484 stackFatalf(t, "Did not get correct sid: expected '%s' got '%s'\n", sid, m[sidIndex]) 485 } 486 if string(m[replyIndex]) != reply { 487 stackFatalf(t, "Did not get correct reply: expected '%s' got '%s'\n", reply, m[replyIndex]) 488 } 489 if string(m[lenIndex]) != len { 490 stackFatalf(t, "Did not get correct msg length: expected '%s' got '%s'\n", len, m[lenIndex]) 491 } 492 if string(m[msgIndex]) != msg { 493 stackFatalf(t, "Did not get correct msg: expected '%s' got '%s'\n", msg, m[msgIndex]) 494 } 495 } 496 497 func checkRmsg(t tLogger, m [][]byte, account, subject, replyAndQueues, len, msg string) { 498 if string(m[accIndex]) != account { 499 stackFatalf(t, "Did not get correct account: expected '%s' got '%s'\n", account, m[accIndex]) 500 } 501 if string(m[rsubIndex]) != subject { 502 stackFatalf(t, "Did not get correct subject: expected '%s' got '%s'\n", subject, m[rsubIndex]) 503 } 504 if string(m[lenIndex]) != len { 505 stackFatalf(t, "Did not get correct msg length: expected '%s' got '%s'\n", len, m[lenIndex]) 506 } 507 if string(m[replyAndQueueIndex]) != replyAndQueues { 508 stackFatalf(t, "Did not get correct reply/queues: expected '%s' got '%s'\n", replyAndQueues, m[replyAndQueueIndex]) 509 } 510 } 511 512 func checkLmsg(t tLogger, m [][]byte, subject, replyAndQueues, len, msg string) { 513 if string(m[rsubIndex-1]) != subject { 514 stackFatalf(t, "Did not get correct subject: expected '%s' got '%s'\n", subject, m[rsubIndex-1]) 515 } 516 if string(m[lenIndex-1]) != len { 517 stackFatalf(t, "Did not get correct msg length: expected '%s' got '%s'\n", len, m[lenIndex-1]) 518 } 519 if string(m[replyAndQueueIndex-1]) != replyAndQueues { 520 stackFatalf(t, "Did not get correct reply/queues: expected '%s' got '%s'\n", replyAndQueues, m[replyAndQueueIndex-1]) 521 } 522 } 523 524 // This will check that we got what we expected from a header message. 525 func checkHmsg(t tLogger, m [][]byte, subject, sid, reply, hlen, len, hdr, msg string) { 526 if string(m[subIndex]) != subject { 527 stackFatalf(t, "Did not get correct subject: expected '%s' got '%s'\n", subject, m[subIndex]) 528 } 529 if sid != "" && string(m[sidIndex]) != sid { 530 stackFatalf(t, "Did not get correct sid: expected '%s' got '%s'\n", sid, m[sidIndex]) 531 } 532 if string(m[replyIndex]) != reply { 533 stackFatalf(t, "Did not get correct reply: expected '%s' got '%s'\n", reply, m[replyIndex]) 534 } 535 if string(m[hlenIndex]) != hlen { 536 stackFatalf(t, "Did not get correct header length: expected '%s' got '%s'\n", hlen, m[hlenIndex]) 537 } 538 if string(m[tlenIndex]) != len { 539 stackFatalf(t, "Did not get correct msg length: expected '%s' got '%s'\n", len, m[tlenIndex]) 540 } 541 // Extract the payload and break up the headers and msg. 542 payload := string(m[hmsgIndex]) 543 hi, _ := strconv.Atoi(hlen) 544 rhdr, rmsg := payload[:hi], payload[hi:] 545 if rhdr != hdr { 546 stackFatalf(t, "Did not get correct headers: expected '%s' got '%s'\n", hdr, rhdr) 547 } 548 if rmsg != msg { 549 stackFatalf(t, "Did not get correct msg: expected '%s' got '%s'\n", msg, rmsg) 550 } 551 } 552 553 // Closure for expectMsgs 554 func expectRmsgsCommand(t tLogger, ef expectFun) func(int) [][][]byte { 555 return func(expected int) [][][]byte { 556 buf := ef(rmsgRe) 557 matches := rmsgRe.FindAllSubmatch(buf, -1) 558 if len(matches) != expected { 559 stackFatalf(t, "Did not get correct # routed msgs: %d vs %d\n", len(matches), expected) 560 } 561 return matches 562 } 563 } 564 565 // Closure for expectHMsgs 566 func expectHeaderMsgsCommand(t tLogger, ef expectFun) func(int) [][][]byte { 567 return func(expected int) [][][]byte { 568 buf := ef(hmsgRe) 569 matches := hmsgRe.FindAllSubmatch(buf, -1) 570 if len(matches) != expected { 571 stackFatalf(t, "Did not get correct # msgs: %d vs %d\n", len(matches), expected) 572 } 573 return matches 574 } 575 } 576 577 // Closure for expectMsgs 578 func expectMsgsCommand(t tLogger, ef expectFun) func(int) [][][]byte { 579 return func(expected int) [][][]byte { 580 buf := ef(msgRe) 581 matches := msgRe.FindAllSubmatch(buf, -1) 582 if len(matches) != expected { 583 stackFatalf(t, "Did not get correct # msgs: %d vs %d\n", len(matches), expected) 584 } 585 return matches 586 } 587 } 588 589 // This will check that the matches include at least one of the sids. Useful for checking 590 // that we received messages on a certain queue group. 591 func checkForQueueSid(t tLogger, matches [][][]byte, sids []string) { 592 seen := make(map[string]int, len(sids)) 593 for _, sid := range sids { 594 seen[sid] = 0 595 } 596 for _, m := range matches { 597 sid := string(m[sidIndex]) 598 if _, ok := seen[sid]; ok { 599 seen[sid]++ 600 } 601 } 602 // Make sure we only see one and exactly one. 603 total := 0 604 for _, n := range seen { 605 total += n 606 } 607 if total != 1 { 608 stackFatalf(t, "Did not get a msg for queue sids group: expected 1 got %d\n", total) 609 } 610 } 611 612 // This will check that the matches include all of the sids. Useful for checking 613 // that we received messages on all subscribers. 614 func checkForPubSids(t tLogger, matches [][][]byte, sids []string) { 615 seen := make(map[string]int, len(sids)) 616 for _, sid := range sids { 617 seen[sid] = 0 618 } 619 for _, m := range matches { 620 sid := string(m[sidIndex]) 621 if _, ok := seen[sid]; ok { 622 seen[sid]++ 623 } 624 } 625 // Make sure we only see one and exactly one for each sid. 626 for sid, n := range seen { 627 if n != 1 { 628 stackFatalf(t, "Did not get a msg for sid[%s]: expected 1 got %d\n", sid, n) 629 630 } 631 } 632 } 633 634 // Helper function to generate next opts to make sure no port conflicts etc. 635 func nextServerOpts(opts *server.Options) *server.Options { 636 nopts := opts.Clone() 637 nopts.Port++ 638 nopts.Cluster.Port++ 639 nopts.HTTPPort++ 640 return nopts 641 } 642 643 func createTempFile(t testing.TB, prefix string) *os.File { 644 t.Helper() 645 file, err := os.CreateTemp(t.TempDir(), prefix) 646 if err != nil { 647 t.Fatal(err) 648 } 649 return file 650 }