github.com/nats-io/nats-server/v2@v2.11.0-preview.2/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, jsOpts []nats.JSOpt, 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 jo := []nats.JSOpt{nats.MaxWait(10 * time.Second)} 1194 if len(jsOpts) > 0 { 1195 jo = append(jo, jsOpts...) 1196 } 1197 js, err := nc.JetStream(jo...) 1198 if err != nil { 1199 t.Fatalf("Unexpected error getting JetStream context: %v", err) 1200 } 1201 return nc, js 1202 } 1203 1204 func jsClientConnectURL(t testing.TB, url string, opts ...nats.Option) (*nats.Conn, nats.JetStreamContext) { 1205 t.Helper() 1206 1207 nc, err := nats.Connect(url, opts...) 1208 if err != nil { 1209 t.Fatalf("Failed to create client: %v", err) 1210 } 1211 js, err := nc.JetStream(nats.MaxWait(10 * time.Second)) 1212 if err != nil { 1213 t.Fatalf("Unexpected error getting JetStream context: %v", err) 1214 } 1215 return nc, js 1216 } 1217 1218 func checkSubsPending(t *testing.T, sub *nats.Subscription, numExpected int) { 1219 t.Helper() 1220 checkFor(t, 10*time.Second, 20*time.Millisecond, func() error { 1221 if nmsgs, _, err := sub.Pending(); err != nil || nmsgs != numExpected { 1222 return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, numExpected) 1223 } 1224 return nil 1225 }) 1226 } 1227 1228 func fetchMsgs(t *testing.T, sub *nats.Subscription, numExpected int, totalWait time.Duration) []*nats.Msg { 1229 t.Helper() 1230 result := make([]*nats.Msg, 0, numExpected) 1231 for start, count, wait := time.Now(), numExpected, totalWait; len(result) != numExpected; { 1232 msgs, err := sub.Fetch(count, nats.MaxWait(wait)) 1233 if err != nil { 1234 t.Fatal(err) 1235 } 1236 result = append(result, msgs...) 1237 count -= len(msgs) 1238 if wait = totalWait - time.Since(start); wait < 0 { 1239 break 1240 } 1241 } 1242 if len(result) != numExpected { 1243 t.Fatalf("Unexpected msg count, got %d, want %d", len(result), numExpected) 1244 } 1245 return result 1246 } 1247 1248 func (c *cluster) restartServer(rs *Server) *Server { 1249 c.t.Helper() 1250 index := -1 1251 var opts *Options 1252 for i, s := range c.servers { 1253 if s == rs { 1254 index = i 1255 break 1256 } 1257 } 1258 if index < 0 { 1259 c.t.Fatalf("Could not find server %v to restart", rs) 1260 } 1261 opts = c.opts[index] 1262 s, o := RunServerWithConfig(opts.ConfigFile) 1263 c.servers[index] = s 1264 c.opts[index] = o 1265 return s 1266 } 1267 1268 func (c *cluster) checkClusterFormed() { 1269 c.t.Helper() 1270 checkClusterFormed(c.t, c.servers...) 1271 } 1272 1273 func (c *cluster) waitOnPeerCount(n int) { 1274 c.t.Helper() 1275 c.waitOnLeader() 1276 leader := c.leader() 1277 for leader == nil { 1278 c.waitOnLeader() 1279 leader = c.leader() 1280 } 1281 expires := time.Now().Add(30 * time.Second) 1282 for time.Now().Before(expires) { 1283 if peers := leader.JetStreamClusterPeers(); len(peers) == n { 1284 return 1285 } 1286 time.Sleep(100 * time.Millisecond) 1287 leader = c.leader() 1288 for leader == nil { 1289 c.waitOnLeader() 1290 leader = c.leader() 1291 } 1292 } 1293 c.t.Fatalf("Expected a cluster peer count of %d, got %d", n, len(leader.JetStreamClusterPeers())) 1294 } 1295 1296 func (c *cluster) waitOnConsumerLeader(account, stream, consumer string) { 1297 c.t.Helper() 1298 expires := time.Now().Add(30 * time.Second) 1299 for time.Now().Before(expires) { 1300 if leader := c.consumerLeader(account, stream, consumer); leader != nil { 1301 time.Sleep(200 * time.Millisecond) 1302 return 1303 } 1304 time.Sleep(100 * time.Millisecond) 1305 } 1306 c.t.Fatalf("Expected a consumer leader for %q %q %q, got none", account, stream, consumer) 1307 } 1308 1309 func (c *cluster) consumerLeader(account, stream, consumer string) *Server { 1310 c.t.Helper() 1311 for _, s := range c.servers { 1312 if s.JetStreamIsConsumerLeader(account, stream, consumer) { 1313 return s 1314 } 1315 } 1316 return nil 1317 } 1318 1319 func (c *cluster) randomNonConsumerLeader(account, stream, consumer string) *Server { 1320 c.t.Helper() 1321 for _, s := range c.servers { 1322 if !s.JetStreamIsConsumerLeader(account, stream, consumer) { 1323 return s 1324 } 1325 } 1326 return nil 1327 } 1328 1329 func (c *cluster) waitOnStreamLeader(account, stream string) { 1330 c.t.Helper() 1331 expires := time.Now().Add(30 * time.Second) 1332 for time.Now().Before(expires) { 1333 if leader := c.streamLeader(account, stream); leader != nil { 1334 time.Sleep(200 * time.Millisecond) 1335 return 1336 } 1337 time.Sleep(100 * time.Millisecond) 1338 } 1339 c.t.Fatalf("Expected a stream leader for %q %q, got none", account, stream) 1340 } 1341 1342 func (c *cluster) randomNonStreamLeader(account, stream string) *Server { 1343 c.t.Helper() 1344 for _, s := range c.servers { 1345 if s.JetStreamIsStreamAssigned(account, stream) && !s.JetStreamIsStreamLeader(account, stream) { 1346 return s 1347 } 1348 } 1349 return nil 1350 } 1351 1352 func (c *cluster) streamLeader(account, stream string) *Server { 1353 c.t.Helper() 1354 for _, s := range c.servers { 1355 if s.JetStreamIsStreamLeader(account, stream) { 1356 return s 1357 } 1358 } 1359 return nil 1360 } 1361 1362 func (c *cluster) waitOnStreamCurrent(s *Server, account, stream string) { 1363 c.t.Helper() 1364 expires := time.Now().Add(30 * time.Second) 1365 for time.Now().Before(expires) { 1366 if s.JetStreamIsStreamCurrent(account, stream) { 1367 time.Sleep(100 * time.Millisecond) 1368 return 1369 } 1370 time.Sleep(100 * time.Millisecond) 1371 } 1372 c.t.Fatalf("Expected server %q to eventually be current for stream %q", s, stream) 1373 } 1374 1375 func (c *cluster) waitOnServerHealthz(s *Server) { 1376 c.t.Helper() 1377 expires := time.Now().Add(30 * time.Second) 1378 for time.Now().Before(expires) { 1379 hs := s.healthz(nil) 1380 if hs.Status == "ok" && hs.Error == _EMPTY_ { 1381 return 1382 } 1383 time.Sleep(100 * time.Millisecond) 1384 } 1385 c.t.Fatalf("Expected server %q to eventually return healthz 'ok', but got %q", s, s.healthz(nil).Error) 1386 } 1387 1388 func (c *cluster) waitOnServerCurrent(s *Server) { 1389 c.t.Helper() 1390 expires := time.Now().Add(30 * time.Second) 1391 for time.Now().Before(expires) { 1392 time.Sleep(100 * time.Millisecond) 1393 if !s.JetStreamEnabled() || s.JetStreamIsCurrent() { 1394 return 1395 } 1396 } 1397 c.t.Fatalf("Expected server %q to eventually be current", s) 1398 } 1399 1400 func (c *cluster) waitOnAllCurrent() { 1401 c.t.Helper() 1402 for _, cs := range c.servers { 1403 c.waitOnServerCurrent(cs) 1404 } 1405 } 1406 1407 func (c *cluster) serverByName(sname string) *Server { 1408 for _, s := range c.servers { 1409 if s.Name() == sname { 1410 return s 1411 } 1412 } 1413 return nil 1414 } 1415 1416 func (c *cluster) randomNonLeader() *Server { 1417 // range should randomize.. but.. 1418 for _, s := range c.servers { 1419 if s.Running() && !s.JetStreamIsLeader() { 1420 return s 1421 } 1422 } 1423 return nil 1424 } 1425 1426 func (c *cluster) leader() *Server { 1427 for _, s := range c.servers { 1428 if s.JetStreamIsLeader() { 1429 return s 1430 } 1431 } 1432 return nil 1433 } 1434 1435 func (c *cluster) expectNoLeader() { 1436 c.t.Helper() 1437 expires := time.Now().Add(maxElectionTimeout) 1438 for time.Now().Before(expires) { 1439 if c.leader() == nil { 1440 return 1441 } 1442 time.Sleep(20 * time.Millisecond) 1443 } 1444 c.t.Fatalf("Expected no leader but have one") 1445 } 1446 1447 func (c *cluster) waitOnLeader() { 1448 c.t.Helper() 1449 expires := time.Now().Add(40 * time.Second) 1450 for time.Now().Before(expires) { 1451 if leader := c.leader(); leader != nil { 1452 time.Sleep(100 * time.Millisecond) 1453 return 1454 } 1455 time.Sleep(10 * time.Millisecond) 1456 } 1457 1458 c.t.Fatalf("Expected a cluster leader, got none") 1459 } 1460 1461 func (c *cluster) waitOnAccount(account string) { 1462 c.t.Helper() 1463 expires := time.Now().Add(40 * time.Second) 1464 for time.Now().Before(expires) { 1465 found := true 1466 for _, s := range c.servers { 1467 acc, err := s.fetchAccount(account) 1468 found = found && err == nil && acc != nil 1469 } 1470 if found { 1471 return 1472 } 1473 time.Sleep(100 * time.Millisecond) 1474 continue 1475 } 1476 1477 c.t.Fatalf("Expected account %q to exist but didn't", account) 1478 } 1479 1480 // Helper function to check that a cluster is formed 1481 func (c *cluster) waitOnClusterReady() { 1482 c.t.Helper() 1483 c.waitOnClusterReadyWithNumPeers(len(c.servers)) 1484 } 1485 1486 func (c *cluster) waitOnClusterReadyWithNumPeers(numPeersExpected int) { 1487 c.t.Helper() 1488 var leader *Server 1489 expires := time.Now().Add(40 * time.Second) 1490 for time.Now().Before(expires) { 1491 if leader = c.leader(); leader != nil { 1492 break 1493 } 1494 time.Sleep(50 * time.Millisecond) 1495 } 1496 // Now make sure we have all peers. 1497 for leader != nil && time.Now().Before(expires) { 1498 if len(leader.JetStreamClusterPeers()) == numPeersExpected { 1499 time.Sleep(100 * time.Millisecond) 1500 return 1501 } 1502 time.Sleep(10 * time.Millisecond) 1503 } 1504 1505 if leader == nil { 1506 c.shutdown() 1507 c.t.Fatalf("Failed to elect a meta-leader") 1508 } 1509 1510 peersSeen := len(leader.JetStreamClusterPeers()) 1511 c.shutdown() 1512 1513 if leader == nil { 1514 c.t.Fatalf("Expected a cluster leader and fully formed cluster, no leader") 1515 } else { 1516 c.t.Fatalf("Expected a fully formed cluster, only %d of %d peers seen", peersSeen, numPeersExpected) 1517 } 1518 } 1519 1520 // Helper function to remove JetStream from a server. 1521 func (c *cluster) removeJetStream(s *Server) { 1522 c.t.Helper() 1523 index := -1 1524 for i, cs := range c.servers { 1525 if cs == s { 1526 index = i 1527 break 1528 } 1529 } 1530 cf := c.opts[index].ConfigFile 1531 cb, _ := os.ReadFile(cf) 1532 var sb strings.Builder 1533 for _, l := range strings.Split(string(cb), "\n") { 1534 if !strings.HasPrefix(strings.TrimSpace(l), "jetstream") { 1535 sb.WriteString(l + "\n") 1536 } 1537 } 1538 if err := os.WriteFile(cf, []byte(sb.String()), 0644); err != nil { 1539 c.t.Fatalf("Error writing updated config file: %v", err) 1540 } 1541 if err := s.Reload(); err != nil { 1542 c.t.Fatalf("Error on server reload: %v", err) 1543 } 1544 time.Sleep(100 * time.Millisecond) 1545 } 1546 1547 func (c *cluster) stopAll() { 1548 c.t.Helper() 1549 for _, s := range c.servers { 1550 s.Shutdown() 1551 } 1552 } 1553 1554 func (c *cluster) restartAll() { 1555 c.t.Helper() 1556 for i, s := range c.servers { 1557 if !s.Running() { 1558 opts := c.opts[i] 1559 s, o := RunServerWithConfig(opts.ConfigFile) 1560 c.servers[i] = s 1561 c.opts[i] = o 1562 } 1563 } 1564 c.waitOnClusterReady() 1565 } 1566 1567 func (c *cluster) lameDuckRestartAll() { 1568 c.t.Helper() 1569 for i, s := range c.servers { 1570 s.lameDuckMode() 1571 s.WaitForShutdown() 1572 if !s.Running() { 1573 opts := c.opts[i] 1574 s, o := RunServerWithConfig(opts.ConfigFile) 1575 c.servers[i] = s 1576 c.opts[i] = o 1577 } 1578 } 1579 c.waitOnClusterReady() 1580 } 1581 1582 func (c *cluster) restartAllSamePorts() { 1583 c.t.Helper() 1584 for i, s := range c.servers { 1585 if !s.Running() { 1586 opts := c.opts[i] 1587 s := RunServer(opts) 1588 c.servers[i] = s 1589 } 1590 } 1591 c.waitOnClusterReady() 1592 } 1593 1594 func (c *cluster) totalSubs() (total int) { 1595 c.t.Helper() 1596 for _, s := range c.servers { 1597 total += int(s.NumSubscriptions()) 1598 } 1599 return total 1600 } 1601 1602 func (c *cluster) stableTotalSubs() (total int) { 1603 nsubs := -1 1604 checkFor(c.t, 2*time.Second, 250*time.Millisecond, func() error { 1605 subs := c.totalSubs() 1606 if subs == nsubs { 1607 return nil 1608 } 1609 nsubs = subs 1610 return fmt.Errorf("Still stabilizing") 1611 }) 1612 return nsubs 1613 1614 } 1615 1616 func addStream(t *testing.T, nc *nats.Conn, cfg *StreamConfig) *StreamInfo { 1617 t.Helper() 1618 si, err := addStreamWithError(t, nc, cfg) 1619 if err != nil { 1620 t.Fatalf("Unexpected error: %+v", err) 1621 } 1622 return si 1623 } 1624 1625 func addStreamWithError(t *testing.T, nc *nats.Conn, cfg *StreamConfig) (*StreamInfo, *ApiError) { 1626 t.Helper() 1627 req, err := json.Marshal(cfg) 1628 require_NoError(t, err) 1629 rmsg, err := nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, 5*time.Second) 1630 require_NoError(t, err) 1631 var resp JSApiStreamCreateResponse 1632 err = json.Unmarshal(rmsg.Data, &resp) 1633 require_NoError(t, err) 1634 if resp.Type != JSApiStreamCreateResponseType { 1635 t.Fatalf("Invalid response type %s expected %s", resp.Type, JSApiStreamCreateResponseType) 1636 } 1637 return resp.StreamInfo, resp.Error 1638 } 1639 1640 func updateStream(t *testing.T, nc *nats.Conn, cfg *StreamConfig) *StreamInfo { 1641 t.Helper() 1642 req, err := json.Marshal(cfg) 1643 require_NoError(t, err) 1644 rmsg, err := nc.Request(fmt.Sprintf(JSApiStreamUpdateT, cfg.Name), req, time.Second) 1645 require_NoError(t, err) 1646 var resp JSApiStreamCreateResponse 1647 err = json.Unmarshal(rmsg.Data, &resp) 1648 require_NoError(t, err) 1649 if resp.Type != JSApiStreamUpdateResponseType { 1650 t.Fatalf("Invalid response type %s expected %s", resp.Type, JSApiStreamUpdateResponseType) 1651 } 1652 if resp.Error != nil { 1653 t.Fatalf("Unexpected error: %+v", resp.Error) 1654 } 1655 return resp.StreamInfo 1656 } 1657 1658 // setInActiveDeleteThreshold sets the delete threshold for how long to wait 1659 // before deleting an inactive consumer. 1660 func (o *consumer) setInActiveDeleteThreshold(dthresh time.Duration) error { 1661 o.mu.Lock() 1662 defer o.mu.Unlock() 1663 1664 deleteWasRunning := o.dtmr != nil 1665 stopAndClearTimer(&o.dtmr) 1666 // Do not add jitter if set via here. 1667 o.dthresh = dthresh 1668 if deleteWasRunning { 1669 o.dtmr = time.AfterFunc(o.dthresh, func() { o.deleteNotActive() }) 1670 } 1671 return nil 1672 } 1673 1674 // Net Proxy - For introducing RTT and BW constraints. 1675 type netProxy struct { 1676 sync.RWMutex 1677 listener net.Listener 1678 conns []net.Conn 1679 rtt time.Duration 1680 up int 1681 down int 1682 url string 1683 surl string 1684 } 1685 1686 func newNetProxy(rtt time.Duration, upRate, downRate int, serverURL string) *netProxy { 1687 return createNetProxy(rtt, upRate, downRate, serverURL, true) 1688 } 1689 1690 func createNetProxy(rtt time.Duration, upRate, downRate int, serverURL string, start bool) *netProxy { 1691 hp := net.JoinHostPort("127.0.0.1", "0") 1692 l, e := net.Listen("tcp", hp) 1693 if e != nil { 1694 panic(fmt.Sprintf("Error listening on port: %s, %q", hp, e)) 1695 } 1696 port := l.Addr().(*net.TCPAddr).Port 1697 proxy := &netProxy{ 1698 listener: l, 1699 rtt: rtt, 1700 up: upRate, 1701 down: downRate, 1702 url: fmt.Sprintf("nats://127.0.0.1:%d", port), 1703 surl: serverURL, 1704 } 1705 if start { 1706 proxy.start() 1707 } 1708 return proxy 1709 } 1710 1711 func (np *netProxy) start() { 1712 u, err := url.Parse(np.surl) 1713 if err != nil { 1714 panic(fmt.Sprintf("Could not parse server URL: %v", err)) 1715 } 1716 host := u.Host 1717 1718 go func() { 1719 for { 1720 client, err := np.listener.Accept() 1721 if err != nil { 1722 return 1723 } 1724 server, err := net.DialTimeout("tcp", host, time.Second) 1725 if err != nil { 1726 continue 1727 } 1728 np.conns = append(np.conns, client, server) 1729 go np.loop(np.up, client, server) 1730 go np.loop(np.down, server, client) 1731 } 1732 }() 1733 } 1734 1735 func (np *netProxy) clientURL() string { 1736 return np.url 1737 } 1738 1739 func (np *netProxy) routeURL() string { 1740 return strings.Replace(np.url, "nats", "nats-route", 1) 1741 } 1742 1743 func (np *netProxy) loop(tbw int, r, w net.Conn) { 1744 const rbl = 8192 1745 var buf [rbl]byte 1746 ctx := context.Background() 1747 1748 rl := rate.NewLimiter(rate.Limit(tbw), rbl) 1749 1750 for { 1751 n, err := r.Read(buf[:]) 1752 if err != nil { 1753 w.Close() 1754 return 1755 } 1756 // RTT delays 1757 np.RLock() 1758 delay := np.rtt / 2 1759 np.RUnlock() 1760 if delay > 0 { 1761 time.Sleep(delay) 1762 } 1763 if err := rl.WaitN(ctx, n); err != nil { 1764 return 1765 } 1766 if _, err = w.Write(buf[:n]); err != nil { 1767 r.Close() 1768 return 1769 } 1770 } 1771 } 1772 1773 func (np *netProxy) updateRTT(rtt time.Duration) { 1774 np.Lock() 1775 np.rtt = rtt 1776 np.Unlock() 1777 } 1778 1779 func (np *netProxy) stop() { 1780 if np.listener != nil { 1781 np.listener.Close() 1782 np.listener = nil 1783 for _, c := range np.conns { 1784 c.Close() 1785 } 1786 } 1787 } 1788 1789 // Bitset, aka bitvector, allows tracking of large number of bits efficiently 1790 type bitset struct { 1791 // Bit map storage 1792 bitmap []uint8 1793 // Number of bits currently set to 1 1794 currentCount uint64 1795 // Number of bits stored 1796 size uint64 1797 } 1798 1799 func NewBitset(size uint64) *bitset { 1800 byteSize := (size + 7) / 8 //Round up to the nearest byte 1801 1802 return &bitset{ 1803 bitmap: make([]uint8, int(byteSize)), 1804 size: size, 1805 currentCount: 0, 1806 } 1807 } 1808 1809 func (b *bitset) get(index uint64) bool { 1810 if index >= b.size { 1811 panic(fmt.Sprintf("Index %d out of bounds, size %d", index, b.size)) 1812 } 1813 byteIndex := index / 8 1814 bitIndex := uint(index % 8) 1815 bit := (b.bitmap[byteIndex] & (uint8(1) << bitIndex)) 1816 return bit != 0 1817 } 1818 1819 func (b *bitset) set(index uint64, value bool) { 1820 if index >= b.size { 1821 panic(fmt.Sprintf("Index %d out of bounds, size %d", index, b.size)) 1822 } 1823 byteIndex := index / 8 1824 bitIndex := uint(index % 8) 1825 byteMask := uint8(1) << bitIndex 1826 isSet := (b.bitmap[byteIndex] & (uint8(1) << bitIndex)) != 0 1827 if value { 1828 b.bitmap[byteIndex] |= byteMask 1829 if !isSet { 1830 b.currentCount += 1 1831 } 1832 } else { 1833 b.bitmap[byteIndex] &= ^byteMask 1834 if isSet { 1835 b.currentCount -= 1 1836 } 1837 } 1838 } 1839 1840 func (b *bitset) count() uint64 { 1841 return b.currentCount 1842 } 1843 1844 func (b *bitset) String() string { 1845 const block = 8 // 8 bytes, 64 bits per line 1846 sb := strings.Builder{} 1847 1848 sb.WriteString(fmt.Sprintf("Bits set: %d/%d\n", b.currentCount, b.size)) 1849 for i := 0; i < len(b.bitmap); i++ { 1850 if i%block == 0 { 1851 if i > 0 { 1852 sb.WriteString("\n") 1853 } 1854 sb.WriteString(fmt.Sprintf("[%4d] ", i*8)) 1855 } 1856 for j := uint8(0); j < 8; j++ { 1857 if b.bitmap[i]&(1<<j) > 0 { 1858 sb.WriteString("1") 1859 } else { 1860 sb.WriteString("0") 1861 } 1862 } 1863 } 1864 sb.WriteString("\n") 1865 return sb.String() 1866 }