Repository: nats-io/nats-server
Pull request #3232 (2022-06-30 21:08:49)

Close leafnode connection when same cluster name detected
Signed-off-by: Derek Collison <derek@nats.io>

/cc @nats-io/core


derekcollison: Fixed test. 
kozlovic: This test seem to fail too, is that the one that was fixed? 
```
=== RUN   TestClientClampMaxSubsErrReport
    client_test.go:2534: Expected 1 connected leafnode(s) for server "NCZSORUN25U6ESFJWOYBYBFGSR62NZJLHN7BWUNBZJ2EKIVCIBWGREP5", got 0
--- FAIL: TestClientClampMaxSubsErrReport (5.06s)
```
derekcollison: Will squash once green then merge.

Patch:
diff --git a/server/accounts.go b/server/accounts.go
index 4b584fea..e2b24658 100644
--- a/server/accounts.go
+++ b/server/accounts.go
@@ -617,9 +617,8 @@ func (a *Account) AddWeightedMappings(src string, dests ...*MapDest) error {
 		if tw > 100 {
 			return fmt.Errorf("total weight needs to be <= 100")
 		}
-		err := ValidateMappingDestination(d.Subject)
-		if err != nil {
-			return err
+		if !IsValidSubject(d.Subject) {
+			return ErrBadSubject
 		}
 		tr, err := newTransform(src, d.Subject)
 		if err != nil {
@@ -4190,41 +4189,33 @@ func placeHolderIndex(token string) ([]int, int32, error) {
 			return []int{tp}, -1, nil
 		}
 
-		// New 'mustache' style mapping
+		// New 'moustache' style mapping
 		// wildcard(wildcard token index) (equivalent to $)
 		args := getMappingFunctionArgs(wildcardMappingFunctionRegEx, token)
 		if args != nil {
-			if len(args) == 1 && args[0] == _EMPTY_ {
-				return []int{-1}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
-			}
 			if len(args) == 1 {
 				tp, err := strconv.Atoi(strings.Trim(args[0], " "))
 				if err != nil {
-					return []int{}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
+					return []int{}, -1, err
 				}
 				return []int{tp}, -1, nil
-			} else {
-				return []int{}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionTooManyArguments}
 			}
 		}
 
 		// partition(number of partitions, token1, token2, ...)
 		args = getMappingFunctionArgs(partitionMappingFunctionRegEx, token)
 		if args != nil {
-			if len(args) < 2 {
-				return []int{-1}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
-			}
 			if len(args) >= 2 {
 				tphnp, err := strconv.Atoi(strings.Trim(args[0], " "))
 				if err != nil {
-					return []int{}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
+					return []int{}, -1, err
 				}
 				var numPositions = len(args[1:])
 				tps := make([]int, numPositions)
 				for ti, t := range args[1:] {
 					i, err := strconv.Atoi(strings.Trim(t, " "))
 					if err != nil {
-						return []int{}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
+						return []int{}, -1, err
 					}
 					tps[ti] = i
 				}
@@ -4277,7 +4268,7 @@ func newTransform(src, dest string) (*transform, error) {
 		for _, token := range dtokens {
 			tp, nb, err := placeHolderIndex(token)
 			if err != nil {
-				return nil, err
+				return nil, ErrBadSubjectMappingDestination
 			}
 			if tp[0] >= 0 {
 				nphs++
@@ -4285,7 +4276,7 @@ func newTransform(src, dest string) (*transform, error) {
 				var stis []int
 				for _, position := range tp {
 					if position > npwcs {
-						return nil, &mappingDestinationErr{fmt.Sprintf("%s: [%d]", token, position), ErrorMappingDestinationFunctionWildcardIndexOutOfRange}
+						return nil, ErrBadSubjectMappingDestination
 					}
 					stis = append(stis, sti[position])
 				}
@@ -4297,8 +4288,7 @@ func newTransform(src, dest string) (*transform, error) {
 			}
 		}
 		if nphs < npwcs {
-			// not all wildcards are being used in the destination
-			return nil, &mappingDestinationErr{dest, ErrMappingDestinationNotUsingAllWildcards}
+			return nil, ErrBadSubjectMappingDestination
 		}
 	}
 
diff --git a/server/client.go b/server/client.go
index 8f3e19b6..3b86af09 100644
--- a/server/client.go
+++ b/server/client.go
@@ -206,6 +206,7 @@ const (
 	DuplicateClientID
 	DuplicateServerName
 	MinimumVersionRequired
+	ClusterNamesIdentical
 )
 
 // Some flags passed to processMsgResults
diff --git a/server/errors.go b/server/errors.go
index b82a0f5b..91dbcfbd 100644
--- a/server/errors.go
+++ b/server/errors.go
@@ -46,6 +46,9 @@ var (
 	// ErrBadSubject represents an error condition for an invalid subject.
 	ErrBadSubject = errors.New("invalid subject")
 
+	// ErrBadSubjectMappingDestination is used to error on a bad transform destination mapping
+	ErrBadSubjectMappingDestination = errors.New("invalid subject mapping destination")
+
 	// ErrBadQualifier is used to error on a bad qualifier for a transform.
 	ErrBadQualifier = errors.New("bad qualifier")
 
@@ -75,6 +78,10 @@ var (
 	// attempted to connect to the leaf node listen port.
 	ErrClientConnectedToLeafNodePort = errors.New("attempted to connect to leaf node port")
 
+	// ErrLeafNodeHasSameClusterName represents an error condition when a leafnode is a cluster
+	// and it has the same cluster name as the hub cluster.
+	ErrLeafNodeHasSameClusterName = errors.New("remote leafnode has same cluster name")
+
 	// ErrConnectedToWrongPort represents an error condition when a connection is attempted
 	// to the wrong listen port (for instance a LeafNode to a client port, etc...)
 	ErrConnectedToWrongPort = errors.New("attempted to connect to wrong port")
@@ -188,46 +195,8 @@ var (
 
 	// ErrMinimumVersionRequired is returned when a connection is not at the minimum version required.
 	ErrMinimumVersionRequired = errors.New("minimum version required")
-
-	// ErrInvalidMappingDestination is used for all subject mapping destination errors
-	ErrInvalidMappingDestination = errors.New("invalid mapping destination")
-
-	// ErrInvalidMappingDestinationSubject is used to error on a bad transform destination mapping
-	ErrInvalidMappingDestinationSubject = fmt.Errorf("%w: invalid subject", ErrInvalidMappingDestination)
-
-	// ErrMappingDestinationNotUsingAllWildcards is used to error on a transform destination not using all of the token wildcards
-	ErrMappingDestinationNotUsingAllWildcards = fmt.Errorf("%w: not using all of the token wildcard(s)", ErrInvalidMappingDestination)
-
-	// ErrUnknownMappingDestinationFunction is returned when a subject mapping destination contains an unknown mustache-escaped mapping function.
-	ErrUnknownMappingDestinationFunction = fmt.Errorf("%w: unknown function", ErrInvalidMappingDestination)
-
-	// ErrorMappingDestinationFunctionWildcardIndexOutOfRange is returned when the mapping destination function is passed an out of range wildcard index value for one of it's arguments
-	ErrorMappingDestinationFunctionWildcardIndexOutOfRange = fmt.Errorf("%w: wildcard index out of range", ErrInvalidMappingDestination)
-
-	// ErrorMappingDestinationFunctionNotEnoughArguments is returned when the mapping destination function is not passed enough arguments
-	ErrorMappingDestinationFunctionNotEnoughArguments = fmt.Errorf("%w: not enough arguments passed to the function", ErrInvalidMappingDestination)
-
-	// ErrorMappingDestinationFunctionInvalidArgument is returned when the mapping destination function is passed and invalid argument
-	ErrorMappingDestinationFunctionInvalidArgument = fmt.Errorf("%w: function argument is invalid or in the wrong format", ErrInvalidMappingDestination)
-
-	// ErrorMappingDestinationFunctionTooManyArguments is returned when the mapping destination function is passed too many arguments
-	ErrorMappingDestinationFunctionTooManyArguments = fmt.Errorf("%w: too many arguments passed to the function", ErrInvalidMappingDestination)
 )
 
-// mappingDestinationErr is a type of subject mapping destination error
-type mappingDestinationErr struct {
-	token string
-	err   error
-}
-
-func (e *mappingDestinationErr) Error() string {
-	return fmt.Sprintf("%s in %s", e.err, e.token)
-}
-
-func (e *mappingDestinationErr) Is(target error) bool {
-	return target == ErrInvalidMappingDestination
-}
-
 // configErr is a configuration error.
 type configErr struct {
 	token  token
diff --git a/server/leafnode.go b/server/leafnode.go
index 78adef19..c3e2dfd3 100644
--- a/server/leafnode.go
+++ b/server/leafnode.go
@@ -1,4 +1,4 @@
-// Copyright 2019-2021 The NATS Authors
+// Copyright 2019-2022 The NATS Authors
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
@@ -49,6 +49,9 @@ const leafNodeReconnectDelayAfterLoopDetected = 30 * time.Second
 // connection is closed and it won't attempt to reconnect for that long.
 const leafNodeReconnectAfterPermViolation = 30 * time.Second
 
+// When we have the same cluster name as the hub.
+const leafNodeReconnectDelayAfterClusterNameSame = 30 * time.Second
+
 // Prefix for loop detection subject
 const leafNodeLoopDetectionSubjectPrefix = "$LDS."
 
@@ -1382,6 +1385,13 @@ func (c *client) processLeafNodeConnect(s *Server, arg []byte, lang string) erro
 		return err
 	}
 
+	// Check for cluster name collisions.
+	if cn := s.cachedClusterName(); cn != _EMPTY_ && proto.Cluster != _EMPTY_ && proto.Cluster == cn {
+		c.sendErrAndErr(ErrLeafNodeHasSameClusterName.Error())
+		c.closeConnection(ClusterNamesIdentical)
+		return ErrLeafNodeHasSameClusterName
+	}
+
 	// Reject if this has Gateway which means that it would be from a gateway
 	// connection that incorrectly connects to the leafnode port.
 	if proto.Gateway != _EMPTY_ {
@@ -2269,6 +2279,13 @@ func (c *client) leafPermViolation(pub bool, subj []byte) {
 
 // Invoked from generic processErr() for LEAF connections.
 func (c *client) leafProcessErr(errStr string) {
+	// Check if we got a cluster name collision.
+	if strings.Contains(errStr, ErrLeafNodeHasSameClusterName.Error()) {
+		_, delay := c.setLeafConnectDelayIfSoliciting(leafNodeReconnectDelayAfterClusterNameSame)
+		c.Errorf("Leafnode connection dropped with same cluster name error. Delaying attempt to reconnect for %v", delay)
+		return
+	}
+
 	// We will look for Loop detected error coming from the other side.
 	// If we solicit, set the connect delay.
 	if !strings.Contains(errStr, "Loop detected") {
diff --git a/server/monitor.go b/server/monitor.go
index 9c257911..77f7d765 100644
--- a/server/monitor.go
+++ b/server/monitor.go
@@ -2240,6 +2240,8 @@ func (reason ClosedState) String() string {
 		return "Duplicate Server Name"
 	case MinimumVersionRequired:
 		return "Minimum Version Required"
+	case ClusterNamesIdentical:
+		return "Cluster Names Identical"
 	}
 
 	return "Unknown State"
diff --git a/server/sublist.go b/server/sublist.go
index 99230dde..2ab89943 100644
--- a/server/sublist.go
+++ b/server/sublist.go
@@ -1061,11 +1061,10 @@ func IsValidSubject(subject string) bool {
 	sfwc := false
 	tokens := strings.Split(subject, tsep)
 	for _, t := range tokens {
-		length := len(t)
-		if length == 0 || sfwc {
+		if len(t) == 0 || sfwc {
 			return false
 		}
-		if length > 1 {
+		if len(t) > 1 {
 			if strings.ContainsAny(t, "\t\n\f\r ") {
 				return false
 			}
@@ -1129,33 +1128,6 @@ func isValidLiteralSubject(tokens []string) bool {
 	return true
 }
 
-// ValidateMappingDestination returns nil error if the subject is a valid subject mapping destination subject
-func ValidateMappingDestination(subject string) error {
-	subjectTokens := strings.Split(subject, tsep)
-	sfwc := false
-	for _, t := range subjectTokens {
-		length := len(t)
-		if length == 0 || sfwc {
-			return &mappingDestinationErr{t, ErrInvalidMappingDestinationSubject}
-		}
-
-		if length > 4 && t[0] == '{' && t[1] == '{' && t[length-2] == '}' && t[length-1] == '}' {
-			if !partitionMappingFunctionRegEx.MatchString(t) && !wildcardMappingFunctionRegEx.MatchString(t) {
-				return &mappingDestinationErr{t, ErrUnknownMappingDestinationFunction}
-			} else {
-				continue
-			}
-		}
-
-		if length == 1 && t[0] == fwc {
-			sfwc = true
-		} else if strings.ContainsAny(t, "\t\n\f\r ") {
-			return ErrInvalidMappingDestinationSubject
-		}
-	}
-	return nil
-}
-
 // Will check tokens and report back if the have any partial or full wildcards.
 func analyzeTokens(tokens []string) (hasPWC, hasFWC bool) {
 	for _, t := range tokens {


Test patch:
diff --git a/server/accounts_test.go b/server/accounts_test.go
index 3071a6c4..eaff2c56 100644
--- a/server/accounts_test.go
+++ b/server/accounts_test.go
@@ -16,7 +16,6 @@ package server
 import (
 	"encoding/base64"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"net/http"
 	"reflect"
@@ -3263,13 +3262,11 @@ func TestSamplingHeader(t *testing.T) {
 func TestSubjectTransforms(t *testing.T) {
 	shouldErr := func(src, dest string) {
 		t.Helper()
-		if _, err := newTransform(src, dest); err != ErrBadSubject && !errors.Is(err, ErrInvalidMappingDestination) {
+		if _, err := newTransform(src, dest); err != ErrBadSubject && err != ErrBadSubjectMappingDestination {
 			t.Fatalf("Did not get an error for src=%q and dest=%q", src, dest)
 		}
 	}
 
-	shouldErr("foo.*.*", "bar.$2") // Must place all pwcs.
-
 	// Must be valid subjects.
 	shouldErr("foo", "")
 	shouldErr("foo..", "bar")
@@ -3278,17 +3275,10 @@ func TestSubjectTransforms(t *testing.T) {
 	// e.g. foo.* -> bar.$1.
 	// Need to have as many pwcs as placements on other side.
 	shouldErr("foo.*", "bar.*")
-	shouldErr("foo.*", "bar.$2")                   // Bad pwc token identifier
-	shouldErr("foo.*", "bar.$1.>")                 // fwcs have to match.
-	shouldErr("foo.>", "bar.baz")                  // fwcs have to match.
-	shouldErr("foo.*.*", "bar.$2")                 // Must place all pwcs.
-	shouldErr("foo.*", "foo.$foo")                 // invalid $ value
-	shouldErr("foo.*", "foo.{{wildcard(2)}}")      // Mapping function being passed an out of range wildcard index
-	shouldErr("foo.*", "foo.{{unimplemented(1)}}") // Mapping trying to use an unknown mapping function
-	shouldErr("foo.*", "foo.{{partition(10)}}")    // Not enough arguments passed to the mapping function
-	shouldErr("foo.*", "foo.{{wildcard(foo)}}")    // Invalid argument passed to the mapping function
-	shouldErr("foo.*", "foo.{{wildcard()}}")       // Not enough arguments passed to the mapping function
-	shouldErr("foo.*", "foo.{{wildcard(1,2)}}")    // Too many arguments passed to the mapping function
+	shouldErr("foo.*", "bar.$2")   // Bad pwc token identifier
+	shouldErr("foo.*", "bar.$1.>") // fwcs have to match.
+	shouldErr("foo.>", "bar.baz")  // fwcs have to match.
+	shouldErr("foo.*.*", "bar.$2") // Must place all pwcs.
 
 	shouldBeOK := func(src, dest string) *transform {
 		t.Helper()
diff --git a/server/client_test.go b/server/client_test.go
index 8a5aa6af..66312fc9 100644
--- a/server/client_test.go
+++ b/server/client_test.go
@@ -2526,6 +2526,7 @@ func TestClientClampMaxSubsErrReport(t *testing.T) {
 	s1.SetLogger(l, false, false)
 
 	o2 := DefaultOptions()
+	o2.Cluster.Name = "xyz"
 	u, _ := url.Parse(fmt.Sprintf("nats://127.0.0.1:%d", o1.LeafNode.Port))
 	o2.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{u}}}
 	s2 := RunServer(o2)
diff --git a/server/jetstream_cluster_test.go b/server/jetstream_cluster_test.go
index 8082e6a8..7609a67f 100644
--- a/server/jetstream_cluster_test.go
+++ b/server/jetstream_cluster_test.go
@@ -11194,7 +11194,7 @@ func TestJetStreamClusterConsumerAndStreamNamesWithPathSeparators(t *testing.T)
 }
 
 func TestJetStreamClusterFilteredMirrors(t *testing.T) {
-	c := createJetStreamClusterExplicit(t, "MSR", 5)
+	c := createJetStreamClusterExplicit(t, "MSR", 3)
 	defer c.shutdown()
 
 	// Client for API requests.
@@ -11250,5 +11250,22 @@ func TestJetStreamClusterFilteredMirrors(t *testing.T) {
 		require_True(t, meta.Sequence.Stream == sseq)
 		sseq += 3
 	}
+}
+
+// Test for making sure we error on same cluster name.
+func TestJetStreamClusterSameClusterLeafNodes(t *testing.T) {
+	c := createJetStreamCluster(t, jsClusterAccountsTempl, "SAME", _EMPTY_, 3, 11233, true)
+	defer c.shutdown()
 
+	// Do by hand since by default we check for connections.
+	tmpl := c.createLeafSolicit(jsClusterTemplWithLeafNode)
+	lc := createJetStreamCluster(t, tmpl, "SAME", "S-", 2, 22111, false)
+	defer lc.shutdown()
+
+	time.Sleep(200 * time.Millisecond)
+
+	// Make sure no leafnodes are connected.
+	for _, s := range lc.servers {
+		checkLeafNodeConnectedCount(t, s, 0)
+	}
 }
diff --git a/server/jetstream_helpers_test.go b/server/jetstream_helpers_test.go
index 6ff138b7..fd87e08b 100644
--- a/server/jetstream_helpers_test.go
+++ b/server/jetstream_helpers_test.go
@@ -410,16 +410,22 @@ func createJetStreamSuperClusterWithTemplateAndModHook(t *testing.T, tmpl string
 }
 
 func (sc *supercluster) createLeafNodes(clusterName string, numServers int) *cluster {
+	sc.t.Helper()
+
 	// Create our leafnode cluster template first.
 	return sc.createLeafNodesWithDomain(clusterName, numServers, "")
 }
 
 func (sc *supercluster) createLeafNodesWithDomain(clusterName string, numServers int, domain string) *cluster {
+	sc.t.Helper()
+
 	// Create our leafnode cluster template first.
 	return sc.randomCluster().createLeafNodes(clusterName, numServers, domain)
 }
 
 func (sc *supercluster) createSingleLeafNode(extend bool) *Server {
+	sc.t.Helper()
+
 	return sc.randomCluster().createLeafNode(extend)
 }
 
@@ -828,14 +834,17 @@ var jsLeafFrag = `
 `
 
 func (c *cluster) createLeafNodes(clusterName string, numServers int, domain string) *cluster {
+	c.t.Helper()
 	return c.createLeafNodesWithStartPortAndDomain(clusterName, numServers, 22111, domain)
 }
 
 func (c *cluster) createLeafNodesNoJS(clusterName string, numServers int) *cluster {
+	c.t.Helper()
 	return c.createLeafNodesWithTemplateAndStartPort(jsClusterTemplWithLeafNodeNoJS, clusterName, numServers, 21333)
 }
 
 func (c *cluster) createLeafNodesWithStartPortAndDomain(clusterName string, numServers int, portStart int, domain string) *cluster {
+	c.t.Helper()
 	if domain == _EMPTY_ {
 		return c.createLeafNodesWithTemplateAndStartPort(jsClusterTemplWithLeafNode, clusterName, numServers, portStart)
 	}
@@ -844,6 +853,7 @@ func (c *cluster) createLeafNodesWithStartPortAndDomain(clusterName string, numS
 }
 
 func (c *cluster) createLeafNode(extend bool) *Server {
+	c.t.Helper()
 	if extend {
 		return c.createLeafNodeWithTemplate("LNS",
 			strings.ReplaceAll(jsClusterTemplWithSingleLeafNode, "store_dir:", " extension_hint: will_extend, store_dir:"))
@@ -853,6 +863,7 @@ func (c *cluster) createLeafNode(extend bool) *Server {
 }
 
 func (c *cluster) createLeafNodeWithTemplate(name, template string) *Server {
+	c.t.Helper()
 	tmpl := c.createLeafSolicit(template)
 	conf := fmt.Sprintf(tmpl, name, createDir(c.t, JetStreamStoreDir))
 	s, o := RunServerWithConfig(createConfFile(c.t, []byte(conf)))
@@ -863,6 +874,8 @@ func (c *cluster) createLeafNodeWithTemplate(name, template string) *Server {
 
 // Helper to generate the leaf solicit configs.
 func (c *cluster) createLeafSolicit(tmpl string) string {
+	c.t.Helper()
+
 	// Create our leafnode cluster template first.
 	var lns, lnss []string
 	for _, s := range c.servers {
@@ -880,6 +893,8 @@ func (c *cluster) createLeafSolicit(tmpl string) string {
 }
 
 func (c *cluster) createLeafNodesWithTemplateMixedMode(template, clusterName string, numJsServers, numNonServers int, doJSConfig bool) *cluster {
+	c.t.Helper()
+
 	// Create our leafnode cluster template first.
 	tmpl := c.createLeafSolicit(template)
 	pre := clusterName + "-"
@@ -894,6 +909,8 @@ func (c *cluster) createLeafNodesWithTemplateMixedMode(template, clusterName str
 }
 
 func (c *cluster) createLeafNodesWithTemplateAndStartPort(template, clusterName string, numServers int, portStart int) *cluster {
+	c.t.Helper()
+
 	// Create our leafnode cluster template first.
 	tmpl := c.createLeafSolicit(template)
 	pre := clusterName + "-"
@@ -906,6 +923,8 @@ func (c *cluster) createLeafNodesWithTemplateAndStartPort(template, clusterName
 
 // Will add in the mapping for the account to each server.
 func (c *cluster) addSubjectMapping(account, src, dest string) {
+	c.t.Helper()
+
 	for _, s := range c.servers {
 		if s.ClusterName() != c.name {
 			continue
diff --git a/server/leafnode_test.go b/server/leafnode_test.go
index 33519bd1..19c62e50 100644
--- a/server/leafnode_test.go
+++ b/server/leafnode_test.go
@@ -360,6 +360,7 @@ func TestLeafNodeAccountNotFound(t *testing.T) {
 	u, _ := url.Parse(fmt.Sprintf("nats://127.0.0.1:%d", ob.LeafNode.Port))
 
 	oa := DefaultOptions()
+	oa.Cluster.Name = "xyz"
 	oa.LeafNode.ReconnectInterval = 10 * time.Millisecond
 	oa.LeafNode.Remotes = []*RemoteLeafOpts{
 		{
@@ -498,6 +499,7 @@ func TestLeafNodeRTT(t *testing.T) {
 
 	lnBURL, _ := url.Parse(fmt.Sprintf("nats://127.0.0.1:%d", ob.LeafNode.Port))
 	oa := DefaultOptions()
+	oa.Cluster.Name = "xyz"
 	oa.PingInterval = 15 * time.Millisecond
 	oa.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{lnBURL}}}
 	sa := RunServer(oa)
@@ -562,6 +564,7 @@ func TestLeafNodeRTT(t *testing.T) {
 	// Now check that initial RTT is computed prior to first PingInterval
 	// Get new options to avoid possible race changing the ping interval.
 	ob = DefaultOptions()
+	ob.Cluster.Name = "xyz"
 	ob.PingInterval = time.Minute
 	ob.LeafNode.Host = "127.0.0.1"
 	ob.LeafNode.Port = -1
@@ -857,6 +860,7 @@ func TestLeafNodeLoop(t *testing.T) {
 	sa.SetLogger(l, false, false)
 
 	ob := DefaultOptions()
+	ob.Cluster.Name = "xyz"
 	ob.LeafNode.ReconnectInterval = 10 * time.Millisecond
 	ob.LeafNode.Port = 5678
 	ua, _ := url.Parse("nats://127.0.0.1:1234")
@@ -1262,6 +1266,7 @@ func TestLeafNodePermissions(t *testing.T) {
 
 	u, _ := url.Parse(fmt.Sprintf("nats://%s:%d", lo1.LeafNode.Host, lo1.LeafNode.Port))
 	lo2 := DefaultOptions()
+	lo2.Cluster.Name = "xyz"
 	lo2.LeafNode.ReconnectInterval = 5 * time.Millisecond
 	lo2.LeafNode.connDelay = 100 * time.Millisecond
 	lo2.LeafNode.Remotes = []*RemoteLeafOpts{
@@ -1405,6 +1410,7 @@ func TestLeafNodePermissionsConcurrentAccess(t *testing.T) {
 
 	u, _ := url.Parse(fmt.Sprintf("nats://%s:%d", lo1.LeafNode.Host, lo1.LeafNode.Port))
 	lo2 := DefaultOptions()
+	lo2.Cluster.Name = "xyz"
 	lo2.LeafNode.ReconnectInterval = 5 * time.Millisecond
 	lo2.LeafNode.connDelay = 500 * time.Millisecond
 	lo2.LeafNode.Remotes = []*RemoteLeafOpts{
@@ -1674,6 +1680,7 @@ func TestLeafNodeTmpClients(t *testing.T) {
 	// Check with normal leafnode connection that once connected,
 	// the tmp map is also emptied.
 	bo := DefaultOptions()
+	bo.Cluster.Name = "xyz"
 	bo.LeafNode.ReconnectInterval = 5 * time.Millisecond
 	u, err := url.Parse(fmt.Sprintf("nats://127.0.0.1:%d", ao.LeafNode.Port))
 	if err != nil {
@@ -1729,6 +1736,8 @@ func TestLeafNodeTLSVerifyAndMap(t *testing.T) {
 			defer s.Shutdown()
 
 			slo := DefaultOptions()
+			slo.Cluster.Name = "xyz"
+
 			sltlsc := &tls.Config{}
 			if test.provideCert {
 				tc := &TLSConfigOpts{
@@ -1969,7 +1978,7 @@ func TestLeafNodeOriginClusterInfo(t *testing.T) {
 			remotes [ { url: "nats://127.0.0.1:%d" } ]
 		}
 		cluster {
-			name: "abc"
+			name: "xyz"
 			listen: "127.0.0.1:-1"
 		}
 	`, hopts.LeafNode.Port)))
@@ -1987,8 +1996,8 @@ func TestLeafNodeOriginClusterInfo(t *testing.T) {
 	checkLeafNodeConnected(t, s)
 
 	l = grabLeaf()
-	if rc := l.remoteCluster(); rc != "abc" {
-		t.Fatalf("Expected a remote cluster name of \"abc\", got %q", rc)
+	if rc := l.remoteCluster(); rc != "xyz" {
+		t.Fatalf("Expected a remote cluster name of \"xyz\", got %q", rc)
 	}
 	pcid := l.cid
 
@@ -2265,6 +2274,7 @@ func TestLeafNodeNoDuplicateWithinCluster(t *testing.T) {
 
 	oLeaf1 := DefaultOptions()
 	oLeaf1.ServerName = "leaf1"
+	oLeaf1.Cluster.Name = "xyz"
 	oLeaf1.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{u}}}
 	leaf1 := RunServer(oLeaf1)
 	defer leaf1.Shutdown()
@@ -2273,6 +2283,7 @@ func TestLeafNodeNoDuplicateWithinCluster(t *testing.T) {
 
 	oLeaf2 := DefaultOptions()
 	oLeaf2.ServerName = "leaf2"
+	oLeaf2.Cluster.Name = "xyz"
 	oLeaf2.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{u}}}
 	oLeaf2.Routes = RoutesFromStr(leaf1ClusterURL)
 	leaf2 := RunServer(oLeaf2)
@@ -2378,11 +2389,13 @@ func TestLeafNodeLMsgSplit(t *testing.T) {
 	remoteLeafs := []*RemoteLeafOpts{{URLs: []*url.URL{u1, u2}}}
 
 	oLeaf1 := DefaultOptions()
+	oLeaf1.Cluster.Name = "xyz"
 	oLeaf1.LeafNode.Remotes = remoteLeafs
 	leaf1 := RunServer(oLeaf1)
 	defer leaf1.Shutdown()
 
 	oLeaf2 := DefaultOptions()
+	oLeaf2.Cluster.Name = "xyz"
 	oLeaf2.LeafNode.Remotes = remoteLeafs
 	oLeaf2.Routes = RoutesFromStr(fmt.Sprintf("nats://127.0.0.1:%d", oLeaf1.Cluster.Port))
 	leaf2 := RunServer(oLeaf2)
@@ -2475,6 +2488,7 @@ func TestLeafNodeRouteParseLSUnsub(t *testing.T) {
 	remoteLeafs := []*RemoteLeafOpts{{URLs: []*url.URL{u2}}}
 
 	oLeaf2 := DefaultOptions()
+	oLeaf2.Cluster.Name = "xyz"
 	oLeaf2.LeafNode.Remotes = remoteLeafs
 	leaf2 := RunServer(oLeaf2)
 	defer leaf2.Shutdown()
@@ -3296,6 +3310,7 @@ func TestLeafNodeStreamImport(t *testing.T) {
 
 	o2 := DefaultOptions()
 	o2.LeafNode.Port = -1
+	o2.Cluster.Name = "xyz"
 
 	accB := NewAccount("B")
 	if err := accB.AddStreamExport(">", nil); err != nil {
diff --git a/server/server_test.go b/server/server_test.go
index 1ccdbb50..22900e64 100644
--- a/server/server_test.go
+++ b/server/server_test.go
@@ -1828,6 +1828,7 @@ func TestReconnectErrorReports(t *testing.T) {
 
 	// Now try with leaf nodes
 	csOpts.Cluster.Port = 0
+	csOpts.Cluster.Name = _EMPTY_
 	csOpts.LeafNode.Host = "127.0.0.1"
 	csOpts.LeafNode.Port = -1
 
@@ -1835,6 +1836,7 @@ func TestReconnectErrorReports(t *testing.T) {
 	defer cs.Shutdown()
 
 	opts.Cluster.Port = 0
+	opts.Cluster.Name = _EMPTY_
 	opts.Routes = nil
 	u, _ := url.Parse(fmt.Sprintf("nats://127.0.0.1:%d", csOpts.LeafNode.Port))
 	opts.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{u}}}
diff --git a/server/sublist_test.go b/server/sublist_test.go
index 05a14dd2..b8d3b8a2 100644
--- a/server/sublist_test.go
+++ b/server/sublist_test.go
@@ -14,7 +14,6 @@
 package server
 
 import (
-	"errors"
 	"flag"
 	"fmt"
 	"math/rand"
@@ -552,13 +551,6 @@ func checkBool(b, expected bool, t *testing.T) {
 	}
 }
 
-func checkError(err, expected error, t *testing.T) {
-	t.Helper()
-	if err != expected && err != nil && !errors.Is(err, expected) {
-		t.Fatalf("Expected %v, but got %v\n", expected, err)
-	}
-}
-
 func TestSublistValidLiteralSubjects(t *testing.T) {
 	checkBool(IsValidLiteralSubject("foo"), true, t)
 	checkBool(IsValidLiteralSubject(".foo"), false, t)
@@ -586,7 +578,7 @@ func TestSublistValidLiteralSubjects(t *testing.T) {
 	checkBool(IsValidLiteralSubject(">bar"), true, t)
 }
 
-func TestSublistValidSubjects(t *testing.T) {
+func TestSublistValidlSubjects(t *testing.T) {
 	checkBool(IsValidSubject("."), false, t)
 	checkBool(IsValidSubject(".foo"), false, t)
 	checkBool(IsValidSubject("foo."), false, t)
@@ -655,26 +647,6 @@ func TestSubjectIsLiteral(t *testing.T) {
 	checkBool(subjectIsLiteral("foo.bar.>"), false, t)
 }
 
-func TestValidateDestinationSubject(t *testing.T) {
-	checkError(ValidateMappingDestination("foo"), nil, t)
-	checkError(ValidateMappingDestination("foo.bar"), nil, t)
-	checkError(ValidateMappingDestination("*"), nil, t)
-	checkError(ValidateMappingDestination(">"), nil, t)
-	checkError(ValidateMappingDestination("foo.*"), nil, t)
-	checkError(ValidateMappingDestination("foo.>"), nil, t)
-	checkError(ValidateMappingDestination("foo.*.>"), nil, t)
-	checkError(ValidateMappingDestination("foo.*.bar"), nil, t)
-	checkError(ValidateMappingDestination("foo.bar.>"), nil, t)
-	checkError(ValidateMappingDestination("foo.{{wildcard(1)}}"), nil, t)
-	checkError(ValidateMappingDestination("foo.{{ wildcard(1) }}"), nil, t)
-	checkError(ValidateMappingDestination("foo.{{wildcard( 1 )}}"), nil, t)
-	checkError(ValidateMappingDestination("foo.{{partition(2,1)}}"), nil, t)
-	checkError(ValidateMappingDestination("foo.{{unknown(1)}}"), ErrInvalidMappingDestination, t)
-	checkError(ValidateMappingDestination("foo..}"), ErrInvalidMappingDestination, t)
-	checkError(ValidateMappingDestination("foo. bar}"), ErrInvalidMappingDestinationSubject, t)
-
-}
-
 func TestSubjectToken(t *testing.T) {
 	checkToken := func(token, expected string) {
 		t.Helper()