get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/jetstream_helpers_test.go (about) 1 // Copyright 2020-2023 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 // Do not exlude this file with the !skip_js_tests since those helpers 15 // are also used by MQTT. 16 17 package server 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "math/rand" 24 "net" 25 "net/url" 26 "os" 27 "strings" 28 "sync" 29 "testing" 30 "time" 31 32 "github.com/nats-io/nats.go" 33 "golang.org/x/time/rate" 34 ) 35 36 // Support functions 37 38 func init() { 39 // Speed up raft for tests. 40 hbInterval = 50 * time.Millisecond 41 minElectionTimeout = 750 * time.Millisecond 42 maxElectionTimeout = 2500 * time.Millisecond 43 lostQuorumInterval = 500 * time.Millisecond 44 lostQuorumCheck = 4 * hbInterval 45 } 46 47 // Used to setup clusters of clusters for tests. 48 type cluster struct { 49 servers []*Server 50 opts []*Options 51 name string 52 t testing.TB 53 nproxies []*netProxy 54 } 55 56 // Used to setup superclusters for tests. 57 type supercluster struct { 58 t *testing.T 59 clusters []*cluster 60 nproxies []*netProxy 61 } 62 63 func (sc *supercluster) shutdown() { 64 if sc == nil { 65 return 66 } 67 for _, np := range sc.nproxies { 68 np.stop() 69 } 70 for _, c := range sc.clusters { 71 shutdownCluster(c) 72 } 73 } 74 75 func (sc *supercluster) randomServer() *Server { 76 return sc.randomCluster().randomServer() 77 } 78 79 func (sc *supercluster) serverByName(sname string) *Server { 80 for _, c := range sc.clusters { 81 if s := c.serverByName(sname); s != nil { 82 return s 83 } 84 } 85 return nil 86 } 87 88 func (sc *supercluster) waitOnStreamLeader(account, stream string) { 89 sc.t.Helper() 90 expires := time.Now().Add(30 * time.Second) 91 for time.Now().Before(expires) { 92 for _, c := range sc.clusters { 93 if leader := c.streamLeader(account, stream); leader != nil { 94 time.Sleep(200 * time.Millisecond) 95 return 96 } 97 } 98 time.Sleep(100 * time.Millisecond) 99 } 100 sc.t.Fatalf("Expected a stream leader for %q %q, got none", account, stream) 101 } 102 103 var jsClusterAccountsTempl = ` 104 listen: 127.0.0.1:-1 105 106 server_name: %s 107 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 108 109 leaf { 110 listen: 127.0.0.1:-1 111 } 112 113 cluster { 114 name: %s 115 listen: 127.0.0.1:%d 116 routes = [%s] 117 } 118 119 websocket { 120 listen: 127.0.0.1:-1 121 compression: true 122 handshake_timeout: "5s" 123 no_tls: true 124 } 125 126 no_auth_user: one 127 128 accounts { 129 ONE { users = [ { user: "one", pass: "p" } ]; jetstream: enabled } 130 TWO { users = [ { user: "two", pass: "p" } ]; jetstream: enabled } 131 NOJS { users = [ { user: "nojs", pass: "p" } ] } 132 $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } 133 } 134 ` 135 136 var jsClusterTempl = ` 137 listen: 127.0.0.1:-1 138 server_name: %s 139 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 140 141 leaf { 142 listen: 127.0.0.1:-1 143 } 144 145 cluster { 146 name: %s 147 listen: 127.0.0.1:%d 148 routes = [%s] 149 } 150 151 # For access to system account. 152 accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } 153 ` 154 155 var jsClusterEncryptedTempl = ` 156 listen: 127.0.0.1:-1 157 server_name: %s 158 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s', key: "s3cr3t!"} 159 160 leaf { 161 listen: 127.0.0.1:-1 162 } 163 164 cluster { 165 name: %s 166 listen: 127.0.0.1:%d 167 routes = [%s] 168 } 169 170 # For access to system account. 171 accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } 172 ` 173 174 var jsClusterMaxBytesTempl = ` 175 listen: 127.0.0.1:-1 176 server_name: %s 177 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 178 179 leaf { 180 listen: 127.0.0.1:-1 181 } 182 183 cluster { 184 name: %s 185 listen: 127.0.0.1:%d 186 routes = [%s] 187 } 188 189 no_auth_user: u 190 191 accounts { 192 $U { 193 users = [ { user: "u", pass: "p" } ] 194 jetstream: { 195 max_mem: 128MB 196 max_file: 18GB 197 max_bytes: true // Forces streams to indicate max_bytes. 198 } 199 } 200 $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } 201 } 202 ` 203 204 var jsClusterMaxBytesAccountLimitTempl = ` 205 listen: 127.0.0.1:-1 206 server_name: %s 207 jetstream: {max_mem_store: 256MB, max_file_store: 4GB, store_dir: '%s'} 208 209 leaf { 210 listen: 127.0.0.1:-1 211 } 212 213 cluster { 214 name: %s 215 listen: 127.0.0.1:%d 216 routes = [%s] 217 } 218 219 no_auth_user: u 220 221 accounts { 222 $U { 223 users = [ { user: "u", pass: "p" } ] 224 jetstream: { 225 max_mem: 128MB 226 max_file: 3GB 227 max_bytes: true // Forces streams to indicate max_bytes. 228 } 229 } 230 $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } 231 } 232 ` 233 234 var jsSuperClusterTempl = ` 235 %s 236 gateway { 237 name: %s 238 listen: 127.0.0.1:%d 239 gateways = [%s 240 ] 241 } 242 243 system_account: "$SYS" 244 ` 245 246 var jsClusterLimitsTempl = ` 247 listen: 127.0.0.1:-1 248 server_name: %s 249 jetstream: {max_mem_store: 2MB, max_file_store: 8MB, store_dir: '%s'} 250 251 cluster { 252 name: %s 253 listen: 127.0.0.1:%d 254 routes = [%s] 255 } 256 257 no_auth_user: u 258 259 accounts { 260 ONE { 261 users = [ { user: "u", pass: "s3cr3t!" } ] 262 jetstream: enabled 263 } 264 $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } 265 } 266 ` 267 268 var jsMixedModeGlobalAccountTempl = ` 269 listen: 127.0.0.1:-1 270 server_name: %s 271 jetstream: {max_mem_store: 2MB, max_file_store: 8MB, store_dir: '%s'} 272 273 cluster { 274 name: %s 275 listen: 127.0.0.1:%d 276 routes = [%s] 277 } 278 279 accounts {$SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } 280 ` 281 282 var jsGWTempl = `%s{name: %s, urls: [%s]}` 283 284 var jsClusterAccountLimitsTempl = ` 285 listen: 127.0.0.1:-1 286 server_name: %s 287 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 288 289 cluster { 290 name: %s 291 listen: 127.0.0.1:%d 292 routes = [%s] 293 } 294 295 no_auth_user: js 296 297 accounts { 298 $JS { users = [ { user: "js", pass: "p" } ]; jetstream: {max_store: 1MB, max_mem: 0} } 299 $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } 300 } 301 ` 302 303 func createJetStreamTaggedSuperCluster(t *testing.T) *supercluster { 304 return createJetStreamTaggedSuperClusterWithGWProxy(t, nil) 305 } 306 307 func createJetStreamTaggedSuperClusterWithGWProxy(t *testing.T, gwm gwProxyMap) *supercluster { 308 sc := createJetStreamSuperClusterWithTemplateAndModHook(t, jsClusterTempl, 3, 3, nil, gwm) 309 sc.waitOnPeerCount(9) 310 311 reset := func(s *Server) { 312 s.mu.Lock() 313 rch := s.sys.resetCh 314 s.mu.Unlock() 315 if rch != nil { 316 rch <- struct{}{} 317 } 318 s.sendStatszUpdate() 319 } 320 321 // Make first cluster AWS, US country code. 322 for _, s := range sc.clusterForName("C1").servers { 323 s.optsMu.Lock() 324 s.opts.Tags.Add("cloud:aws") 325 s.opts.Tags.Add("country:us") 326 s.optsMu.Unlock() 327 reset(s) 328 } 329 // Make second cluster GCP, UK country code. 330 for _, s := range sc.clusterForName("C2").servers { 331 s.optsMu.Lock() 332 s.opts.Tags.Add("cloud:gcp") 333 s.opts.Tags.Add("country:uk") 334 s.optsMu.Unlock() 335 reset(s) 336 } 337 // Make third cluster AZ, JP country code. 338 for _, s := range sc.clusterForName("C3").servers { 339 s.optsMu.Lock() 340 s.opts.Tags.Add("cloud:az") 341 s.opts.Tags.Add("country:jp") 342 s.optsMu.Unlock() 343 reset(s) 344 } 345 346 ml := sc.leader() 347 js := ml.getJetStream() 348 require_True(t, js != nil) 349 js.mu.RLock() 350 defer js.mu.RUnlock() 351 cc := js.cluster 352 require_True(t, cc != nil) 353 354 // Walk and make sure all tags are registered. 355 expires := time.Now().Add(10 * time.Second) 356 for time.Now().Before(expires) { 357 allOK := true 358 for _, p := range cc.meta.Peers() { 359 si, ok := ml.nodeToInfo.Load(p.ID) 360 require_True(t, ok) 361 ni := si.(nodeInfo) 362 if len(ni.tags) == 0 { 363 allOK = false 364 reset(sc.serverByName(ni.name)) 365 } 366 } 367 if allOK { 368 break 369 } 370 } 371 372 return sc 373 } 374 375 func createJetStreamSuperCluster(t *testing.T, numServersPer, numClusters int) *supercluster { 376 return createJetStreamSuperClusterWithTemplate(t, jsClusterTempl, numServersPer, numClusters) 377 } 378 379 func createJetStreamSuperClusterWithTemplate(t *testing.T, tmpl string, numServersPer, numClusters int) *supercluster { 380 return createJetStreamSuperClusterWithTemplateAndModHook(t, tmpl, numServersPer, numClusters, nil, nil) 381 } 382 383 // For doing proxyies in GWs. 384 type gwProxy struct { 385 rtt time.Duration 386 up int 387 down int 388 } 389 390 // For use in normal clusters. 391 type clusterProxy = gwProxy 392 393 // Maps cluster names to proxy settings. 394 type gwProxyMap map[string]*gwProxy 395 396 func createJetStreamSuperClusterWithTemplateAndModHook(t *testing.T, tmpl string, numServersPer, numClusters int, modify modifyCb, gwm gwProxyMap) *supercluster { 397 t.Helper() 398 if numServersPer < 1 { 399 t.Fatalf("Number of servers must be >= 1") 400 } 401 if numClusters <= 1 { 402 t.Fatalf("Number of clusters must be > 1") 403 } 404 405 startClusterPorts := []int{20_022, 22_022, 24_022} 406 startGatewayPorts := []int{20_122, 22_122, 24_122} 407 startClusterPort := startClusterPorts[rand.Intn(len(startClusterPorts))] 408 startGWPort := startGatewayPorts[rand.Intn(len(startGatewayPorts))] 409 410 // Make the GWs form faster for the tests. 411 SetGatewaysSolicitDelay(10 * time.Millisecond) 412 defer ResetGatewaysSolicitDelay() 413 414 cp, gp := startClusterPort, startGWPort 415 var clusters []*cluster 416 var nproxies []*netProxy 417 var gws []string 418 419 // Build GWs first, will be same for all servers. 420 for i, port := 1, gp; i <= numClusters; i++ { 421 cn := fmt.Sprintf("C%d", i) 422 var gwp *gwProxy 423 if len(gwm) > 0 { 424 gwp = gwm[cn] 425 } 426 var urls []string 427 for n := 0; n < numServersPer; n++ { 428 routeURL := fmt.Sprintf("nats-route://127.0.0.1:%d", port) 429 if gwp != nil { 430 np := createNetProxy(gwp.rtt, gwp.up, gwp.down, routeURL, false) 431 nproxies = append(nproxies, np) 432 routeURL = np.routeURL() 433 } 434 urls = append(urls, routeURL) 435 port++ 436 } 437 gws = append(gws, fmt.Sprintf(jsGWTempl, "\n\t\t\t", cn, strings.Join(urls, ","))) 438 } 439 gwconf := strings.Join(gws, _EMPTY_) 440 441 for i := 1; i <= numClusters; i++ { 442 cn := fmt.Sprintf("C%d", i) 443 // Go ahead and build configurations. 444 c := &cluster{servers: make([]*Server, 0, numServersPer), opts: make([]*Options, 0, numServersPer), name: cn} 445 446 // Build out the routes that will be shared with all configs. 447 var routes []string 448 for port := cp; port < cp+numServersPer; port++ { 449 routes = append(routes, fmt.Sprintf("nats-route://127.0.0.1:%d", port)) 450 } 451 routeConfig := strings.Join(routes, ",") 452 453 for si := 0; si < numServersPer; si++ { 454 storeDir := t.TempDir() 455 sn := fmt.Sprintf("%s-S%d", cn, si+1) 456 bconf := fmt.Sprintf(tmpl, sn, storeDir, cn, cp+si, routeConfig) 457 conf := fmt.Sprintf(jsSuperClusterTempl, bconf, cn, gp, gwconf) 458 gp++ 459 if modify != nil { 460 conf = modify(sn, cn, storeDir, conf) 461 } 462 s, o := RunServerWithConfig(createConfFile(t, []byte(conf))) 463 c.servers = append(c.servers, s) 464 c.opts = append(c.opts, o) 465 } 466 checkClusterFormed(t, c.servers...) 467 clusters = append(clusters, c) 468 cp += numServersPer 469 c.t = t 470 } 471 472 // Start any proxies. 473 for _, np := range nproxies { 474 np.start() 475 } 476 477 // Wait for the supercluster to be formed. 478 egws := numClusters - 1 479 for _, c := range clusters { 480 for _, s := range c.servers { 481 waitForOutboundGateways(t, s, egws, 10*time.Second) 482 } 483 } 484 485 sc := &supercluster{t, clusters, nproxies} 486 sc.waitOnLeader() 487 sc.waitOnAllCurrent() 488 489 // Wait for all the peer nodes to be registered. 490 checkFor(t, 5*time.Second, 100*time.Millisecond, func() error { 491 var peers []string 492 if ml := sc.leader(); ml != nil { 493 peers = ml.ActivePeers() 494 if len(peers) == numClusters*numServersPer { 495 return nil 496 } 497 } 498 return fmt.Errorf("Not correct number of peers, expected %d, got %d", numClusters*numServersPer, len(peers)) 499 }) 500 501 if sc.leader() == nil { 502 sc.t.Fatalf("Expected a cluster leader, got none") 503 } 504 505 return sc 506 } 507 508 func (sc *supercluster) createLeafNodes(clusterName string, numServers int) *cluster { 509 sc.t.Helper() 510 511 // Create our leafnode cluster template first. 512 return sc.createLeafNodesWithDomain(clusterName, numServers, "") 513 } 514 515 func (sc *supercluster) createLeafNodesWithDomain(clusterName string, numServers int, domain string) *cluster { 516 sc.t.Helper() 517 518 // Create our leafnode cluster template first. 519 return sc.randomCluster().createLeafNodes(clusterName, numServers, domain) 520 } 521 522 func (sc *supercluster) createSingleLeafNode(extend bool) *Server { 523 sc.t.Helper() 524 525 return sc.randomCluster().createLeafNode(extend) 526 } 527 528 func (sc *supercluster) leader() *Server { 529 for _, c := range sc.clusters { 530 if leader := c.leader(); leader != nil { 531 return leader 532 } 533 } 534 return nil 535 } 536 537 func (sc *supercluster) waitOnLeader() { 538 sc.t.Helper() 539 expires := time.Now().Add(30 * time.Second) 540 for time.Now().Before(expires) { 541 for _, c := range sc.clusters { 542 if leader := c.leader(); leader != nil { 543 time.Sleep(250 * time.Millisecond) 544 return 545 } 546 } 547 time.Sleep(25 * time.Millisecond) 548 } 549 sc.t.Fatalf("Expected a cluster leader, got none") 550 } 551 552 func (sc *supercluster) waitOnAllCurrent() { 553 sc.t.Helper() 554 for _, c := range sc.clusters { 555 c.waitOnAllCurrent() 556 } 557 } 558 559 func (sc *supercluster) clusterForName(name string) *cluster { 560 for _, c := range sc.clusters { 561 if c.name == name { 562 return c 563 } 564 } 565 return nil 566 } 567 568 func (sc *supercluster) randomCluster() *cluster { 569 clusters := append(sc.clusters[:0:0], sc.clusters...) 570 rand.Shuffle(len(clusters), func(i, j int) { clusters[i], clusters[j] = clusters[j], clusters[i] }) 571 return clusters[0] 572 } 573 574 func (sc *supercluster) waitOnPeerCount(n int) { 575 sc.t.Helper() 576 sc.waitOnLeader() 577 leader := sc.leader() 578 expires := time.Now().Add(30 * time.Second) 579 for time.Now().Before(expires) { 580 peers := leader.JetStreamClusterPeers() 581 if len(peers) == n { 582 return 583 } 584 time.Sleep(100 * time.Millisecond) 585 } 586 sc.t.Fatalf("Expected a super cluster peer count of %d, got %d", n, len(leader.JetStreamClusterPeers())) 587 } 588 589 var jsClusterMirrorSourceImportsTempl = ` 590 listen: 127.0.0.1:-1 591 server_name: %s 592 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 593 594 cluster { 595 name: %s 596 listen: 127.0.0.1:%d 597 routes = [%s] 598 } 599 600 no_auth_user: dlc 601 602 accounts { 603 JS { 604 jetstream: enabled 605 users = [ { user: "rip", pass: "pass" } ] 606 exports [ 607 { service: "$JS.API.CONSUMER.>" } # To create internal consumers to mirror/source. 608 { stream: "RI.DELIVER.SYNC.>" } # For the mirror/source consumers sending to IA via delivery subject. 609 { service: "$JS.FC.>" } 610 ] 611 } 612 IA { 613 jetstream: enabled 614 users = [ { user: "dlc", pass: "pass" } ] 615 imports [ 616 { service: { account: JS, subject: "$JS.API.CONSUMER.>"}, to: "RI.JS.API.CONSUMER.>" } 617 { stream: { account: JS, subject: "RI.DELIVER.SYNC.>"} } 618 { service: {account: JS, subject: "$JS.FC.>" }} 619 ] 620 } 621 $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } 622 } 623 ` 624 625 var jsClusterImportsTempl = ` 626 listen: 127.0.0.1:-1 627 server_name: %s 628 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 629 630 cluster { 631 name: %s 632 listen: 127.0.0.1:%d 633 routes = [%s] 634 } 635 636 no_auth_user: dlc 637 638 accounts { 639 JS { 640 jetstream: enabled 641 users = [ { user: "rip", pass: "pass" } ] 642 exports [ 643 { service: "$JS.API.>", response: stream } 644 { service: "TEST" } # For publishing to the stream. 645 { service: "$JS.ACK.TEST.*.>" } 646 ] 647 } 648 IA { 649 users = [ { user: "dlc", pass: "pass" } ] 650 imports [ 651 { service: { subject: "$JS.API.>", account: JS }} 652 { service: { subject: "TEST", account: JS }} 653 { service: { subject: "$JS.ACK.TEST.*.>", account: JS }} 654 ] 655 } 656 $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } 657 } 658 ` 659 660 func createMixedModeCluster(t testing.TB, tmpl string, clusterName, snPre string, numJsServers, numNonServers int, doJSConfig bool) *cluster { 661 t.Helper() 662 663 if clusterName == _EMPTY_ || numJsServers < 0 || numNonServers < 1 { 664 t.Fatalf("Bad params") 665 } 666 667 numServers := numJsServers + numNonServers 668 const startClusterPort = 23232 669 670 // Build out the routes that will be shared with all configs. 671 var routes []string 672 for cp := startClusterPort; cp < startClusterPort+numServers; cp++ { 673 routes = append(routes, fmt.Sprintf("nats-route://127.0.0.1:%d", cp)) 674 } 675 routeConfig := strings.Join(routes, ",") 676 677 // Go ahead and build configurations and start servers. 678 c := &cluster{servers: make([]*Server, 0, numServers), opts: make([]*Options, 0, numServers), name: clusterName} 679 680 for cp := startClusterPort; cp < startClusterPort+numServers; cp++ { 681 storeDir := t.TempDir() 682 683 sn := fmt.Sprintf("%sS-%d", snPre, cp-startClusterPort+1) 684 conf := fmt.Sprintf(tmpl, sn, storeDir, clusterName, cp, routeConfig) 685 686 // Disable JS here. 687 if cp-startClusterPort >= numJsServers { 688 // We can disable by commmenting it out, meaning no JS config, or can set the config up and just set disabled. 689 // e.g. jetstream: {domain: "SPOKE", enabled: false} 690 if doJSConfig { 691 conf = strings.Replace(conf, "jetstream: {", "jetstream: { enabled: false, ", 1) 692 } else { 693 conf = strings.Replace(conf, "jetstream: ", "# jetstream: ", 1) 694 } 695 } 696 697 s, o := RunServerWithConfig(createConfFile(t, []byte(conf))) 698 c.servers = append(c.servers, s) 699 c.opts = append(c.opts, o) 700 } 701 c.t = t 702 703 // Wait til we are formed and have a leader. 704 c.checkClusterFormed() 705 if numJsServers > 0 { 706 c.waitOnPeerCount(numJsServers) 707 } 708 709 return c 710 } 711 712 // This will create a cluster that is explicitly configured for the routes, etc. 713 // and also has a defined clustername. All configs for routes and cluster name will be the same. 714 func createJetStreamClusterExplicit(t testing.TB, clusterName string, numServers int) *cluster { 715 return createJetStreamClusterWithTemplate(t, jsClusterTempl, clusterName, numServers) 716 } 717 718 func createJetStreamClusterWithTemplate(t testing.TB, tmpl string, clusterName string, numServers int) *cluster { 719 return createJetStreamClusterWithTemplateAndModHook(t, tmpl, clusterName, numServers, nil) 720 } 721 722 func createJetStreamClusterWithTemplateAndModHook(t testing.TB, tmpl string, clusterName string, numServers int, modify modifyCb) *cluster { 723 startPorts := []int{7_022, 9_022, 11_022, 15_022} 724 port := startPorts[rand.Intn(len(startPorts))] 725 return createJetStreamClusterAndModHook(t, tmpl, clusterName, _EMPTY_, numServers, port, true, modify) 726 } 727 728 func createJetStreamCluster(t testing.TB, tmpl string, clusterName, snPre string, numServers int, portStart int, waitOnReady bool) *cluster { 729 return createJetStreamClusterAndModHook(t, tmpl, clusterName, snPre, numServers, portStart, waitOnReady, nil) 730 } 731 732 type modifyCb func(serverName, clusterName, storeDir, conf string) string 733 734 func createJetStreamClusterAndModHook(t testing.TB, tmpl, cName, snPre string, numServers int, portStart int, waitOnReady bool, modify modifyCb) *cluster { 735 return createJetStreamClusterEx(t, tmpl, cName, snPre, numServers, portStart, waitOnReady, modify, nil) 736 } 737 738 func createJetStreamClusterWithNetProxy(t testing.TB, cName string, numServers int, cnp *clusterProxy) *cluster { 739 startPorts := []int{7_122, 9_122, 11_122, 15_122} 740 port := startPorts[rand.Intn(len(startPorts))] 741 return createJetStreamClusterEx(t, jsClusterTempl, cName, _EMPTY_, numServers, port, true, nil, cnp) 742 } 743 744 func createJetStreamClusterEx(t testing.TB, tmpl, cName, snPre string, numServers int, portStart int, wait bool, modify modifyCb, cnp *clusterProxy) *cluster { 745 t.Helper() 746 if cName == _EMPTY_ || numServers < 1 { 747 t.Fatalf("Bad params") 748 } 749 750 // Flaky test prevention: 751 // Binding a socket to IP stack port 0 will bind an ephemeral port from an OS-specific range. 752 // If someone passes in to us a port spec which would cover that range, the test would be flaky. 753 // Adjust these ports to be the most inclusive across the port runner OSes. 754 // Linux: /proc/sys/net/ipv4/ip_local_port_range : 32768:60999 755 // <https://dataplane.org/ephemeralports.html> is useful, and shows there's no safe available range without OS-specific tuning. 756 // Our tests are usually run on Linux. Folks who care about other OSes: if you can't tune your test-runner OS to match, please 757 // propose a viable alternative. 758 const prohibitedPortFirst = 32768 759 const prohibitedPortLast = 60999 760 if (portStart >= prohibitedPortFirst && portStart <= prohibitedPortLast) || 761 (portStart+numServers-1 >= prohibitedPortFirst && portStart+numServers-1 <= prohibitedPortLast) { 762 t.Fatalf("test setup failure: may not specify a cluster port range which falls within %d:%d", prohibitedPortFirst, prohibitedPortLast) 763 } 764 765 // Build out the routes that will be shared with all configs. 766 var routes []string 767 var nproxies []*netProxy 768 for cp := portStart; cp < portStart+numServers; cp++ { 769 routeURL := fmt.Sprintf("nats-route://127.0.0.1:%d", cp) 770 if cnp != nil { 771 np := createNetProxy(cnp.rtt, cnp.up, cnp.down, routeURL, false) 772 nproxies = append(nproxies, np) 773 routeURL = np.routeURL() 774 } 775 routes = append(routes, routeURL) 776 } 777 routeConfig := strings.Join(routes, ",") 778 779 // Go ahead and build configurations and start servers. 780 c := &cluster{servers: make([]*Server, 0, numServers), opts: make([]*Options, 0, numServers), name: cName, nproxies: nproxies} 781 782 // Start any proxies. 783 for _, np := range nproxies { 784 np.start() 785 } 786 787 for cp := portStart; cp < portStart+numServers; cp++ { 788 storeDir := t.TempDir() 789 sn := fmt.Sprintf("%sS-%d", snPre, cp-portStart+1) 790 conf := fmt.Sprintf(tmpl, sn, storeDir, cName, cp, routeConfig) 791 if modify != nil { 792 conf = modify(sn, cName, storeDir, conf) 793 } 794 s, o := RunServerWithConfig(createConfFile(t, []byte(conf))) 795 c.servers = append(c.servers, s) 796 c.opts = append(c.opts, o) 797 } 798 c.t = t 799 800 // Wait til we are formed and have a leader. 801 c.checkClusterFormed() 802 if wait { 803 c.waitOnClusterReady() 804 } 805 806 return c 807 } 808 809 func (c *cluster) addInNewServer() *Server { 810 c.t.Helper() 811 sn := fmt.Sprintf("S-%d", len(c.servers)+1) 812 storeDir := c.t.TempDir() 813 seedRoute := fmt.Sprintf("nats-route://127.0.0.1:%d", c.opts[0].Cluster.Port) 814 conf := fmt.Sprintf(jsClusterTempl, sn, storeDir, c.name, -1, seedRoute) 815 s, o := RunServerWithConfig(createConfFile(c.t, []byte(conf))) 816 c.servers = append(c.servers, s) 817 c.opts = append(c.opts, o) 818 c.checkClusterFormed() 819 return s 820 } 821 822 // This is tied to jsClusterAccountsTempl, so changes there to users needs to be reflected here. 823 func (c *cluster) createSingleLeafNodeNoSystemAccount() *Server { 824 as := c.randomServer() 825 lno := as.getOpts().LeafNode 826 ln1 := fmt.Sprintf("nats://one:p@%s:%d", lno.Host, lno.Port) 827 ln2 := fmt.Sprintf("nats://two:p@%s:%d", lno.Host, lno.Port) 828 conf := fmt.Sprintf(jsClusterSingleLeafNodeTempl, c.t.TempDir(), ln1, ln2) 829 s, o := RunServerWithConfig(createConfFile(c.t, []byte(conf))) 830 c.servers = append(c.servers, s) 831 c.opts = append(c.opts, o) 832 833 checkLeafNodeConnectedCount(c.t, as, 2) 834 835 return s 836 } 837 838 // This is tied to jsClusterAccountsTempl, so changes there to users needs to be reflected here. 839 func (c *cluster) createSingleLeafNodeNoSystemAccountAndEnablesJetStream() *Server { 840 return c.createSingleLeafNodeNoSystemAccountAndEnablesJetStreamWithDomain(_EMPTY_, "nojs") 841 } 842 843 func (c *cluster) createSingleLeafNodeNoSystemAccountAndEnablesJetStreamWithDomain(domain, user string) *Server { 844 tmpl := jsClusterSingleLeafNodeLikeNGSTempl 845 if domain != _EMPTY_ { 846 nsc := fmt.Sprintf("domain: %s, store_dir:", domain) 847 tmpl = strings.Replace(jsClusterSingleLeafNodeLikeNGSTempl, "store_dir:", nsc, 1) 848 } 849 as := c.randomServer() 850 lno := as.getOpts().LeafNode 851 ln := fmt.Sprintf("nats://%s:p@%s:%d", user, lno.Host, lno.Port) 852 conf := fmt.Sprintf(tmpl, c.t.TempDir(), ln) 853 s, o := RunServerWithConfig(createConfFile(c.t, []byte(conf))) 854 c.servers = append(c.servers, s) 855 c.opts = append(c.opts, o) 856 857 checkLeafNodeConnectedCount(c.t, as, 1) 858 859 return s 860 } 861 862 var jsClusterSingleLeafNodeLikeNGSTempl = ` 863 listen: 127.0.0.1:-1 864 server_name: LNJS 865 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 866 867 leaf { remotes [ { urls: [ %s ] } ] } 868 ` 869 870 var jsClusterSingleLeafNodeTempl = ` 871 listen: 127.0.0.1:-1 872 server_name: LNJS 873 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 874 875 leaf { remotes [ 876 { urls: [ %s ], account: "JSY" } 877 { urls: [ %s ], account: "JSN" } ] 878 } 879 880 accounts { 881 JSY { users = [ { user: "y", pass: "p" } ]; jetstream: true } 882 JSN { users = [ { user: "n", pass: "p" } ] } 883 $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } 884 } 885 ` 886 887 var jsClusterTemplWithLeafNode = ` 888 listen: 127.0.0.1:-1 889 server_name: %s 890 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 891 892 {{leaf}} 893 894 cluster { 895 name: %s 896 listen: 127.0.0.1:%d 897 routes = [%s] 898 } 899 900 # For access to system account. 901 accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } 902 ` 903 904 var jsClusterTemplWithLeafNodeNoJS = ` 905 listen: 127.0.0.1:-1 906 server_name: %s 907 908 # Need to keep below since it fills in the store dir by default so just comment out. 909 # jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 910 911 {{leaf}} 912 913 cluster { 914 name: %s 915 listen: 127.0.0.1:%d 916 routes = [%s] 917 } 918 919 # For access to system account. 920 accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } 921 ` 922 923 var jsClusterTemplWithSingleLeafNode = ` 924 listen: 127.0.0.1:-1 925 server_name: %s 926 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 927 928 {{leaf}} 929 930 # For access to system account. 931 accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } 932 ` 933 934 var jsClusterTemplWithSingleFleetLeafNode = ` 935 listen: 127.0.0.1:-1 936 server_name: %s 937 cluster: { name: fleet } 938 jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} 939 940 {{leaf}} 941 942 # For access to system account. 943 accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } 944 ` 945 946 var jsClusterTemplWithSingleLeafNodeNoJS = ` 947 listen: 127.0.0.1:-1 948 server_name: %s 949 950 # jetstream: {store_dir: '%s'} 951 952 {{leaf}} 953 954 # For access to system account. 955 accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } 956 ` 957 958 var jsLeafFrag = ` 959 leaf { 960 remotes [ 961 { urls: [ %s ] } 962 { urls: [ %s ], account: "$SYS" } 963 ] 964 } 965 ` 966 var jsLeafNoSysFrag = ` 967 leaf { 968 remotes [ 969 { urls: [ %s ] } 970 ] 971 } 972 ` 973 974 func (c *cluster) createLeafNodes(clusterName string, numServers int, domain string) *cluster { 975 c.t.Helper() 976 return c.createLeafNodesWithStartPortAndDomain(clusterName, numServers, 22111, domain) 977 } 978 979 func (c *cluster) createLeafNodesNoJS(clusterName string, numServers int) *cluster { 980 c.t.Helper() 981 return c.createLeafNodesWithTemplateAndStartPort(jsClusterTemplWithLeafNodeNoJS, clusterName, numServers, 21333) 982 } 983 984 func (c *cluster) createLeafNodesWithStartPortAndDomain(clusterName string, numServers int, portStart int, domain string) *cluster { 985 c.t.Helper() 986 if domain == _EMPTY_ { 987 return c.createLeafNodesWithTemplateAndStartPort(jsClusterTemplWithLeafNode, clusterName, numServers, portStart) 988 } 989 tmpl := strings.Replace(jsClusterTemplWithLeafNode, "store_dir:", fmt.Sprintf(`domain: "%s", store_dir:`, domain), 1) 990 return c.createLeafNodesWithTemplateAndStartPort(tmpl, clusterName, numServers, portStart) 991 } 992 993 func (c *cluster) createLeafNode(extend bool) *Server { 994 c.t.Helper() 995 if extend { 996 return c.createLeafNodeWithTemplate("LNS", 997 strings.ReplaceAll(jsClusterTemplWithSingleLeafNode, "store_dir:", " extension_hint: will_extend, store_dir:")) 998 } else { 999 return c.createLeafNodeWithTemplate("LNS", jsClusterTemplWithSingleLeafNode) 1000 } 1001 } 1002 1003 func (c *cluster) createLeafNodeWithTemplate(name, template string) *Server { 1004 c.t.Helper() 1005 tmpl := c.createLeafSolicit(template) 1006 conf := fmt.Sprintf(tmpl, name, c.t.TempDir()) 1007 s, o := RunServerWithConfig(createConfFile(c.t, []byte(conf))) 1008 c.servers = append(c.servers, s) 1009 c.opts = append(c.opts, o) 1010 return s 1011 } 1012 1013 func (c *cluster) createLeafNodeWithTemplateNoSystem(name, template string) *Server { 1014 return c.createLeafNodeWithTemplateNoSystemWithProto(name, template, "nats") 1015 } 1016 1017 func (c *cluster) createLeafNodeWithTemplateNoSystemWithProto(name, template, proto string) *Server { 1018 c.t.Helper() 1019 tmpl := c.createLeafSolicitNoSystemWithProto(template, proto) 1020 conf := fmt.Sprintf(tmpl, name, c.t.TempDir()) 1021 s, o := RunServerWithConfig(createConfFile(c.t, []byte(conf))) 1022 c.servers = append(c.servers, s) 1023 c.opts = append(c.opts, o) 1024 return s 1025 } 1026 1027 // Helper to generate the leaf solicit configs. 1028 func (c *cluster) createLeafSolicit(tmpl string) string { 1029 return c.createLeafSolicitWithProto(tmpl, "nats") 1030 } 1031 1032 func (c *cluster) createLeafSolicitWithProto(tmpl, proto string) string { 1033 c.t.Helper() 1034 1035 // Create our leafnode cluster template first. 1036 var lns, lnss []string 1037 for _, s := range c.servers { 1038 if s.ClusterName() != c.name { 1039 continue 1040 } 1041 ln := s.getOpts().LeafNode 1042 lns = append(lns, fmt.Sprintf("%s://%s:%d", proto, ln.Host, ln.Port)) 1043 lnss = append(lnss, fmt.Sprintf("%s://admin:s3cr3t!@%s:%d", proto, ln.Host, ln.Port)) 1044 } 1045 lnc := strings.Join(lns, ", ") 1046 lnsc := strings.Join(lnss, ", ") 1047 lconf := fmt.Sprintf(jsLeafFrag, lnc, lnsc) 1048 return strings.Replace(tmpl, "{{leaf}}", lconf, 1) 1049 } 1050 1051 func (c *cluster) createLeafSolicitNoSystemWithProto(tmpl, proto string) string { 1052 c.t.Helper() 1053 1054 // Create our leafnode cluster template first. 1055 var lns []string 1056 for _, s := range c.servers { 1057 if s.ClusterName() != c.name { 1058 continue 1059 } 1060 switch proto { 1061 case "nats", "tls": 1062 ln := s.getOpts().LeafNode 1063 lns = append(lns, fmt.Sprintf("%s://%s:%d", proto, ln.Host, ln.Port)) 1064 case "ws", "wss": 1065 ln := s.getOpts().Websocket 1066 lns = append(lns, fmt.Sprintf("%s://%s:%d", proto, ln.Host, ln.Port)) 1067 } 1068 } 1069 lnc := strings.Join(lns, ", ") 1070 return strings.Replace(tmpl, "{{leaf}}", fmt.Sprintf(jsLeafNoSysFrag, lnc), 1) 1071 } 1072 1073 func (c *cluster) createLeafNodesWithTemplateMixedMode(template, clusterName string, numJsServers, numNonServers int, doJSConfig bool) *cluster { 1074 c.t.Helper() 1075 1076 // Create our leafnode cluster template first. 1077 tmpl := c.createLeafSolicit(template) 1078 pre := clusterName + "-" 1079 1080 lc := createMixedModeCluster(c.t, tmpl, clusterName, pre, numJsServers, numNonServers, doJSConfig) 1081 for _, s := range lc.servers { 1082 checkLeafNodeConnectedCount(c.t, s, 2) 1083 } 1084 lc.waitOnClusterReadyWithNumPeers(numJsServers) 1085 1086 return lc 1087 } 1088 1089 func (c *cluster) createLeafNodesWithTemplateAndStartPort(template, clusterName string, numServers int, portStart int) *cluster { 1090 c.t.Helper() 1091 1092 // Create our leafnode cluster template first. 1093 tmpl := c.createLeafSolicit(template) 1094 pre := clusterName + "-" 1095 lc := createJetStreamCluster(c.t, tmpl, clusterName, pre, numServers, portStart, false) 1096 for _, s := range lc.servers { 1097 checkLeafNodeConnectedCount(c.t, s, 2) 1098 } 1099 return lc 1100 } 1101 1102 // Helper function to close and disable leafnodes. 1103 func (s *Server) closeAndDisableLeafnodes() { 1104 var leafs []*client 1105 s.mu.Lock() 1106 for _, ln := range s.leafs { 1107 leafs = append(leafs, ln) 1108 } 1109 // Disable leafnodes for now. 1110 s.leafDisableConnect = true 1111 s.mu.Unlock() 1112 1113 for _, ln := range leafs { 1114 ln.closeConnection(Revocation) 1115 } 1116 } 1117 1118 // Helper function to re-enable leafnode connections. 1119 func (s *Server) reEnableLeafnodes() { 1120 s.mu.Lock() 1121 // Re-enable leafnodes. 1122 s.leafDisableConnect = false 1123 s.mu.Unlock() 1124 } 1125 1126 // Helper to set the remote migrate feature. 1127 func (s *Server) setJetStreamMigrateOnRemoteLeaf() { 1128 s.mu.Lock() 1129 for _, cfg := range s.leafRemoteCfgs { 1130 cfg.JetStreamClusterMigrate = true 1131 } 1132 s.mu.Unlock() 1133 } 1134 1135 // Will add in the mapping for the account to each server. 1136 func (c *cluster) addSubjectMapping(account, src, dest string) { 1137 c.t.Helper() 1138 1139 for _, s := range c.servers { 1140 if s.ClusterName() != c.name { 1141 continue 1142 } 1143 acc, err := s.LookupAccount(account) 1144 if err != nil { 1145 c.t.Fatalf("Unexpected error on %v: %v", s, err) 1146 } 1147 if err := acc.AddMapping(src, dest); err != nil { 1148 c.t.Fatalf("Error adding mapping: %v", err) 1149 } 1150 } 1151 // Make sure interest propagates. 1152 time.Sleep(200 * time.Millisecond) 1153 } 1154 1155 // Adjust limits for the given account. 1156 func (c *cluster) updateLimits(account string, newLimits map[string]JetStreamAccountLimits) { 1157 c.t.Helper() 1158 for _, s := range c.servers { 1159 acc, err := s.LookupAccount(account) 1160 if err != nil { 1161 c.t.Fatalf("Unexpected error: %v", err) 1162 } 1163 if err := acc.UpdateJetStreamLimits(newLimits); err != nil { 1164 c.t.Fatalf("Unexpected error: %v", err) 1165 } 1166 } 1167 } 1168 1169 // Hack for staticcheck 1170 var skip = func(t *testing.T) { 1171 t.SkipNow() 1172 } 1173 1174 func jsClientConnect(t testing.TB, s *Server, opts ...nats.Option) (*nats.Conn, nats.JetStreamContext) { 1175 t.Helper() 1176 nc, err := nats.Connect(s.ClientURL(), opts...) 1177 if err != nil { 1178 t.Fatalf("Failed to create client: %v", err) 1179 } 1180 js, err := nc.JetStream(nats.MaxWait(10 * time.Second)) 1181 if err != nil { 1182 t.Fatalf("Unexpected error getting JetStream context: %v", err) 1183 } 1184 return nc, js 1185 } 1186 1187 func jsClientConnectEx(t testing.TB, s *Server, domain string, opts ...nats.Option) (*nats.Conn, nats.JetStreamContext) { 1188 t.Helper() 1189 nc, err := nats.Connect(s.ClientURL(), opts...) 1190 if err != nil { 1191 t.Fatalf("Failed to create client: %v", err) 1192 } 1193 js, err := nc.JetStream(nats.MaxWait(10*time.Second), nats.Domain(domain)) 1194 if err != nil { 1195 t.Fatalf("Unexpected error getting JetStream context: %v", err) 1196 } 1197 return nc, js 1198 } 1199 1200 func jsClientConnectURL(t testing.TB, url string, opts ...nats.Option) (*nats.Conn, nats.JetStreamContext) { 1201 t.Helper() 1202 1203 nc, err := nats.Connect(url, opts...) 1204 if err != nil { 1205 t.Fatalf("Failed to create client: %v", err) 1206 } 1207 js, err := nc.JetStream(nats.MaxWait(10 * time.Second)) 1208 if err != nil { 1209 t.Fatalf("Unexpected error getting JetStream context: %v", err) 1210 } 1211 return nc, js 1212 } 1213 1214 func checkSubsPending(t *testing.T, sub *nats.Subscription, numExpected int) { 1215 t.Helper() 1216 checkFor(t, 10*time.Second, 20*time.Millisecond, func() error { 1217 if nmsgs, _, err := sub.Pending(); err != nil || nmsgs != numExpected { 1218 return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, numExpected) 1219 } 1220 return nil 1221 }) 1222 } 1223 1224 func fetchMsgs(t *testing.T, sub *nats.Subscription, numExpected int, totalWait time.Duration) []*nats.Msg { 1225 t.Helper() 1226 result := make([]*nats.Msg, 0, numExpected) 1227 for start, count, wait := time.Now(), numExpected, totalWait; len(result) != numExpected; { 1228 msgs, err := sub.Fetch(count, nats.MaxWait(wait)) 1229 if err != nil { 1230 t.Fatal(err) 1231 } 1232 result = append(result, msgs...) 1233 count -= len(msgs) 1234 if wait = totalWait - time.Since(start); wait < 0 { 1235 break 1236 } 1237 } 1238 if len(result) != numExpected { 1239 t.Fatalf("Unexpected msg count, got %d, want %d", len(result), numExpected) 1240 } 1241 return result 1242 } 1243 1244 func (c *cluster) restartServer(rs *Server) *Server { 1245 c.t.Helper() 1246 index := -1 1247 var opts *Options 1248 for i, s := range c.servers { 1249 if s == rs { 1250 index = i 1251 break 1252 } 1253 } 1254 if index < 0 { 1255 c.t.Fatalf("Could not find server %v to restart", rs) 1256 } 1257 opts = c.opts[index] 1258 s, o := RunServerWithConfig(opts.ConfigFile) 1259 c.servers[index] = s 1260 c.opts[index] = o 1261 return s 1262 } 1263 1264 func (c *cluster) checkClusterFormed() { 1265 c.t.Helper() 1266 checkClusterFormed(c.t, c.servers...) 1267 } 1268 1269 func (c *cluster) waitOnPeerCount(n int) { 1270 c.t.Helper() 1271 c.waitOnLeader() 1272 leader := c.leader() 1273 for leader == nil { 1274 c.waitOnLeader() 1275 leader = c.leader() 1276 } 1277 expires := time.Now().Add(30 * time.Second) 1278 for time.Now().Before(expires) { 1279 if peers := leader.JetStreamClusterPeers(); len(peers) == n { 1280 return 1281 } 1282 time.Sleep(100 * time.Millisecond) 1283 leader = c.leader() 1284 for leader == nil { 1285 c.waitOnLeader() 1286 leader = c.leader() 1287 } 1288 } 1289 c.t.Fatalf("Expected a cluster peer count of %d, got %d", n, len(leader.JetStreamClusterPeers())) 1290 } 1291 1292 func (c *cluster) waitOnConsumerLeader(account, stream, consumer string) { 1293 c.t.Helper() 1294 expires := time.Now().Add(30 * time.Second) 1295 for time.Now().Before(expires) { 1296 if leader := c.consumerLeader(account, stream, consumer); leader != nil { 1297 time.Sleep(200 * time.Millisecond) 1298 return 1299 } 1300 time.Sleep(100 * time.Millisecond) 1301 } 1302 c.t.Fatalf("Expected a consumer leader for %q %q %q, got none", account, stream, consumer) 1303 } 1304 1305 func (c *cluster) consumerLeader(account, stream, consumer string) *Server { 1306 c.t.Helper() 1307 for _, s := range c.servers { 1308 if s.JetStreamIsConsumerLeader(account, stream, consumer) { 1309 return s 1310 } 1311 } 1312 return nil 1313 } 1314 1315 func (c *cluster) randomNonConsumerLeader(account, stream, consumer string) *Server { 1316 c.t.Helper() 1317 for _, s := range c.servers { 1318 if !s.JetStreamIsConsumerLeader(account, stream, consumer) { 1319 return s 1320 } 1321 } 1322 return nil 1323 } 1324 1325 func (c *cluster) waitOnStreamLeader(account, stream string) { 1326 c.t.Helper() 1327 expires := time.Now().Add(30 * time.Second) 1328 for time.Now().Before(expires) { 1329 if leader := c.streamLeader(account, stream); leader != nil { 1330 time.Sleep(200 * time.Millisecond) 1331 return 1332 } 1333 time.Sleep(100 * time.Millisecond) 1334 } 1335 c.t.Fatalf("Expected a stream leader for %q %q, got none", account, stream) 1336 } 1337 1338 func (c *cluster) randomNonStreamLeader(account, stream string) *Server { 1339 c.t.Helper() 1340 for _, s := range c.servers { 1341 if s.JetStreamIsStreamAssigned(account, stream) && !s.JetStreamIsStreamLeader(account, stream) { 1342 return s 1343 } 1344 } 1345 return nil 1346 } 1347 1348 func (c *cluster) streamLeader(account, stream string) *Server { 1349 c.t.Helper() 1350 for _, s := range c.servers { 1351 if s.JetStreamIsStreamLeader(account, stream) { 1352 return s 1353 } 1354 } 1355 return nil 1356 } 1357 1358 func (c *cluster) waitOnStreamCurrent(s *Server, account, stream string) { 1359 c.t.Helper() 1360 expires := time.Now().Add(30 * time.Second) 1361 for time.Now().Before(expires) { 1362 if s.JetStreamIsStreamCurrent(account, stream) { 1363 time.Sleep(100 * time.Millisecond) 1364 return 1365 } 1366 time.Sleep(100 * time.Millisecond) 1367 } 1368 c.t.Fatalf("Expected server %q to eventually be current for stream %q", s, stream) 1369 } 1370 1371 func (c *cluster) waitOnServerHealthz(s *Server) { 1372 c.t.Helper() 1373 expires := time.Now().Add(30 * time.Second) 1374 for time.Now().Before(expires) { 1375 hs := s.healthz(nil) 1376 if hs.Status == "ok" && hs.Error == _EMPTY_ { 1377 return 1378 } 1379 time.Sleep(100 * time.Millisecond) 1380 } 1381 c.t.Fatalf("Expected server %q to eventually return healthz 'ok', but got %q", s, s.healthz(nil).Error) 1382 } 1383 1384 func (c *cluster) waitOnServerCurrent(s *Server) { 1385 c.t.Helper() 1386 expires := time.Now().Add(30 * time.Second) 1387 for time.Now().Before(expires) { 1388 time.Sleep(100 * time.Millisecond) 1389 if !s.JetStreamEnabled() || s.JetStreamIsCurrent() { 1390 return 1391 } 1392 } 1393 c.t.Fatalf("Expected server %q to eventually be current", s) 1394 } 1395 1396 func (c *cluster) waitOnAllCurrent() { 1397 c.t.Helper() 1398 for _, cs := range c.servers { 1399 c.waitOnServerCurrent(cs) 1400 } 1401 } 1402 1403 func (c *cluster) serverByName(sname string) *Server { 1404 for _, s := range c.servers { 1405 if s.Name() == sname { 1406 return s 1407 } 1408 } 1409 return nil 1410 } 1411 1412 func (c *cluster) randomNonLeader() *Server { 1413 // range should randomize.. but.. 1414 for _, s := range c.servers { 1415 if s.Running() && !s.JetStreamIsLeader() { 1416 return s 1417 } 1418 } 1419 return nil 1420 } 1421 1422 func (c *cluster) leader() *Server { 1423 for _, s := range c.servers { 1424 if s.JetStreamIsLeader() { 1425 return s 1426 } 1427 } 1428 return nil 1429 } 1430 1431 func (c *cluster) expectNoLeader() { 1432 c.t.Helper() 1433 expires := time.Now().Add(maxElectionTimeout) 1434 for time.Now().Before(expires) { 1435 if c.leader() == nil { 1436 return 1437 } 1438 time.Sleep(20 * time.Millisecond) 1439 } 1440 c.t.Fatalf("Expected no leader but have one") 1441 } 1442 1443 func (c *cluster) waitOnLeader() { 1444 c.t.Helper() 1445 expires := time.Now().Add(40 * time.Second) 1446 for time.Now().Before(expires) { 1447 if leader := c.leader(); leader != nil { 1448 time.Sleep(100 * time.Millisecond) 1449 return 1450 } 1451 time.Sleep(10 * time.Millisecond) 1452 } 1453 1454 c.t.Fatalf("Expected a cluster leader, got none") 1455 } 1456 1457 func (c *cluster) waitOnAccount(account string) { 1458 c.t.Helper() 1459 expires := time.Now().Add(40 * time.Second) 1460 for time.Now().Before(expires) { 1461 found := true 1462 for _, s := range c.servers { 1463 acc, err := s.fetchAccount(account) 1464 found = found && err == nil && acc != nil 1465 } 1466 if found { 1467 return 1468 } 1469 time.Sleep(100 * time.Millisecond) 1470 continue 1471 } 1472 1473 c.t.Fatalf("Expected account %q to exist but didn't", account) 1474 } 1475 1476 // Helper function to check that a cluster is formed 1477 func (c *cluster) waitOnClusterReady() { 1478 c.t.Helper() 1479 c.waitOnClusterReadyWithNumPeers(len(c.servers)) 1480 } 1481 1482 func (c *cluster) waitOnClusterReadyWithNumPeers(numPeersExpected int) { 1483 c.t.Helper() 1484 var leader *Server 1485 expires := time.Now().Add(40 * time.Second) 1486 for time.Now().Before(expires) { 1487 if leader = c.leader(); leader != nil { 1488 break 1489 } 1490 time.Sleep(50 * time.Millisecond) 1491 } 1492 // Now make sure we have all peers. 1493 for leader != nil && time.Now().Before(expires) { 1494 if len(leader.JetStreamClusterPeers()) == numPeersExpected { 1495 time.Sleep(100 * time.Millisecond) 1496 return 1497 } 1498 time.Sleep(10 * time.Millisecond) 1499 } 1500 1501 if leader == nil { 1502 c.shutdown() 1503 c.t.Fatalf("Failed to elect a meta-leader") 1504 } 1505 1506 peersSeen := len(leader.JetStreamClusterPeers()) 1507 c.shutdown() 1508 1509 if leader == nil { 1510 c.t.Fatalf("Expected a cluster leader and fully formed cluster, no leader") 1511 } else { 1512 c.t.Fatalf("Expected a fully formed cluster, only %d of %d peers seen", peersSeen, numPeersExpected) 1513 } 1514 } 1515 1516 // Helper function to remove JetStream from a server. 1517 func (c *cluster) removeJetStream(s *Server) { 1518 c.t.Helper() 1519 index := -1 1520 for i, cs := range c.servers { 1521 if cs == s { 1522 index = i 1523 break 1524 } 1525 } 1526 cf := c.opts[index].ConfigFile 1527 cb, _ := os.ReadFile(cf) 1528 var sb strings.Builder 1529 for _, l := range strings.Split(string(cb), "\n") { 1530 if !strings.HasPrefix(strings.TrimSpace(l), "jetstream") { 1531 sb.WriteString(l + "\n") 1532 } 1533 } 1534 if err := os.WriteFile(cf, []byte(sb.String()), 0644); err != nil { 1535 c.t.Fatalf("Error writing updated config file: %v", err) 1536 } 1537 if err := s.Reload(); err != nil { 1538 c.t.Fatalf("Error on server reload: %v", err) 1539 } 1540 time.Sleep(100 * time.Millisecond) 1541 } 1542 1543 func (c *cluster) stopAll() { 1544 c.t.Helper() 1545 for _, s := range c.servers { 1546 s.Shutdown() 1547 } 1548 } 1549 1550 func (c *cluster) restartAll() { 1551 c.t.Helper() 1552 for i, s := range c.servers { 1553 if !s.Running() { 1554 opts := c.opts[i] 1555 s, o := RunServerWithConfig(opts.ConfigFile) 1556 c.servers[i] = s 1557 c.opts[i] = o 1558 } 1559 } 1560 c.waitOnClusterReady() 1561 } 1562 1563 func (c *cluster) lameDuckRestartAll() { 1564 c.t.Helper() 1565 for i, s := range c.servers { 1566 s.lameDuckMode() 1567 s.WaitForShutdown() 1568 if !s.Running() { 1569 opts := c.opts[i] 1570 s, o := RunServerWithConfig(opts.ConfigFile) 1571 c.servers[i] = s 1572 c.opts[i] = o 1573 } 1574 } 1575 c.waitOnClusterReady() 1576 } 1577 1578 func (c *cluster) restartAllSamePorts() { 1579 c.t.Helper() 1580 for i, s := range c.servers { 1581 if !s.Running() { 1582 opts := c.opts[i] 1583 s := RunServer(opts) 1584 c.servers[i] = s 1585 } 1586 } 1587 c.waitOnClusterReady() 1588 } 1589 1590 func (c *cluster) totalSubs() (total int) { 1591 c.t.Helper() 1592 for _, s := range c.servers { 1593 total += int(s.NumSubscriptions()) 1594 } 1595 return total 1596 } 1597 1598 func (c *cluster) stableTotalSubs() (total int) { 1599 nsubs := -1 1600 checkFor(c.t, 2*time.Second, 250*time.Millisecond, func() error { 1601 subs := c.totalSubs() 1602 if subs == nsubs { 1603 return nil 1604 } 1605 nsubs = subs 1606 return fmt.Errorf("Still stabilizing") 1607 }) 1608 return nsubs 1609 1610 } 1611 1612 func addStream(t *testing.T, nc *nats.Conn, cfg *StreamConfig) *StreamInfo { 1613 t.Helper() 1614 si, err := addStreamWithError(t, nc, cfg) 1615 if err != nil { 1616 t.Fatalf("Unexpected error: %+v", err) 1617 } 1618 return si 1619 } 1620 1621 func addStreamWithError(t *testing.T, nc *nats.Conn, cfg *StreamConfig) (*StreamInfo, *ApiError) { 1622 t.Helper() 1623 req, err := json.Marshal(cfg) 1624 require_NoError(t, err) 1625 rmsg, err := nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, 5*time.Second) 1626 require_NoError(t, err) 1627 var resp JSApiStreamCreateResponse 1628 err = json.Unmarshal(rmsg.Data, &resp) 1629 require_NoError(t, err) 1630 if resp.Type != JSApiStreamCreateResponseType { 1631 t.Fatalf("Invalid response type %s expected %s", resp.Type, JSApiStreamCreateResponseType) 1632 } 1633 return resp.StreamInfo, resp.Error 1634 } 1635 1636 func updateStream(t *testing.T, nc *nats.Conn, cfg *StreamConfig) *StreamInfo { 1637 t.Helper() 1638 req, err := json.Marshal(cfg) 1639 require_NoError(t, err) 1640 rmsg, err := nc.Request(fmt.Sprintf(JSApiStreamUpdateT, cfg.Name), req, time.Second) 1641 require_NoError(t, err) 1642 var resp JSApiStreamCreateResponse 1643 err = json.Unmarshal(rmsg.Data, &resp) 1644 require_NoError(t, err) 1645 if resp.Type != JSApiStreamUpdateResponseType { 1646 t.Fatalf("Invalid response type %s expected %s", resp.Type, JSApiStreamUpdateResponseType) 1647 } 1648 if resp.Error != nil { 1649 t.Fatalf("Unexpected error: %+v", resp.Error) 1650 } 1651 return resp.StreamInfo 1652 } 1653 1654 // setInActiveDeleteThreshold sets the delete threshold for how long to wait 1655 // before deleting an inactive consumer. 1656 func (o *consumer) setInActiveDeleteThreshold(dthresh time.Duration) error { 1657 o.mu.Lock() 1658 defer o.mu.Unlock() 1659 1660 deleteWasRunning := o.dtmr != nil 1661 stopAndClearTimer(&o.dtmr) 1662 // Do not add jitter if set via here. 1663 o.dthresh = dthresh 1664 if deleteWasRunning { 1665 o.dtmr = time.AfterFunc(o.dthresh, func() { o.deleteNotActive() }) 1666 } 1667 return nil 1668 } 1669 1670 // Net Proxy - For introducing RTT and BW constraints. 1671 type netProxy struct { 1672 sync.RWMutex 1673 listener net.Listener 1674 conns []net.Conn 1675 rtt time.Duration 1676 up int 1677 down int 1678 url string 1679 surl string 1680 } 1681 1682 func newNetProxy(rtt time.Duration, upRate, downRate int, serverURL string) *netProxy { 1683 return createNetProxy(rtt, upRate, downRate, serverURL, true) 1684 } 1685 1686 func createNetProxy(rtt time.Duration, upRate, downRate int, serverURL string, start bool) *netProxy { 1687 hp := net.JoinHostPort("127.0.0.1", "0") 1688 l, e := net.Listen("tcp", hp) 1689 if e != nil { 1690 panic(fmt.Sprintf("Error listening on port: %s, %q", hp, e)) 1691 } 1692 port := l.Addr().(*net.TCPAddr).Port 1693 proxy := &netProxy{ 1694 listener: l, 1695 rtt: rtt, 1696 up: upRate, 1697 down: downRate, 1698 url: fmt.Sprintf("nats://127.0.0.1:%d", port), 1699 surl: serverURL, 1700 } 1701 if start { 1702 proxy.start() 1703 } 1704 return proxy 1705 } 1706 1707 func (np *netProxy) start() { 1708 u, err := url.Parse(np.surl) 1709 if err != nil { 1710 panic(fmt.Sprintf("Could not parse server URL: %v", err)) 1711 } 1712 host := u.Host 1713 1714 go func() { 1715 for { 1716 client, err := np.listener.Accept() 1717 if err != nil { 1718 return 1719 } 1720 server, err := net.DialTimeout("tcp", host, time.Second) 1721 if err != nil { 1722 continue 1723 } 1724 np.conns = append(np.conns, client, server) 1725 go np.loop(np.up, client, server) 1726 go np.loop(np.down, server, client) 1727 } 1728 }() 1729 } 1730 1731 func (np *netProxy) clientURL() string { 1732 return np.url 1733 } 1734 1735 func (np *netProxy) routeURL() string { 1736 return strings.Replace(np.url, "nats", "nats-route", 1) 1737 } 1738 1739 func (np *netProxy) loop(tbw int, r, w net.Conn) { 1740 const rbl = 8192 1741 var buf [rbl]byte 1742 ctx := context.Background() 1743 1744 rl := rate.NewLimiter(rate.Limit(tbw), rbl) 1745 1746 for { 1747 n, err := r.Read(buf[:]) 1748 if err != nil { 1749 w.Close() 1750 return 1751 } 1752 // RTT delays 1753 np.RLock() 1754 delay := np.rtt / 2 1755 np.RUnlock() 1756 if delay > 0 { 1757 time.Sleep(delay) 1758 } 1759 if err := rl.WaitN(ctx, n); err != nil { 1760 return 1761 } 1762 if _, err = w.Write(buf[:n]); err != nil { 1763 r.Close() 1764 return 1765 } 1766 } 1767 } 1768 1769 func (np *netProxy) updateRTT(rtt time.Duration) { 1770 np.Lock() 1771 np.rtt = rtt 1772 np.Unlock() 1773 } 1774 1775 func (np *netProxy) stop() { 1776 if np.listener != nil { 1777 np.listener.Close() 1778 np.listener = nil 1779 for _, c := range np.conns { 1780 c.Close() 1781 } 1782 } 1783 } 1784 1785 // Bitset, aka bitvector, allows tracking of large number of bits efficiently 1786 type bitset struct { 1787 // Bit map storage 1788 bitmap []uint8 1789 // Number of bits currently set to 1 1790 currentCount uint64 1791 // Number of bits stored 1792 size uint64 1793 } 1794 1795 func NewBitset(size uint64) *bitset { 1796 byteSize := (size + 7) / 8 //Round up to the nearest byte 1797 1798 return &bitset{ 1799 bitmap: make([]uint8, int(byteSize)), 1800 size: size, 1801 currentCount: 0, 1802 } 1803 } 1804 1805 func (b *bitset) get(index uint64) bool { 1806 if index >= b.size { 1807 panic(fmt.Sprintf("Index %d out of bounds, size %d", index, b.size)) 1808 } 1809 byteIndex := index / 8 1810 bitIndex := uint(index % 8) 1811 bit := (b.bitmap[byteIndex] & (uint8(1) << bitIndex)) 1812 return bit != 0 1813 } 1814 1815 func (b *bitset) set(index uint64, value bool) { 1816 if index >= b.size { 1817 panic(fmt.Sprintf("Index %d out of bounds, size %d", index, b.size)) 1818 } 1819 byteIndex := index / 8 1820 bitIndex := uint(index % 8) 1821 byteMask := uint8(1) << bitIndex 1822 isSet := (b.bitmap[byteIndex] & (uint8(1) << bitIndex)) != 0 1823 if value { 1824 b.bitmap[byteIndex] |= byteMask 1825 if !isSet { 1826 b.currentCount += 1 1827 } 1828 } else { 1829 b.bitmap[byteIndex] &= ^byteMask 1830 if isSet { 1831 b.currentCount -= 1 1832 } 1833 } 1834 } 1835 1836 func (b *bitset) count() uint64 { 1837 return b.currentCount 1838 } 1839 1840 func (b *bitset) String() string { 1841 const block = 8 // 8 bytes, 64 bits per line 1842 sb := strings.Builder{} 1843 1844 sb.WriteString(fmt.Sprintf("Bits set: %d/%d\n", b.currentCount, b.size)) 1845 for i := 0; i < len(b.bitmap); i++ { 1846 if i%block == 0 { 1847 if i > 0 { 1848 sb.WriteString("\n") 1849 } 1850 sb.WriteString(fmt.Sprintf("[%4d] ", i*8)) 1851 } 1852 for j := uint8(0); j < 8; j++ { 1853 if b.bitmap[i]&(1<<j) > 0 { 1854 sb.WriteString("1") 1855 } else { 1856 sb.WriteString("0") 1857 } 1858 } 1859 } 1860 sb.WriteString("\n") 1861 return sb.String() 1862 }