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  }