get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/test/operator_test.go (about) 1 // Copyright 2018-2019 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package test 15 16 import ( 17 "bytes" 18 "fmt" 19 "os" 20 "strings" 21 "testing" 22 "time" 23 24 "get.pme.sh/pnats/server" 25 "github.com/nats-io/jwt/v2" 26 "github.com/nats-io/nats.go" 27 "github.com/nats-io/nkeys" 28 ) 29 30 const ( 31 testOpConfig = "./configs/operator.conf" 32 testOpInlineConfig = "./configs/operator_inline.conf" 33 ) 34 35 // This matches ./configs/nkeys_jwts/test.seed 36 // Test operator seed. 37 var oSeed = []byte("SOAFYNORQLQFJYBYNUGC5D7SH2MXMUX5BFEWWGHN3EK4VGG5TPT5DZP7QU") 38 39 // This is a signing key seed. 40 var skSeed = []byte("SOAEL3NFOTU6YK3DBTEKQYZ2C5IWSVZWWZCQDASBUOHJKBFLVANK27JMMQ") 41 42 func checkKeys(t *testing.T, opts *server.Options, opc *jwt.OperatorClaims, expected int) { 43 // We should have filled in the TrustedKeys here. 44 if len(opts.TrustedKeys) != expected { 45 t.Fatalf("Should have %d trusted keys, got %d", expected, len(opts.TrustedKeys)) 46 } 47 // Check that we properly placed all keys from the opc into TrustedKeys 48 chkMember := func(s string) { 49 for _, c := range opts.TrustedKeys { 50 if s == c { 51 return 52 } 53 } 54 t.Fatalf("Expected %q to be in TrustedKeys", s) 55 } 56 chkMember(opc.Issuer) 57 for _, sk := range opc.SigningKeys { 58 chkMember(sk) 59 } 60 } 61 62 // This will test that we enforce certain restrictions when you use trusted operators. 63 // Like auth is always true, can't define accounts or users, required to define an account resolver, etc. 64 func TestOperatorRestrictions(t *testing.T) { 65 opts, err := server.ProcessConfigFile(testOpConfig) 66 if err != nil { 67 t.Fatalf("Error processing config file: %v", err) 68 } 69 opts.NoSigs = true 70 if _, err := server.NewServer(opts); err != nil { 71 t.Fatalf("Expected to create a server successfully") 72 } 73 // TrustedKeys get defined when processing from above, trying again with 74 // same opts should not work. 75 if _, err := server.NewServer(opts); err == nil { 76 t.Fatalf("Expected an error with TrustedKeys defined") 77 } 78 // Must wipe and rebuild to succeed. 79 wipeOpts := func() { 80 opts.TrustedKeys = nil 81 opts.Accounts = nil 82 opts.Users = nil 83 opts.Nkeys = nil 84 } 85 86 wipeOpts() 87 opts.Accounts = []*server.Account{{Name: "TEST"}} 88 if _, err := server.NewServer(opts); err == nil { 89 t.Fatalf("Expected an error with Accounts defined") 90 } 91 wipeOpts() 92 opts.Users = []*server.User{{Username: "TEST"}} 93 if _, err := server.NewServer(opts); err == nil { 94 t.Fatalf("Expected an error with Users defined") 95 } 96 wipeOpts() 97 opts.Nkeys = []*server.NkeyUser{{Nkey: "TEST"}} 98 if _, err := server.NewServer(opts); err == nil { 99 t.Fatalf("Expected an error with Nkey Users defined") 100 } 101 wipeOpts() 102 103 opts.AccountResolver = nil 104 if _, err := server.NewServer(opts); err == nil { 105 t.Fatalf("Expected an error without an AccountResolver defined") 106 } 107 } 108 109 func TestOperatorConfig(t *testing.T) { 110 opts, err := server.ProcessConfigFile(testOpConfig) 111 if err != nil { 112 t.Fatalf("Error processing config file: %v", err) 113 } 114 opts.NoSigs = true 115 // Check we have the TrustedOperators 116 if len(opts.TrustedOperators) != 1 { 117 t.Fatalf("Expected to load the operator") 118 } 119 _, err = server.NewServer(opts) 120 if err != nil { 121 t.Fatalf("Expected to create a server: %v", err) 122 } 123 // We should have filled in the public TrustedKeys here. 124 // Our master public key (issuer) plus the signing keys (3). 125 checkKeys(t, opts, opts.TrustedOperators[0], 4) 126 } 127 128 func TestOperatorConfigInline(t *testing.T) { 129 opts, err := server.ProcessConfigFile(testOpInlineConfig) 130 if err != nil { 131 t.Fatalf("Error processing config file: %v", err) 132 } 133 opts.NoSigs = true 134 // Check we have the TrustedOperators 135 if len(opts.TrustedOperators) != 1 { 136 t.Fatalf("Expected to load the operator") 137 } 138 _, err = server.NewServer(opts) 139 if err != nil { 140 t.Fatalf("Expected to create a server: %v", err) 141 } 142 // We should have filled in the public TrustedKeys here. 143 // Our master public key (issuer) plus the signing keys (3). 144 checkKeys(t, opts, opts.TrustedOperators[0], 4) 145 } 146 147 func runOperatorServer(t *testing.T) (*server.Server, *server.Options) { 148 return RunServerWithConfig(testOpConfig) 149 } 150 151 func publicKeyFromKeyPair(t *testing.T, pair nkeys.KeyPair) (pkey string) { 152 var err error 153 if pkey, err = pair.PublicKey(); err != nil { 154 t.Fatalf("Expected no error %v", err) 155 } 156 return 157 } 158 159 func createAccountForOperatorKey(t *testing.T, s *server.Server, seed []byte) nkeys.KeyPair { 160 t.Helper() 161 okp, _ := nkeys.FromSeed(seed) 162 akp, _ := nkeys.CreateAccount() 163 pub, _ := akp.PublicKey() 164 nac := jwt.NewAccountClaims(pub) 165 jwt, _ := nac.Encode(okp) 166 if err := s.AccountResolver().Store(pub, jwt); err != nil { 167 t.Fatalf("Account Resolver returned an error: %v", err) 168 } 169 return akp 170 } 171 172 func createAccount(t *testing.T, s *server.Server) (acc *server.Account, akp nkeys.KeyPair) { 173 t.Helper() 174 akp = createAccountForOperatorKey(t, s, oSeed) 175 if pub, err := akp.PublicKey(); err != nil { 176 t.Fatalf("Expected this to pass, got %v", err) 177 } else if acc, err = s.LookupAccount(pub); err != nil { 178 t.Fatalf("Error looking up account: %v", err) 179 } 180 return acc, akp 181 } 182 183 func createUserCreds(t *testing.T, s *server.Server, akp nkeys.KeyPair) nats.Option { 184 t.Helper() 185 opt, _ := createUserCredsOption(t, s, akp) 186 return opt 187 } 188 189 func createUserCredsOption(t *testing.T, s *server.Server, akp nkeys.KeyPair) (nats.Option, string) { 190 t.Helper() 191 kp, _ := nkeys.CreateUser() 192 pub, _ := kp.PublicKey() 193 nuc := jwt.NewUserClaims(pub) 194 ujwt, err := nuc.Encode(akp) 195 if err != nil { 196 t.Fatalf("Error generating user JWT: %v", err) 197 } 198 userCB := func() (string, error) { 199 return ujwt, nil 200 } 201 sigCB := func(nonce []byte) ([]byte, error) { 202 sig, _ := kp.Sign(nonce) 203 return sig, nil 204 } 205 return nats.UserJWT(userCB, sigCB), pub 206 } 207 208 func TestOperatorServer(t *testing.T) { 209 s, opts := runOperatorServer(t) 210 defer s.Shutdown() 211 212 url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) 213 if _, err := nats.Connect(url); err == nil { 214 t.Fatalf("Expected to fail with no credentials") 215 } 216 217 _, akp := createAccount(t, s) 218 nc, err := nats.Connect(url, createUserCreds(t, s, akp)) 219 if err != nil { 220 t.Fatalf("Error on connect: %v", err) 221 } 222 nc.Close() 223 224 // Now create an account from another operator, this should fail. 225 okp, _ := nkeys.CreateOperator() 226 seed, _ := okp.Seed() 227 akp = createAccountForOperatorKey(t, s, seed) 228 _, err = nats.Connect(url, createUserCreds(t, s, akp)) 229 if err == nil { 230 t.Fatalf("Expected error on connect") 231 } 232 // The account should not be in memory either 233 if v, err := s.LookupAccount(publicKeyFromKeyPair(t, akp)); err == nil { 234 t.Fatalf("Expected account to NOT be in memory: %v", v) 235 } 236 } 237 238 func TestOperatorSystemAccount(t *testing.T) { 239 s, _ := runOperatorServer(t) 240 defer s.Shutdown() 241 242 // Create an account from another operator, this should fail if used as a system account. 243 okp, _ := nkeys.CreateOperator() 244 seed, _ := okp.Seed() 245 akp := createAccountForOperatorKey(t, s, seed) 246 if err := s.SetSystemAccount(publicKeyFromKeyPair(t, akp)); err == nil { 247 t.Fatalf("Expected this to fail") 248 } 249 if acc := s.SystemAccount(); acc != nil { 250 t.Fatalf("Expected no account to be set for system account") 251 } 252 253 acc, _ := createAccount(t, s) 254 if err := s.SetSystemAccount(acc.Name); err != nil { 255 t.Fatalf("Expected this succeed, got %v", err) 256 } 257 if sysAcc := s.SystemAccount(); sysAcc != acc { 258 t.Fatalf("Did not get matching account for system account") 259 } 260 } 261 262 func TestOperatorSigningKeys(t *testing.T) { 263 s, opts := runOperatorServer(t) 264 defer s.Shutdown() 265 266 // Create an account with a signing key, not the master key. 267 akp := createAccountForOperatorKey(t, s, skSeed) 268 // Make sure we can set system account. 269 if err := s.SetSystemAccount(publicKeyFromKeyPair(t, akp)); err != nil { 270 t.Fatalf("Expected this succeed, got %v", err) 271 } 272 273 // Make sure we can create users with it too. 274 url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) 275 nc, err := nats.Connect(url, createUserCreds(t, s, akp)) 276 if err != nil { 277 t.Fatalf("Error on connect: %v", err) 278 } 279 nc.Close() 280 } 281 282 func TestOperatorMemResolverPreload(t *testing.T) { 283 s, opts := RunServerWithConfig("./configs/resolver_preload.conf") 284 defer s.Shutdown() 285 286 // Make sure we can look up the account. 287 acc, _ := s.LookupAccount("ADM2CIIL3RWXBA6T2HW3FODNCQQOUJEHHQD6FKCPVAMHDNTTSMO73ROX") 288 if acc == nil { 289 t.Fatalf("Expected to properly lookup account") 290 } 291 sacc := s.SystemAccount() 292 if sacc == nil { 293 t.Fatalf("Expected to have system account registered") 294 } 295 if sacc.Name != opts.SystemAccount { 296 t.Fatalf("System account does not match, wanted %q, got %q", opts.SystemAccount, sacc.Name) 297 } 298 } 299 300 func TestOperatorConfigReloadDoesntKillNonce(t *testing.T) { 301 s, _ := runOperatorServer(t) 302 defer s.Shutdown() 303 304 if !s.NonceRequired() { 305 t.Fatalf("Error nonce should be required") 306 } 307 308 if err := s.Reload(); err != nil { 309 t.Fatalf("Error on reload: %v", err) 310 } 311 312 if !s.NonceRequired() { 313 t.Fatalf("Error nonce should still be required after reload") 314 } 315 } 316 317 func createAccountForConfig(t *testing.T) (string, nkeys.KeyPair) { 318 t.Helper() 319 okp, _ := nkeys.FromSeed(oSeed) 320 akp, _ := nkeys.CreateAccount() 321 pub, _ := akp.PublicKey() 322 nac := jwt.NewAccountClaims(pub) 323 jwt, _ := nac.Encode(okp) 324 return jwt, akp 325 } 326 327 func TestReloadDoesNotWipeAccountsWithOperatorMode(t *testing.T) { 328 // We will run an operator mode server that forms a cluster. We will 329 // make sure that a reload does not wipe account information. 330 // We will force reload of auth by changing cluster auth timeout. 331 332 // Create two accounts, system and normal account. 333 sysJWT, sysKP := createAccountForConfig(t) 334 sysPub, _ := sysKP.PublicKey() 335 336 accJWT, accKP := createAccountForConfig(t) 337 accPub, _ := accKP.PublicKey() 338 339 cf := ` 340 listen: 127.0.0.1:-1 341 cluster { 342 name: "A" 343 listen: 127.0.0.1:-1 344 pool_size: -1 345 compression: "disabled" 346 authorization { 347 timeout: 2.2 348 } %s 349 } 350 351 operator = "./configs/nkeys/op.jwt" 352 system_account = "%s" 353 354 resolver = MEMORY 355 resolver_preload = { 356 %s : "%s" 357 %s : "%s" 358 } 359 ` 360 contents := strings.Replace(fmt.Sprintf(cf, "", sysPub, sysPub, sysJWT, accPub, accJWT), "\n\t", "\n", -1) 361 conf := createConfFile(t, []byte(contents)) 362 363 s, opts := RunServerWithConfig(conf) 364 defer s.Shutdown() 365 366 // Create a new server and route to main one. 367 routeStr := fmt.Sprintf("\n\t\troutes = [nats-route://%s:%d]", opts.Cluster.Host, opts.Cluster.Port) 368 contents2 := strings.Replace(fmt.Sprintf(cf, routeStr, sysPub, sysPub, sysJWT, accPub, accJWT), "\n\t", "\n", -1) 369 370 conf2 := createConfFile(t, []byte(contents2)) 371 372 s2, opts2 := RunServerWithConfig(conf2) 373 defer s2.Shutdown() 374 375 checkClusterFormed(t, s, s2) 376 377 // Create a client on the first server and subscribe. 378 url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) 379 nc, err := nats.Connect(url, createUserCreds(t, s, accKP)) 380 if err != nil { 381 t.Fatalf("Error on connect: %v", err) 382 } 383 defer nc.Close() 384 385 ch := make(chan bool) 386 nc.Subscribe("foo", func(m *nats.Msg) { ch <- true }) 387 nc.Flush() 388 389 // Use this to check for message. 390 checkForMsg := func() { 391 t.Helper() 392 select { 393 case <-ch: 394 case <-time.After(2 * time.Second): 395 t.Fatal("Timeout waiting for message across route") 396 } 397 } 398 399 // Wait for "foo" interest to be propagated to s2's account `accPub` 400 checkSubInterest(t, s2, accPub, "foo", 2*time.Second) 401 402 // Create second client and send message from this one. Interest should be here. 403 url2 := fmt.Sprintf("nats://%s:%d/", opts2.Host, opts2.Port) 404 nc2, err := nats.Connect(url2, createUserCreds(t, s2, accKP)) 405 if err != nil { 406 t.Fatalf("Error creating client: %v\n", err) 407 } 408 defer nc2.Close() 409 410 // Check that we can send messages. 411 nc2.Publish("foo", nil) 412 checkForMsg() 413 414 // Now shutdown nc2 and srvA. 415 nc2.Close() 416 s2.Shutdown() 417 418 // Now change config and do reload which will do an auth change. 419 b, err := os.ReadFile(conf) 420 if err != nil { 421 t.Fatal(err) 422 } 423 newConf := bytes.Replace(b, []byte("2.2"), []byte("3.3"), 1) 424 err = os.WriteFile(conf, newConf, 0644) 425 if err != nil { 426 t.Fatal(err) 427 } 428 429 // This will cause reloadAuthorization to kick in and reprocess accounts. 430 s.Reload() 431 432 s2, opts2 = RunServerWithConfig(conf2) 433 defer s2.Shutdown() 434 435 checkClusterFormed(t, s, s2) 436 437 checkSubInterest(t, s2, accPub, "foo", 2*time.Second) 438 439 // Reconnect and make sure this works. If accounts blown away this will fail. 440 url2 = fmt.Sprintf("nats://%s:%d/", opts2.Host, opts2.Port) 441 nc2, err = nats.Connect(url2, createUserCreds(t, s2, accKP)) 442 if err != nil { 443 t.Fatalf("Error creating client: %v\n", err) 444 } 445 defer nc2.Close() 446 447 // Check that we can send messages. 448 nc2.Publish("foo", nil) 449 checkForMsg() 450 } 451 452 func TestReloadDoesUpdateAccountsWithMemoryResolver(t *testing.T) { 453 // We will run an operator mode server with a memory resolver. 454 // Reloading should behave similar to configured accounts. 455 456 // Create two accounts, system and normal account. 457 sysJWT, sysKP := createAccountForConfig(t) 458 sysPub, _ := sysKP.PublicKey() 459 460 accJWT, accKP := createAccountForConfig(t) 461 accPub, _ := accKP.PublicKey() 462 463 cf := ` 464 listen: 127.0.0.1:-1 465 cluster { 466 name: "A" 467 listen: 127.0.0.1:-1 468 pool_size: -1 469 authorization { 470 timeout: 2.2 471 } %s 472 } 473 474 operator = "./configs/nkeys/op.jwt" 475 system_account = "%s" 476 477 resolver = MEMORY 478 resolver_preload = { 479 %s : "%s" 480 %s : "%s" 481 } 482 ` 483 contents := strings.Replace(fmt.Sprintf(cf, "", sysPub, sysPub, sysJWT, accPub, accJWT), "\n\t", "\n", -1) 484 conf := createConfFile(t, []byte(contents)) 485 486 s, opts := RunServerWithConfig(conf) 487 defer s.Shutdown() 488 489 // Create a client on the first server and subscribe. 490 url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) 491 nc, err := nats.Connect(url, createUserCreds(t, s, accKP)) 492 if err != nil { 493 t.Fatalf("Error on connect: %v", err) 494 } 495 asyncErr := make(chan error, 1) 496 nc.SetErrorHandler(func(nc *nats.Conn, sub *nats.Subscription, err error) { 497 asyncErr <- err 498 }) 499 defer nc.Close() 500 501 nc.Subscribe("foo", func(m *nats.Msg) {}) 502 nc.Flush() 503 504 // Now update and remove normal account and make sure we get disconnected. 505 accJWT2, accKP2 := createAccountForConfig(t) 506 accPub2, _ := accKP2.PublicKey() 507 contents = strings.Replace(fmt.Sprintf(cf, "", sysPub, sysPub, sysJWT, accPub2, accJWT2), "\n\t", "\n", -1) 508 err = os.WriteFile(conf, []byte(contents), 0644) 509 if err != nil { 510 t.Fatal(err) 511 } 512 513 // This will cause reloadAuthorization to kick in and reprocess accounts. 514 s.Reload() 515 516 select { 517 case err := <-asyncErr: 518 if err != nats.ErrAuthorization { 519 t.Fatalf("Expected ErrAuthorization, got %v", err) 520 } 521 case <-time.After(2 * time.Second): 522 // Give it up to 2 sec. 523 t.Fatal("Expected connection to be disconnected") 524 } 525 526 // Make sure we can lool up new account and not old one. 527 if _, err := s.LookupAccount(accPub2); err != nil { 528 t.Fatalf("Error looking up account: %v", err) 529 } 530 531 if _, err := s.LookupAccount(accPub); err == nil { 532 t.Fatalf("Expected error looking up old account") 533 } 534 } 535 536 func TestReloadFailsWithBadAccountsWithMemoryResolver(t *testing.T) { 537 // Create two accounts, system and normal account. 538 sysJWT, sysKP := createAccountForConfig(t) 539 sysPub, _ := sysKP.PublicKey() 540 541 // Create an expired account by hand here. We want to make sure we start up correctly 542 // with expired or otherwise accounts with validation issues. 543 okp, _ := nkeys.FromSeed(oSeed) 544 545 akp, _ := nkeys.CreateAccount() 546 apub, _ := akp.PublicKey() 547 nac := jwt.NewAccountClaims(apub) 548 nac.IssuedAt = time.Now().Add(-10 * time.Second).Unix() 549 nac.Expires = time.Now().Add(-2 * time.Second).Unix() 550 ajwt, err := nac.Encode(okp) 551 if err != nil { 552 t.Fatalf("Error generating account JWT: %v", err) 553 } 554 555 cf := ` 556 listen: 127.0.0.1:-1 557 cluster { 558 name: "A" 559 listen: 127.0.0.1:-1 560 pool_size: -1 561 authorization { 562 timeout: 2.2 563 } %s 564 } 565 566 operator = "./configs/nkeys/op.jwt" 567 system_account = "%s" 568 569 resolver = MEMORY 570 resolver_preload = { 571 %s : "%s" 572 %s : "%s" 573 } 574 ` 575 contents := strings.Replace(fmt.Sprintf(cf, "", sysPub, sysPub, sysJWT, apub, ajwt), "\n\t", "\n", -1) 576 conf := createConfFile(t, []byte(contents)) 577 578 s, _ := RunServerWithConfig(conf) 579 defer s.Shutdown() 580 581 // Now add in bogus account for second item and make sure reload fails. 582 contents = strings.Replace(fmt.Sprintf(cf, "", sysPub, sysPub, sysJWT, "foo", "bar"), "\n\t", "\n", -1) 583 err = os.WriteFile(conf, []byte(contents), 0644) 584 if err != nil { 585 t.Fatal(err) 586 } 587 588 if err := s.Reload(); err == nil { 589 t.Fatalf("Expected fatal error with bad account on reload") 590 } 591 592 // Put it back with a normal account and reload should succeed. 593 accJWT, accKP := createAccountForConfig(t) 594 accPub, _ := accKP.PublicKey() 595 596 contents = strings.Replace(fmt.Sprintf(cf, "", sysPub, sysPub, sysJWT, accPub, accJWT), "\n\t", "\n", -1) 597 err = os.WriteFile(conf, []byte(contents), 0644) 598 if err != nil { 599 t.Fatal(err) 600 } 601 if err := s.Reload(); err != nil { 602 t.Fatalf("Got unexpected error on reload: %v", err) 603 } 604 } 605 606 func TestConnsRequestDoesNotLoadAccountCheckingConnLimits(t *testing.T) { 607 // Create two accounts, system and normal account. 608 sysJWT, sysKP := createAccountForConfig(t) 609 sysPub, _ := sysKP.PublicKey() 610 611 // Do this account by hand to add in connection limits 612 okp, _ := nkeys.FromSeed(oSeed) 613 accKP, _ := nkeys.CreateAccount() 614 accPub, _ := accKP.PublicKey() 615 nac := jwt.NewAccountClaims(accPub) 616 nac.Limits.Conn = 10 617 accJWT, _ := nac.Encode(okp) 618 619 cf := ` 620 listen: 127.0.0.1:-1 621 cluster { 622 name: "A" 623 listen: 127.0.0.1:-1 624 authorization { 625 timeout: 2.2 626 } %s 627 } 628 629 operator = "./configs/nkeys/op.jwt" 630 system_account = "%s" 631 632 resolver = MEMORY 633 resolver_preload = { 634 %s : "%s" 635 %s : "%s" 636 } 637 ` 638 contents := strings.Replace(fmt.Sprintf(cf, "", sysPub, sysPub, sysJWT, accPub, accJWT), "\n\t", "\n", -1) 639 conf := createConfFile(t, []byte(contents)) 640 641 s, opts := RunServerWithConfig(conf) 642 defer s.Shutdown() 643 644 // Create a new server and route to main one. 645 routeStr := fmt.Sprintf("\n\t\troutes = [nats-route://%s:%d]", opts.Cluster.Host, opts.Cluster.Port) 646 contents2 := strings.Replace(fmt.Sprintf(cf, routeStr, sysPub, sysPub, sysJWT, accPub, accJWT), "\n\t", "\n", -1) 647 648 conf2 := createConfFile(t, []byte(contents2)) 649 650 s2, _ := RunServerWithConfig(conf2) 651 defer s2.Shutdown() 652 653 checkClusterFormed(t, s, s2) 654 655 // Make sure that we do not have the account loaded. 656 // Just SYS and $G 657 if nla := s.NumLoadedAccounts(); nla != 2 { 658 t.Fatalf("Expected only 2 loaded accounts, got %d", nla) 659 } 660 if nla := s2.NumLoadedAccounts(); nla != 2 { 661 t.Fatalf("Expected only 2 loaded accounts, got %d", nla) 662 } 663 664 // Now connect to first server on accPub. 665 nc, err := nats.Connect(s.ClientURL(), createUserCreds(t, s, accKP)) 666 if err != nil { 667 t.Fatalf("Error on connect: %v", err) 668 } 669 defer nc.Close() 670 671 // Just wait for the request for connections to move to S2 and cause a fetch. 672 // This is what we want to fix. 673 time.Sleep(100 * time.Millisecond) 674 675 // We should have 3 here for sure. 676 if nla := s.NumLoadedAccounts(); nla != 3 { 677 t.Fatalf("Expected 3 loaded accounts, got %d", nla) 678 } 679 680 // Now make sure that we still only have 2 loaded accounts on server 2. 681 if nla := s2.NumLoadedAccounts(); nla != 2 { 682 t.Fatalf("Expected only 2 loaded accounts, got %d", nla) 683 } 684 }