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

     1  // Copyright 2018 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  	"fmt"
    19  	"strings"
    20  	"testing"
    21  )
    22  
    23  func TestConfigCheck(t *testing.T) {
    24  	tests := []struct {
    25  		// name is the name of the test.
    26  		name string
    27  
    28  		// config is content of the configuration file.
    29  		config string
    30  
    31  		// warningErr is an error that does not prevent server from starting.
    32  		warningErr error
    33  
    34  		// errorLine is the location of the error.
    35  		errorLine int
    36  
    37  		// errorPos is the position of the error.
    38  		errorPos int
    39  
    40  		// warning errors also include a reason optionally.
    41  		reason string
    42  
    43  		// newDefaultErr is a configuration error that includes source of error.
    44  		err error
    45  	}{
    46  		{
    47  			name: "when unknown field is used at top level",
    48  			config: `
    49                  monitor = "127.0.0.1:4442"
    50                  `,
    51  			err:       errors.New(`unknown field "monitor"`),
    52  			errorLine: 2,
    53  			errorPos:  17,
    54  		},
    55  		{
    56  			name: "when default permissions are used at top level",
    57  			config: `
    58                  "default_permissions" {
    59                    publish = ["_SANDBOX.>"]
    60                    subscribe = ["_SANDBOX.>"]
    61                  }
    62                  `,
    63  			err:       errors.New(`unknown field "default_permissions"`),
    64  			errorLine: 2,
    65  			errorPos:  18,
    66  		},
    67  		{
    68  			name: "when authorization config is empty",
    69  			config: `
    70  		authorization = {
    71  		}
    72  		`,
    73  			err: nil,
    74  		},
    75  		{
    76  			name: "when authorization config has unknown fields",
    77  			config: `
    78  		authorization = {
    79  		  foo = "bar"
    80  		}
    81  		`,
    82  			err:       errors.New(`unknown field "foo"`),
    83  			errorLine: 3,
    84  			errorPos:  5,
    85  		},
    86  		{
    87  			name: "when authorization config has unknown fields",
    88  			config: `
    89  		port = 4222
    90  
    91  		authorization = {
    92  		  user = "hello"
    93  		  foo = "bar"
    94  		  password = "world"
    95  		}
    96  
    97  		`,
    98  			err:       errors.New(`unknown field "foo"`),
    99  			errorLine: 6,
   100  			errorPos:  5,
   101  		},
   102  		{
   103  			name: "when user authorization config has unknown fields",
   104  			config: `
   105  		authorization = {
   106  		  users = [
   107  		    {
   108  		      user = "foo"
   109  		      pass = "bar"
   110  		      token = "quux"
   111  		    }
   112  		  ]
   113  		}
   114  		`,
   115  			err:       errors.New(`unknown field "token"`),
   116  			errorLine: 7,
   117  			errorPos:  9,
   118  		},
   119  		{
   120  			name: "when user authorization permissions config has unknown fields",
   121  			config: `
   122  		authorization {
   123  		  permissions {
   124  		    subscribe = {}
   125  		    inboxes = {}
   126  		    publish = {}
   127  		  }
   128  		}
   129  		`,
   130  			err:       errors.New(`Unknown field "inboxes" parsing permissions`),
   131  			errorLine: 5,
   132  			errorPos:  7,
   133  		},
   134  		{
   135  			name: "when user authorization permissions config has unknown fields within allow or deny",
   136  			config: `
   137  		authorization {
   138  		  permissions {
   139  		    subscribe = {
   140  		      allow = ["hello", "world"]
   141  		      deny = ["foo", "bar"]
   142  		      denied = "_INBOX.>"
   143  		    }
   144  		    publish = {}
   145  		  }
   146  		}
   147  		`,
   148  			err:       errors.New(`Unknown field name "denied" parsing subject permissions, only 'allow' or 'deny' are permitted`),
   149  			errorLine: 7,
   150  			errorPos:  9,
   151  		},
   152  		{
   153  			name: "when user authorization permissions config has unknown fields within allow or deny",
   154  			config: `
   155  		authorization {
   156  		  permissions {
   157  		    publish = {
   158  		      allow = ["hello", "world"]
   159  		      deny = ["foo", "bar"]
   160  		      allowed = "_INBOX.>"
   161  		    }
   162  		    subscribe = {}
   163  		  }
   164  		}
   165  		`,
   166  			err:       errors.New(`Unknown field name "allowed" parsing subject permissions, only 'allow' or 'deny' are permitted`),
   167  			errorLine: 7,
   168  			errorPos:  9,
   169  		},
   170  		{
   171  			name: "when user authorization permissions config has unknown fields using arrays",
   172  			config: `
   173  		authorization {
   174  
   175  		 default_permissions {
   176  		   subscribe = ["a"]
   177  		   publish = ["b"]
   178  		   inboxes = ["c"]
   179  		 }
   180  
   181  		 users = [
   182  		   {
   183  		     user = "foo"
   184  		     pass = "bar"
   185  		   }
   186  		  ]
   187  		}
   188  		`,
   189  			err:       errors.New(`Unknown field "inboxes" parsing permissions`),
   190  			errorLine: 7,
   191  			errorPos:  6,
   192  		},
   193  		{
   194  			name: "when user authorization permissions config has unknown fields using strings",
   195  			config: `
   196  		authorization {
   197  
   198  		 default_permissions {
   199  		   subscribe = "a"
   200  		   requests = "b"
   201  		   publish = "c"
   202  		 }
   203  
   204  		 users = [
   205  		   {
   206  		     user = "foo"
   207  		     pass = "bar"
   208  		   }
   209  		  ]
   210  		}
   211  		`,
   212  			err:       errors.New(`Unknown field "requests" parsing permissions`),
   213  			errorLine: 6,
   214  			errorPos:  6,
   215  		},
   216  		{
   217  			name: "when user authorization permissions config is empty",
   218  			config: `
   219  		authorization = {
   220  		  users = [
   221  		    {
   222  		      user = "foo", pass = "bar", permissions = {
   223  		      }
   224  		    }
   225  		  ]
   226  		}
   227  		`,
   228  			err: nil,
   229  		},
   230  		{
   231  			name: "when unknown permissions are included in user config",
   232  			config: `
   233  		authorization = {
   234  		  users = [
   235  		    {
   236  		      user = "foo", pass = "bar", permissions {
   237  		        inboxes = true
   238  		      }
   239  		    }
   240  		  ]
   241  		}
   242  		`,
   243  			err:       errors.New(`Unknown field "inboxes" parsing permissions`),
   244  			errorLine: 6,
   245  			errorPos:  11,
   246  		},
   247  		{
   248  			name: "when clustering config is empty",
   249  			config: `
   250  		cluster = {
   251  		}
   252  		`,
   253  
   254  			err: nil,
   255  		},
   256  		{
   257  			name: "when unknown option is in clustering config",
   258  			config: `
   259  		# NATS Server Configuration
   260  		port = 4222
   261  
   262  		cluster = {
   263  
   264  		  port = 6222
   265  
   266  		  foo = "bar"
   267  
   268  		  authorization {
   269  		    user = "hello"
   270  		    pass = "world"
   271  		  }
   272  
   273  		}
   274  		`,
   275  
   276  			err:       errors.New(`unknown field "foo"`),
   277  			errorLine: 9,
   278  			errorPos:  5,
   279  		},
   280  		{
   281  			name: "when unknown option is in clustering authorization config",
   282  			config: `
   283  		cluster = {
   284  		  authorization {
   285  		    foo = "bar"
   286  		  }
   287  		}
   288  		`,
   289  
   290  			err:       errors.New(`unknown field "foo"`),
   291  			errorLine: 4,
   292  			errorPos:  7,
   293  		},
   294  		{
   295  			name: "when unknown option is in tls config",
   296  			config: `
   297  		tls = {
   298  		  hello = "world"
   299  		}
   300  		`,
   301  			err:       errors.New(`error parsing tls config, unknown field "hello"`),
   302  			errorLine: 3,
   303  			errorPos:  5,
   304  		},
   305  		{
   306  			name: "when unknown option is in cluster tls config",
   307  			config: `
   308  		cluster {
   309  		  tls = {
   310  		    foo = "bar"
   311  		  }
   312  		}
   313  		`,
   314  			err:       errors.New(`error parsing tls config, unknown field "foo"`),
   315  			errorLine: 4,
   316  			errorPos:  7,
   317  		},
   318  		{
   319  			name: "when using cipher suites in the TLS config",
   320  			config: `
   321  		tls = {
   322  		    cipher_suites: [
   323  			"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
   324  			"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
   325  		    ]
   326  		    preferences = []
   327  		}
   328  		`,
   329  			err:       errors.New(`error parsing tls config, unknown field "preferences"`),
   330  			errorLine: 7,
   331  			errorPos:  7,
   332  		},
   333  		{
   334  			name: "when using curve preferences in the TLS config",
   335  			config: `
   336  		tls = {
   337  		    curve_preferences: [
   338  			"CurveP256",
   339  			"CurveP384",
   340  			"CurveP521"
   341  		    ]
   342  		    suites = []
   343  		}
   344  		`,
   345  			err:       errors.New(`error parsing tls config, unknown field "suites"`),
   346  			errorLine: 8,
   347  			errorPos:  7,
   348  		},
   349  		{
   350  			name: "when using curve preferences in the TLS config",
   351  			config: `
   352  		tls = {
   353  		    curve_preferences: [
   354  			"CurveP5210000"
   355  		    ]
   356  		}
   357  		`,
   358  			err:       errors.New(`unrecognized curve preference CurveP5210000`),
   359  			errorLine: 4,
   360  			errorPos:  5,
   361  		},
   362  		{
   363  			name: "verify_cert_and_check_known_urls not support for clients",
   364  			config: `
   365  		tls = {
   366  						cert_file: "configs/certs/server.pem"
   367  						key_file: "configs/certs/key.pem"
   368  					    verify_cert_and_check_known_urls: true
   369  		}
   370  		`,
   371  			err:       errors.New("verify_cert_and_check_known_urls not supported in this context"),
   372  			errorLine: 5,
   373  			errorPos:  10,
   374  		},
   375  		{
   376  			name: "when unknown option is in cluster config with defined routes",
   377  			config: `
   378  		cluster {
   379  		  port = 6222
   380  		  routes = [
   381  		    nats://127.0.0.1:6222
   382  		  ]
   383  		  peers = []
   384  		}
   385  		`,
   386  			err:       errors.New(`unknown field "peers"`),
   387  			errorLine: 7,
   388  			errorPos:  5,
   389  		},
   390  		{
   391  			name: "when used as variable in authorization block it should not be considered as unknown field",
   392  			config: `
   393  		# listen:   127.0.0.1:-1
   394  		listen:   127.0.0.1:4222
   395  
   396  		authorization {
   397  		  # Superuser can do anything.
   398  		  super_user = {
   399  		    publish = ">"
   400  		    subscribe = ">"
   401  		  }
   402  
   403  		  # Can do requests on foo or bar, and subscribe to anything
   404  		  # that is a response to an _INBOX.
   405  		  #
   406  		  # Notice that authorization filters can be singletons or arrays.
   407  		  req_pub_user = {
   408  		    publish = ["req.foo", "req.bar"]
   409  		    subscribe = "_INBOX.>"
   410  		  }
   411  
   412  		  # Setup a default user that can subscribe to anything, but has
   413  		  # no publish capabilities.
   414  		  default_user = {
   415  		    subscribe = "PUBLIC.>"
   416  		  }
   417  
   418  		  unused = "hello"
   419  
   420  		  # Default permissions if none presented. e.g. susan below.
   421  		  default_permissions: $default_user
   422  
   423  		  # Users listed with persmissions.
   424  		  users = [
   425  		    {user: alice, password: foo, permissions: $super_user}
   426  		    {user: bob,   password: bar, permissions: $req_pub_user}
   427  		    {user: susan, password: baz}
   428  		  ]
   429  		}
   430  		`,
   431  			err:       errors.New(`unknown field "unused"`),
   432  			errorLine: 27,
   433  			errorPos:  5,
   434  		},
   435  		{
   436  			name: "when used as variable in top level config it should not be considered as unknown field",
   437  			config: `
   438  		monitoring_port = 8222
   439  
   440  		http_port = $monitoring_port
   441  
   442  		port = 4222
   443  		`,
   444  			err: nil,
   445  		},
   446  		{
   447  			name: "when used as variable in cluster config it should not be considered as unknown field",
   448  			config: `
   449  		cluster {
   450  		  clustering_port = 6222
   451  		  port = $clustering_port
   452  		}
   453  		`,
   454  			err: nil,
   455  		},
   456  		{
   457  			name: "when setting permissions within cluster authorization block",
   458  			config: `
   459  		cluster {
   460  		  authorization {
   461  		    permissions = {
   462  		      publish = { allow = ["foo", "bar"] }
   463  		    }
   464  		  }
   465  
   466  		  permissions = {
   467  		    publish = { deny = ["foo", "bar"] }
   468  		  }
   469  		}
   470  		`,
   471  			warningErr: errors.New(`invalid use of field "authorization"`),
   472  			errorLine:  3,
   473  			errorPos:   5,
   474  			reason:     `setting "permissions" within cluster authorization block is deprecated`,
   475  		},
   476  		{
   477  			name: "when write deadline is used with deprecated usage",
   478  			config: `
   479                  write_deadline = 100
   480  		`,
   481  			warningErr: errors.New(`invalid use of field "write_deadline"`),
   482  			errorLine:  2,
   483  			errorPos:   17,
   484  			reason:     `write_deadline should be converted to a duration`,
   485  		},
   486  		/////////////////////
   487  		// ACCOUNTS	   //
   488  		/////////////////////
   489  		{
   490  			name: "when accounts block is correctly configured",
   491  			config: `
   492  		http_port = 8222
   493  
   494  		accounts {
   495  
   496  		  #
   497  		  # synadia > nats.io, cncf
   498  		  #
   499  		  synadia {
   500  		    # SAADJL5XAEM6BDYSWDTGVILJVY54CQXZM5ZLG4FRUAKB62HWRTPNSGXOHA
   501  		    nkey = "AC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL"
   502  
   503  		    users [
   504  		      {
   505  		        # SUAEL6RU3BSDAFKOHNTEOK5Q6FTM5FTAMWVIKBET6FHPO4JRII3CYELVNM
   506  		        nkey = "UCARKS2E3KVB7YORL2DG34XLT7PUCOL2SVM7YXV6ETHLW6Z46UUJ2VZ3"
   507  		      }
   508  		    ]
   509  
   510  		    exports = [
   511  		      { service: "synadia.requests", accounts: [nats, cncf] }
   512  		    ]
   513  		  }
   514  
   515  		  #
   516  		  # nats < synadia
   517  		  #
   518  		  nats {
   519  		    # SUAJTM55JH4BNYDA22DMDZJSRBRKVDGSLYK2HDIOCM3LPWCDXIDV5Q4CIE
   520  		    nkey = "ADRZ42QBM7SXQDXXTSVWT2WLLFYOQGAFC4TO6WOAXHEKQHIXR4HFYJDS"
   521  
   522  		    users [
   523  		      {
   524  		        # SUADZTYQAKTY5NQM7XRB5XR3C24M6ROGZLBZ6P5HJJSSOFUGC5YXOOECOM
   525  		        nkey = "UD6AYQSOIN2IN5OGC6VQZCR4H3UFMIOXSW6NNS6N53CLJA4PB56CEJJI"
   526  		      }
   527  		    ]
   528  
   529  		    imports = [
   530  		      # This account has to send requests to 'nats.requests' subject
   531  		      { service: { account: "synadia", subject: "synadia.requests" }, to: "nats.requests" }
   532  		    ]
   533  		  }
   534  
   535  		  #
   536  		  # cncf < synadia
   537  		  #
   538  		  cncf {
   539  		    # SAAFHDZX7SGZ2SWHPS22JRPPK5WX44NPLNXQHR5C5RIF6QRI3U65VFY6C4
   540  		    nkey = "AD4YRVUJF2KASKPGRMNXTYKIYSCB3IHHB4Y2ME6B2PDIV5QJ23C2ZRIT"
   541  
   542  		    users [
   543  		      {
   544  		        # SUAKINP3Z2BPUXWOFSW2FZC7TFJCMMU7DHKP2C62IJQUDASOCDSTDTRMJQ
   545  		        nkey = "UB57IEMPG4KOTPFV5A66QKE2HZ3XBXFHVRCCVMJEWKECMVN2HSH3VTSJ"
   546  		      }
   547  		    ]
   548  
   549  		    imports = [
   550  		      # This account has to send requests to 'synadia.requests' subject
   551  		      { service: { account: "synadia", subject: "synadia.requests" } }
   552  		    ]
   553  		  }
   554  		}
   555  				`,
   556  			err: nil,
   557  		},
   558  		{
   559  			name: "when nkey is invalid within accounts block",
   560  			config: `
   561  		accounts {
   562  
   563  		  #
   564  		  # synadia > nats.io, cncf
   565  		  #
   566  		  synadia {
   567  		    # SAADJL5XAEM6BDYSWDTGVILJVY54CQXZM5ZLG4FRUAKB62HWRTPNSGXOHA
   568  		    nkey = "AC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL"
   569  
   570  		    users [
   571  		      {
   572  		        # SUAEL6RU3BSDAFKOHNTEOK5Q6FTM5FTAMWVIKBET6FHPO4JRII3CYELVNM
   573  		        nkey = "SCARKS2E3KVB7YORL2DG34XLT7PUCOL2SVM7YXV6ETHLW6Z46UUJ2VZ3"
   574  		      }
   575  		    ]
   576  
   577  		    exports = [
   578  		      { service: "synadia.requests", accounts: [nats, cncf] }
   579  		    ]
   580  		  }
   581  
   582  		  #
   583  		  # nats < synadia
   584  		  #
   585  		  nats {
   586  		    # SUAJTM55JH4BNYDA22DMDZJSRBRKVDGSLYK2HDIOCM3LPWCDXIDV5Q4CIE
   587  		    nkey = "ADRZ42QBM7SXQDXXTSVWT2WLLFYOQGAFC4TO6WOAXHEKQHIXR4HFYJDS"
   588  
   589  		    users [
   590  		      {
   591  		        # SUADZTYQAKTY5NQM7XRB5XR3C24M6ROGZLBZ6P5HJJSSOFUGC5YXOOECOM
   592  		        nkey = "UD6AYQSOIN2IN5OGC6VQZCR4H3UFMIOXSW6NNS6N53CLJA4PB56CEJJI"
   593  		      }
   594  		    ]
   595  
   596  		    imports = [
   597  		      # This account has to send requests to 'nats.requests' subject
   598  		      { service: { account: "synadia", subject: "synadia.requests" }, to: "nats.requests" }
   599  		    ]
   600  		  }
   601  
   602  		  #
   603  		  # cncf < synadia
   604  		  #
   605  		  cncf {
   606  		    # SAAFHDZX7SGZ2SWHPS22JRPPK5WX44NPLNXQHR5C5RIF6QRI3U65VFY6C4
   607  		    nkey = "AD4YRVUJF2KASKPGRMNXTYKIYSCB3IHHB4Y2ME6B2PDIV5QJ23C2ZRIT"
   608  
   609  		    users [
   610  		      {
   611  		        # SUAKINP3Z2BPUXWOFSW2FZC7TFJCMMU7DHKP2C62IJQUDASOCDSTDTRMJQ
   612  		        nkey = "UB57IEMPG4KOTPFV5A66QKE2HZ3XBXFHVRCCVMJEWKECMVN2HSH3VTSJ"
   613  		      }
   614  		    ]
   615  
   616  		    imports = [
   617  		      # This account has to send requests to 'synadia.requests' subject
   618  		      { service: { account: "synadia", subject: "synadia.requests" } }
   619  		    ]
   620  		  }
   621  		}
   622  				`,
   623  			err:       errors.New(`Not a valid public nkey for a user`),
   624  			errorLine: 14,
   625  			errorPos:  11,
   626  		},
   627  		{
   628  			name: "when accounts block has unknown fields",
   629  			config: `
   630  		http_port = 8222
   631  
   632  		accounts {
   633                    foo = "bar"
   634  		}`,
   635  			err:       errors.New(`Expected map entries for accounts`),
   636  			errorLine: 5,
   637  			errorPos:  19,
   638  		},
   639  		{
   640  			name: "when accounts has a referenced config variable within same block",
   641  			config: `
   642  			  accounts {
   643  			    PERMISSIONS = {
   644  				publish = {
   645  				  allow = ["foo","bar"]
   646  				  deny = ["quux"]
   647  				}
   648  			    }
   649  
   650  			    synadia {
   651  				nkey = "AC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL"
   652  
   653  				users [
   654  				  {
   655  				    nkey = "UCARKS2E3KVB7YORL2DG34XLT7PUCOL2SVM7YXV6ETHLW6Z46UUJ2VZ3"
   656  				    permissions = $PERMISSIONS
   657  				  }
   658  				]
   659  				exports = [
   660  				  { stream: "synadia.>" }
   661  				]
   662  			    }
   663  			  }`,
   664  			err: nil,
   665  		},
   666  		{
   667  			name: "when accounts has an unreferenced config variables within same block",
   668  			config: `
   669  			  accounts {
   670  			    PERMISSIONS = {
   671  				publish = {
   672  				  allow = ["foo","bar"]
   673  				  deny = ["quux"]
   674  				}
   675  			    }
   676  
   677  			    synadia {
   678  				nkey = "AC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL"
   679  
   680  				users [
   681  				  {
   682  				    nkey = "UCARKS2E3KVB7YORL2DG34XLT7PUCOL2SVM7YXV6ETHLW6Z46UUJ2VZ3"
   683  				  }
   684  				]
   685  				exports = [
   686  				  { stream: "synadia.>" }
   687  				]
   688  			   }
   689  			 }`,
   690  			err:       errors.New(`unknown field "publish"`),
   691  			errorLine: 4,
   692  			errorPos:  5,
   693  		},
   694  		{
   695  			name: "when accounts block defines a global account",
   696  			config: `
   697  		http_port = 8222
   698  
   699  		accounts {
   700                    $G = {
   701                    }
   702  		}
   703  				`,
   704  			err:       errors.New(`"$G" is a Reserved Account`),
   705  			errorLine: 5,
   706  			errorPos:  19,
   707  		},
   708  		{
   709  			name: "when accounts block uses an invalid public key",
   710  			config: `
   711  		accounts {
   712                    synadia = {
   713                      nkey = "invalid"
   714                    }
   715  		}
   716  				`,
   717  			err:       errors.New(`Not a valid public nkey for an account: "invalid"`),
   718  			errorLine: 4,
   719  			errorPos:  21,
   720  		},
   721  		{
   722  			name: "when accounts list includes reserved account",
   723  			config: `
   724                  port = 4222
   725  
   726  		accounts = [foo, bar, "$G"]
   727  
   728                  http_port = 8222
   729  				`,
   730  			err:       errors.New(`"$G" is a Reserved Account`),
   731  			errorLine: 4,
   732  			errorPos:  26,
   733  		},
   734  		{
   735  			name: "when accounts list includes a dupe entry",
   736  			config: `
   737                  port = 4222
   738  
   739  		accounts = [foo, bar, bar]
   740  
   741                  http_port = 8222
   742  				`,
   743  			err:       errors.New(`Duplicate Account Entry: bar`),
   744  			errorLine: 4,
   745  			errorPos:  25,
   746  		},
   747  		{
   748  			name: "when accounts block includes a dupe user",
   749  			config: `
   750                  port = 4222
   751  
   752  		accounts = {
   753                    nats {
   754                      users = [
   755                        { user: "foo",   pass: "bar" },
   756                        { user: "hello", pass: "world" },
   757                        { user: "foo",   pass: "bar" }
   758                      ]
   759                    }
   760                  }
   761  
   762                  http_port = 8222
   763  				`,
   764  			err:       errors.New(`Duplicate user "foo" detected`),
   765  			errorLine: 6,
   766  			errorPos:  21,
   767  		},
   768  		{
   769  			name: "when accounts block imports are not a list",
   770  			config: `
   771                  port = 4222
   772  
   773  		accounts = {
   774                    nats {
   775                      imports = true
   776                    }
   777                  }
   778  
   779                  http_port = 8222
   780  				`,
   781  			err:       errors.New(`Imports should be an array, got bool`),
   782  			errorLine: 6,
   783  			errorPos:  21,
   784  		},
   785  		{
   786  			name: "when accounts block exports are not a list",
   787  			config: `
   788                  port = 4222
   789  
   790  		accounts = {
   791                    nats {
   792                      exports = true
   793                    }
   794                  }
   795  
   796                  http_port = 8222
   797  				`,
   798  			err:       errors.New(`Exports should be an array, got bool`),
   799  			errorLine: 6,
   800  			errorPos:  21,
   801  		},
   802  		{
   803  			name: "when accounts block imports items are not a map",
   804  			config: `
   805                  port = 4222
   806  
   807  		accounts = {
   808                    nats {
   809                      imports = [
   810                        false
   811                      ]
   812                    }
   813                  }
   814  
   815                  http_port = 8222
   816  				`,
   817  			err:       errors.New(`Import Items should be a map with type entry, got bool`),
   818  			errorLine: 7,
   819  			errorPos:  23,
   820  		},
   821  		{
   822  			name: "when accounts block export items are not a map",
   823  			config: `
   824                  port = 4222
   825  
   826  		accounts = {
   827                    nats {
   828                      exports = [
   829                        false
   830                      ]
   831                    }
   832                  }
   833  
   834                  http_port = 8222
   835  				`,
   836  			err:       errors.New(`Export Items should be a map with type entry, got bool`),
   837  			errorLine: 7,
   838  			errorPos:  23,
   839  		},
   840  		{
   841  			name: "when accounts exports has a stream name that is not a string",
   842  			config: `
   843                  port = 4222
   844  
   845  		accounts = {
   846                    nats {
   847                      exports = [
   848                        {
   849                          stream: false
   850                        }
   851                      ]
   852                    }
   853                  }
   854  
   855                  http_port = 8222
   856  				`,
   857  			err:       errors.New(`Expected stream name to be string, got bool`),
   858  			errorLine: 8,
   859  			errorPos:  25,
   860  		},
   861  		{
   862  			name: "when accounts exports has a service name that is not a string",
   863  			config: `
   864  		accounts = {
   865                    nats {
   866                      exports = [
   867                        {
   868                          service: false
   869                        }
   870                      ]
   871                    }
   872                  }
   873  				`,
   874  			err:       errors.New(`Expected service name to be string, got bool`),
   875  			errorLine: 6,
   876  			errorPos:  25,
   877  		},
   878  		{
   879  			name: "when accounts imports stream without name",
   880  			config: `
   881                  port = 4222
   882  
   883  		accounts = {
   884                    nats {
   885                      imports = [
   886                        { stream: { }}
   887                      ]
   888                    }
   889                  }
   890  
   891                  http_port = 8222
   892  				`,
   893  			err:       errors.New(`Expect an account name and a subject`),
   894  			errorLine: 7,
   895  			errorPos:  25,
   896  		},
   897  		{
   898  			name: "when accounts imports service without name",
   899  			config: `
   900                  port = 4222
   901  
   902  		accounts = {
   903                    nats {
   904                      imports = [
   905                        { service: { }}
   906                      ]
   907                    }
   908                  }
   909  
   910                  http_port = 8222
   911  				`,
   912  			err:       errors.New(`Expect an account name and a subject`),
   913  			errorLine: 7,
   914  			errorPos:  25,
   915  		},
   916  		{
   917  			name: "when account trace destination is of the wrong type",
   918  			config: `
   919                  accounts {
   920                    A { trace_dest: 123 }
   921                  }
   922  			`,
   923  			err:       errors.New(`Expected account message trace "trace_dest" to be a string or a map/struct, got int64`),
   924  			errorLine: 3,
   925  			errorPos:  23,
   926  		},
   927  		{
   928  			name: "when account trace destination is not a valid destination",
   929  			config: `
   930                  accounts {
   931                    A { trace_dest: "invalid..dest" }
   932                  }
   933  			`,
   934  			err:       errors.New(`Trace destination "invalid..dest" is not valid`),
   935  			errorLine: 3,
   936  			errorPos:  23,
   937  		},
   938  		{
   939  			name: "when account trace destination is not a valid publish subject",
   940  			config: `
   941                  accounts {
   942                    A { trace_dest: "invalid.publish.*.subject" }
   943                  }
   944  			`,
   945  			err:       errors.New(`Trace destination "invalid.publish.*.subject" is not valid`),
   946  			errorLine: 3,
   947  			errorPos:  23,
   948  		},
   949  		{
   950  			name: "when account message trace dest is wrong type",
   951  			config: `
   952                  accounts {
   953                    A { msg_trace: {dest: 123} }
   954                  }
   955  			`,
   956  			err:       errors.New(`Field "dest" should be a string, got int64`),
   957  			errorLine: 3,
   958  			errorPos:  35,
   959  		},
   960  		{
   961  			name: "when account message trace dest is invalid",
   962  			config: `
   963                  accounts {
   964                    A { msg_trace: {dest: "invalid..dest"} }
   965                  }
   966  			`,
   967  			err:       errors.New(`Trace destination "invalid..dest" is not valid`),
   968  			errorLine: 3,
   969  			errorPos:  35,
   970  		},
   971  		{
   972  			name: "when account message trace sampling is wrong type",
   973  			config: `
   974                  accounts {
   975                    A { msg_trace: {dest: "acc.dest", sampling: {wront: "type"}} }
   976                  }
   977  			`,
   978  			err:       errors.New(`Trace destination sampling field "sampling" should be an integer or a percentage, got map[string]interface {}`),
   979  			errorLine: 3,
   980  			errorPos:  53,
   981  		},
   982  		{
   983  			name: "when account message trace sampling is wrong string",
   984  			config: `
   985                  accounts {
   986                    A { msg_trace: {dest: "acc.dest", sampling: abc%} }
   987                  }
   988  			`,
   989  			err:       errors.New(`Invalid trace destination sampling value "abc%"`),
   990  			errorLine: 3,
   991  			errorPos:  53,
   992  		},
   993  		{
   994  			name: "when account message trace sampling is negative",
   995  			config: `
   996                  accounts {
   997                    A { msg_trace: {dest: "acc.dest", sampling: -1} }
   998                  }
   999  			`,
  1000  			err:       errors.New(`Ttrace destination sampling value -1 is invalid, needs to be [1..100]`),
  1001  			errorLine: 3,
  1002  			errorPos:  53,
  1003  		},
  1004  		{
  1005  			name: "when account message trace sampling is zero",
  1006  			config: `
  1007                  accounts {
  1008                    A { msg_trace: {dest: "acc.dest", sampling: 0} }
  1009                  }
  1010  			`,
  1011  			err:       errors.New(`Ttrace destination sampling value 0 is invalid, needs to be [1..100]`),
  1012  			errorLine: 3,
  1013  			errorPos:  53,
  1014  		},
  1015  		{
  1016  			name: "when account message trace sampling is more than 100",
  1017  			config: `
  1018                  accounts {
  1019                    A { msg_trace: {dest: "acc.dest", sampling: 101} }
  1020                  }
  1021  			`,
  1022  			err:       errors.New(`Ttrace destination sampling value 101 is invalid, needs to be [1..100]`),
  1023  			errorLine: 3,
  1024  			errorPos:  53,
  1025  		},
  1026  		{
  1027  			name: "when account message trace has unknown field",
  1028  			config: `
  1029                  accounts {
  1030                    A { msg_trace: {wrong: "field"} }
  1031                  }
  1032  			`,
  1033  			err:       errors.New(`Unknown field "wrong" parsing account message trace map/struct "msg_trace"`),
  1034  			errorLine: 3,
  1035  			errorPos:  35,
  1036  		},
  1037  		{
  1038  			name: "when user authorization config has both token and users",
  1039  			config: `
  1040  		authorization = {
  1041  			token = "s3cr3t"
  1042  			users = [
  1043  				{
  1044  					user = "foo"
  1045  					pass = "bar"
  1046  				}
  1047  			]
  1048  		}
  1049  		`,
  1050  			err:       errors.New(`Can not have a token and a users array`),
  1051  			errorLine: 2,
  1052  			errorPos:  3,
  1053  		},
  1054  		{
  1055  			name: "when user authorization config has both token and user",
  1056  			config: `
  1057  		authorization = {
  1058  			user = "foo"
  1059  			pass = "bar"
  1060  			token = "baz"
  1061  		}
  1062  		`,
  1063  			err:       errors.New(`Cannot have a user/pass and token`),
  1064  			errorLine: 2,
  1065  			errorPos:  3,
  1066  		},
  1067  		{
  1068  			name: "when user authorization config has both user and users array",
  1069  			config: `
  1070  		authorization = {
  1071  			user = "user1"
  1072  			pass = "pwd1"
  1073  			users = [
  1074  				{
  1075  					user = "user2"
  1076  					pass = "pwd2"
  1077  				}
  1078  			]
  1079  		}
  1080  		`,
  1081  			err:       errors.New(`Can not have a single user/pass and a users array`),
  1082  			errorLine: 2,
  1083  			errorPos:  3,
  1084  		},
  1085  		{
  1086  			name: "when user authorization has duplicate users",
  1087  			config: `
  1088  		authorization = {
  1089  			users = [
  1090  				{user: "user1", pass: "pwd"}
  1091  				{user: "user2", pass: "pwd"}
  1092  				{user: "user1", pass: "pwd"}
  1093  			]
  1094  		}
  1095  		`,
  1096  			err:       fmt.Errorf(`Duplicate user %q detected`, "user1"),
  1097  			errorLine: 2,
  1098  			errorPos:  3,
  1099  		},
  1100  		{
  1101  			name: "when user authorization has duplicate nkeys",
  1102  			config: `
  1103  		authorization = {
  1104  			users = [
  1105  				{nkey: UC6NLCN7AS34YOJVCYD4PJ3QB7QGLYG5B5IMBT25VW5K4TNUJODM7BOX }
  1106  				{nkey: UBAAQWTW6CG2G6ANGNKB5U2B7HRWHSGMZEZX3AQSAJOQDAUGJD46LD2E }
  1107  				{nkey: UC6NLCN7AS34YOJVCYD4PJ3QB7QGLYG5B5IMBT25VW5K4TNUJODM7BOX }
  1108  			]
  1109  		}
  1110  		`,
  1111  			err:       fmt.Errorf(`Duplicate nkey %q detected`, "UC6NLCN7AS34YOJVCYD4PJ3QB7QGLYG5B5IMBT25VW5K4TNUJODM7BOX"),
  1112  			errorLine: 2,
  1113  			errorPos:  3,
  1114  		},
  1115  		{
  1116  			name: "when user authorization config has users not as a list",
  1117  			config: `
  1118  		authorization = {
  1119  		  users = false
  1120  		}
  1121  		`,
  1122  			err:       errors.New(`Expected users field to be an array, got false`),
  1123  			errorLine: 3,
  1124  			errorPos:  5,
  1125  		},
  1126  		{
  1127  			name: "when user authorization config has users not as a map",
  1128  			config: `
  1129  		authorization = {
  1130  		  users = [false]
  1131  		}
  1132  		`,
  1133  			err:       errors.New(`Expected user entry to be a map/struct, got false`),
  1134  			errorLine: 3,
  1135  			errorPos:  14,
  1136  		},
  1137  		{
  1138  			name: "when user authorization config has permissions not as a map",
  1139  			config: `
  1140  		authorization = {
  1141  		  users = [{user: hello, pass: world}]
  1142                    permissions = false
  1143  		}
  1144  		`,
  1145  			err:       errors.New(`Expected permissions to be a map/struct, got false`),
  1146  			errorLine: 4,
  1147  			errorPos:  19,
  1148  		},
  1149  		{
  1150  			name: "when user authorization permissions config has invalid fields within allow",
  1151  			config: `
  1152  		authorization {
  1153  		  permissions {
  1154  		    publish = {
  1155  		      allow = [false, "hello", "world"]
  1156  		      deny = ["foo", "bar"]
  1157  		    }
  1158  		    subscribe = {}
  1159  		  }
  1160  		}
  1161  		`,
  1162  			err:       errors.New(`Subject in permissions array cannot be cast to string`),
  1163  			errorLine: 5,
  1164  			errorPos:  18,
  1165  		},
  1166  		{
  1167  			name: "when user authorization permissions config has invalid fields within deny",
  1168  			config: `
  1169  		authorization {
  1170  		  permissions {
  1171  		    publish = {
  1172  		      allow = ["hello", "world"]
  1173  		      deny = [true, "foo", "bar"]
  1174  		    }
  1175  		    subscribe = {}
  1176  		  }
  1177  		}
  1178  		`,
  1179  			err:       errors.New(`Subject in permissions array cannot be cast to string`),
  1180  			errorLine: 6,
  1181  			errorPos:  17,
  1182  		},
  1183  		{
  1184  			name: "when user authorization permissions config has invalid type",
  1185  			config: `
  1186  		authorization {
  1187  		  permissions {
  1188  		    publish = {
  1189  		      allow = false
  1190  		    }
  1191  		    subscribe = {}
  1192  		  }
  1193  		}
  1194  		`,
  1195  			err:       errors.New(`Expected subject permissions to be a subject, or array of subjects, got bool`),
  1196  			errorLine: 5,
  1197  			errorPos:  9,
  1198  		},
  1199  		{
  1200  			name: "when user authorization permissions subject is invalid",
  1201  			config: `
  1202  		authorization {
  1203  		  permissions {
  1204  		    publish = {
  1205  		      allow = ["foo..bar"]
  1206  		    }
  1207  		    subscribe = {}
  1208  		  }
  1209  		}
  1210  		`,
  1211  			err:       errors.New(`subject "foo..bar" is not a valid subject`),
  1212  			errorLine: 5,
  1213  			errorPos:  9,
  1214  		},
  1215  		{
  1216  			name: "when cluster config listen is invalid",
  1217  			config: `
  1218  		cluster {
  1219  		  listen = "0.0.0.0:XXXX"
  1220  		}
  1221  		`,
  1222  			err:       errors.New(`could not parse port "XXXX"`),
  1223  			errorLine: 3,
  1224  			errorPos:  5,
  1225  		},
  1226  		{
  1227  			name: "when cluster config includes multiple users",
  1228  			config: `
  1229  		cluster {
  1230  		  authorization {
  1231                      users = []
  1232                    }
  1233  		}
  1234  		`,
  1235  			err:       errors.New(`Cluster authorization does not allow multiple users`),
  1236  			errorLine: 3,
  1237  			errorPos:  5,
  1238  		},
  1239  		{
  1240  			name: "when cluster routes are invalid",
  1241  			config: `
  1242  		cluster {
  1243                    routes = [
  1244                      "0.0.0.0:XXXX"
  1245                      # "0.0.0.0:YYYY"
  1246                      # "0.0.0.0:ZZZZ"
  1247                    ]
  1248  		}
  1249  		`,
  1250  			err:       errors.New(`error parsing route url ["0.0.0.0:XXXX"]`),
  1251  			errorLine: 4,
  1252  			errorPos:  22,
  1253  		},
  1254  		{
  1255  			name: "when setting invalid TLS config within cluster block",
  1256  			config: `
  1257  		cluster {
  1258  		  tls {
  1259  		  }
  1260  		}
  1261  		`,
  1262  			err:       nil,
  1263  			errorLine: 0,
  1264  			errorPos:  0,
  1265  		},
  1266  		{
  1267  			name: "invalid lame_duck_duration type",
  1268  			config: `
  1269  				lame_duck_duration: abc
  1270  			`,
  1271  			err:       errors.New(`error parsing lame_duck_duration: time: invalid duration`),
  1272  			errorLine: 2,
  1273  			errorPos:  5,
  1274  		},
  1275  		{
  1276  			name: "lame_duck_duration too small",
  1277  			config: `
  1278  				lame_duck_duration: "5s"
  1279  			`,
  1280  			err:       errors.New(`invalid lame_duck_duration of 5s, minimum is 30 seconds`),
  1281  			errorLine: 2,
  1282  			errorPos:  5,
  1283  		},
  1284  		{
  1285  			name: "invalid lame_duck_grace_period type",
  1286  			config: `
  1287  				lame_duck_grace_period: abc
  1288  			`,
  1289  			err:       errors.New(`error parsing lame_duck_grace_period: time: invalid duration`),
  1290  			errorLine: 2,
  1291  			errorPos:  5,
  1292  		},
  1293  		{
  1294  			name: "lame_duck_grace_period should be positive",
  1295  			config: `
  1296  				lame_duck_grace_period: "-5s"
  1297  			`,
  1298  			err:       errors.New(`invalid lame_duck_grace_period, needs to be positive`),
  1299  			errorLine: 2,
  1300  			errorPos:  5,
  1301  		},
  1302  		{
  1303  			name: "when only setting TLS timeout for a leafnode remote",
  1304  			config: `
  1305  		leafnodes {
  1306  		  remotes = [
  1307  		    {
  1308  		      url: "tls://nats:7422"
  1309  		      tls {
  1310  		        timeout: 0.01
  1311  		      }
  1312  		    }
  1313  		  ]
  1314  		}`,
  1315  			err:       nil,
  1316  			errorLine: 0,
  1317  			errorPos:  0,
  1318  		},
  1319  		{
  1320  			name: "verify_cert_and_check_known_urls do not work for leaf nodes",
  1321  			config: `
  1322  		leafnodes {
  1323  		  remotes = [
  1324  		    {
  1325  		      url: "tls://nats:7422"
  1326  		      tls {
  1327  		        timeout: 0.01
  1328  				verify_cert_and_check_known_urls: true
  1329  		      }
  1330  		    }
  1331  		  ]
  1332  		}`,
  1333  			//Unexpected error after processing config: /var/folders/9h/6g_c9l6n6bb8gp331d_9y0_w0000gn/T/057996446:8:5:
  1334  			err:       errors.New("verify_cert_and_check_known_urls not supported in this context"),
  1335  			errorLine: 8,
  1336  			errorPos:  5,
  1337  		},
  1338  		{
  1339  			name: "when leafnode remotes use wrong type",
  1340  			config: `
  1341  		leafnodes {
  1342  		  remotes: {
  1343    	            url: "tls://nats:7422"
  1344  		  }
  1345  		}`,
  1346  			err:       errors.New(`Expected remotes field to be an array, got map[string]interface {}`),
  1347  			errorLine: 3,
  1348  			errorPos:  5,
  1349  		},
  1350  		{
  1351  			name: "when leafnode remotes url uses wrong type",
  1352  			config: `
  1353  		leafnodes {
  1354  		  remotes: [
  1355    	            { urls: 1234 }
  1356  		  ]
  1357  		}`,
  1358  			err:       errors.New(`Expected remote leafnode url to be an array or string, got 1234`),
  1359  			errorLine: 4,
  1360  			errorPos:  18,
  1361  		},
  1362  		{
  1363  			name: "when leafnode min_version is wrong type",
  1364  			config: `
  1365  				leafnodes {
  1366  					port: -1
  1367  					min_version = 123
  1368  				}`,
  1369  			err:       errors.New(`interface conversion: interface {} is int64, not string`),
  1370  			errorLine: 4,
  1371  			errorPos:  6,
  1372  		},
  1373  		{
  1374  			name: "when leafnode min_version has parsing error",
  1375  			config: `
  1376  				leafnodes {
  1377  					port: -1
  1378  					min_version = bad.version
  1379  				}`,
  1380  			err:       errors.New(`invalid leafnode's minimum version: invalid semver`),
  1381  			errorLine: 4,
  1382  			errorPos:  6,
  1383  		},
  1384  		{
  1385  			name: "when leafnode min_version is too low",
  1386  			config: `
  1387  				leafnodes {
  1388  					port: -1
  1389  					min_version = 2.7.9
  1390  				}`,
  1391  			err:       errors.New(`the minimum version should be at least 2.8.0`),
  1392  			errorLine: 4,
  1393  			errorPos:  6,
  1394  		},
  1395  		{
  1396  			name: "when setting latency tracking with a system account",
  1397  			config: `
  1398                  system_account: sys
  1399  
  1400                  accounts {
  1401                    sys { users = [ {user: sys, pass: "" } ] }
  1402  
  1403                    nats.io: {
  1404                      users = [ { user : bar, pass: "" } ]
  1405  
  1406                      exports = [
  1407                        { service: "nats.add"
  1408                          response: singleton
  1409                          latency: {
  1410                            sampling: 100%
  1411                            subject: "latency.tracking.add"
  1412                          }
  1413                        }
  1414  
  1415                      ]
  1416                    }
  1417                  }
  1418                  `,
  1419  			err:       nil,
  1420  			errorLine: 0,
  1421  			errorPos:  0,
  1422  		},
  1423  		{
  1424  			name: "when setting latency tracking with an invalid publish subject",
  1425  			config: `
  1426                  system_account = sys
  1427                  accounts {
  1428                    sys { users = [ {user: sys, pass: "" } ] }
  1429  
  1430                    nats.io: {
  1431                      users = [ { user : bar, pass: "" } ]
  1432  
  1433                      exports = [
  1434                        { service: "nats.add"
  1435                          response: singleton
  1436                          latency: "*"
  1437                        }
  1438                      ]
  1439                    }
  1440                  }
  1441                  `,
  1442  			err:       errors.New(`Error adding service latency sampling for "nats.add" on subject "*": invalid publish subject`),
  1443  			errorLine: 3,
  1444  			errorPos:  17,
  1445  		},
  1446  		{
  1447  			name: "when setting latency tracking on a stream",
  1448  			config: `
  1449                  system_account = sys
  1450                  accounts {
  1451                    sys { users = [ {user: sys, pass: "" } ] }
  1452  
  1453                    nats.io: {
  1454                      users = [ { user : bar, pass: "" } ]
  1455  
  1456                      exports = [
  1457                        { stream: "nats.add"
  1458                          latency: "foo"
  1459                        }
  1460                      ]
  1461                    }
  1462                  }
  1463                  `,
  1464  			err:       errors.New(`Detected latency directive on non-service`),
  1465  			errorLine: 11,
  1466  			errorPos:  25,
  1467  		},
  1468  		{
  1469  			name: "when setting allow_trace on a stream export (after)",
  1470  			config: `
  1471                  system_account = sys
  1472                  accounts {
  1473                    sys { users = [ {user: sys, pass: "" } ] }
  1474  
  1475                    nats.io: {
  1476                      users = [ { user : bar, pass: "" } ]
  1477                      exports = [ { stream: "nats.add", allow_trace: true } ]
  1478                    }
  1479                  }
  1480                  `,
  1481  			err:       errors.New(`Detected allow_trace directive on non-service`),
  1482  			errorLine: 8,
  1483  			errorPos:  55,
  1484  		},
  1485  		{
  1486  			name: "when setting allow_trace on a stream export (before)",
  1487  			config: `
  1488                  system_account = sys
  1489                  accounts {
  1490                    sys { users = [ {user: sys, pass: "" } ] }
  1491  
  1492                    nats.io: {
  1493                      users = [ { user : bar, pass: "" } ]
  1494                      exports = [ { allow_trace: true, stream: "nats.add" } ]
  1495                    }
  1496                  }
  1497                  `,
  1498  			err:       errors.New(`Detected allow_trace directive on non-service`),
  1499  			errorLine: 8,
  1500  			errorPos:  35,
  1501  		},
  1502  		{
  1503  			name: "when setting allow_trace on a service import (after)",
  1504  			config: `
  1505                  accounts {
  1506                    A: {
  1507                      users = [ {user: user1, pass: ""} ]
  1508                      exports = [{service: "foo"}]
  1509                    }
  1510                    B: {
  1511                      users = [ {user: user2, pass: ""} ]
  1512                      imports = [ { service: {account: "A", subject: "foo"}, allow_trace: true } ]
  1513                    }
  1514                  }
  1515                  `,
  1516  			err:       errors.New(`Detected allow_trace directive on a non-stream`),
  1517  			errorLine: 9,
  1518  			errorPos:  76,
  1519  		},
  1520  		{
  1521  			name: "when setting allow_trace on a service import (before)",
  1522  			config: `
  1523                  accounts {
  1524                    A: {
  1525                      users = [ {user: user1, pass: ""} ]
  1526                      exports = [{service: "foo"}]
  1527                    }
  1528                    B: {
  1529                      users = [ {user: user2, pass: ""} ]
  1530                      imports = [ { allow_trace: true, service: {account: "A", subject: "foo"} } ]
  1531                    }
  1532                  }
  1533                  `,
  1534  			err:       errors.New(`Detected allow_trace directive on a non-stream`),
  1535  			errorLine: 9,
  1536  			errorPos:  35,
  1537  		},
  1538  		{
  1539  			name: "when using duplicate service import subject",
  1540  			config: `
  1541  								accounts {
  1542  									 A: {
  1543  										 users = [ {user: user1, pass: ""} ]
  1544  										 exports = [
  1545  											 {service: "remote1"}
  1546  											 {service: "remote2"}
  1547  										 ]
  1548  									 }
  1549  									 B: {
  1550  										 users = [ {user: user2, pass: ""} ]
  1551  										 imports = [
  1552  											 {service: {account: "A", subject: "remote1"}, to: "local"}
  1553  											 {service: {account: "A", subject: "remote2"}, to: "local"}
  1554  										 ]
  1555  									 }
  1556  								}
  1557  							`,
  1558  			err:       errors.New(`Duplicate service import subject "local", previously used in import for account "A", subject "remote1"`),
  1559  			errorLine: 14,
  1560  			errorPos:  71,
  1561  		},
  1562  		{
  1563  			name: "mixing single and multi users in leafnode authorization",
  1564  			config: `
  1565                  leafnodes {
  1566                     authorization {
  1567                       user: user1
  1568                       password: pwd
  1569                       users = [{user: user2, password: pwd}]
  1570                     }
  1571                  }
  1572                `,
  1573  			err:       errors.New("can not have a single user/pass and a users array"),
  1574  			errorLine: 3,
  1575  			errorPos:  20,
  1576  		},
  1577  		{
  1578  			name: "duplicate usernames in leafnode authorization",
  1579  			config: `
  1580                  leafnodes {
  1581                      authorization {
  1582                          users = [
  1583                              {user: user, password: pwd}
  1584                              {user: user, password: pwd}
  1585                          ]
  1586                      }
  1587                  }
  1588                `,
  1589  			err:       errors.New(`duplicate user "user" detected in leafnode authorization`),
  1590  			errorLine: 3,
  1591  			errorPos:  21,
  1592  		},
  1593  		{
  1594  			name: "mqtt bad type",
  1595  			config: `
  1596                  mqtt [
  1597  					"wrong"
  1598  				]
  1599  			`,
  1600  			err:       errors.New(`Expected mqtt to be a map, got []interface {}`),
  1601  			errorLine: 2,
  1602  			errorPos:  17,
  1603  		},
  1604  		{
  1605  			name: "mqtt bad listen",
  1606  			config: `
  1607                  mqtt {
  1608                      listen: "xxxxxxxx"
  1609  				}
  1610  			`,
  1611  			err:       errors.New(`could not parse address string "xxxxxxxx"`),
  1612  			errorLine: 3,
  1613  			errorPos:  21,
  1614  		},
  1615  		{
  1616  			name: "mqtt bad host",
  1617  			config: `
  1618                  mqtt {
  1619                      host: 1234
  1620  				}
  1621  			`,
  1622  			err:       errors.New(`interface conversion: interface {} is int64, not string`),
  1623  			errorLine: 3,
  1624  			errorPos:  21,
  1625  		},
  1626  		{
  1627  			name: "mqtt bad port",
  1628  			config: `
  1629                  mqtt {
  1630                      port: "abc"
  1631  				}
  1632  			`,
  1633  			err:       errors.New(`interface conversion: interface {} is string, not int64`),
  1634  			errorLine: 3,
  1635  			errorPos:  21,
  1636  		},
  1637  		{
  1638  			name: "mqtt bad TLS",
  1639  			config: `
  1640                  mqtt {
  1641  					port: -1
  1642                      tls {
  1643                          cert_file: "./configs/certs/server.pem"
  1644  					}
  1645  				}
  1646  			`,
  1647  			err:       errors.New(`missing 'key_file' in TLS configuration`),
  1648  			errorLine: 4,
  1649  			errorPos:  21,
  1650  		},
  1651  		{
  1652  			name: "connection types wrong type",
  1653  			config: `
  1654                     authorization {
  1655                         users [
  1656                             {user: a, password: pwd, allowed_connection_types: 123}
  1657  					   ]
  1658  				   }
  1659  			`,
  1660  			err:       errors.New(`error parsing allowed connection types: unsupported type int64`),
  1661  			errorLine: 4,
  1662  			errorPos:  53,
  1663  		},
  1664  		{
  1665  			name: "connection types content wrong type",
  1666  			config: `
  1667                     authorization {
  1668                         users [
  1669                             {user: a, password: pwd, allowed_connection_types: [
  1670                                 123
  1671                                 WEBSOCKET
  1672  							]}
  1673  					   ]
  1674  				   }
  1675  			`,
  1676  			err:       errors.New(`error parsing allowed connection types: unsupported type in array int64`),
  1677  			errorLine: 5,
  1678  			errorPos:  32,
  1679  		},
  1680  		{
  1681  			name: "connection types type unknown",
  1682  			config: `
  1683                     authorization {
  1684                         users [
  1685                             {user: a, password: pwd, allowed_connection_types: [ "UNKNOWN" ]}
  1686  					   ]
  1687  				   }
  1688  			`,
  1689  			err:       fmt.Errorf("invalid connection types [%q]", "UNKNOWN"),
  1690  			errorLine: 4,
  1691  			errorPos:  53,
  1692  		},
  1693  		{
  1694  			name: "websocket auth unknown var",
  1695  			config: `
  1696  				websocket {
  1697  					authorization {
  1698                          unknown: "field"
  1699  				   }
  1700  				}
  1701  			`,
  1702  			err:       fmt.Errorf("unknown field %q", "unknown"),
  1703  			errorLine: 4,
  1704  			errorPos:  25,
  1705  		},
  1706  		{
  1707  			name: "websocket bad tls",
  1708  			config: `
  1709  				websocket {
  1710                      tls {
  1711  						cert_file: "configs/certs/server.pem"
  1712  					}
  1713  				}
  1714  			`,
  1715  			err:       fmt.Errorf("missing 'key_file' in TLS configuration"),
  1716  			errorLine: 3,
  1717  			errorPos:  21,
  1718  		},
  1719  		{
  1720  			name: "verify_cert_and_check_known_urls not support for websockets",
  1721  			config: `
  1722  				websocket {
  1723                      tls {
  1724  						cert_file: "configs/certs/server.pem"
  1725  						key_file: "configs/certs/key.pem"
  1726  					    verify_cert_and_check_known_urls: true
  1727  					}
  1728  				}
  1729  			`,
  1730  			err:       fmt.Errorf("verify_cert_and_check_known_urls not supported in this context"),
  1731  			errorLine: 6,
  1732  			errorPos:  10,
  1733  		},
  1734  		{
  1735  			name: "ambiguous store dir",
  1736  			config: `
  1737                                  store_dir: "foo"
  1738                                  jetstream {
  1739                                    store_dir: "bar"
  1740                                  }
  1741                          `,
  1742  			err: fmt.Errorf(`Duplicate 'store_dir' configuration`),
  1743  		},
  1744  		{
  1745  			name: "token not supported in cluster",
  1746  			config: `
  1747  				cluster {
  1748  					port: -1
  1749  					authorization {
  1750  						token: "my_token"
  1751  					}
  1752  				}
  1753  			`,
  1754  			err:       fmt.Errorf("Cluster authorization does not support tokens"),
  1755  			errorLine: 4,
  1756  			errorPos:  6,
  1757  		},
  1758  		{
  1759  			name: "token not supported in gateway",
  1760  			config: `
  1761  				gateway {
  1762  					port: -1
  1763  					name: "A"
  1764  					authorization {
  1765  						token: "my_token"
  1766  					}
  1767  				}
  1768  			`,
  1769  			err:       fmt.Errorf("Gateway authorization does not support tokens"),
  1770  			errorLine: 5,
  1771  			errorPos:  6,
  1772  		},
  1773  		{
  1774  			name: "wrong type for cluster pool size",
  1775  			config: `
  1776  				cluster {
  1777  					port: -1
  1778  					pool_size: "abc"
  1779  				}
  1780  			`,
  1781  			err:       fmt.Errorf("interface conversion: interface {} is string, not int64"),
  1782  			errorLine: 4,
  1783  			errorPos:  6,
  1784  		},
  1785  		{
  1786  			name: "wrong type for cluster accounts",
  1787  			config: `
  1788  				cluster {
  1789  					port: -1
  1790  					accounts: 123
  1791  				}
  1792  			`,
  1793  			err:       fmt.Errorf("error parsing accounts: unsupported type int64"),
  1794  			errorLine: 4,
  1795  			errorPos:  6,
  1796  		},
  1797  		{
  1798  			name: "wrong type for cluster compression",
  1799  			config: `
  1800  				cluster {
  1801  					port: -1
  1802  					compression: 123
  1803  				}
  1804  			`,
  1805  			err:       fmt.Errorf("field %q should be a boolean or a structure, got int64", "compression"),
  1806  			errorLine: 4,
  1807  			errorPos:  6,
  1808  		},
  1809  		{
  1810  			name: "wrong type for cluster compression mode",
  1811  			config: `
  1812  				cluster {
  1813  					port: -1
  1814  					compression: {
  1815  						mode: 123
  1816  					}
  1817  				}
  1818  			`,
  1819  			err:       fmt.Errorf("interface conversion: interface {} is int64, not string"),
  1820  			errorLine: 5,
  1821  			errorPos:  7,
  1822  		},
  1823  		{
  1824  			name: "wrong type for cluster compression rtt thresholds",
  1825  			config: `
  1826  				cluster {
  1827  					port: -1
  1828  					compression: {
  1829  						mode: "s2_auto"
  1830  						rtt_thresholds: 123
  1831  					}
  1832  				}
  1833  			`,
  1834  			err:       fmt.Errorf("interface conversion: interface {} is int64, not []interface {}"),
  1835  			errorLine: 6,
  1836  			errorPos:  7,
  1837  		},
  1838  		{
  1839  			name: "invalid durations for cluster compression rtt thresholds",
  1840  			config: `
  1841  				cluster {
  1842  					port: -1
  1843  					compression: {
  1844  						mode: "s2_auto"
  1845  						rtt_thresholds: [abc]
  1846  					}
  1847  				}
  1848  			`,
  1849  			err:       fmt.Errorf("time: invalid duration %q", "abc"),
  1850  			errorLine: 6,
  1851  			errorPos:  7,
  1852  		},
  1853  		{
  1854  			name: "invalid durations for cluster ping interval",
  1855  			config: `
  1856  				cluster {
  1857  					port: -1
  1858  					ping_interval: -1
  1859  					ping_max: 6
  1860  				}
  1861  			`,
  1862  			err:       fmt.Errorf(`invalid use of field "ping_interval": ping_interval should be converted to a duration`),
  1863  			errorLine: 4,
  1864  			errorPos:  6,
  1865  		},
  1866  		{
  1867  			name: "invalid durations for cluster ping interval",
  1868  			config: `
  1869  				cluster {
  1870  					port: -1
  1871  					ping_interval: '2m'
  1872  					ping_max: 6
  1873  				}
  1874  			`,
  1875  			warningErr: fmt.Errorf(`Cluster 'ping_interval' will reset to 30s which is the max for routes`),
  1876  			errorLine:  4,
  1877  			errorPos:   6,
  1878  		},
  1879  		{
  1880  			name: "wrong type for leafnodes compression",
  1881  			config: `
  1882  				leafnodes {
  1883  					port: -1
  1884  					compression: 123
  1885  				}
  1886  			`,
  1887  			err:       fmt.Errorf("field %q should be a boolean or a structure, got int64", "compression"),
  1888  			errorLine: 4,
  1889  			errorPos:  6,
  1890  		},
  1891  		{
  1892  			name: "wrong type for leafnodes compression mode",
  1893  			config: `
  1894  				leafnodes {
  1895  					port: -1
  1896  					compression: {
  1897  						mode: 123
  1898  					}
  1899  				}
  1900  			`,
  1901  			err:       fmt.Errorf("interface conversion: interface {} is int64, not string"),
  1902  			errorLine: 5,
  1903  			errorPos:  7,
  1904  		},
  1905  		{
  1906  			name: "wrong type for leafnodes compression rtt thresholds",
  1907  			config: `
  1908  				leafnodes {
  1909  					port: -1
  1910  					compression: {
  1911  						mode: "s2_auto"
  1912  						rtt_thresholds: 123
  1913  					}
  1914  				}
  1915  			`,
  1916  			err:       fmt.Errorf("interface conversion: interface {} is int64, not []interface {}"),
  1917  			errorLine: 6,
  1918  			errorPos:  7,
  1919  		},
  1920  		{
  1921  			name: "invalid durations for leafnodes compression rtt thresholds",
  1922  			config: `
  1923  				leafnodes {
  1924  					port: -1
  1925  					compression: {
  1926  						mode: "s2_auto"
  1927  						rtt_thresholds: [abc]
  1928  					}
  1929  				}
  1930  			`,
  1931  			err:       fmt.Errorf("time: invalid duration %q", "abc"),
  1932  			errorLine: 6,
  1933  			errorPos:  7,
  1934  		},
  1935  		{
  1936  			name: "wrong type for remote leafnodes compression",
  1937  			config: `
  1938  				leafnodes {
  1939  					port: -1
  1940  					remotes [
  1941  						{
  1942  							url: "nats://127.0.0.1:123"
  1943  							compression: 123
  1944  						}
  1945  					]
  1946  				}
  1947  			`,
  1948  			err:       fmt.Errorf("field %q should be a boolean or a structure, got int64", "compression"),
  1949  			errorLine: 7,
  1950  			errorPos:  8,
  1951  		},
  1952  		{
  1953  			name: "wrong type for remote leafnodes compression mode",
  1954  			config: `
  1955  				leafnodes {
  1956  					port: -1
  1957  					remotes [
  1958  						{
  1959  							url: "nats://127.0.0.1:123"
  1960  							compression: {
  1961  								mode: 123
  1962  							}
  1963  						}
  1964  					]
  1965  				}
  1966  			`,
  1967  			err:       fmt.Errorf("interface conversion: interface {} is int64, not string"),
  1968  			errorLine: 8,
  1969  			errorPos:  9,
  1970  		},
  1971  		{
  1972  			name: "wrong type for remote leafnodes compression rtt thresholds",
  1973  			config: `
  1974  				leafnodes {
  1975  					port: -1
  1976  					remotes [
  1977  						{
  1978  							url: "nats://127.0.0.1:123"
  1979  							compression: {
  1980  								mode: "s2_auto"
  1981  								rtt_thresholds: 123
  1982  							}
  1983  						}
  1984  					]
  1985  				}
  1986  			`,
  1987  			err:       fmt.Errorf("interface conversion: interface {} is int64, not []interface {}"),
  1988  			errorLine: 9,
  1989  			errorPos:  9,
  1990  		},
  1991  		{
  1992  			name: "invalid durations for remote leafnodes compression rtt thresholds",
  1993  			config: `
  1994  				leafnodes {
  1995  					port: -1
  1996  					remotes [
  1997  						{
  1998  							url: "nats://127.0.0.1:123"
  1999  							compression: {
  2000  								mode: "s2_auto"
  2001  								rtt_thresholds: [abc]
  2002  							}
  2003  						}
  2004  					]
  2005  				}
  2006  			`,
  2007  			err:       fmt.Errorf("time: invalid duration %q", "abc"),
  2008  			errorLine: 9,
  2009  			errorPos:  9,
  2010  		},
  2011  		{
  2012  			name:       "show warnings on empty configs without values",
  2013  			config:     ``,
  2014  			warningErr: errors.New(`config has no values or is empty`),
  2015  			errorLine:  0,
  2016  			errorPos:   0,
  2017  			reason:     "",
  2018  		},
  2019  		{
  2020  			name: "show warnings on empty configs without values and only comments",
  2021  			config: `# Valid file but has no usable values.
  2022                                      `,
  2023  			warningErr: errors.New(`config has no values or is empty`),
  2024  			errorLine:  0,
  2025  			errorPos:   0,
  2026  			reason:     "",
  2027  		},
  2028  		{
  2029  			name: "TLS handshake first, wrong type",
  2030  			config: `
  2031  				port: -1
  2032  				tls {
  2033  					first: 123
  2034  				}
  2035  			`,
  2036  			err:       fmt.Errorf("field %q should be a boolean or a string, got int64", "first"),
  2037  			errorLine: 4,
  2038  			errorPos:  6,
  2039  		},
  2040  		{
  2041  			name: "TLS handshake first, wrong value",
  2042  			config: `
  2043  				port: -1
  2044  				tls {
  2045  					first: "123"
  2046  				}
  2047  			`,
  2048  			err:       fmt.Errorf("field %q's value %q is invalid", "first", "123"),
  2049  			errorLine: 4,
  2050  			errorPos:  6,
  2051  		},
  2052  		{
  2053  			name: "TLS multiple certs",
  2054  			config: `
  2055  				port: -1
  2056  				tls {
  2057  					certs: [
  2058  					  { cert_file: "configs/certs/server.pem", key_file: "configs/certs/key.pem"},
  2059  					  { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"},
  2060  					]
  2061  				}
  2062  			`,
  2063  			err: nil,
  2064  		},
  2065  		{
  2066  			name: "TLS multiple certs, bad type",
  2067  			config: `
  2068  				port: -1
  2069  				tls {
  2070  					certs: [
  2071  					  { cert_file: "configs/certs/server.pem", key_file: 123 },
  2072  					  { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"},
  2073  					]
  2074  				}
  2075  			`,
  2076  			err:       fmt.Errorf("error parsing certificates config: unsupported type int64"),
  2077  			errorLine: 5,
  2078  			errorPos:  49,
  2079  		},
  2080  		{
  2081  			name: "TLS multiple certs, missing key_file",
  2082  			config: `
  2083  				port: -1
  2084  				tls {
  2085  					certs: [
  2086  					  { cert_file: "configs/certs/server.pem" }
  2087  					  { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"}
  2088  					]
  2089  				}
  2090  			`,
  2091  			err:       fmt.Errorf("error parsing certificates config: both 'cert_file' and 'cert_key' options are required"),
  2092  			errorLine: 5,
  2093  			errorPos:  10,
  2094  		},
  2095  		{
  2096  			name: "TLS multiple certs and single cert options at the same time",
  2097  			config: `
  2098  				port: -1
  2099  				tls {
  2100  					cert_file: "configs/certs/server.pem"
  2101  					key_file: "configs/certs/key.pem"
  2102  					certs: [
  2103  					  { cert_file: "configs/certs/server.pem", key_file: "configs/certs/key.pem"},
  2104  					  { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"},
  2105  					]
  2106  				}
  2107  			`,
  2108  			err:       fmt.Errorf("error parsing tls config, cannot combine 'cert_file' option with 'certs' option"),
  2109  			errorLine: 3,
  2110  			errorPos:  5,
  2111  		},
  2112  		{
  2113  			name: "TLS multiple certs used but not configured, but cert_file configured",
  2114  			config: `
  2115  				port: -1
  2116  				tls {
  2117  					cert_file: "configs/certs/server.pem"
  2118  					key_file: "configs/certs/key.pem"
  2119  					certs: []
  2120  				}
  2121  			`,
  2122  			err: nil,
  2123  		},
  2124  		{
  2125  			name: "TLS multiple certs, missing bad path",
  2126  			config: `
  2127  				port: -1
  2128  				tls {
  2129  					certs: [
  2130  					  { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"}
  2131  					  { cert_file: "configs/certs/server.pem", key_file: "configs/certs/key.new.pom" }
  2132  					]
  2133  				}
  2134  			`,
  2135  			err:       fmt.Errorf("error parsing X509 certificate/key pair 2/2: open configs/certs/key.new.pom: no such file or directory"),
  2136  			errorLine: 3,
  2137  			errorPos:  5,
  2138  		},
  2139  	}
  2140  
  2141  	checkConfig := func(config string) error {
  2142  		opts := &Options{
  2143  			CheckConfig: true,
  2144  		}
  2145  		return opts.ProcessConfigFile(config)
  2146  	}
  2147  
  2148  	checkErr := func(t *testing.T, err, expectedErr error) {
  2149  		t.Helper()
  2150  		switch {
  2151  		case err == nil && expectedErr == nil:
  2152  			// OK
  2153  		case err != nil && expectedErr == nil:
  2154  			t.Errorf("Unexpected error after processing config: %s", err)
  2155  		case err == nil && expectedErr != nil:
  2156  			t.Errorf("Expected %q error after processing invalid config but got nothing", expectedErr)
  2157  		}
  2158  	}
  2159  	for _, test := range tests {
  2160  		t.Run(test.name, func(t *testing.T) {
  2161  			conf := createConfFile(t, []byte(test.config))
  2162  			err := checkConfig(conf)
  2163  			var expectedErr error
  2164  
  2165  			// Check for either warnings or errors.
  2166  			if test.err != nil {
  2167  				expectedErr = test.err
  2168  			} else if test.warningErr != nil {
  2169  				expectedErr = test.warningErr
  2170  			}
  2171  
  2172  			if err != nil && expectedErr != nil {
  2173  				var msg string
  2174  
  2175  				if test.errorPos > 0 {
  2176  					msg = fmt.Sprintf("%s:%d:%d: %s", conf, test.errorLine, test.errorPos, expectedErr.Error())
  2177  					if test.reason != "" {
  2178  						msg += ": " + test.reason
  2179  					}
  2180  				} else if test.warningErr != nil {
  2181  					msg = expectedErr.Error()
  2182  				} else {
  2183  					msg = test.reason
  2184  				}
  2185  
  2186  				if !strings.Contains(err.Error(), msg) {
  2187  					t.Errorf("Expected:\n%q\ngot:\n%q", msg, err.Error())
  2188  				}
  2189  			}
  2190  
  2191  			checkErr(t, err, expectedErr)
  2192  		})
  2193  	}
  2194  }
  2195  
  2196  func TestConfigCheckIncludes(t *testing.T) {
  2197  	// Check happy path first.
  2198  	opts := &Options{
  2199  		CheckConfig: true,
  2200  	}
  2201  	err := opts.ProcessConfigFile("./configs/include_conf_check_a.conf")
  2202  	if err != nil {
  2203  		t.Errorf("Unexpected error processing include files with configuration check enabled: %v", err)
  2204  	}
  2205  
  2206  	opts = &Options{
  2207  		CheckConfig: true,
  2208  	}
  2209  	err = opts.ProcessConfigFile("./configs/include_bad_conf_check_a.conf")
  2210  	if err == nil {
  2211  		t.Errorf("Expected error processing include files with configuration check enabled: %v", err)
  2212  	}
  2213  	expectedErr := `include_bad_conf_check_b.conf:10:19: unknown field "monitoring_port"` + "\n"
  2214  	if err != nil && !strings.HasSuffix(err.Error(), expectedErr) {
  2215  		t.Errorf("Expected: \n%q, got\n: %q", expectedErr, err.Error())
  2216  	}
  2217  }
  2218  
  2219  func TestConfigCheckMultipleErrors(t *testing.T) {
  2220  	opts := &Options{
  2221  		CheckConfig: true,
  2222  	}
  2223  	err := opts.ProcessConfigFile("./configs/multiple_errors.conf")
  2224  	if err == nil {
  2225  		t.Errorf("Expected error processing config files with multiple errors check enabled: %v", err)
  2226  	}
  2227  	cerr, ok := err.(*processConfigErr)
  2228  	if !ok {
  2229  		t.Fatalf("Expected a configuration process error")
  2230  	}
  2231  	got := len(cerr.Warnings())
  2232  	expected := 1
  2233  	if got != expected {
  2234  		t.Errorf("Expected a %d warning, got: %d", expected, got)
  2235  	}
  2236  	got = len(cerr.Errors())
  2237  	// Could be 7 or 8 errors depending on internal ordering of the parsing.
  2238  	if got != 7 && got != 8 {
  2239  		t.Errorf("Expected 7 or 8 errors, got: %d", got)
  2240  	}
  2241  
  2242  	errMsg := err.Error()
  2243  
  2244  	errs := []string{
  2245  		`./configs/multiple_errors.conf:12:1: invalid use of field "write_deadline": write_deadline should be converted to a duration`,
  2246  		`./configs/multiple_errors.conf:2:1: Cannot have a user/pass and token`,
  2247  		`./configs/multiple_errors.conf:10:1: unknown field "monitoring"`,
  2248  		`./configs/multiple_errors.conf:67:3: Cluster authorization does not allow multiple users`,
  2249  		`./configs/multiple_errors.conf:21:5: Not a valid public nkey for an account: "OC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL"`,
  2250  		`./configs/multiple_errors.conf:26:9: Not a valid public nkey for a user`,
  2251  		`./configs/multiple_errors.conf:36:5: Not a valid public nkey for an account: "ODRZ42QBM7SXQDXXTSVWT2WLLFYOQGAFC4TO6WOAXHEKQHIXR4HFYJDS"`,
  2252  		`./configs/multiple_errors.conf:41:9: Not a valid public nkey for a user`,
  2253  	}
  2254  	for _, msg := range errs {
  2255  		found := strings.Contains(errMsg, msg)
  2256  		if !found {
  2257  			t.Fatalf("Expected to find error %q", msg)
  2258  		}
  2259  	}
  2260  	if got == 8 {
  2261  		extra := "./configs/multiple_errors.conf:54:5: Can not have a single user/pass and accounts"
  2262  		if !strings.Contains(errMsg, extra) {
  2263  			t.Fatalf("Expected to find error %q (%s)", extra, errMsg)
  2264  		}
  2265  	}
  2266  }