get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/sublist_test.go (about)

     1  // Copyright 2016-2023 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 server
    15  
    16  import (
    17  	"errors"
    18  	"flag"
    19  	"fmt"
    20  	"math/rand"
    21  	"os"
    22  	"runtime"
    23  	"strconv"
    24  	"strings"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/nats-io/nuid"
    30  )
    31  
    32  func stackFatalf(t *testing.T, f string, args ...interface{}) {
    33  	lines := make([]string, 0, 32)
    34  	msg := fmt.Sprintf(f, args...)
    35  	lines = append(lines, msg)
    36  
    37  	// Generate the Stack of callers: Skip us and verify* frames.
    38  	for i := 2; true; i++ {
    39  		_, file, line, ok := runtime.Caller(i)
    40  		if !ok {
    41  			break
    42  		}
    43  		msg := fmt.Sprintf("%d - %s:%d", i, file, line)
    44  		lines = append(lines, msg)
    45  	}
    46  	t.Fatalf("%s", strings.Join(lines, "\n"))
    47  }
    48  
    49  func verifyCount(s *Sublist, count uint32, t *testing.T) {
    50  	t.Helper()
    51  	if s.Count() != count {
    52  		t.Fatalf("Count is %d, should be %d", s.Count(), count)
    53  	}
    54  }
    55  
    56  func verifyLen(r []*subscription, l int, t *testing.T) {
    57  	t.Helper()
    58  	if len(r) != l {
    59  		t.Fatalf("Results len is %d, should be %d", len(r), l)
    60  	}
    61  }
    62  
    63  func verifyQLen(r [][]*subscription, l int, t *testing.T) {
    64  	t.Helper()
    65  	if len(r) != l {
    66  		t.Fatalf("Queue Results len is %d, should be %d", len(r), l)
    67  	}
    68  }
    69  
    70  func verifyNumLevels(s *Sublist, expected int, t *testing.T) {
    71  	t.Helper()
    72  	dl := s.numLevels()
    73  	if dl != expected {
    74  		t.Fatalf("NumLevels is %d, should be %d", dl, expected)
    75  	}
    76  }
    77  
    78  func verifyQMember(qsubs [][]*subscription, val *subscription, t *testing.T) {
    79  	t.Helper()
    80  	verifyMember(qsubs[findQSlot(val.queue, qsubs)], val, t)
    81  }
    82  
    83  func verifyMember(r []*subscription, val *subscription, t *testing.T) {
    84  	t.Helper()
    85  	for _, v := range r {
    86  		if v == nil {
    87  			continue
    88  		}
    89  		if v == val {
    90  			return
    91  		}
    92  	}
    93  	t.Fatalf("Subscription (%p) for [%s : %s] not found in results", val, val.subject, val.queue)
    94  }
    95  
    96  // Helpers to generate test subscriptions.
    97  func newSub(subject string) *subscription {
    98  	c := &client{kind: CLIENT}
    99  	return &subscription{client: c, subject: []byte(subject)}
   100  }
   101  
   102  func newQSub(subject, queue string) *subscription {
   103  	if queue != "" {
   104  		return &subscription{subject: []byte(subject), queue: []byte(queue)}
   105  	}
   106  	return newSub(subject)
   107  }
   108  
   109  func newRemoteQSub(subject, queue string, num int32) *subscription {
   110  	if queue != "" {
   111  		c := &client{kind: ROUTER}
   112  		return &subscription{client: c, subject: []byte(subject), queue: []byte(queue), qw: num}
   113  	}
   114  	return newSub(subject)
   115  }
   116  
   117  func TestSublistInit(t *testing.T) {
   118  	s := NewSublistWithCache()
   119  	verifyCount(s, 0, t)
   120  }
   121  
   122  func TestSublistInsertCount(t *testing.T) {
   123  	testSublistInsertCount(t, NewSublistWithCache())
   124  }
   125  
   126  func TestSublistInsertCountNoCache(t *testing.T) {
   127  	testSublistInsertCount(t, NewSublistNoCache())
   128  }
   129  
   130  func testSublistInsertCount(t *testing.T, s *Sublist) {
   131  	s.Insert(newSub("foo"))
   132  	s.Insert(newSub("bar"))
   133  	s.Insert(newSub("foo.bar"))
   134  	verifyCount(s, 3, t)
   135  }
   136  
   137  func TestSublistSimple(t *testing.T) {
   138  	testSublistSimple(t, NewSublistWithCache())
   139  }
   140  
   141  func TestSublistSimpleNoCache(t *testing.T) {
   142  	testSublistSimple(t, NewSublistNoCache())
   143  }
   144  
   145  func testSublistSimple(t *testing.T, s *Sublist) {
   146  	subject := "foo"
   147  	sub := newSub(subject)
   148  	s.Insert(sub)
   149  	r := s.Match(subject)
   150  	verifyLen(r.psubs, 1, t)
   151  	verifyMember(r.psubs, sub, t)
   152  }
   153  
   154  func TestSublistSimpleMultiTokens(t *testing.T) {
   155  	testSublistSimpleMultiTokens(t, NewSublistWithCache())
   156  }
   157  
   158  func TestSublistSimpleMultiTokensNoCache(t *testing.T) {
   159  	testSublistSimpleMultiTokens(t, NewSublistNoCache())
   160  }
   161  
   162  func testSublistSimpleMultiTokens(t *testing.T, s *Sublist) {
   163  	subject := "foo.bar.baz"
   164  	sub := newSub(subject)
   165  	s.Insert(sub)
   166  	r := s.Match(subject)
   167  	verifyLen(r.psubs, 1, t)
   168  	verifyMember(r.psubs, sub, t)
   169  }
   170  
   171  func TestSublistPartialWildcard(t *testing.T) {
   172  	testSublistPartialWildcard(t, NewSublistWithCache())
   173  }
   174  
   175  func TestSublistPartialWildcardNoCache(t *testing.T) {
   176  	testSublistPartialWildcard(t, NewSublistNoCache())
   177  }
   178  
   179  func testSublistPartialWildcard(t *testing.T, s *Sublist) {
   180  	lsub := newSub("a.b.c")
   181  	psub := newSub("a.*.c")
   182  	s.Insert(lsub)
   183  	s.Insert(psub)
   184  	r := s.Match("a.b.c")
   185  	verifyLen(r.psubs, 2, t)
   186  	verifyMember(r.psubs, lsub, t)
   187  	verifyMember(r.psubs, psub, t)
   188  }
   189  
   190  func TestSublistPartialWildcardAtEnd(t *testing.T) {
   191  	testSublistPartialWildcardAtEnd(t, NewSublistWithCache())
   192  }
   193  
   194  func TestSublistPartialWildcardAtEndNoCache(t *testing.T) {
   195  	testSublistPartialWildcardAtEnd(t, NewSublistNoCache())
   196  }
   197  
   198  func testSublistPartialWildcardAtEnd(t *testing.T, s *Sublist) {
   199  	lsub := newSub("a.b.c")
   200  	psub := newSub("a.b.*")
   201  	s.Insert(lsub)
   202  	s.Insert(psub)
   203  	r := s.Match("a.b.c")
   204  	verifyLen(r.psubs, 2, t)
   205  	verifyMember(r.psubs, lsub, t)
   206  	verifyMember(r.psubs, psub, t)
   207  }
   208  
   209  func TestSublistFullWildcard(t *testing.T) {
   210  	testSublistFullWildcard(t, NewSublistWithCache())
   211  }
   212  
   213  func TestSublistFullWildcardNoCache(t *testing.T) {
   214  	testSublistFullWildcard(t, NewSublistNoCache())
   215  }
   216  
   217  func testSublistFullWildcard(t *testing.T, s *Sublist) {
   218  	lsub := newSub("a.b.c")
   219  	fsub := newSub("a.>")
   220  	s.Insert(lsub)
   221  	s.Insert(fsub)
   222  	r := s.Match("a.b.c")
   223  	verifyLen(r.psubs, 2, t)
   224  	verifyMember(r.psubs, lsub, t)
   225  	verifyMember(r.psubs, fsub, t)
   226  
   227  	r = s.Match("a.>")
   228  	verifyLen(r.psubs, 1, t)
   229  	verifyMember(r.psubs, fsub, t)
   230  }
   231  
   232  func TestSublistRemove(t *testing.T) {
   233  	testSublistRemove(t, NewSublistWithCache())
   234  }
   235  
   236  func TestSublistRemoveNoCache(t *testing.T) {
   237  	testSublistRemove(t, NewSublistNoCache())
   238  }
   239  
   240  func testSublistRemove(t *testing.T, s *Sublist) {
   241  	subject := "a.b.c.d"
   242  	sub := newSub(subject)
   243  	s.Insert(sub)
   244  	verifyCount(s, 1, t)
   245  	r := s.Match(subject)
   246  	verifyLen(r.psubs, 1, t)
   247  	s.Remove(newSub("a.b.c"))
   248  	verifyCount(s, 1, t)
   249  	s.Remove(sub)
   250  	verifyCount(s, 0, t)
   251  	r = s.Match(subject)
   252  	verifyLen(r.psubs, 0, t)
   253  }
   254  
   255  func TestSublistRemoveWildcard(t *testing.T) {
   256  	testSublistRemoveWildcard(t, NewSublistWithCache())
   257  }
   258  
   259  func TestSublistRemoveWildcardNoCache(t *testing.T) {
   260  	testSublistRemoveWildcard(t, NewSublistNoCache())
   261  }
   262  
   263  func testSublistRemoveWildcard(t *testing.T, s *Sublist) {
   264  	subject := "a.b.c.d"
   265  	sub := newSub(subject)
   266  	psub := newSub("a.b.*.d")
   267  	fsub := newSub("a.b.>")
   268  	s.Insert(sub)
   269  	s.Insert(psub)
   270  	s.Insert(fsub)
   271  	verifyCount(s, 3, t)
   272  	r := s.Match(subject)
   273  	verifyLen(r.psubs, 3, t)
   274  	s.Remove(sub)
   275  	verifyCount(s, 2, t)
   276  	s.Remove(fsub)
   277  	verifyCount(s, 1, t)
   278  	s.Remove(psub)
   279  	verifyCount(s, 0, t)
   280  	r = s.Match(subject)
   281  	verifyLen(r.psubs, 0, t)
   282  }
   283  
   284  func TestSublistRemoveCleanup(t *testing.T) {
   285  	testSublistRemoveCleanup(t, NewSublistWithCache())
   286  }
   287  
   288  func TestSublistRemoveCleanupNoCache(t *testing.T) {
   289  	testSublistRemoveCleanup(t, NewSublistNoCache())
   290  }
   291  
   292  func testSublistRemoveCleanup(t *testing.T, s *Sublist) {
   293  	literal := "a.b.c.d.e.f"
   294  	depth := len(strings.Split(literal, tsep))
   295  	sub := newSub(literal)
   296  	verifyNumLevels(s, 0, t)
   297  	s.Insert(sub)
   298  	verifyNumLevels(s, depth, t)
   299  	s.Remove(sub)
   300  	verifyNumLevels(s, 0, t)
   301  }
   302  
   303  func TestSublistRemoveCleanupWildcards(t *testing.T) {
   304  	testSublistRemoveCleanupWildcards(t, NewSublistWithCache())
   305  }
   306  
   307  func TestSublistRemoveCleanupWildcardsNoCache(t *testing.T) {
   308  	testSublistRemoveCleanupWildcards(t, NewSublistNoCache())
   309  }
   310  
   311  func testSublistRemoveCleanupWildcards(t *testing.T, s *Sublist) {
   312  	subject := "a.b.*.d.e.>"
   313  	depth := len(strings.Split(subject, tsep))
   314  	sub := newSub(subject)
   315  	verifyNumLevels(s, 0, t)
   316  	s.Insert(sub)
   317  	verifyNumLevels(s, depth, t)
   318  	s.Remove(sub)
   319  	verifyNumLevels(s, 0, t)
   320  }
   321  
   322  func TestSublistRemoveWithLargeSubs(t *testing.T) {
   323  	testSublistRemoveWithLargeSubs(t, NewSublistWithCache())
   324  }
   325  
   326  func TestSublistRemoveWithLargeSubsNoCache(t *testing.T) {
   327  	testSublistRemoveWithLargeSubs(t, NewSublistNoCache())
   328  }
   329  
   330  func testSublistRemoveWithLargeSubs(t *testing.T, s *Sublist) {
   331  	subject := "foo"
   332  	for i := 0; i < plistMin*2; i++ {
   333  		sub := newSub(subject)
   334  		s.Insert(sub)
   335  	}
   336  	r := s.Match(subject)
   337  	verifyLen(r.psubs, plistMin*2, t)
   338  	// Remove one that is in the middle
   339  	s.Remove(r.psubs[plistMin])
   340  	// Remove first one
   341  	s.Remove(r.psubs[0])
   342  	// Remove last one
   343  	s.Remove(r.psubs[len(r.psubs)-1])
   344  	// Check len again
   345  	r = s.Match(subject)
   346  	verifyLen(r.psubs, plistMin*2-3, t)
   347  }
   348  
   349  func TestSublistInvalidSubjectsInsert(t *testing.T) {
   350  	testSublistInvalidSubjectsInsert(t, NewSublistWithCache())
   351  }
   352  
   353  func TestSublistInvalidSubjectsInsertNoCache(t *testing.T) {
   354  	testSublistInvalidSubjectsInsert(t, NewSublistNoCache())
   355  }
   356  
   357  func TestSublistNoCacheRemoveBatch(t *testing.T) {
   358  	s := NewSublistNoCache()
   359  	s.Insert(newSub("foo"))
   360  	sub := newSub("bar")
   361  	s.Insert(sub)
   362  	s.RemoveBatch([]*subscription{sub})
   363  	// Now test that this did not turn on cache
   364  	for i := 0; i < 10; i++ {
   365  		s.Match("foo")
   366  	}
   367  	if s.CacheEnabled() {
   368  		t.Fatalf("Cache should not be enabled")
   369  	}
   370  }
   371  
   372  func TestSublistRemoveBatchWithError(t *testing.T) {
   373  	s := NewSublistNoCache()
   374  	sub1 := newSub("foo")
   375  	sub2 := newSub("bar")
   376  	sub3 := newSub("baz")
   377  	s.Insert(sub1)
   378  	s.Insert(sub2)
   379  	s.Insert(sub3)
   380  	subNotPresent := newSub("not.inserted")
   381  	// Try to remove all subs, but include the sub that has not been inserted.
   382  	err := s.RemoveBatch([]*subscription{subNotPresent, sub1, sub3})
   383  	// We expect an error to be returned, but sub1,2 and 3 to have been removed.
   384  	require_Error(t, err, ErrNotFound)
   385  	// Make sure that we have only sub2 present
   386  	verifyCount(s, 1, t)
   387  	r := s.Match("bar")
   388  	verifyLen(r.psubs, 1, t)
   389  	verifyMember(r.psubs, sub2, t)
   390  	r = s.Match("foo")
   391  	verifyLen(r.psubs, 0, t)
   392  	r = s.Match("baz")
   393  	verifyLen(r.psubs, 0, t)
   394  }
   395  
   396  func testSublistInvalidSubjectsInsert(t *testing.T, s *Sublist) {
   397  	// Insert, or subscriptions, can have wildcards, but not empty tokens,
   398  	// and can not have a FWC that is not the terminal token.
   399  
   400  	// beginning empty token
   401  	if err := s.Insert(newSub(".foo")); err != ErrInvalidSubject {
   402  		t.Fatal("Expected invalid subject error")
   403  	}
   404  
   405  	// trailing empty token
   406  	if err := s.Insert(newSub("foo.")); err != ErrInvalidSubject {
   407  		t.Fatal("Expected invalid subject error")
   408  	}
   409  	// empty middle token
   410  	if err := s.Insert(newSub("foo..bar")); err != ErrInvalidSubject {
   411  		t.Fatal("Expected invalid subject error")
   412  	}
   413  	// empty middle token #2
   414  	if err := s.Insert(newSub("foo.bar..baz")); err != ErrInvalidSubject {
   415  		t.Fatal("Expected invalid subject error")
   416  	}
   417  	// fwc not terminal
   418  	if err := s.Insert(newSub("foo.>.bar")); err != ErrInvalidSubject {
   419  		t.Fatal("Expected invalid subject error")
   420  	}
   421  }
   422  
   423  func TestSublistCache(t *testing.T) {
   424  	s := NewSublistWithCache()
   425  
   426  	// Test add a remove logistics
   427  	subject := "a.b.c.d"
   428  	sub := newSub(subject)
   429  	psub := newSub("a.b.*.d")
   430  	fsub := newSub("a.b.>")
   431  	s.Insert(sub)
   432  	r := s.Match(subject)
   433  	verifyLen(r.psubs, 1, t)
   434  	s.Insert(psub)
   435  	s.Insert(fsub)
   436  	verifyCount(s, 3, t)
   437  	r = s.Match(subject)
   438  	verifyLen(r.psubs, 3, t)
   439  	s.Remove(sub)
   440  	verifyCount(s, 2, t)
   441  	s.Remove(fsub)
   442  	verifyCount(s, 1, t)
   443  	s.Remove(psub)
   444  	verifyCount(s, 0, t)
   445  
   446  	// Check that cache is now empty
   447  	if cc := s.CacheCount(); cc != 0 {
   448  		t.Fatalf("Cache should be zero, got %d\n", cc)
   449  	}
   450  
   451  	r = s.Match(subject)
   452  	verifyLen(r.psubs, 0, t)
   453  
   454  	for i := 0; i < 2*slCacheMax; i++ {
   455  		s.Match(fmt.Sprintf("foo-%d\n", i))
   456  	}
   457  
   458  	checkFor(t, 2*time.Second, 10*time.Millisecond, func() error {
   459  		if cc := s.CacheCount(); cc > slCacheMax {
   460  			return fmt.Errorf("Cache should be constrained by cacheMax, got %d for current count", cc)
   461  		}
   462  		return nil
   463  	})
   464  
   465  	// Test that adding to a wildcard properly adds to the cache.
   466  	s = NewSublistWithCache()
   467  	s.Insert(newSub("foo.*"))
   468  	s.Insert(newSub("foo.bar"))
   469  	r = s.Match("foo.baz")
   470  	verifyLen(r.psubs, 1, t)
   471  	r = s.Match("foo.bar")
   472  	verifyLen(r.psubs, 2, t)
   473  	s.Insert(newSub("foo.>"))
   474  	r = s.Match("foo.bar")
   475  	verifyLen(r.psubs, 3, t)
   476  }
   477  
   478  func TestSublistBasicQueueResults(t *testing.T) {
   479  	testSublistBasicQueueResults(t, NewSublistWithCache())
   480  }
   481  
   482  func TestSublistBasicQueueResultsNoCache(t *testing.T) {
   483  	testSublistBasicQueueResults(t, NewSublistNoCache())
   484  }
   485  
   486  func testSublistBasicQueueResults(t *testing.T, s *Sublist) {
   487  	// Test some basics
   488  	subject := "foo"
   489  	sub := newSub(subject)
   490  	sub1 := newQSub(subject, "bar")
   491  	sub2 := newQSub(subject, "baz")
   492  
   493  	s.Insert(sub1)
   494  	r := s.Match(subject)
   495  	verifyLen(r.psubs, 0, t)
   496  	verifyQLen(r.qsubs, 1, t)
   497  	verifyLen(r.qsubs[0], 1, t)
   498  	verifyQMember(r.qsubs, sub1, t)
   499  
   500  	s.Insert(sub2)
   501  	r = s.Match(subject)
   502  	verifyLen(r.psubs, 0, t)
   503  	verifyQLen(r.qsubs, 2, t)
   504  	verifyLen(r.qsubs[0], 1, t)
   505  	verifyLen(r.qsubs[1], 1, t)
   506  	verifyQMember(r.qsubs, sub1, t)
   507  	verifyQMember(r.qsubs, sub2, t)
   508  
   509  	s.Insert(sub)
   510  	r = s.Match(subject)
   511  	verifyLen(r.psubs, 1, t)
   512  	verifyQLen(r.qsubs, 2, t)
   513  	verifyLen(r.qsubs[0], 1, t)
   514  	verifyLen(r.qsubs[1], 1, t)
   515  	verifyQMember(r.qsubs, sub1, t)
   516  	verifyQMember(r.qsubs, sub2, t)
   517  	verifyMember(r.psubs, sub, t)
   518  
   519  	sub3 := newQSub(subject, "bar")
   520  	sub4 := newQSub(subject, "baz")
   521  
   522  	s.Insert(sub3)
   523  	s.Insert(sub4)
   524  
   525  	r = s.Match(subject)
   526  	verifyLen(r.psubs, 1, t)
   527  	verifyQLen(r.qsubs, 2, t)
   528  	verifyLen(r.qsubs[0], 2, t)
   529  	verifyLen(r.qsubs[1], 2, t)
   530  	verifyQMember(r.qsubs, sub1, t)
   531  	verifyQMember(r.qsubs, sub2, t)
   532  	verifyQMember(r.qsubs, sub3, t)
   533  	verifyQMember(r.qsubs, sub4, t)
   534  	verifyMember(r.psubs, sub, t)
   535  
   536  	// Now removal
   537  	s.Remove(sub)
   538  
   539  	r = s.Match(subject)
   540  	verifyLen(r.psubs, 0, t)
   541  	verifyQLen(r.qsubs, 2, t)
   542  	verifyLen(r.qsubs[0], 2, t)
   543  	verifyLen(r.qsubs[1], 2, t)
   544  	verifyQMember(r.qsubs, sub1, t)
   545  	verifyQMember(r.qsubs, sub2, t)
   546  
   547  	s.Remove(sub1)
   548  	r = s.Match(subject)
   549  	verifyLen(r.psubs, 0, t)
   550  	verifyQLen(r.qsubs, 2, t)
   551  	verifyLen(r.qsubs[findQSlot(sub1.queue, r.qsubs)], 1, t)
   552  	verifyLen(r.qsubs[findQSlot(sub2.queue, r.qsubs)], 2, t)
   553  	verifyQMember(r.qsubs, sub2, t)
   554  	verifyQMember(r.qsubs, sub3, t)
   555  	verifyQMember(r.qsubs, sub4, t)
   556  
   557  	s.Remove(sub3) // Last one
   558  	r = s.Match(subject)
   559  	verifyLen(r.psubs, 0, t)
   560  	verifyQLen(r.qsubs, 1, t)
   561  	verifyLen(r.qsubs[0], 2, t) // this is sub2/baz now
   562  	verifyQMember(r.qsubs, sub2, t)
   563  
   564  	s.Remove(sub2)
   565  	s.Remove(sub4)
   566  	r = s.Match(subject)
   567  	verifyLen(r.psubs, 0, t)
   568  	verifyQLen(r.qsubs, 0, t)
   569  }
   570  
   571  func checkBool(b, expected bool, t *testing.T) {
   572  	t.Helper()
   573  	if b != expected {
   574  		t.Fatalf("Expected %v, but got %v\n", expected, b)
   575  	}
   576  }
   577  
   578  func checkError(err, expected error, t *testing.T) {
   579  	t.Helper()
   580  	if err != expected && err != nil && !errors.Is(err, expected) {
   581  		t.Fatalf("Expected %v, but got %v\n", expected, err)
   582  	}
   583  }
   584  
   585  func TestSublistValidLiteralSubjects(t *testing.T) {
   586  	checkBool(IsValidLiteralSubject("foo"), true, t)
   587  	checkBool(IsValidLiteralSubject(".foo"), false, t)
   588  	checkBool(IsValidLiteralSubject("foo."), false, t)
   589  	checkBool(IsValidLiteralSubject("foo..bar"), false, t)
   590  	checkBool(IsValidLiteralSubject("foo.bar.*"), false, t)
   591  	checkBool(IsValidLiteralSubject("foo.bar.>"), false, t)
   592  	checkBool(IsValidLiteralSubject("*"), false, t)
   593  	checkBool(IsValidLiteralSubject(">"), false, t)
   594  	// The followings have widlcards characters but are not
   595  	// considered as such because they are not individual tokens.
   596  	checkBool(IsValidLiteralSubject("foo*"), true, t)
   597  	checkBool(IsValidLiteralSubject("foo**"), true, t)
   598  	checkBool(IsValidLiteralSubject("foo.**"), true, t)
   599  	checkBool(IsValidLiteralSubject("foo*bar"), true, t)
   600  	checkBool(IsValidLiteralSubject("foo.*bar"), true, t)
   601  	checkBool(IsValidLiteralSubject("foo*.bar"), true, t)
   602  	checkBool(IsValidLiteralSubject("*bar"), true, t)
   603  	checkBool(IsValidLiteralSubject("foo>"), true, t)
   604  	checkBool(IsValidLiteralSubject("foo>>"), true, t)
   605  	checkBool(IsValidLiteralSubject("foo.>>"), true, t)
   606  	checkBool(IsValidLiteralSubject("foo>bar"), true, t)
   607  	checkBool(IsValidLiteralSubject("foo.>bar"), true, t)
   608  	checkBool(IsValidLiteralSubject("foo>.bar"), true, t)
   609  	checkBool(IsValidLiteralSubject(">bar"), true, t)
   610  }
   611  
   612  func TestSublistValidSubjects(t *testing.T) {
   613  	checkBool(IsValidSubject("."), false, t)
   614  	checkBool(IsValidSubject(".foo"), false, t)
   615  	checkBool(IsValidSubject("foo."), false, t)
   616  	checkBool(IsValidSubject("foo..bar"), false, t)
   617  	checkBool(IsValidSubject(">.bar"), false, t)
   618  	checkBool(IsValidSubject("foo.>.bar"), false, t)
   619  	checkBool(IsValidSubject("foo"), true, t)
   620  	checkBool(IsValidSubject("foo.bar.*"), true, t)
   621  	checkBool(IsValidSubject("foo.bar.>"), true, t)
   622  	checkBool(IsValidSubject("*"), true, t)
   623  	checkBool(IsValidSubject(">"), true, t)
   624  	checkBool(IsValidSubject("foo*"), true, t)
   625  	checkBool(IsValidSubject("foo**"), true, t)
   626  	checkBool(IsValidSubject("foo.**"), true, t)
   627  	checkBool(IsValidSubject("foo*bar"), true, t)
   628  	checkBool(IsValidSubject("foo.*bar"), true, t)
   629  	checkBool(IsValidSubject("foo*.bar"), true, t)
   630  	checkBool(IsValidSubject("*bar"), true, t)
   631  	checkBool(IsValidSubject("foo>"), true, t)
   632  	checkBool(IsValidSubject("foo.>>"), true, t)
   633  	checkBool(IsValidSubject("foo>bar"), true, t)
   634  	checkBool(IsValidSubject("foo.>bar"), true, t)
   635  	checkBool(IsValidSubject("foo>.bar"), true, t)
   636  	checkBool(IsValidSubject(">bar"), true, t)
   637  }
   638  
   639  func TestSublistMatchLiterals(t *testing.T) {
   640  	checkBool(matchLiteral("foo", "foo"), true, t)
   641  	checkBool(matchLiteral("foo", "bar"), false, t)
   642  	checkBool(matchLiteral("foo", "*"), true, t)
   643  	checkBool(matchLiteral("foo", ">"), true, t)
   644  	checkBool(matchLiteral("foo.bar", ">"), true, t)
   645  	checkBool(matchLiteral("foo.bar", "foo.>"), true, t)
   646  	checkBool(matchLiteral("foo.bar", "bar.>"), false, t)
   647  	checkBool(matchLiteral("stats.test.22", "stats.>"), true, t)
   648  	checkBool(matchLiteral("stats.test.22", "stats.*.*"), true, t)
   649  	checkBool(matchLiteral("foo.bar", "foo"), false, t)
   650  	checkBool(matchLiteral("stats.test.foos", "stats.test.foos"), true, t)
   651  	checkBool(matchLiteral("stats.test.foos", "stats.test.foo"), false, t)
   652  	checkBool(matchLiteral("stats.test", "stats.test.*"), false, t)
   653  	checkBool(matchLiteral("stats.test.foos", "stats.*"), false, t)
   654  	checkBool(matchLiteral("stats.test.foos", "stats.*.*.foos"), false, t)
   655  
   656  	// These are cases where wildcards characters should not be considered
   657  	// wildcards since they do not follow the rules of wildcards.
   658  	checkBool(matchLiteral("*bar", "*bar"), true, t)
   659  	checkBool(matchLiteral("foo*", "foo*"), true, t)
   660  	checkBool(matchLiteral("foo*bar", "foo*bar"), true, t)
   661  	checkBool(matchLiteral("foo.***.bar", "foo.***.bar"), true, t)
   662  	checkBool(matchLiteral(">bar", ">bar"), true, t)
   663  	checkBool(matchLiteral("foo>", "foo>"), true, t)
   664  	checkBool(matchLiteral("foo>bar", "foo>bar"), true, t)
   665  	checkBool(matchLiteral("foo.>>>.bar", "foo.>>>.bar"), true, t)
   666  }
   667  
   668  func TestSubjectIsLiteral(t *testing.T) {
   669  	checkBool(subjectIsLiteral("foo"), true, t)
   670  	checkBool(subjectIsLiteral("foo.bar"), true, t)
   671  	checkBool(subjectIsLiteral("foo*.bar"), true, t)
   672  	checkBool(subjectIsLiteral("*"), false, t)
   673  	checkBool(subjectIsLiteral(">"), false, t)
   674  	checkBool(subjectIsLiteral("foo.*"), false, t)
   675  	checkBool(subjectIsLiteral("foo.>"), false, t)
   676  	checkBool(subjectIsLiteral("foo.*.>"), false, t)
   677  	checkBool(subjectIsLiteral("foo.*.bar"), false, t)
   678  	checkBool(subjectIsLiteral("foo.bar.>"), false, t)
   679  }
   680  
   681  func TestValidateDestinationSubject(t *testing.T) {
   682  	checkError(ValidateMappingDestination("foo"), nil, t)
   683  	checkError(ValidateMappingDestination("foo.bar"), nil, t)
   684  	checkError(ValidateMappingDestination("*"), nil, t)
   685  	checkError(ValidateMappingDestination(">"), nil, t)
   686  	checkError(ValidateMappingDestination("foo.*"), nil, t)
   687  	checkError(ValidateMappingDestination("foo.>"), nil, t)
   688  	checkError(ValidateMappingDestination("foo.*.>"), nil, t)
   689  	checkError(ValidateMappingDestination("foo.*.bar"), nil, t)
   690  	checkError(ValidateMappingDestination("foo.bar.>"), nil, t)
   691  	checkError(ValidateMappingDestination("foo.{{wildcard(1)}}"), nil, t)
   692  	checkError(ValidateMappingDestination("foo.{{ wildcard(1) }}"), nil, t)
   693  	checkError(ValidateMappingDestination("foo.{{wildcard( 1 )}}"), nil, t)
   694  	checkError(ValidateMappingDestination("foo.{{partition(2,1)}}"), nil, t)
   695  	checkError(ValidateMappingDestination("foo.{{SplitFromLeft(2,1)}}"), nil, t)
   696  	checkError(ValidateMappingDestination("foo.{{SplitFromRight(2,1)}}"), nil, t)
   697  	checkError(ValidateMappingDestination("foo.{{unknown(1)}}"), ErrInvalidMappingDestination, t)
   698  	checkError(ValidateMappingDestination("foo..}"), ErrInvalidMappingDestination, t)
   699  	checkError(ValidateMappingDestination("foo. bar}"), ErrInvalidMappingDestinationSubject, t)
   700  
   701  }
   702  
   703  func TestSubjectToken(t *testing.T) {
   704  	checkToken := func(token, expected string) {
   705  		t.Helper()
   706  		if token != expected {
   707  			t.Fatalf("Expected token of %q, got %q", expected, token)
   708  		}
   709  	}
   710  	checkToken(tokenAt("foo.bar.baz.*", 0), "")
   711  	checkToken(tokenAt("foo.bar.baz.*", 1), "foo")
   712  	checkToken(tokenAt("foo.bar.baz.*", 2), "bar")
   713  	checkToken(tokenAt("foo.bar.baz.*", 3), "baz")
   714  	checkToken(tokenAt("foo.bar.baz.*", 4), "*")
   715  	checkToken(tokenAt("foo.bar.baz.*", 5), "")
   716  }
   717  
   718  func TestSublistBadSubjectOnRemove(t *testing.T) {
   719  	testSublistBadSubjectOnRemove(t, NewSublistWithCache())
   720  }
   721  
   722  func TestSublistBadSubjectOnRemoveNoCache(t *testing.T) {
   723  	testSublistBadSubjectOnRemove(t, NewSublistNoCache())
   724  }
   725  
   726  func testSublistBadSubjectOnRemove(t *testing.T, s *Sublist) {
   727  	bad := "a.b..d"
   728  	sub := newSub(bad)
   729  
   730  	if err := s.Insert(sub); err != ErrInvalidSubject {
   731  		t.Fatalf("Expected ErrInvalidSubject, got %v\n", err)
   732  	}
   733  
   734  	if err := s.Remove(sub); err != ErrInvalidSubject {
   735  		t.Fatalf("Expected ErrInvalidSubject, got %v\n", err)
   736  	}
   737  
   738  	badfwc := "a.>.b"
   739  	if err := s.Remove(newSub(badfwc)); err != ErrInvalidSubject {
   740  		t.Fatalf("Expected ErrInvalidSubject, got %v\n", err)
   741  	}
   742  }
   743  
   744  // This is from bug report #18
   745  func TestSublistTwoTokenPubMatchSingleTokenSub(t *testing.T) {
   746  	testSublistTwoTokenPubMatchSingleTokenSub(t, NewSublistWithCache())
   747  }
   748  
   749  func TestSublistTwoTokenPubMatchSingleTokenSubNoCache(t *testing.T) {
   750  	testSublistTwoTokenPubMatchSingleTokenSub(t, NewSublistNoCache())
   751  }
   752  
   753  func testSublistTwoTokenPubMatchSingleTokenSub(t *testing.T, s *Sublist) {
   754  	sub := newSub("foo")
   755  	s.Insert(sub)
   756  	r := s.Match("foo")
   757  	verifyLen(r.psubs, 1, t)
   758  	verifyMember(r.psubs, sub, t)
   759  	r = s.Match("foo.bar")
   760  	verifyLen(r.psubs, 0, t)
   761  }
   762  
   763  func TestSublistInsertWithWildcardsAsLiterals(t *testing.T) {
   764  	testSublistInsertWithWildcardsAsLiterals(t, NewSublistWithCache())
   765  }
   766  
   767  func TestSublistInsertWithWildcardsAsLiteralsNoCache(t *testing.T) {
   768  	testSublistInsertWithWildcardsAsLiterals(t, NewSublistNoCache())
   769  }
   770  
   771  func testSublistInsertWithWildcardsAsLiterals(t *testing.T, s *Sublist) {
   772  	subjects := []string{"foo.*-", "foo.>-"}
   773  	for _, subject := range subjects {
   774  		sub := newSub(subject)
   775  		s.Insert(sub)
   776  		// Should find no match
   777  		r := s.Match("foo.bar")
   778  		verifyLen(r.psubs, 0, t)
   779  		// Should find a match
   780  		r = s.Match(subject)
   781  		verifyLen(r.psubs, 1, t)
   782  	}
   783  }
   784  
   785  func TestSublistRemoveWithWildcardsAsLiterals(t *testing.T) {
   786  	testSublistRemoveWithWildcardsAsLiterals(t, NewSublistWithCache())
   787  }
   788  
   789  func TestSublistRemoveWithWildcardsAsLiteralsNoCache(t *testing.T) {
   790  	testSublistRemoveWithWildcardsAsLiterals(t, NewSublistNoCache())
   791  }
   792  
   793  func testSublistRemoveWithWildcardsAsLiterals(t *testing.T, s *Sublist) {
   794  	subjects := []string{"foo.*-", "foo.>-"}
   795  	for _, subject := range subjects {
   796  		sub := newSub(subject)
   797  		s.Insert(sub)
   798  		// Should find no match
   799  		rsub := newSub("foo.bar")
   800  		s.Remove(rsub)
   801  		if c := s.Count(); c != 1 {
   802  			t.Fatalf("Expected sublist to still contain sub, got %v", c)
   803  		}
   804  		s.Remove(sub)
   805  		if c := s.Count(); c != 0 {
   806  			t.Fatalf("Expected sublist to be empty, got %v", c)
   807  		}
   808  	}
   809  }
   810  
   811  func TestSublistRaceOnRemove(t *testing.T) {
   812  	testSublistRaceOnRemove(t, NewSublistWithCache())
   813  }
   814  
   815  func TestSublistRaceOnRemoveNoCache(t *testing.T) {
   816  	testSublistRaceOnRemove(t, NewSublistNoCache())
   817  }
   818  
   819  func testSublistRaceOnRemove(t *testing.T, s *Sublist) {
   820  	var (
   821  		total = 100
   822  		subs  = make(map[int]*subscription, total) // use map for randomness
   823  	)
   824  	for i := 0; i < total; i++ {
   825  		sub := newQSub("foo", "bar")
   826  		subs[i] = sub
   827  	}
   828  
   829  	for i := 0; i < 2; i++ {
   830  		for _, sub := range subs {
   831  			s.Insert(sub)
   832  		}
   833  		// Call Match() once or twice, to make sure we get from cache
   834  		if i == 1 {
   835  			s.Match("foo")
   836  		}
   837  		// This will be from cache when i==1
   838  		r := s.Match("foo")
   839  		wg := sync.WaitGroup{}
   840  		wg.Add(1)
   841  		go func() {
   842  			for _, sub := range subs {
   843  				s.Remove(sub)
   844  			}
   845  			wg.Done()
   846  		}()
   847  		for _, qsub := range r.qsubs {
   848  			for i := 0; i < len(qsub); i++ {
   849  				sub := qsub[i]
   850  				if string(sub.queue) != "bar" {
   851  					t.Fatalf("Queue name should be bar, got %s", qsub[i].queue)
   852  				}
   853  			}
   854  		}
   855  		wg.Wait()
   856  	}
   857  
   858  	// Repeat tests with regular subs
   859  	for i := 0; i < total; i++ {
   860  		sub := newSub("foo")
   861  		subs[i] = sub
   862  	}
   863  
   864  	for i := 0; i < 2; i++ {
   865  		for _, sub := range subs {
   866  			s.Insert(sub)
   867  		}
   868  		// Call Match() once or twice, to make sure we get from cache
   869  		if i == 1 {
   870  			s.Match("foo")
   871  		}
   872  		// This will be from cache when i==1
   873  		r := s.Match("foo")
   874  		wg := sync.WaitGroup{}
   875  		wg.Add(1)
   876  		go func() {
   877  			for _, sub := range subs {
   878  				s.Remove(sub)
   879  			}
   880  			wg.Done()
   881  		}()
   882  		for i := 0; i < len(r.psubs); i++ {
   883  			sub := r.psubs[i]
   884  			if string(sub.subject) != "foo" {
   885  				t.Fatalf("Subject should be foo, got %s", sub.subject)
   886  			}
   887  		}
   888  		wg.Wait()
   889  	}
   890  }
   891  
   892  func TestSublistRaceOnInsert(t *testing.T) {
   893  	testSublistRaceOnInsert(t, NewSublistWithCache())
   894  }
   895  
   896  func TestSublistRaceOnInsertNoCache(t *testing.T) {
   897  	testSublistRaceOnInsert(t, NewSublistNoCache())
   898  }
   899  
   900  func testSublistRaceOnInsert(t *testing.T, s *Sublist) {
   901  	var (
   902  		total = 100
   903  		subs  = make(map[int]*subscription, total) // use map for randomness
   904  		wg    sync.WaitGroup
   905  	)
   906  	for i := 0; i < total; i++ {
   907  		sub := newQSub("foo", "bar")
   908  		subs[i] = sub
   909  	}
   910  	wg.Add(1)
   911  	go func() {
   912  		for _, sub := range subs {
   913  			s.Insert(sub)
   914  		}
   915  		wg.Done()
   916  	}()
   917  	for i := 0; i < 1000; i++ {
   918  		r := s.Match("foo")
   919  		for _, qsubs := range r.qsubs {
   920  			for _, qsub := range qsubs {
   921  				if string(qsub.queue) != "bar" {
   922  					t.Fatalf("Expected queue name to be bar, got %v", string(qsub.queue))
   923  				}
   924  			}
   925  		}
   926  	}
   927  	wg.Wait()
   928  
   929  	// Repeat the test with plain subs
   930  	for i := 0; i < total; i++ {
   931  		sub := newSub("foo")
   932  		subs[i] = sub
   933  	}
   934  	wg.Add(1)
   935  	go func() {
   936  		for _, sub := range subs {
   937  			s.Insert(sub)
   938  		}
   939  		wg.Done()
   940  	}()
   941  	for i := 0; i < 1000; i++ {
   942  		r := s.Match("foo")
   943  		for _, sub := range r.psubs {
   944  			if string(sub.subject) != "foo" {
   945  				t.Fatalf("Expected subject to be foo, got %v", string(sub.subject))
   946  			}
   947  		}
   948  	}
   949  	wg.Wait()
   950  }
   951  
   952  func TestSublistRaceOnMatch(t *testing.T) {
   953  	s := NewSublistNoCache()
   954  	s.Insert(newQSub("foo.*", "workers"))
   955  	s.Insert(newQSub("foo.bar", "workers"))
   956  	s.Insert(newSub("foo.*"))
   957  	s.Insert(newSub("foo.bar"))
   958  
   959  	wg := sync.WaitGroup{}
   960  	wg.Add(2)
   961  	errCh := make(chan error, 2)
   962  	f := func() {
   963  		defer wg.Done()
   964  		for i := 0; i < 10; i++ {
   965  			r := s.Match("foo.bar")
   966  			for _, sub := range r.psubs {
   967  				if !strings.HasPrefix(string(sub.subject), "foo.") {
   968  					errCh <- fmt.Errorf("Wrong subject: %s", sub.subject)
   969  					return
   970  				}
   971  			}
   972  			for _, qsub := range r.qsubs {
   973  				for _, sub := range qsub {
   974  					if string(sub.queue) != "workers" {
   975  						errCh <- fmt.Errorf("Wrong queue name: %s", sub.queue)
   976  						return
   977  					}
   978  				}
   979  			}
   980  		}
   981  	}
   982  	go f()
   983  	go f()
   984  	wg.Wait()
   985  	select {
   986  	case e := <-errCh:
   987  		t.Fatalf(e.Error())
   988  	default:
   989  	}
   990  }
   991  
   992  // Remote subscriptions for queue subscribers will be weighted such that a single subscription
   993  // is received, but represents all of the queue subscribers on the remote side.
   994  func TestSublistRemoteQueueSubscriptions(t *testing.T) {
   995  	testSublistRemoteQueueSubscriptions(t, NewSublistWithCache())
   996  }
   997  
   998  func TestSublistRemoteQueueSubscriptionsNoCache(t *testing.T) {
   999  	testSublistRemoteQueueSubscriptions(t, NewSublistNoCache())
  1000  }
  1001  
  1002  func testSublistRemoteQueueSubscriptions(t *testing.T, s *Sublist) {
  1003  	// Normals
  1004  	s1 := newQSub("foo", "bar")
  1005  	s2 := newQSub("foo", "bar")
  1006  	s.Insert(s1)
  1007  	s.Insert(s2)
  1008  
  1009  	// Now do weighted remotes.
  1010  	rs1 := newRemoteQSub("foo", "bar", 10)
  1011  	s.Insert(rs1)
  1012  	rs2 := newRemoteQSub("foo", "bar", 10)
  1013  	s.Insert(rs2)
  1014  
  1015  	// These are just shadowed in results, so should appear as 4 subs.
  1016  	verifyCount(s, 4, t)
  1017  
  1018  	r := s.Match("foo")
  1019  	verifyLen(r.psubs, 0, t)
  1020  	verifyQLen(r.qsubs, 1, t)
  1021  	verifyLen(r.qsubs[0], 22, t)
  1022  
  1023  	s.Remove(s1)
  1024  	s.Remove(rs1)
  1025  
  1026  	verifyCount(s, 2, t)
  1027  
  1028  	// Now make sure our shadowed results are correct after a removal.
  1029  	r = s.Match("foo")
  1030  	verifyLen(r.psubs, 0, t)
  1031  	verifyQLen(r.qsubs, 1, t)
  1032  	verifyLen(r.qsubs[0], 11, t)
  1033  
  1034  	// Now do an update to an existing remote sub to update its weight.
  1035  	rs2.qw = 1
  1036  	s.UpdateRemoteQSub(rs2)
  1037  
  1038  	// Results should reflect new weight.
  1039  	r = s.Match("foo")
  1040  	verifyLen(r.psubs, 0, t)
  1041  	verifyQLen(r.qsubs, 1, t)
  1042  	verifyLen(r.qsubs[0], 2, t)
  1043  }
  1044  
  1045  func TestSublistSharedEmptyResult(t *testing.T) {
  1046  	s := NewSublistWithCache()
  1047  	r1 := s.Match("foo")
  1048  	verifyLen(r1.psubs, 0, t)
  1049  	verifyQLen(r1.qsubs, 0, t)
  1050  
  1051  	r2 := s.Match("bar")
  1052  	verifyLen(r2.psubs, 0, t)
  1053  	verifyQLen(r2.qsubs, 0, t)
  1054  
  1055  	if r1 != r2 {
  1056  		t.Fatalf("Expected empty result to be a shared result set")
  1057  	}
  1058  }
  1059  
  1060  func TestSublistNoCacheStats(t *testing.T) {
  1061  	s := NewSublistNoCache()
  1062  	s.Insert(newSub("foo"))
  1063  	s.Insert(newSub("bar"))
  1064  	s.Insert(newSub("baz"))
  1065  	s.Insert(newSub("foo.bar.baz"))
  1066  	s.Match("a.b.c")
  1067  	s.Match("bar")
  1068  	stats := s.Stats()
  1069  	if stats.NumCache != 0 {
  1070  		t.Fatalf("Expected 0 for NumCache stat, got %d", stats.NumCache)
  1071  	}
  1072  }
  1073  
  1074  func TestSublistAll(t *testing.T) {
  1075  	s := NewSublistNoCache()
  1076  	subs := []*subscription{
  1077  		newSub("foo.bar.baz"),
  1078  		newSub("foo"),
  1079  		newSub("baz"),
  1080  	}
  1081  	// alter client's kind
  1082  	subs[0].client.kind = LEAF
  1083  	for _, sub := range subs {
  1084  		s.Insert(sub)
  1085  	}
  1086  
  1087  	var buf [32]*subscription
  1088  	output := buf[:0]
  1089  	s.All(&output)
  1090  	if len(output) != len(subs) {
  1091  		t.Fatalf("Expected %d for All, got %d", len(subs), len(output))
  1092  	}
  1093  }
  1094  
  1095  func TestIsSubsetMatch(t *testing.T) {
  1096  	for _, test := range []struct {
  1097  		subject string
  1098  		test    string
  1099  		result  bool
  1100  	}{
  1101  		{"foo.bar", "foo.bar", true},
  1102  		{"foo.*", ">", true},
  1103  		{"foo.*", "*.*", true},
  1104  		{"foo.*", "foo.*", true},
  1105  		{"foo.*", "foo.bar", false},
  1106  		{"foo.>", ">", true},
  1107  		{"foo.>", "*.>", true},
  1108  		{"foo.>", "foo.>", true},
  1109  		{"foo.>", "foo.bar", false},
  1110  		{"foo..bar", "foo.*", false}, // Bad subject, we return false
  1111  		{"foo.*", "foo..bar", false}, // Bad subject, we return false
  1112  	} {
  1113  		t.Run("", func(t *testing.T) {
  1114  			if res := subjectIsSubsetMatch(test.subject, test.test); res != test.result {
  1115  				t.Fatalf("Subject %q subset match of %q, should be %v, got %v",
  1116  					test.test, test.subject, test.result, res)
  1117  			}
  1118  		})
  1119  	}
  1120  }
  1121  
  1122  func TestSublistRegisterInterestNotification(t *testing.T) {
  1123  	s := NewSublistWithCache()
  1124  	ch := make(chan bool, 1)
  1125  
  1126  	expectErr := func(subject string) {
  1127  		if err := s.RegisterNotification("foo.*", ch); err != ErrInvalidSubject {
  1128  			t.Fatalf("Expected err, got %v", err)
  1129  		}
  1130  	}
  1131  
  1132  	// Test that we require a literal subject.
  1133  	expectErr("foo.*")
  1134  	expectErr(">")
  1135  
  1136  	// Chan needs to be non-nil
  1137  	if err := s.RegisterNotification("foo", nil); err != ErrNilChan {
  1138  		t.Fatalf("Expected err, got %v", err)
  1139  	}
  1140  
  1141  	// Clearing one that is not there will return false.
  1142  	if s.ClearNotification("foo", ch) {
  1143  		t.Fatalf("Expected to return false on non-existent notification entry")
  1144  	}
  1145  
  1146  	// This should work properly.
  1147  	if err := s.RegisterNotification("foo", ch); err != nil {
  1148  		t.Fatalf("Unexpected error: %v", err)
  1149  	}
  1150  
  1151  	tt := time.NewTimer(time.Second)
  1152  	expectBoolWithCh := func(ch chan bool, b bool) {
  1153  		t.Helper()
  1154  		tt.Reset(time.Second)
  1155  		defer tt.Stop()
  1156  		select {
  1157  		case v := <-ch:
  1158  			if v != b {
  1159  				t.Fatalf("Expected %v, got %v", b, v)
  1160  			}
  1161  		case <-tt.C:
  1162  			t.Fatalf("Timeout waiting for expected value")
  1163  		}
  1164  	}
  1165  	expectBool := func(b bool) {
  1166  		t.Helper()
  1167  		expectBoolWithCh(ch, b)
  1168  	}
  1169  	expectFalse := func() {
  1170  		t.Helper()
  1171  		expectBool(false)
  1172  	}
  1173  	expectTrue := func() {
  1174  		t.Helper()
  1175  		expectBool(true)
  1176  	}
  1177  	expectNone := func() {
  1178  		t.Helper()
  1179  		if lch := len(ch); lch != 0 {
  1180  			t.Fatalf("Expected no notifications, had %d and first was %v", lch, <-ch)
  1181  		}
  1182  	}
  1183  	expectOneWithCh := func(ch chan bool) {
  1184  		t.Helper()
  1185  		if len(ch) != 1 {
  1186  			t.Fatalf("Expected 1 notification")
  1187  		}
  1188  	}
  1189  	expectOne := func() {
  1190  		t.Helper()
  1191  		expectOneWithCh(ch)
  1192  	}
  1193  
  1194  	expectOne()
  1195  	expectFalse()
  1196  	sub := newSub("foo")
  1197  	s.Insert(sub)
  1198  	expectTrue()
  1199  
  1200  	sub2 := newSub("foo")
  1201  	s.Insert(sub2)
  1202  	expectNone()
  1203  
  1204  	if err := s.RegisterNotification("bar", ch); err != nil {
  1205  		t.Fatalf("Unexpected error: %v", err)
  1206  	}
  1207  	expectFalse()
  1208  
  1209  	sub3 := newSub("foo")
  1210  	s.Insert(sub3)
  1211  	expectNone()
  1212  
  1213  	// Now remove literals.
  1214  	s.Remove(sub)
  1215  	expectNone()
  1216  	s.Remove(sub2)
  1217  	expectNone()
  1218  	s.Remove(sub3)
  1219  	expectFalse()
  1220  
  1221  	if err := s.RegisterNotification("test.node", ch); err != nil {
  1222  		t.Fatalf("Unexpected error: %v", err)
  1223  	}
  1224  	expectOne()
  1225  	expectFalse()
  1226  
  1227  	tnSub1 := newSub("test.node.already.exist")
  1228  	s.Insert(tnSub1)
  1229  	expectNone()
  1230  
  1231  	tnSub2 := newSub("test.node")
  1232  	s.Insert(tnSub2)
  1233  	expectTrue()
  1234  
  1235  	tnSub3 := newSub("test.node")
  1236  	s.Insert(tnSub3)
  1237  	expectNone()
  1238  
  1239  	s.Remove(tnSub1)
  1240  	expectNone()
  1241  	s.Remove(tnSub2)
  1242  	expectNone()
  1243  	s.Remove(tnSub3)
  1244  	expectFalse()
  1245  
  1246  	if !s.ClearNotification("test.node", ch) {
  1247  		t.Fatalf("Expected to return true")
  1248  	}
  1249  
  1250  	sub4 := newSub("bar")
  1251  	s.Insert(sub4)
  1252  	expectTrue()
  1253  
  1254  	if !s.ClearNotification("bar", ch) {
  1255  		t.Fatalf("Expected to return true")
  1256  	}
  1257  	s.RLock()
  1258  	lnr := len(s.notify.remove)
  1259  	s.RUnlock()
  1260  	if lnr != 0 {
  1261  		t.Fatalf("Expected zero entries for remove notify, got %d", lnr)
  1262  	}
  1263  	if !s.ClearNotification("foo", ch) {
  1264  		t.Fatalf("Expected to return true")
  1265  	}
  1266  	s.RLock()
  1267  	notifyMap := s.notify
  1268  	s.RUnlock()
  1269  	if notifyMap != nil {
  1270  		t.Fatalf("Expected the notify map to be nil")
  1271  	}
  1272  
  1273  	// Let's do some wildcard checks.
  1274  	// Wildcards will not trigger interest.
  1275  	subpwc := newSub("*")
  1276  	s.Insert(subpwc)
  1277  	expectNone()
  1278  
  1279  	if err := s.RegisterNotification("foo", ch); err != nil {
  1280  		t.Fatalf("Unexpected error: %v", err)
  1281  	}
  1282  	expectFalse()
  1283  
  1284  	s.Insert(sub)
  1285  	expectTrue()
  1286  
  1287  	s.Remove(sub)
  1288  	expectFalse()
  1289  
  1290  	s.Remove(subpwc)
  1291  	expectNone()
  1292  
  1293  	subfwc := newSub(">")
  1294  	s.Insert(subfwc)
  1295  	expectNone()
  1296  
  1297  	s.Insert(subpwc)
  1298  	expectNone()
  1299  
  1300  	s.Remove(subpwc)
  1301  	expectNone()
  1302  
  1303  	s.Remove(subfwc)
  1304  	expectNone()
  1305  
  1306  	// Test batch
  1307  	subs := []*subscription{sub, sub2, sub3, sub4, subpwc, subfwc}
  1308  	for _, sub := range subs {
  1309  		s.Insert(sub)
  1310  	}
  1311  	expectTrue()
  1312  
  1313  	s.RemoveBatch(subs)
  1314  	expectOne()
  1315  	expectFalse()
  1316  
  1317  	// Test queue subs
  1318  	// We know make sure that if you have qualified a queue group it has to match, etc.
  1319  	// Also if you do not specify one they will not trigger.
  1320  	qsub := newQSub("foo.bar.baz", "1")
  1321  	s.Insert(qsub)
  1322  	expectNone()
  1323  
  1324  	if err := s.RegisterNotification("foo.bar.baz", ch); err != nil {
  1325  		t.Fatalf("Unexpected error: %v", err)
  1326  	}
  1327  	expectFalse()
  1328  
  1329  	wcqsub := newQSub("foo.bar.>", "1")
  1330  	s.Insert(wcqsub)
  1331  	expectNone()
  1332  
  1333  	s.Remove(qsub)
  1334  	expectNone()
  1335  
  1336  	s.Remove(wcqsub)
  1337  	expectNone()
  1338  
  1339  	s.Insert(wcqsub)
  1340  	expectNone()
  1341  
  1342  	if err := s.RegisterQueueNotification("queue.test.node", "q22", ch); err != nil {
  1343  		t.Fatalf("Unexpected error: %v", err)
  1344  	}
  1345  	expectOne()
  1346  	expectFalse()
  1347  
  1348  	qsub1 := newQSub("queue.test.node.already.exist", "queue")
  1349  	s.Insert(qsub1)
  1350  	expectNone()
  1351  
  1352  	qsub2 := newQSub("queue.test.node", "q22")
  1353  	s.Insert(qsub2)
  1354  	expectTrue()
  1355  
  1356  	qsub3 := newQSub("queue.test.node", "otherqueue")
  1357  	s.Insert(qsub3)
  1358  	expectNone()
  1359  
  1360  	qsub4 := newQSub("queue.different.node", "q22")
  1361  	s.Insert(qsub4)
  1362  	expectNone()
  1363  
  1364  	qsub5 := newQSub("queue.test.node", "q22")
  1365  	s.Insert(qsub5)
  1366  	expectNone()
  1367  
  1368  	s.Remove(qsub3)
  1369  	expectNone()
  1370  	s.Remove(qsub1)
  1371  	expectNone()
  1372  	s.Remove(qsub2)
  1373  	expectNone()
  1374  	s.Remove(qsub4)
  1375  	expectNone()
  1376  	s.Remove(qsub5)
  1377  	expectFalse()
  1378  
  1379  	if !s.ClearQueueNotification("queue.test.node", "q22", ch) {
  1380  		t.Fatalf("Expected to return true")
  1381  	}
  1382  
  1383  	if err := s.RegisterQueueNotification("some.subject", "queue1", ch); err != nil {
  1384  		t.Fatalf("Unexpected error: %v", err)
  1385  	}
  1386  	expectOne()
  1387  	expectFalse()
  1388  
  1389  	qsub1 = newQSub("some.subject", "queue1")
  1390  	s.Insert(qsub1)
  1391  	expectTrue()
  1392  
  1393  	// Create a second channel for this other queue
  1394  	ch2 := make(chan bool, 1)
  1395  	if err := s.RegisterQueueNotification("some.subject", "queue2", ch2); err != nil {
  1396  		t.Fatalf("Unexpected error: %v", err)
  1397  	}
  1398  	expectOneWithCh(ch2)
  1399  	expectBoolWithCh(ch2, false)
  1400  
  1401  	qsub2 = newQSub("some.subject", "queue2")
  1402  	s.Insert(qsub2)
  1403  	expectBoolWithCh(ch2, true)
  1404  
  1405  	// But we should not get notification on queue1
  1406  	expectNone()
  1407  
  1408  	s.Remove(qsub1)
  1409  	expectFalse()
  1410  	s.Remove(qsub2)
  1411  	expectBoolWithCh(ch2, false)
  1412  
  1413  	if !s.ClearQueueNotification("some.subject", "queue1", ch) {
  1414  		t.Fatalf("Expected to return true")
  1415  	}
  1416  	if !s.ClearQueueNotification("some.subject", "queue2", ch2) {
  1417  		t.Fatalf("Expected to return true")
  1418  	}
  1419  
  1420  	// Test non-blocking notifications.
  1421  	if err := s.RegisterNotification("bar", ch); err != nil {
  1422  		t.Fatalf("Unexpected error: %v", err)
  1423  	}
  1424  
  1425  	if err := s.RegisterNotification("baz", ch); err != nil {
  1426  		t.Fatalf("Unexpected error: %v", err)
  1427  	}
  1428  
  1429  	s.Insert(newSub("baz"))
  1430  	s.Insert(newSub("bar"))
  1431  	s.Insert(subpwc)
  1432  	expectOne()
  1433  	expectFalse()
  1434  }
  1435  
  1436  func TestSublistReverseMatch(t *testing.T) {
  1437  	s := NewSublistWithCache()
  1438  	fooSub := newSub("foo")
  1439  	barSub := newSub("bar")
  1440  	fooBarSub := newSub("foo.bar")
  1441  	fooBazSub := newSub("foo.baz")
  1442  	fooBarBazSub := newSub("foo.bar.baz")
  1443  	s.Insert(fooSub)
  1444  	s.Insert(barSub)
  1445  	s.Insert(fooBarSub)
  1446  	s.Insert(fooBazSub)
  1447  	s.Insert(fooBarBazSub)
  1448  
  1449  	r := s.ReverseMatch("foo")
  1450  	verifyLen(r.psubs, 1, t)
  1451  	verifyMember(r.psubs, fooSub, t)
  1452  
  1453  	r = s.ReverseMatch("bar")
  1454  	verifyLen(r.psubs, 1, t)
  1455  	verifyMember(r.psubs, barSub, t)
  1456  
  1457  	r = s.ReverseMatch("*")
  1458  	verifyLen(r.psubs, 2, t)
  1459  	verifyMember(r.psubs, fooSub, t)
  1460  	verifyMember(r.psubs, barSub, t)
  1461  
  1462  	r = s.ReverseMatch("baz")
  1463  	verifyLen(r.psubs, 0, t)
  1464  
  1465  	r = s.ReverseMatch("foo.*")
  1466  	verifyLen(r.psubs, 2, t)
  1467  	verifyMember(r.psubs, fooBarSub, t)
  1468  	verifyMember(r.psubs, fooBazSub, t)
  1469  
  1470  	r = s.ReverseMatch("*.*")
  1471  	verifyLen(r.psubs, 2, t)
  1472  	verifyMember(r.psubs, fooBarSub, t)
  1473  	verifyMember(r.psubs, fooBazSub, t)
  1474  
  1475  	r = s.ReverseMatch("*.bar")
  1476  	verifyLen(r.psubs, 1, t)
  1477  	verifyMember(r.psubs, fooBarSub, t)
  1478  
  1479  	r = s.ReverseMatch("*.baz")
  1480  	verifyLen(r.psubs, 1, t)
  1481  	verifyMember(r.psubs, fooBazSub, t)
  1482  
  1483  	r = s.ReverseMatch("bar.*")
  1484  	verifyLen(r.psubs, 0, t)
  1485  
  1486  	r = s.ReverseMatch("*.bat")
  1487  	verifyLen(r.psubs, 0, t)
  1488  
  1489  	r = s.ReverseMatch("foo.>")
  1490  	verifyLen(r.psubs, 3, t)
  1491  	verifyMember(r.psubs, fooBarSub, t)
  1492  	verifyMember(r.psubs, fooBazSub, t)
  1493  	verifyMember(r.psubs, fooBarBazSub, t)
  1494  
  1495  	r = s.ReverseMatch(">")
  1496  	verifyLen(r.psubs, 5, t)
  1497  	verifyMember(r.psubs, fooSub, t)
  1498  	verifyMember(r.psubs, barSub, t)
  1499  	verifyMember(r.psubs, fooBarSub, t)
  1500  	verifyMember(r.psubs, fooBazSub, t)
  1501  	verifyMember(r.psubs, fooBarBazSub, t)
  1502  }
  1503  
  1504  func TestSublistReverseMatchWider(t *testing.T) {
  1505  	s := NewSublistWithCache()
  1506  	sub := newSub("uplink.*.*.>")
  1507  	s.Insert(sub)
  1508  
  1509  	r := s.ReverseMatch("uplink.1.*.*.>")
  1510  	verifyLen(r.psubs, 1, t)
  1511  	verifyMember(r.psubs, sub, t)
  1512  
  1513  	r = s.ReverseMatch("uplink.1.2.3.>")
  1514  	verifyLen(r.psubs, 1, t)
  1515  	verifyMember(r.psubs, sub, t)
  1516  }
  1517  
  1518  func TestSublistMatchWithEmptyTokens(t *testing.T) {
  1519  	for _, test := range []struct {
  1520  		name  string
  1521  		cache bool
  1522  	}{
  1523  		{"cache", true},
  1524  		{"no cache", false},
  1525  	} {
  1526  		t.Run(test.name, func(t *testing.T) {
  1527  			sl := NewSublist(true)
  1528  			sub1 := newSub(">")
  1529  			sub2 := newQSub(">", "queue")
  1530  			sl.Insert(sub1)
  1531  			sl.Insert(sub2)
  1532  
  1533  			for _, subj := range []string{".foo", "..foo", "foo..", "foo.", "foo..bar", "foo...bar"} {
  1534  				t.Run(subj, func(t *testing.T) {
  1535  					r := sl.Match(subj)
  1536  					verifyLen(r.psubs, 0, t)
  1537  					verifyQLen(r.qsubs, 0, t)
  1538  				})
  1539  			}
  1540  		})
  1541  	}
  1542  }
  1543  
  1544  func TestSublistSubjectCollide(t *testing.T) {
  1545  	require_False(t, SubjectsCollide("foo.*", "foo.*.bar.>"))
  1546  	require_False(t, SubjectsCollide("foo.*.bar.>", "foo.*"))
  1547  	require_True(t, SubjectsCollide("foo.*", "foo.foo"))
  1548  	require_True(t, SubjectsCollide("foo.*", "*.foo"))
  1549  	require_True(t, SubjectsCollide("foo.bar.>", "*.bar.foo"))
  1550  }
  1551  
  1552  func TestSublistAddCacheHitRate(t *testing.T) {
  1553  	sl1 := NewSublistWithCache()
  1554  	fooSub := newSub("foo")
  1555  	sl1.Insert(fooSub)
  1556  	for i := 0; i < 4; i++ {
  1557  		sl1.Match("foo")
  1558  	}
  1559  	stats1 := sl1.Stats()
  1560  	require_True(t, stats1.CacheHitRate == 0.75)
  1561  
  1562  	sl2 := NewSublistWithCache()
  1563  	barSub := newSub("bar")
  1564  	sl2.Insert(barSub)
  1565  	for i := 0; i < 4; i++ {
  1566  		sl2.Match("bar")
  1567  	}
  1568  	stats2 := sl2.Stats()
  1569  	require_True(t, stats2.CacheHitRate == 0.75)
  1570  
  1571  	ts := &SublistStats{}
  1572  	ts.add(stats1)
  1573  	ts.add(stats2)
  1574  	require_True(t, ts.CacheHitRate == 0.75)
  1575  }
  1576  
  1577  // -- Benchmarks Setup --
  1578  
  1579  var benchSublistSubs []*subscription
  1580  var benchSublistSl = NewSublistWithCache()
  1581  
  1582  // https://github.com/golang/go/issues/31859
  1583  func TestMain(m *testing.M) {
  1584  	flag.StringVar(&testDefaultClusterCompression, "cluster_compression", _EMPTY_, "Test with this compression level as the default")
  1585  	flag.StringVar(&testDefaultLeafNodeCompression, "leafnode_compression", _EMPTY_, "Test with this compression level as the default")
  1586  	flag.Parse()
  1587  	initSublist := false
  1588  	flag.Visit(func(f *flag.Flag) {
  1589  		if f.Name == "test.bench" {
  1590  			initSublist = true
  1591  		}
  1592  	})
  1593  	if initSublist {
  1594  		benchSublistSubs = make([]*subscription, 0, 256*1024)
  1595  		toks := []string{"synadia", "nats", "jetstream", "nkeys", "jwt", "deny", "auth", "drain"}
  1596  		subsInit("", toks)
  1597  		for i := 0; i < len(benchSublistSubs); i++ {
  1598  			benchSublistSl.Insert(benchSublistSubs[i])
  1599  		}
  1600  		addWildcards()
  1601  	}
  1602  	os.Exit(m.Run())
  1603  }
  1604  
  1605  func subsInit(pre string, toks []string) {
  1606  	var sub string
  1607  	for _, t := range toks {
  1608  		if len(pre) > 0 {
  1609  			sub = pre + tsep + t
  1610  		} else {
  1611  			sub = t
  1612  		}
  1613  		benchSublistSubs = append(benchSublistSubs, newSub(sub))
  1614  		if len(strings.Split(sub, tsep)) < 5 {
  1615  			subsInit(sub, toks)
  1616  		}
  1617  	}
  1618  }
  1619  
  1620  func addWildcards() {
  1621  	benchSublistSl.Insert(newSub("cloud.>"))
  1622  	benchSublistSl.Insert(newSub("cloud.nats.component.>"))
  1623  	benchSublistSl.Insert(newSub("cloud.*.*.nkeys.*"))
  1624  }
  1625  
  1626  // -- Benchmarks Setup End --
  1627  
  1628  func Benchmark______________________SublistInsert(b *testing.B) {
  1629  	s := NewSublistWithCache()
  1630  	for i, l := 0, len(benchSublistSubs); i < b.N; i++ {
  1631  		index := i % l
  1632  		s.Insert(benchSublistSubs[index])
  1633  	}
  1634  }
  1635  
  1636  func Benchmark_______________SublistInsertNoCache(b *testing.B) {
  1637  	s := NewSublistNoCache()
  1638  	for i, l := 0, len(benchSublistSubs); i < b.N; i++ {
  1639  		index := i % l
  1640  		s.Insert(benchSublistSubs[index])
  1641  	}
  1642  }
  1643  
  1644  func benchSublistTokens(b *testing.B, tokens string) {
  1645  	for i := 0; i < b.N; i++ {
  1646  		benchSublistSl.Match(tokens)
  1647  	}
  1648  }
  1649  
  1650  func Benchmark____________SublistMatchSingleToken(b *testing.B) {
  1651  	benchSublistTokens(b, "synadia")
  1652  }
  1653  
  1654  func Benchmark______________SublistMatchTwoTokens(b *testing.B) {
  1655  	benchSublistTokens(b, "synadia.nats")
  1656  }
  1657  
  1658  func Benchmark____________SublistMatchThreeTokens(b *testing.B) {
  1659  	benchSublistTokens(b, "synadia.nats.jetstream")
  1660  }
  1661  
  1662  func Benchmark_____________SublistMatchFourTokens(b *testing.B) {
  1663  	benchSublistTokens(b, "synadia.nats.jetstream.nkeys")
  1664  }
  1665  
  1666  func Benchmark_SublistMatchFourTokensSingleResult(b *testing.B) {
  1667  	benchSublistTokens(b, "synadia.nats.jetstream.nkeys")
  1668  }
  1669  
  1670  func Benchmark_SublistMatchFourTokensMultiResults(b *testing.B) {
  1671  	benchSublistTokens(b, "cloud.nats.component.router")
  1672  }
  1673  
  1674  func Benchmark_______SublistMissOnLastTokenOfFive(b *testing.B) {
  1675  	benchSublistTokens(b, "synadia.nats.jetstream.nkeys.ZZZZ")
  1676  }
  1677  
  1678  func multiRead(b *testing.B, num int) {
  1679  	var swg, fwg sync.WaitGroup
  1680  	swg.Add(num)
  1681  	fwg.Add(num)
  1682  	s := "synadia.nats.jetstream.nkeys"
  1683  	for i := 0; i < num; i++ {
  1684  		go func() {
  1685  			swg.Done()
  1686  			swg.Wait()
  1687  			n := b.N / num
  1688  			for i := 0; i < n; i++ {
  1689  				benchSublistSl.Match(s)
  1690  			}
  1691  			fwg.Done()
  1692  		}()
  1693  	}
  1694  	swg.Wait()
  1695  	b.ResetTimer()
  1696  	fwg.Wait()
  1697  }
  1698  
  1699  func Benchmark____________Sublist10XMultipleReads(b *testing.B) {
  1700  	multiRead(b, 10)
  1701  }
  1702  
  1703  func Benchmark___________Sublist100XMultipleReads(b *testing.B) {
  1704  	multiRead(b, 100)
  1705  }
  1706  
  1707  func Benchmark__________Sublist1000XMultipleReads(b *testing.B) {
  1708  	multiRead(b, 1000)
  1709  }
  1710  
  1711  func Benchmark________________SublistMatchLiteral(b *testing.B) {
  1712  	cachedSubj := "foo.foo.foo.foo.foo.foo.foo.foo.foo.foo"
  1713  	subjects := []string{
  1714  		"foo.foo.foo.foo.foo.foo.foo.foo.foo.foo",
  1715  		"foo.foo.foo.foo.foo.foo.foo.foo.foo.>",
  1716  		"foo.foo.foo.foo.foo.foo.foo.foo.>",
  1717  		"foo.foo.foo.foo.foo.foo.foo.>",
  1718  		"foo.foo.foo.foo.foo.foo.>",
  1719  		"foo.foo.foo.foo.foo.>",
  1720  		"foo.foo.foo.foo.>",
  1721  		"foo.foo.foo.>",
  1722  		"foo.foo.>",
  1723  		"foo.>",
  1724  		">",
  1725  		"foo.foo.foo.foo.foo.foo.foo.foo.foo.*",
  1726  		"foo.foo.foo.foo.foo.foo.foo.foo.*.*",
  1727  		"foo.foo.foo.foo.foo.foo.foo.*.*.*",
  1728  		"foo.foo.foo.foo.foo.foo.*.*.*.*",
  1729  		"foo.foo.foo.foo.foo.*.*.*.*.*",
  1730  		"foo.foo.foo.foo.*.*.*.*.*.*",
  1731  		"foo.foo.foo.*.*.*.*.*.*.*",
  1732  		"foo.foo.*.*.*.*.*.*.*.*",
  1733  		"foo.*.*.*.*.*.*.*.*.*",
  1734  		"*.*.*.*.*.*.*.*.*.*",
  1735  	}
  1736  	b.ResetTimer()
  1737  	for i := 0; i < b.N; i++ {
  1738  		for _, subject := range subjects {
  1739  			if !matchLiteral(cachedSubj, subject) {
  1740  				b.Fatalf("Subject %q no match with %q", cachedSubj, subject)
  1741  			}
  1742  		}
  1743  	}
  1744  }
  1745  
  1746  func Benchmark_____SublistMatch10kSubsWithNoCache(b *testing.B) {
  1747  	var nsubs = 512
  1748  	s := NewSublistNoCache()
  1749  	subject := "foo"
  1750  	for i := 0; i < nsubs; i++ {
  1751  		s.Insert(newSub(subject))
  1752  	}
  1753  	b.ResetTimer()
  1754  	for i := 0; i < b.N; i++ {
  1755  		r := s.Match(subject)
  1756  		if len(r.psubs) != nsubs {
  1757  			b.Fatalf("Results len is %d, should be %d", len(r.psubs), nsubs)
  1758  		}
  1759  	}
  1760  }
  1761  
  1762  func removeTest(b *testing.B, singleSubject, doBatch bool, qgroup string) {
  1763  	s := NewSublistWithCache()
  1764  	subject := "foo"
  1765  
  1766  	subs := make([]*subscription, 0, b.N)
  1767  	for i := 0; i < b.N; i++ {
  1768  		var sub *subscription
  1769  		if singleSubject {
  1770  			sub = newQSub(subject, qgroup)
  1771  		} else {
  1772  			sub = newQSub(fmt.Sprintf("%s.%d\n", subject, i), qgroup)
  1773  		}
  1774  		s.Insert(sub)
  1775  		subs = append(subs, sub)
  1776  	}
  1777  
  1778  	// Actual test on Remove
  1779  	b.ResetTimer()
  1780  	if doBatch {
  1781  		s.RemoveBatch(subs)
  1782  	} else {
  1783  		for _, sub := range subs {
  1784  			s.Remove(sub)
  1785  		}
  1786  	}
  1787  }
  1788  
  1789  func Benchmark__________SublistRemove1TokenSingle(b *testing.B) {
  1790  	removeTest(b, true, false, "")
  1791  }
  1792  
  1793  func Benchmark___________SublistRemove1TokenBatch(b *testing.B) {
  1794  	removeTest(b, true, true, "")
  1795  }
  1796  
  1797  func Benchmark_________SublistRemove2TokensSingle(b *testing.B) {
  1798  	removeTest(b, false, false, "")
  1799  }
  1800  
  1801  func Benchmark__________SublistRemove2TokensBatch(b *testing.B) {
  1802  	removeTest(b, false, true, "")
  1803  }
  1804  
  1805  func Benchmark________SublistRemove1TokenQGSingle(b *testing.B) {
  1806  	removeTest(b, true, false, "bar")
  1807  }
  1808  
  1809  func Benchmark_________SublistRemove1TokenQGBatch(b *testing.B) {
  1810  	removeTest(b, true, true, "bar")
  1811  }
  1812  
  1813  func removeMultiTest(b *testing.B, singleSubject, doBatch bool) {
  1814  	s := NewSublistWithCache()
  1815  	subject := "foo"
  1816  	var swg, fwg sync.WaitGroup
  1817  	swg.Add(b.N)
  1818  	fwg.Add(b.N)
  1819  
  1820  	// We will have b.N go routines each with 1k subscriptions.
  1821  	sc := 1000
  1822  
  1823  	for i := 0; i < b.N; i++ {
  1824  		go func() {
  1825  			subs := make([]*subscription, 0, sc)
  1826  			for n := 0; n < sc; n++ {
  1827  				var sub *subscription
  1828  				if singleSubject {
  1829  					sub = newSub(subject)
  1830  				} else {
  1831  					sub = newSub(fmt.Sprintf("%s.%d\n", subject, n))
  1832  				}
  1833  				s.Insert(sub)
  1834  				subs = append(subs, sub)
  1835  			}
  1836  			// Wait to start test
  1837  			swg.Done()
  1838  			swg.Wait()
  1839  			// Actual test on Remove
  1840  			if doBatch {
  1841  				s.RemoveBatch(subs)
  1842  			} else {
  1843  				for _, sub := range subs {
  1844  					s.Remove(sub)
  1845  				}
  1846  			}
  1847  			fwg.Done()
  1848  		}()
  1849  	}
  1850  	swg.Wait()
  1851  	b.ResetTimer()
  1852  	fwg.Wait()
  1853  }
  1854  
  1855  // Check contention rates for remove from multiple Go routines.
  1856  // Reason for BatchRemove.
  1857  func Benchmark_________SublistRemove1kSingleMulti(b *testing.B) {
  1858  	removeMultiTest(b, true, false)
  1859  }
  1860  
  1861  // Batch version
  1862  func Benchmark__________SublistRemove1kBatchMulti(b *testing.B) {
  1863  	removeMultiTest(b, true, true)
  1864  }
  1865  
  1866  func Benchmark__SublistRemove1kSingle2TokensMulti(b *testing.B) {
  1867  	removeMultiTest(b, false, false)
  1868  }
  1869  
  1870  // Batch version
  1871  func Benchmark___SublistRemove1kBatch2TokensMulti(b *testing.B) {
  1872  	removeMultiTest(b, false, true)
  1873  }
  1874  
  1875  // Cache contention tests
  1876  func cacheContentionTest(b *testing.B, numMatchers, numAdders, numRemovers int) {
  1877  	var swg, fwg, mwg sync.WaitGroup
  1878  	total := numMatchers + numAdders + numRemovers
  1879  	swg.Add(total)
  1880  	fwg.Add(total)
  1881  	mwg.Add(numMatchers)
  1882  
  1883  	mu := sync.RWMutex{}
  1884  	subs := make([]*subscription, 0, 8192)
  1885  
  1886  	quitCh := make(chan struct{})
  1887  
  1888  	// Set up a new sublist. subjects will be foo.bar.baz.N
  1889  	s := NewSublistWithCache()
  1890  	mu.Lock()
  1891  	for i := 0; i < 10000; i++ {
  1892  		sub := newSub(fmt.Sprintf("foo.bar.baz.%d", i))
  1893  		s.Insert(sub)
  1894  		subs = append(subs, sub)
  1895  	}
  1896  	mu.Unlock()
  1897  
  1898  	// Now warm up the cache
  1899  	for i := 0; i < slCacheMax; i++ {
  1900  		s.Match(fmt.Sprintf("foo.bar.baz.%d", i))
  1901  	}
  1902  
  1903  	// Setup go routines.
  1904  
  1905  	// Adders
  1906  	for i := 0; i < numAdders; i++ {
  1907  		go func() {
  1908  			swg.Done()
  1909  			swg.Wait()
  1910  			for {
  1911  				select {
  1912  				case <-quitCh:
  1913  					fwg.Done()
  1914  					return
  1915  				default:
  1916  					mu.Lock()
  1917  					next := len(subs)
  1918  					subj := "foo.bar.baz." + strconv.FormatInt(int64(next), 10)
  1919  					sub := newSub(subj)
  1920  					subs = append(subs, sub)
  1921  					mu.Unlock()
  1922  					s.Insert(sub)
  1923  				}
  1924  			}
  1925  		}()
  1926  	}
  1927  
  1928  	// Removers
  1929  	for i := 0; i < numRemovers; i++ {
  1930  		go func() {
  1931  			prand := rand.New(rand.NewSource(time.Now().UnixNano()))
  1932  			swg.Done()
  1933  			swg.Wait()
  1934  			for {
  1935  				select {
  1936  				case <-quitCh:
  1937  					fwg.Done()
  1938  					return
  1939  				default:
  1940  					mu.RLock()
  1941  					lh := len(subs) - 1
  1942  					index := prand.Intn(lh)
  1943  					sub := subs[index]
  1944  					mu.RUnlock()
  1945  					s.Remove(sub)
  1946  				}
  1947  			}
  1948  		}()
  1949  	}
  1950  
  1951  	// Matchers
  1952  	for i := 0; i < numMatchers; i++ {
  1953  		go func() {
  1954  			id := nuid.New()
  1955  			swg.Done()
  1956  			swg.Wait()
  1957  
  1958  			// We will miss on purpose to blow the cache.
  1959  			n := b.N / numMatchers
  1960  			for i := 0; i < n; i++ {
  1961  				subj := "foo.bar.baz." + id.Next()
  1962  				s.Match(subj)
  1963  			}
  1964  			mwg.Done()
  1965  			fwg.Done()
  1966  		}()
  1967  	}
  1968  
  1969  	swg.Wait()
  1970  	b.ResetTimer()
  1971  	mwg.Wait()
  1972  	b.StopTimer()
  1973  	close(quitCh)
  1974  	fwg.Wait()
  1975  }
  1976  
  1977  func Benchmark____SublistCacheContention10M10A10R(b *testing.B) {
  1978  	cacheContentionTest(b, 10, 10, 10)
  1979  }
  1980  
  1981  func Benchmark_SublistCacheContention100M100A100R(b *testing.B) {
  1982  	cacheContentionTest(b, 100, 100, 100)
  1983  }
  1984  
  1985  func Benchmark____SublistCacheContention1kM1kA1kR(b *testing.B) {
  1986  	cacheContentionTest(b, 1024, 1024, 1024)
  1987  }
  1988  
  1989  func Benchmark_SublistCacheContention10kM10kA10kR(b *testing.B) {
  1990  	cacheContentionTest(b, 10*1024, 10*1024, 10*1024)
  1991  }
  1992  
  1993  func Benchmark______________IsValidLiteralSubject(b *testing.B) {
  1994  	for i := 0; i < b.N; i++ {
  1995  		IsValidLiteralSubject("foo.bar.baz.22")
  1996  	}
  1997  }
  1998  
  1999  func Benchmark___________________subjectIsLiteral(b *testing.B) {
  2000  	for i := 0; i < b.N; i++ {
  2001  		subjectIsLiteral("foo.bar.baz.22")
  2002  	}
  2003  }