github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/monitor_test.go (about) 1 // Copyright 2013-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 package server 15 16 import ( 17 "bytes" 18 "crypto/tls" 19 "encoding/json" 20 "errors" 21 "fmt" 22 "io" 23 "math/rand" 24 "net" 25 "net/http" 26 "net/url" 27 "os" 28 "reflect" 29 "runtime" 30 "sort" 31 "strings" 32 "sync" 33 "testing" 34 "time" 35 "unicode" 36 37 "github.com/nats-io/jwt/v2" 38 "github.com/nats-io/nats.go" 39 "github.com/nats-io/nkeys" 40 ) 41 42 const CLIENT_PORT = -1 43 const MONITOR_PORT = -1 44 const CLUSTER_PORT = -1 45 46 func DefaultMonitorOptions() *Options { 47 return &Options{ 48 Host: "127.0.0.1", 49 Port: CLIENT_PORT, 50 HTTPHost: "127.0.0.1", 51 HTTPPort: MONITOR_PORT, 52 HTTPBasePath: "/", 53 ServerName: "monitor_server", 54 NoLog: true, 55 NoSigs: true, 56 Tags: []string{"tag"}, 57 } 58 } 59 60 func runMonitorServer() *Server { 61 resetPreviousHTTPConnections() 62 opts := DefaultMonitorOptions() 63 opts.NoSystemAccount = true 64 return RunServer(opts) 65 } 66 67 func runMonitorServerWithAccounts() *Server { 68 resetPreviousHTTPConnections() 69 opts := DefaultMonitorOptions() 70 opts.NoSystemAccount = true 71 aA := NewAccount("A") 72 aB := NewAccount("B") 73 opts.Accounts = append(opts.Accounts, aA, aB) 74 opts.Users = append(opts.Users, 75 &User{Username: "a", Password: "a", Account: aA}, 76 &User{Username: "b", Password: "b", Account: aB}) 77 return RunServer(opts) 78 } 79 80 func runMonitorServerNoHTTPPort() *Server { 81 resetPreviousHTTPConnections() 82 opts := DefaultMonitorOptions() 83 opts.NoSystemAccount = true 84 opts.HTTPPort = 0 85 return RunServer(opts) 86 } 87 88 func resetPreviousHTTPConnections() { 89 http.DefaultTransport.(*http.Transport).CloseIdleConnections() 90 } 91 92 func TestMyUptime(t *testing.T) { 93 // Make sure we print this stuff right. 94 var d time.Duration 95 var s string 96 97 d = 22 * time.Second 98 s = myUptime(d) 99 if s != "22s" { 100 t.Fatalf("Expected `22s`, go ``%s`", s) 101 } 102 d = 4*time.Minute + d 103 s = myUptime(d) 104 if s != "4m22s" { 105 t.Fatalf("Expected `4m22s`, go ``%s`", s) 106 } 107 d = 4*time.Hour + d 108 s = myUptime(d) 109 if s != "4h4m22s" { 110 t.Fatalf("Expected `4h4m22s`, go ``%s`", s) 111 } 112 d = 32*24*time.Hour + d 113 s = myUptime(d) 114 if s != "32d4h4m22s" { 115 t.Fatalf("Expected `32d4h4m22s`, go ``%s`", s) 116 } 117 d = 22*365*24*time.Hour + d 118 s = myUptime(d) 119 if s != "22y32d4h4m22s" { 120 t.Fatalf("Expected `22y32d4h4m22s`, go ``%s`", s) 121 } 122 } 123 124 // Make sure that we do not run the http server for monitoring unless asked. 125 func TestNoMonitorPort(t *testing.T) { 126 s := runMonitorServerNoHTTPPort() 127 defer s.Shutdown() 128 129 // this test might be meaningless now that we're testing with random ports? 130 url := fmt.Sprintf("http://127.0.0.1:%d/", 11245) 131 if resp, err := http.Get(url + "varz"); err == nil { 132 t.Fatalf("Expected error: Got %+v\n", resp) 133 } 134 if resp, err := http.Get(url + "healthz"); err == nil { 135 t.Fatalf("Expected error: Got %+v\n", resp) 136 } 137 if resp, err := http.Get(url + "connz"); err == nil { 138 t.Fatalf("Expected error: Got %+v\n", resp) 139 } 140 } 141 142 var ( 143 appJSONContent = "application/json" 144 appJSContent = "application/javascript" 145 textPlain = "text/plain; charset=utf-8" 146 textHTML = "text/html; charset=utf-8" 147 ) 148 149 func readBodyEx(t *testing.T, url string, status int, content string) []byte { 150 t.Helper() 151 resp, err := http.Get(url) 152 if err != nil { 153 t.Fatalf("Expected no error: Got %v\n", err) 154 } 155 defer resp.Body.Close() 156 if resp.StatusCode != status { 157 t.Fatalf("Expected a %d response, got %d\n", status, resp.StatusCode) 158 } 159 ct := resp.Header.Get("Content-Type") 160 if ct != content { 161 t.Fatalf("Expected %q content-type, got %q\n", content, ct) 162 } 163 // Check the CORS header for "application/json" requests only. 164 if ct == appJSONContent { 165 acao := resp.Header.Get("Access-Control-Allow-Origin") 166 if acao != "*" { 167 t.Fatalf("Expected with %q Content-Type an Access-Control-Allow-Origin header with value %q, got %q\n", appJSONContent, "*", acao) 168 } 169 } 170 body, err := io.ReadAll(resp.Body) 171 if err != nil { 172 t.Fatalf("Got an error reading the body: %v\n", err) 173 } 174 return body 175 } 176 177 func TestHTTPBasePath(t *testing.T) { 178 resetPreviousHTTPConnections() 179 opts := DefaultMonitorOptions() 180 opts.NoSystemAccount = true 181 opts.HTTPBasePath = "/nats" 182 183 s := RunServer(opts) 184 defer s.Shutdown() 185 186 url := fmt.Sprintf("http://127.0.0.1:%d/nats", s.MonitorAddr().Port) 187 readBodyEx(t, url, http.StatusOK, textHTML) 188 } 189 190 func readBody(t *testing.T, url string) []byte { 191 return readBodyEx(t, url, http.StatusOK, appJSONContent) 192 } 193 194 func pollVarz(t *testing.T, s *Server, mode int, url string, opts *VarzOptions) *Varz { 195 t.Helper() 196 if mode == 0 { 197 v := &Varz{} 198 body := readBody(t, url) 199 if err := json.Unmarshal(body, v); err != nil { 200 t.Fatalf("Got an error unmarshalling the body: %v\n", err) 201 } 202 return v 203 } 204 v, err := s.Varz(opts) 205 if err != nil { 206 t.Fatalf("Error on Varz: %v", err) 207 } 208 return v 209 } 210 211 // https://github.com/nats-io/nats-server/issues/2170 212 // Just the ever increasing subs part. 213 func TestVarzSubscriptionsResetProperly(t *testing.T) { 214 // Run with JS to create a bunch of subs to start. 215 resetPreviousHTTPConnections() 216 opts := DefaultMonitorOptions() 217 opts.JetStream = true 218 s := RunServer(opts) 219 defer s.Shutdown() 220 221 // This bug seems to only happen via the http endpoint, not direct calls. 222 // Every time you call it doubles. 223 url := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 224 osubs := pollVarz(t, s, 0, url, nil).Subscriptions 225 // Make sure we get same number back. 226 if v := pollVarz(t, s, 0, url, nil); v.Subscriptions != osubs { 227 t.Fatalf("Expected subs to stay the same, %d vs %d", osubs, v.Subscriptions) 228 } 229 } 230 231 func TestHandleVarz(t *testing.T) { 232 s := runMonitorServer() 233 defer s.Shutdown() 234 235 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 236 237 for mode := 0; mode < 2; mode++ { 238 v := pollVarz(t, s, mode, url+"varz", nil) 239 240 // Do some sanity checks on values 241 if time.Since(v.Start) > 10*time.Second { 242 t.Fatal("Expected start time to be within 10 seconds.") 243 } 244 } 245 246 time.Sleep(100 * time.Millisecond) 247 248 nc := createClientConnSubscribeAndPublish(t, s) 249 defer nc.Close() 250 251 for mode := 0; mode < 2; mode++ { 252 v := pollVarz(t, s, mode, url+"varz", nil) 253 254 if v.Connections != 1 { 255 t.Fatalf("Expected Connections of 1, got %v\n", v.Connections) 256 } 257 if v.TotalConnections < 1 { 258 t.Fatalf("Expected Total Connections of at least 1, got %v\n", v.TotalConnections) 259 } 260 if v.InMsgs != 1 { 261 t.Fatalf("Expected InMsgs of 1, got %v\n", v.InMsgs) 262 } 263 if v.OutMsgs != 1 { 264 t.Fatalf("Expected OutMsgs of 1, got %v\n", v.OutMsgs) 265 } 266 if v.InBytes != 5 { 267 t.Fatalf("Expected InBytes of 5, got %v\n", v.InBytes) 268 } 269 if v.OutBytes != 5 { 270 t.Fatalf("Expected OutBytes of 5, got %v\n", v.OutBytes) 271 } 272 if v.Subscriptions != 0 { 273 t.Fatalf("Expected Subscriptions of 0, got %v\n", v.Subscriptions) 274 } 275 if v.Name != "monitor_server" { 276 t.Fatal("Expected ServerName to be 'monitor_server'") 277 } 278 if !v.Tags.Contains("tag") { 279 t.Fatal("Expected tags to be 'tag'") 280 } 281 } 282 283 // Test JSONP 284 readBodyEx(t, url+"varz?callback=callback", http.StatusOK, appJSContent) 285 } 286 287 func pollConz(t *testing.T, s *Server, mode int, url string, opts *ConnzOptions) *Connz { 288 t.Helper() 289 if mode == 0 { 290 body := readBody(t, url) 291 c := &Connz{} 292 if err := json.Unmarshal(body, &c); err != nil { 293 t.Fatalf("Got an error unmarshalling the body: %v\n", err) 294 } 295 return c 296 } 297 c, err := s.Connz(opts) 298 if err != nil { 299 t.Fatalf("Error on Connz(): %v", err) 300 } 301 return c 302 } 303 304 func TestConnz(t *testing.T) { 305 s := runMonitorServer() 306 defer s.Shutdown() 307 308 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 309 310 testConnz := func(mode int) { 311 c := pollConz(t, s, mode, url+"connz", nil) 312 313 // Test contents.. 314 if c.NumConns != 0 { 315 t.Fatalf("Expected 0 connections, got %d\n", c.NumConns) 316 } 317 if c.Total != 0 { 318 t.Fatalf("Expected 0 live connections, got %d\n", c.Total) 319 } 320 if c.Conns == nil || len(c.Conns) != 0 { 321 t.Fatalf("Expected 0 connections in array, got %p\n", c.Conns) 322 } 323 324 // Test with connections. 325 nc := createClientConnSubscribeAndPublish(t, s) 326 defer nc.Close() 327 328 time.Sleep(50 * time.Millisecond) 329 330 c = pollConz(t, s, mode, url+"connz", nil) 331 332 if c.NumConns != 1 { 333 t.Fatalf("Expected 1 connection, got %d\n", c.NumConns) 334 } 335 if c.Total != 1 { 336 t.Fatalf("Expected 1 live connection, got %d\n", c.Total) 337 } 338 if c.Conns == nil || len(c.Conns) != 1 { 339 t.Fatalf("Expected 1 connection in array, got %d\n", len(c.Conns)) 340 } 341 342 if c.Limit != DefaultConnListSize { 343 t.Fatalf("Expected limit of %d, got %v\n", DefaultConnListSize, c.Limit) 344 } 345 346 if c.Offset != 0 { 347 t.Fatalf("Expected offset of 0, got %v\n", c.Offset) 348 } 349 350 // Test inside details of each connection 351 ci := c.Conns[0] 352 353 if ci.Cid == 0 { 354 t.Fatalf("Expected non-zero cid, got %v\n", ci.Cid) 355 } 356 if ci.IP != "127.0.0.1" { 357 t.Fatalf("Expected \"127.0.0.1\" for IP, got %v\n", ci.IP) 358 } 359 if ci.Port == 0 { 360 t.Fatalf("Expected non-zero port, got %v\n", ci.Port) 361 } 362 if ci.NumSubs != 0 { 363 t.Fatalf("Expected num_subs of 0, got %v\n", ci.NumSubs) 364 } 365 if len(ci.Subs) != 0 { 366 t.Fatalf("Expected subs of 0, got %v\n", ci.Subs) 367 } 368 if len(ci.SubsDetail) != 0 { 369 t.Fatalf("Expected subsdetail of 0, got %v\n", ci.SubsDetail) 370 } 371 if ci.InMsgs != 1 { 372 t.Fatalf("Expected InMsgs of 1, got %v\n", ci.InMsgs) 373 } 374 if ci.OutMsgs != 1 { 375 t.Fatalf("Expected OutMsgs of 1, got %v\n", ci.OutMsgs) 376 } 377 if ci.InBytes != 5 { 378 t.Fatalf("Expected InBytes of 1, got %v\n", ci.InBytes) 379 } 380 if ci.OutBytes != 5 { 381 t.Fatalf("Expected OutBytes of 1, got %v\n", ci.OutBytes) 382 } 383 if ci.Start.IsZero() { 384 t.Fatal("Expected Start to be valid\n") 385 } 386 if ci.Uptime == "" { 387 t.Fatal("Expected Uptime to be valid\n") 388 } 389 if ci.LastActivity.IsZero() { 390 t.Fatal("Expected LastActivity to be valid\n") 391 } 392 if ci.LastActivity.UnixNano() < ci.Start.UnixNano() { 393 t.Fatalf("Expected LastActivity [%v] to be > Start [%v]\n", ci.LastActivity, ci.Start) 394 } 395 if ci.Idle == "" { 396 t.Fatal("Expected Idle to be valid\n") 397 } 398 // This is a change, we now expect them to be set for connections when the 399 // client sends a connect. 400 if ci.RTT == "" { 401 t.Fatal("Expected RTT to be set for new connection\n") 402 } 403 } 404 405 for mode := 0; mode < 2; mode++ { 406 testConnz(mode) 407 checkClientsCount(t, s, 0) 408 } 409 410 // Test JSONP 411 readBodyEx(t, url+"connz?callback=callback", http.StatusOK, appJSContent) 412 } 413 414 func TestConnzBadParams(t *testing.T) { 415 s := runMonitorServer() 416 defer s.Shutdown() 417 418 url := fmt.Sprintf("http://127.0.0.1:%d/connz?", s.MonitorAddr().Port) 419 readBodyEx(t, url+"auth=xxx", http.StatusBadRequest, textPlain) 420 readBodyEx(t, url+"subs=xxx", http.StatusBadRequest, textPlain) 421 readBodyEx(t, url+"offset=xxx", http.StatusBadRequest, textPlain) 422 readBodyEx(t, url+"limit=xxx", http.StatusBadRequest, textPlain) 423 readBodyEx(t, url+"state=xxx", http.StatusBadRequest, textPlain) 424 } 425 426 func TestConnzWithSubs(t *testing.T) { 427 s := runMonitorServer() 428 defer s.Shutdown() 429 430 nc := createClientConnSubscribeAndPublish(t, s) 431 defer nc.Close() 432 433 nc.Subscribe("hello.foo", func(m *nats.Msg) {}) 434 ensureServerActivityRecorded(t, nc) 435 436 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 437 for mode := 0; mode < 2; mode++ { 438 c := pollConz(t, s, mode, url+"connz?subs=1", &ConnzOptions{Subscriptions: true}) 439 // Test inside details of each connection 440 ci := c.Conns[0] 441 if len(ci.Subs) != 1 || ci.Subs[0] != "hello.foo" { 442 t.Fatalf("Expected subs of 1, got %v\n", ci.Subs) 443 } 444 } 445 } 446 447 func TestConnzWithSubsDetail(t *testing.T) { 448 s := runMonitorServer() 449 defer s.Shutdown() 450 451 nc := createClientConnSubscribeAndPublish(t, s) 452 defer nc.Close() 453 454 nc.Subscribe("hello.foo", func(m *nats.Msg) {}) 455 ensureServerActivityRecorded(t, nc) 456 457 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 458 for mode := 0; mode < 2; mode++ { 459 c := pollConz(t, s, mode, url+"connz?subs=detail", &ConnzOptions{SubscriptionsDetail: true}) 460 // Test inside details of each connection 461 ci := c.Conns[0] 462 if len(ci.SubsDetail) != 1 || ci.SubsDetail[0].Subject != "hello.foo" { 463 t.Fatalf("Expected subsdetail of 1, got %v\n", ci.Subs) 464 } 465 } 466 } 467 468 func TestClosedConnzWithSubsDetail(t *testing.T) { 469 s := runMonitorServer() 470 defer s.Shutdown() 471 472 nc := createClientConnSubscribeAndPublish(t, s) 473 474 nc.Subscribe("hello.foo", func(m *nats.Msg) {}) 475 ensureServerActivityRecorded(t, nc) 476 nc.Close() 477 478 s.mu.Lock() 479 for len(s.clients) != 0 { 480 s.mu.Unlock() 481 <-time.After(100 * time.Millisecond) 482 s.mu.Lock() 483 } 484 s.mu.Unlock() 485 486 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 487 for mode := 0; mode < 2; mode++ { 488 c := pollConz(t, s, mode, url+"connz?state=closed&subs=detail", &ConnzOptions{State: ConnClosed, 489 SubscriptionsDetail: true}) 490 // Test inside details of each connection 491 ci := c.Conns[0] 492 if len(ci.SubsDetail) != 1 || ci.SubsDetail[0].Subject != "hello.foo" { 493 t.Fatalf("Expected subsdetail of 1, got %v\n", ci.Subs) 494 } 495 } 496 } 497 498 func TestConnzWithCID(t *testing.T) { 499 s := runMonitorServer() 500 defer s.Shutdown() 501 502 // The one we will request 503 cid := 5 504 total := 10 505 506 // Create 10 507 for i := 1; i <= total; i++ { 508 nc := createClientConnSubscribeAndPublish(t, s) 509 defer nc.Close() 510 if i == cid { 511 nc.Subscribe("hello.foo", func(m *nats.Msg) {}) 512 nc.Subscribe("hello.bar", func(m *nats.Msg) {}) 513 ensureServerActivityRecorded(t, nc) 514 } 515 } 516 517 url := fmt.Sprintf("http://127.0.0.1:%d/connz?cid=%d", s.MonitorAddr().Port, cid) 518 for mode := 0; mode < 2; mode++ { 519 c := pollConz(t, s, mode, url, &ConnzOptions{CID: uint64(cid)}) 520 // Test inside details of each connection 521 if len(c.Conns) != 1 { 522 t.Fatalf("Expected only one connection, but got %d\n", len(c.Conns)) 523 } 524 if c.NumConns != 1 { 525 t.Fatalf("Expected NumConns to be 1, but got %d\n", c.NumConns) 526 } 527 ci := c.Conns[0] 528 if ci.Cid != uint64(cid) { 529 t.Fatalf("Expected to receive connection %v, but received %v\n", cid, ci.Cid) 530 } 531 if ci.NumSubs != 2 { 532 t.Fatalf("Expected to receive connection with %d subs, but received %d\n", 2, ci.NumSubs) 533 } 534 // Now test a miss 535 badUrl := fmt.Sprintf("http://127.0.0.1:%d/connz?cid=%d", s.MonitorAddr().Port, 100) 536 c = pollConz(t, s, mode, badUrl, &ConnzOptions{CID: uint64(100)}) 537 if len(c.Conns) != 0 { 538 t.Fatalf("Expected no connections, got %d\n", len(c.Conns)) 539 } 540 if c.NumConns != 0 { 541 t.Fatalf("Expected NumConns of 0, got %d\n", c.NumConns) 542 } 543 } 544 } 545 546 // Helper to map to connection name 547 func createConnMap(cz *Connz) map[string]*ConnInfo { 548 cm := make(map[string]*ConnInfo) 549 for _, c := range cz.Conns { 550 cm[c.Name] = c 551 } 552 return cm 553 } 554 555 func getFooAndBar(cm map[string]*ConnInfo) (*ConnInfo, *ConnInfo) { 556 return cm["foo"], cm["bar"] 557 } 558 559 func ensureServerActivityRecorded(t *testing.T, nc *nats.Conn) { 560 nc.Flush() 561 err := nc.Flush() 562 if err != nil { 563 t.Fatalf("Error flushing: %v\n", err) 564 } 565 } 566 567 func TestConnzRTT(t *testing.T) { 568 s := runMonitorServer() 569 defer s.Shutdown() 570 571 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 572 573 testRTT := func(mode int) { 574 // Test with connections. 575 nc := createClientConnSubscribeAndPublish(t, s) 576 defer nc.Close() 577 578 c := pollConz(t, s, mode, url+"connz", nil) 579 580 if c.NumConns != 1 { 581 t.Fatalf("Expected 1 connection, got %d\n", c.NumConns) 582 } 583 584 // Send a server side PING to record RTT 585 s.mu.Lock() 586 ci := c.Conns[0] 587 sc := s.clients[ci.Cid] 588 if sc == nil { 589 t.Fatalf("Error looking up client %v\n", ci.Cid) 590 } 591 s.mu.Unlock() 592 sc.mu.Lock() 593 sc.sendPing() 594 sc.mu.Unlock() 595 596 // Wait for client to respond with PONG 597 time.Sleep(20 * time.Millisecond) 598 599 // Repoll for updated information. 600 c = pollConz(t, s, mode, url+"connz", nil) 601 ci = c.Conns[0] 602 603 rtt, err := time.ParseDuration(ci.RTT) 604 if err != nil { 605 t.Fatalf("Could not parse RTT properly, %v (ci.RTT=%v)", err, ci.RTT) 606 } 607 if rtt <= 0 { 608 t.Fatal("Expected RTT to be valid and non-zero\n") 609 } 610 if (runtime.GOOS == "windows" && rtt > 20*time.Millisecond) || 611 rtt > 20*time.Millisecond || rtt < 100*time.Nanosecond { 612 t.Fatalf("Invalid RTT of %s\n", ci.RTT) 613 } 614 } 615 616 for mode := 0; mode < 2; mode++ { 617 testRTT(mode) 618 checkClientsCount(t, s, 0) 619 } 620 } 621 622 func TestConnzLastActivity(t *testing.T) { 623 s := runMonitorServer() 624 defer s.Shutdown() 625 626 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 627 url += "connz?subs=1" 628 opts := &ConnzOptions{Subscriptions: true} 629 630 var sleepTime time.Duration 631 if runtime.GOOS == "windows" { 632 sleepTime = 10 * time.Millisecond 633 } 634 635 testActivity := func(mode int) { 636 ncFoo := createClientConnWithName(t, "foo", s) 637 defer ncFoo.Close() 638 639 ncBar := createClientConnWithName(t, "bar", s) 640 defer ncBar.Close() 641 642 // Test inside details of each connection 643 ciFoo, ciBar := getFooAndBar(createConnMap(pollConz(t, s, mode, url, opts))) 644 645 // Test that LastActivity is non-zero 646 if ciFoo.LastActivity.IsZero() { 647 t.Fatalf("Expected LastActivity for connection '%s'to be valid\n", ciFoo.Name) 648 } 649 if ciBar.LastActivity.IsZero() { 650 t.Fatalf("Expected LastActivity for connection '%s'to be valid\n", ciBar.Name) 651 } 652 // Foo should be older than Bar 653 if ciFoo.LastActivity.After(ciBar.LastActivity) { 654 t.Fatal("Expected connection 'foo' to be older than 'bar'\n") 655 } 656 657 fooLA := ciFoo.LastActivity 658 barLA := ciBar.LastActivity 659 660 ensureServerActivityRecorded(t, ncFoo) 661 ensureServerActivityRecorded(t, ncBar) 662 663 time.Sleep(sleepTime) 664 665 // Sub should trigger update. 666 sub, _ := ncFoo.Subscribe("hello.world", func(m *nats.Msg) {}) 667 ensureServerActivityRecorded(t, ncFoo) 668 669 ciFoo, _ = getFooAndBar(createConnMap(pollConz(t, s, mode, url, opts))) 670 nextLA := ciFoo.LastActivity 671 if fooLA.Equal(nextLA) { 672 t.Fatalf("Subscribe should have triggered update to LastActivity %+v\n", ciFoo) 673 } 674 fooLA = nextLA 675 676 time.Sleep(sleepTime) 677 678 // Publish and Message Delivery should trigger as well. So both connections 679 // should have updates. 680 ncBar.Publish("hello.world", []byte("Hello")) 681 682 ensureServerActivityRecorded(t, ncFoo) 683 ensureServerActivityRecorded(t, ncBar) 684 685 ciFoo, ciBar = getFooAndBar(createConnMap(pollConz(t, s, mode, url, opts))) 686 nextLA = ciBar.LastActivity 687 if barLA.Equal(nextLA) { 688 t.Fatalf("Publish should have triggered update to LastActivity\n") 689 } 690 691 // Message delivery on ncFoo should have triggered as well. 692 nextLA = ciFoo.LastActivity 693 if fooLA.Equal(nextLA) { 694 t.Fatalf("Message delivery should have triggered update to LastActivity\n") 695 } 696 fooLA = nextLA 697 698 time.Sleep(sleepTime) 699 700 // Unsub should trigger as well 701 sub.Unsubscribe() 702 ensureServerActivityRecorded(t, ncFoo) 703 704 ciFoo, _ = getFooAndBar(createConnMap(pollConz(t, s, mode, url, opts))) 705 nextLA = ciFoo.LastActivity 706 if fooLA.Equal(nextLA) { 707 t.Fatalf("Message delivery should have triggered update to LastActivity\n") 708 } 709 } 710 711 for mode := 0; mode < 2; mode++ { 712 testActivity(mode) 713 } 714 } 715 716 func TestConnzWithOffsetAndLimit(t *testing.T) { 717 s := runMonitorServer() 718 defer s.Shutdown() 719 720 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 721 722 for mode := 0; mode < 2; mode++ { 723 c := pollConz(t, s, mode, url+"connz?offset=1&limit=1", &ConnzOptions{Offset: 1, Limit: 1}) 724 if c.Conns == nil || len(c.Conns) != 0 { 725 t.Fatalf("Expected 0 connections in array, got %p\n", c.Conns) 726 } 727 728 // Test that when given negative values, 0 or default is used 729 c = pollConz(t, s, mode, url+"connz?offset=-1&limit=-1", &ConnzOptions{Offset: -11, Limit: -11}) 730 if c.Conns == nil || len(c.Conns) != 0 { 731 t.Fatalf("Expected 0 connections in array, got %p\n", c.Conns) 732 } 733 if c.Offset != 0 { 734 t.Fatalf("Expected offset to be 0, and limit to be %v, got %v and %v", 735 DefaultConnListSize, c.Offset, c.Limit) 736 } 737 } 738 739 cl1 := createClientConnSubscribeAndPublish(t, s) 740 defer cl1.Close() 741 742 cl2 := createClientConnSubscribeAndPublish(t, s) 743 defer cl2.Close() 744 745 for mode := 0; mode < 2; mode++ { 746 c := pollConz(t, s, mode, url+"connz?offset=1&limit=1", &ConnzOptions{Offset: 1, Limit: 1}) 747 if c.Limit != 1 { 748 t.Fatalf("Expected limit of 1, got %v\n", c.Limit) 749 } 750 751 if c.Offset != 1 { 752 t.Fatalf("Expected offset of 1, got %v\n", c.Offset) 753 } 754 755 if len(c.Conns) != 1 { 756 t.Fatalf("Expected conns of 1, got %v\n", len(c.Conns)) 757 } 758 759 if c.NumConns != 1 { 760 t.Fatalf("Expected NumConns to be 1, got %v\n", c.NumConns) 761 } 762 763 if c.Total != 2 { 764 t.Fatalf("Expected Total to be at least 2, got %v", c.Total) 765 } 766 767 c = pollConz(t, s, mode, url+"connz?offset=2&limit=1", &ConnzOptions{Offset: 2, Limit: 1}) 768 if c.Limit != 1 { 769 t.Fatalf("Expected limit of 1, got %v\n", c.Limit) 770 } 771 772 if c.Offset != 2 { 773 t.Fatalf("Expected offset of 2, got %v\n", c.Offset) 774 } 775 776 if len(c.Conns) != 0 { 777 t.Fatalf("Expected conns of 0, got %v\n", len(c.Conns)) 778 } 779 780 if c.NumConns != 0 { 781 t.Fatalf("Expected NumConns to be 0, got %v\n", c.NumConns) 782 } 783 784 if c.Total != 2 { 785 t.Fatalf("Expected Total to be 2, got %v", c.Total) 786 } 787 } 788 } 789 790 func TestConnzDefaultSorted(t *testing.T) { 791 s := runMonitorServer() 792 defer s.Shutdown() 793 794 clients := make([]*nats.Conn, 4) 795 for i := range clients { 796 clients[i] = createClientConnSubscribeAndPublish(t, s) 797 defer clients[i].Close() 798 } 799 800 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 801 for mode := 0; mode < 2; mode++ { 802 c := pollConz(t, s, mode, url+"connz", nil) 803 if c.Conns[0].Cid > c.Conns[1].Cid || 804 c.Conns[1].Cid > c.Conns[2].Cid || 805 c.Conns[2].Cid > c.Conns[3].Cid { 806 t.Fatalf("Expected conns sorted in ascending order by cid, got %v < %v\n", c.Conns[0].Cid, c.Conns[3].Cid) 807 } 808 } 809 } 810 811 func TestConnzSortedByCid(t *testing.T) { 812 s := runMonitorServer() 813 defer s.Shutdown() 814 815 clients := make([]*nats.Conn, 4) 816 for i := range clients { 817 clients[i] = createClientConnSubscribeAndPublish(t, s) 818 defer clients[i].Close() 819 } 820 821 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 822 for mode := 0; mode < 2; mode++ { 823 c := pollConz(t, s, mode, url+"connz?sort=cid", &ConnzOptions{Sort: ByCid}) 824 if c.Conns[0].Cid > c.Conns[1].Cid || 825 c.Conns[1].Cid > c.Conns[2].Cid || 826 c.Conns[2].Cid > c.Conns[3].Cid { 827 t.Fatalf("Expected conns sorted in ascending order by cid, got [%v, %v, %v, %v]\n", 828 c.Conns[0].Cid, c.Conns[1].Cid, c.Conns[2].Cid, c.Conns[3].Cid) 829 } 830 } 831 } 832 833 func TestConnzSortedByStart(t *testing.T) { 834 s := runMonitorServer() 835 defer s.Shutdown() 836 837 clients := make([]*nats.Conn, 4) 838 for i := range clients { 839 clients[i] = createClientConnSubscribeAndPublish(t, s) 840 defer clients[i].Close() 841 } 842 843 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 844 for mode := 0; mode < 2; mode++ { 845 c := pollConz(t, s, mode, url+"connz?sort=start", &ConnzOptions{Sort: ByStart}) 846 if c.Conns[0].Start.After(c.Conns[1].Start) || 847 c.Conns[1].Start.After(c.Conns[2].Start) || 848 c.Conns[2].Start.After(c.Conns[3].Start) { 849 t.Fatalf("Expected conns sorted in ascending order by startime, got [%v, %v, %v, %v]\n", 850 c.Conns[0].Start, c.Conns[1].Start, c.Conns[2].Start, c.Conns[3].Start) 851 } 852 } 853 } 854 855 func TestConnzSortedByBytesAndMsgs(t *testing.T) { 856 s := runMonitorServer() 857 defer s.Shutdown() 858 859 // Create a connection and make it send more messages than others 860 firstClient := createClientConnSubscribeAndPublish(t, s) 861 for i := 0; i < 100; i++ { 862 firstClient.Publish("foo", []byte("Hello World")) 863 } 864 defer firstClient.Close() 865 firstClient.Flush() 866 867 clients := make([]*nats.Conn, 3) 868 for i := range clients { 869 clients[i] = createClientConnSubscribeAndPublish(t, s) 870 defer clients[i].Close() 871 } 872 873 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 874 for mode := 0; mode < 2; mode++ { 875 c := pollConz(t, s, mode, url+"connz?sort=bytes_to", &ConnzOptions{Sort: ByOutBytes}) 876 if c.Conns[0].OutBytes < c.Conns[1].OutBytes || 877 c.Conns[0].OutBytes < c.Conns[2].OutBytes || 878 c.Conns[0].OutBytes < c.Conns[3].OutBytes { 879 t.Fatalf("Expected conns sorted in descending order by bytes to, got %v < one of [%v, %v, %v]\n", 880 c.Conns[0].OutBytes, c.Conns[1].OutBytes, c.Conns[2].OutBytes, c.Conns[3].OutBytes) 881 } 882 883 c = pollConz(t, s, mode, url+"connz?sort=msgs_to", &ConnzOptions{Sort: ByOutMsgs}) 884 if c.Conns[0].OutMsgs < c.Conns[1].OutMsgs || 885 c.Conns[0].OutMsgs < c.Conns[2].OutMsgs || 886 c.Conns[0].OutMsgs < c.Conns[3].OutMsgs { 887 t.Fatalf("Expected conns sorted in descending order by msgs from, got %v < one of [%v, %v, %v]\n", 888 c.Conns[0].OutMsgs, c.Conns[1].OutMsgs, c.Conns[2].OutMsgs, c.Conns[3].OutMsgs) 889 } 890 891 c = pollConz(t, s, mode, url+"connz?sort=bytes_from", &ConnzOptions{Sort: ByInBytes}) 892 if c.Conns[0].InBytes < c.Conns[1].InBytes || 893 c.Conns[0].InBytes < c.Conns[2].InBytes || 894 c.Conns[0].InBytes < c.Conns[3].InBytes { 895 t.Fatalf("Expected conns sorted in descending order by bytes from, got %v < one of [%v, %v, %v]\n", 896 c.Conns[0].InBytes, c.Conns[1].InBytes, c.Conns[2].InBytes, c.Conns[3].InBytes) 897 } 898 899 c = pollConz(t, s, mode, url+"connz?sort=msgs_from", &ConnzOptions{Sort: ByInMsgs}) 900 if c.Conns[0].InMsgs < c.Conns[1].InMsgs || 901 c.Conns[0].InMsgs < c.Conns[2].InMsgs || 902 c.Conns[0].InMsgs < c.Conns[3].InMsgs { 903 t.Fatalf("Expected conns sorted in descending order by msgs from, got %v < one of [%v, %v, %v]\n", 904 c.Conns[0].InMsgs, c.Conns[1].InMsgs, c.Conns[2].InMsgs, c.Conns[3].InMsgs) 905 } 906 } 907 } 908 909 func TestConnzSortedByPending(t *testing.T) { 910 s := runMonitorServer() 911 defer s.Shutdown() 912 913 firstClient := createClientConnSubscribeAndPublish(t, s) 914 firstClient.Subscribe("hello.world", func(m *nats.Msg) {}) 915 clients := make([]*nats.Conn, 3) 916 for i := range clients { 917 clients[i] = createClientConnSubscribeAndPublish(t, s) 918 defer clients[i].Close() 919 } 920 defer firstClient.Close() 921 922 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 923 for mode := 0; mode < 2; mode++ { 924 c := pollConz(t, s, mode, url+"connz?sort=pending", &ConnzOptions{Sort: ByPending}) 925 if c.Conns[0].Pending < c.Conns[1].Pending || 926 c.Conns[0].Pending < c.Conns[2].Pending || 927 c.Conns[0].Pending < c.Conns[3].Pending { 928 t.Fatalf("Expected conns sorted in descending order by number of pending, got %v < one of [%v, %v, %v]\n", 929 c.Conns[0].Pending, c.Conns[1].Pending, c.Conns[2].Pending, c.Conns[3].Pending) 930 } 931 } 932 } 933 934 func TestConnzSortedBySubs(t *testing.T) { 935 s := runMonitorServer() 936 defer s.Shutdown() 937 938 firstClient := createClientConnSubscribeAndPublish(t, s) 939 firstClient.Subscribe("hello.world", func(m *nats.Msg) {}) 940 defer firstClient.Close() 941 942 clients := make([]*nats.Conn, 3) 943 for i := range clients { 944 clients[i] = createClientConnSubscribeAndPublish(t, s) 945 defer clients[i].Close() 946 } 947 948 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 949 for mode := 0; mode < 2; mode++ { 950 c := pollConz(t, s, mode, url+"connz?sort=subs", &ConnzOptions{Sort: BySubs}) 951 if c.Conns[0].NumSubs < c.Conns[1].NumSubs || 952 c.Conns[0].NumSubs < c.Conns[2].NumSubs || 953 c.Conns[0].NumSubs < c.Conns[3].NumSubs { 954 t.Fatalf("Expected conns sorted in descending order by number of subs, got %v < one of [%v, %v, %v]\n", 955 c.Conns[0].NumSubs, c.Conns[1].NumSubs, c.Conns[2].NumSubs, c.Conns[3].NumSubs) 956 } 957 } 958 } 959 960 func TestConnzSortedByLast(t *testing.T) { 961 resetPreviousHTTPConnections() 962 opts := DefaultMonitorOptions() 963 opts.NoSystemAccount = true 964 s := RunServer(opts) 965 defer s.Shutdown() 966 967 firstClient := createClientConnSubscribeAndPublish(t, s) 968 defer firstClient.Close() 969 firstClient.Subscribe("hello.world", func(m *nats.Msg) {}) 970 firstClient.Flush() 971 972 clients := make([]*nats.Conn, 3) 973 for i := range clients { 974 clients[i] = createClientConnSubscribeAndPublish(t, s) 975 defer clients[i].Close() 976 clients[i].Flush() 977 } 978 979 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 980 for mode := 0; mode < 2; mode++ { 981 c := pollConz(t, s, mode, url+"connz?sort=last", &ConnzOptions{Sort: ByLast}) 982 if c.Conns[0].LastActivity.UnixNano() < c.Conns[1].LastActivity.UnixNano() || 983 c.Conns[1].LastActivity.UnixNano() < c.Conns[2].LastActivity.UnixNano() || 984 c.Conns[2].LastActivity.UnixNano() < c.Conns[3].LastActivity.UnixNano() { 985 t.Fatalf("Expected conns sorted in descending order by lastActivity, got %v < one of [%v, %v, %v]\n", 986 c.Conns[0].LastActivity, c.Conns[1].LastActivity, c.Conns[2].LastActivity, c.Conns[3].LastActivity) 987 } 988 } 989 } 990 991 func TestConnzSortedByUptime(t *testing.T) { 992 s := runMonitorServer() 993 defer s.Shutdown() 994 995 for i := 0; i < 4; i++ { 996 client := createClientConnSubscribeAndPublish(t, s) 997 defer client.Close() 998 // Since we check times (now-start) does not have to be big. 999 time.Sleep(50 * time.Millisecond) 1000 } 1001 1002 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1003 for mode := 0; mode < 2; mode++ { 1004 c := pollConz(t, s, mode, url+"connz?sort=uptime", &ConnzOptions{Sort: ByUptime}) 1005 now := time.Now() 1006 ups := make([]int, 4) 1007 for i := 0; i < 4; i++ { 1008 ups[i] = int(now.Sub(c.Conns[i].Start)) 1009 } 1010 if !sort.IntsAreSorted(ups) { 1011 d := make([]time.Duration, 4) 1012 for i := 0; i < 4; i++ { 1013 d[i] = time.Duration(ups[i]) 1014 } 1015 t.Fatalf("Expected conns sorted in ascending order by uptime (now-Start), got %+v\n", d) 1016 } 1017 } 1018 } 1019 1020 func TestConnzSortedByUptimeClosedConn(t *testing.T) { 1021 s := runMonitorServer() 1022 defer s.Shutdown() 1023 1024 for i := time.Duration(1); i <= 4; i++ { 1025 c := createClientConnSubscribeAndPublish(t, s) 1026 1027 // Grab client and asjust start time such that 1028 client := s.getClient(uint64(i)) 1029 if client == nil { 1030 t.Fatalf("Could nopt retrieve client for %d\n", i) 1031 } 1032 client.mu.Lock() 1033 client.start = client.start.Add(-10 * (4 - i) * time.Second) 1034 client.mu.Unlock() 1035 1036 c.Close() 1037 } 1038 1039 checkClosedConns(t, s, 4, time.Second) 1040 1041 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1042 for mode := 0; mode < 2; mode++ { 1043 c := pollConz(t, s, mode, url+"connz?state=closed&sort=uptime", &ConnzOptions{State: ConnClosed, Sort: ByUptime}) 1044 ups := make([]int, 4) 1045 for i := 0; i < 4; i++ { 1046 ups[i] = int(c.Conns[i].Stop.Sub(c.Conns[i].Start)) 1047 } 1048 if !sort.IntsAreSorted(ups) { 1049 d := make([]time.Duration, 4) 1050 for i := 0; i < 4; i++ { 1051 d[i] = time.Duration(ups[i]) 1052 } 1053 t.Fatalf("Expected conns sorted in ascending order by uptime, got %+v\n", d) 1054 } 1055 } 1056 } 1057 1058 func TestConnzSortedByStopOnOpen(t *testing.T) { 1059 s := runMonitorServer() 1060 defer s.Shutdown() 1061 1062 opts := s.getOpts() 1063 url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) 1064 1065 // 4 clients 1066 for i := 0; i < 4; i++ { 1067 c, err := nats.Connect(url) 1068 if err != nil { 1069 t.Fatalf("Could not create client: %v\n", err) 1070 } 1071 defer c.Close() 1072 } 1073 1074 c, err := s.Connz(&ConnzOptions{Sort: ByStop}) 1075 if err == nil { 1076 t.Fatalf("Expected err to be non-nil, got %+v\n", c) 1077 } 1078 } 1079 1080 func TestConnzSortedByStopTimeClosedConn(t *testing.T) { 1081 s := runMonitorServer() 1082 defer s.Shutdown() 1083 1084 opts := s.getOpts() 1085 url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) 1086 1087 // 4 clients 1088 for i := 0; i < 4; i++ { 1089 c, err := nats.Connect(url) 1090 if err != nil { 1091 t.Fatalf("Could not create client: %v\n", err) 1092 } 1093 c.Close() 1094 } 1095 checkClosedConns(t, s, 4, time.Second) 1096 1097 // Now adjust the Stop times for these with some random values. 1098 s.mu.Lock() 1099 now := time.Now().UTC() 1100 ccs := s.closed.closedClients() 1101 for _, cc := range ccs { 1102 newStop := now.Add(time.Duration(rand.Int()%120) * -time.Minute) 1103 cc.Stop = &newStop 1104 } 1105 s.mu.Unlock() 1106 1107 url = fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1108 for mode := 0; mode < 2; mode++ { 1109 c := pollConz(t, s, mode, url+"connz?state=closed&sort=stop", &ConnzOptions{State: ConnClosed, Sort: ByStop}) 1110 ups := make([]int, 4) 1111 nowU := time.Now().UnixNano() 1112 for i := 0; i < 4; i++ { 1113 ups[i] = int(nowU - c.Conns[i].Stop.UnixNano()) 1114 } 1115 if !sort.IntsAreSorted(ups) { 1116 d := make([]time.Duration, 4) 1117 for i := 0; i < 4; i++ { 1118 d[i] = time.Duration(ups[i]) 1119 } 1120 t.Fatalf("Expected conns sorted in ascending order by stop time, got %+v\n", d) 1121 } 1122 } 1123 } 1124 1125 func TestConnzSortedByReason(t *testing.T) { 1126 s := runMonitorServer() 1127 defer s.Shutdown() 1128 1129 opts := s.getOpts() 1130 url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) 1131 1132 // 20 clients 1133 for i := 0; i < 20; i++ { 1134 c, err := nats.Connect(url) 1135 if err != nil { 1136 t.Fatalf("Could not create client: %v\n", err) 1137 } 1138 c.Close() 1139 } 1140 checkClosedConns(t, s, 20, time.Second) 1141 1142 // Now adjust the Reasons for these with some random values. 1143 s.mu.Lock() 1144 ccs := s.closed.closedClients() 1145 max := int(ServerShutdown) 1146 for _, cc := range ccs { 1147 cc.Reason = ClosedState(rand.Int() % max).String() 1148 } 1149 s.mu.Unlock() 1150 1151 url = fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1152 for mode := 0; mode < 2; mode++ { 1153 c := pollConz(t, s, mode, url+"connz?state=closed&sort=reason", &ConnzOptions{State: ConnClosed, Sort: ByReason}) 1154 rs := make([]string, 20) 1155 for i := 0; i < 20; i++ { 1156 rs[i] = c.Conns[i].Reason 1157 } 1158 if !sort.StringsAreSorted(rs) { 1159 t.Fatalf("Expected conns sorted in order by stop reason, got %#v\n", rs) 1160 } 1161 } 1162 } 1163 1164 func TestConnzSortedByReasonOnOpen(t *testing.T) { 1165 s := runMonitorServer() 1166 defer s.Shutdown() 1167 1168 opts := s.getOpts() 1169 url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) 1170 1171 // 4 clients 1172 for i := 0; i < 4; i++ { 1173 c, err := nats.Connect(url) 1174 if err != nil { 1175 t.Fatalf("Could not create client: %v\n", err) 1176 } 1177 defer c.Close() 1178 } 1179 1180 c, err := s.Connz(&ConnzOptions{Sort: ByReason}) 1181 if err == nil { 1182 t.Fatalf("Expected err to be non-nil, got %+v\n", c) 1183 } 1184 } 1185 1186 func TestConnzSortedByIdle(t *testing.T) { 1187 s := runMonitorServer() 1188 defer s.Shutdown() 1189 1190 url := fmt.Sprintf("http://%s/connz?sort=idle", s.MonitorAddr()) 1191 now := time.Now() 1192 1193 clients := []struct { 1194 start time.Time // Client start time. 1195 last time.Time // Client last activity time. 1196 }{ 1197 {start: now.Add(-10 * time.Second), last: now.Add(-5 * time.Second)}, 1198 {start: now.Add(-20 * time.Second), last: now.Add(-10 * time.Second)}, 1199 {start: now.Add(-3 * time.Second), last: now.Add(-2 * time.Second)}, 1200 {start: now.Add(-30 * time.Second), last: now.Add(-20 * time.Second)}, 1201 } 1202 1203 testIdle := func(mode int) { 1204 // Connect the specified number of clients. 1205 for _, c := range clients { 1206 clientConn := createClientConnSubscribeAndPublish(t, s) 1207 defer clientConn.Close() 1208 1209 cid, err := clientConn.GetClientID() 1210 if err != nil { 1211 t.Fatalf("error getting the client CID: %v", err) 1212 } 1213 1214 client := s.getClient(cid) 1215 if client == nil { 1216 t.Fatalf("error looking up client %d", cid) 1217 } 1218 1219 // Change the client's start and last activity times. 1220 client.mu.Lock() 1221 client.start = c.start 1222 client.last = c.last 1223 client.mu.Unlock() 1224 } 1225 1226 connz := pollConz(t, s, mode, url, &ConnzOptions{Sort: ByIdle}) 1227 1228 wantConns := len(clients) 1229 gotConns := len(connz.Conns) 1230 1231 if gotConns != wantConns { 1232 t.Fatalf("want %d connections, got %d", wantConns, gotConns) 1233 } 1234 1235 idleDurations := getConnsIdleDurations(t, connz.Conns) 1236 1237 if !sortedDurationsDesc(idleDurations) { 1238 t.Errorf("want durations sorted in descending order, got %v", idleDurations) 1239 } 1240 } 1241 1242 for mode := 0; mode < 2; mode++ { 1243 testIdle(mode) 1244 } 1245 } 1246 1247 // getConnsIdleDurations returns a slice of parsed idle durations from a connection info slice. 1248 func getConnsIdleDurations(t *testing.T, conns []*ConnInfo) []time.Duration { 1249 t.Helper() 1250 1251 durations := make([]time.Duration, 0, len(conns)) 1252 1253 for _, conn := range conns { 1254 idle, err := time.ParseDuration(conn.Idle) 1255 if err != nil { 1256 t.Fatalf("error parsing duration %q: %v", conn.Idle, err) 1257 } 1258 durations = append(durations, idle) 1259 } 1260 1261 return durations 1262 } 1263 1264 // sortedDurationsDesc checks if a time.Duration slice is sorted in descending order. 1265 func sortedDurationsDesc(durations []time.Duration) bool { 1266 return sort.SliceIsSorted(durations, func(i, j int) bool { 1267 // Must be longer than the next duration. 1268 return durations[i] > durations[j] 1269 }) 1270 } 1271 1272 func TestConnzSortByIdleTime(t *testing.T) { 1273 now := time.Now().UTC() 1274 1275 cases := map[string]ConnInfos{ 1276 "zero values": {{}, {}, {}, {}}, 1277 "equal last activity times": { 1278 {Start: now.Add(-50 * time.Minute), LastActivity: now.Add(-time.Minute)}, 1279 {Start: now.Add(-30 * time.Minute), LastActivity: now.Add(-time.Minute)}, 1280 {Start: now.Add(-10 * time.Second), LastActivity: now.Add(-time.Minute)}, 1281 {Start: now.Add(-2 * time.Hour), LastActivity: now.Add(-time.Minute)}, 1282 }, 1283 "last activity in the future": { 1284 {Start: now.Add(-50 * time.Minute), LastActivity: now.Add(10 * time.Minute)}, // +10m 1285 {Start: now.Add(-30 * time.Minute), LastActivity: now.Add(5 * time.Minute)}, // +5m 1286 {Start: now.Add(-24 * time.Hour), LastActivity: now.Add(2 * time.Second)}, // +2s 1287 {Start: now.Add(-10 * time.Second), LastActivity: now.Add(15 * time.Minute)}, // +15m 1288 {Start: now.Add(-2 * time.Hour), LastActivity: now.Add(time.Minute)}, // +1m 1289 }, 1290 "unsorted": { 1291 {Start: now.Add(-50 * time.Minute), LastActivity: now.Add(-10 * time.Minute)}, // 10m ago 1292 {Start: now.Add(-30 * time.Minute), LastActivity: now.Add(-5 * time.Minute)}, // 5m ago 1293 {Start: now.Add(-24 * time.Hour), LastActivity: now.Add(-2 * time.Second)}, // 2s ago 1294 {Start: now.Add(-10 * time.Second), LastActivity: now.Add(-15 * time.Minute)}, // 15m ago 1295 {Start: now.Add(-2 * time.Hour), LastActivity: now.Add(-time.Minute)}, // 1m ago 1296 }, 1297 "unsorted with zero value start time": { 1298 {LastActivity: now.Add(-10 * time.Minute)}, // 10m ago 1299 {LastActivity: now.Add(-5 * time.Minute)}, // 5m ago 1300 {LastActivity: now.Add(-2 * time.Second)}, // 2s ago 1301 {LastActivity: now.Add(-15 * time.Minute)}, // 15m ago 1302 {LastActivity: now.Add(-time.Minute)}, // 1m ago 1303 }, 1304 "sorted": { 1305 {Start: now.Add(-24 * time.Hour), LastActivity: now.Add(-2 * time.Second)}, // 2s ago 1306 {Start: now.Add(-2 * time.Hour), LastActivity: now.Add(-time.Minute)}, // 1m ago 1307 {Start: now.Add(-30 * time.Minute), LastActivity: now.Add(-5 * time.Minute)}, // 5m ago 1308 {Start: now.Add(-50 * time.Minute), LastActivity: now.Add(-10 * time.Minute)}, // 10m ago 1309 {Start: now.Add(-10 * time.Second), LastActivity: now.Add(-15 * time.Minute)}, // 15m ago 1310 }, 1311 "sorted with zero value start time": { 1312 {LastActivity: now.Add(-2 * time.Second)}, // 2s ago 1313 {LastActivity: now.Add(-time.Minute)}, // 1m ago 1314 {LastActivity: now.Add(-5 * time.Minute)}, // 5m ago 1315 {LastActivity: now.Add(-10 * time.Minute)}, // 10m ago 1316 {LastActivity: now.Add(-15 * time.Minute)}, // 15m ago 1317 }, 1318 } 1319 1320 for name, conns := range cases { 1321 t.Run(name, func(t *testing.T) { 1322 sort.Sort(byIdle{conns, now}) 1323 1324 idleDurations := getIdleDurations(conns, now) 1325 1326 if !sortedDurationsAsc(idleDurations) { 1327 t.Errorf("want durations sorted in ascending order, got %v", idleDurations) 1328 } 1329 }) 1330 } 1331 } 1332 1333 // getIdleDurations returns a slice of idle durations from a connection info list up until now time. 1334 func getIdleDurations(conns ConnInfos, now time.Time) []time.Duration { 1335 durations := make([]time.Duration, 0, len(conns)) 1336 1337 for _, conn := range conns { 1338 durations = append(durations, now.Sub(conn.LastActivity)) 1339 } 1340 1341 return durations 1342 } 1343 1344 // sortedDurationsAsc checks if a time.Duration slice is sorted in ascending order. 1345 func sortedDurationsAsc(durations []time.Duration) bool { 1346 return sort.SliceIsSorted(durations, func(i, j int) bool { 1347 return durations[i] < durations[j] 1348 }) 1349 } 1350 1351 func TestConnzSortBadRequest(t *testing.T) { 1352 s := runMonitorServer() 1353 defer s.Shutdown() 1354 1355 firstClient := createClientConnSubscribeAndPublish(t, s) 1356 firstClient.Subscribe("hello.world", func(m *nats.Msg) {}) 1357 clients := make([]*nats.Conn, 3) 1358 for i := range clients { 1359 clients[i] = createClientConnSubscribeAndPublish(t, s) 1360 defer clients[i].Close() 1361 } 1362 defer firstClient.Close() 1363 1364 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1365 readBodyEx(t, url+"connz?sort=foo", http.StatusBadRequest, textPlain) 1366 1367 if _, err := s.Connz(&ConnzOptions{Sort: "foo"}); err == nil { 1368 t.Fatal("Expected error, got none") 1369 } 1370 } 1371 1372 func pollRoutez(t *testing.T, s *Server, mode int, url string, opts *RoutezOptions) *Routez { 1373 t.Helper() 1374 if mode == 0 { 1375 rz := &Routez{} 1376 body := readBody(t, url) 1377 if err := json.Unmarshal(body, rz); err != nil { 1378 t.Fatalf("Got an error unmarshalling the body: %v\n", err) 1379 } 1380 return rz 1381 } 1382 rz, err := s.Routez(opts) 1383 if err != nil { 1384 t.Fatalf("Error on Routez: %v", err) 1385 } 1386 return rz 1387 } 1388 1389 func TestConnzWithRoutes(t *testing.T) { 1390 resetPreviousHTTPConnections() 1391 opts := DefaultMonitorOptions() 1392 opts.NoSystemAccount = true 1393 opts.Cluster.Name = "A" 1394 opts.Cluster.Host = "127.0.0.1" 1395 opts.Cluster.Port = CLUSTER_PORT 1396 1397 s := RunServer(opts) 1398 defer s.Shutdown() 1399 1400 opts = &Options{ 1401 Host: "127.0.0.1", 1402 Port: -1, 1403 Cluster: ClusterOpts{ 1404 Name: "A", 1405 Host: "127.0.0.1", 1406 Port: -1, 1407 }, 1408 NoLog: true, 1409 NoSigs: true, 1410 NoSystemAccount: true, 1411 } 1412 routeURL, _ := url.Parse(fmt.Sprintf("nats-route://127.0.0.1:%d", s.ClusterAddr().Port)) 1413 opts.Routes = []*url.URL{routeURL} 1414 1415 start := time.Now() 1416 sc := RunServer(opts) 1417 defer sc.Shutdown() 1418 1419 checkClusterFormed(t, s, sc) 1420 1421 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1422 for mode := 0; mode < 2; mode++ { 1423 c := pollConz(t, s, mode, url+"connz", nil) 1424 // Test contents.. 1425 // Make sure routes don't show up under connz, but do under routez 1426 if c.NumConns != 0 { 1427 t.Fatalf("Expected 0 connections, got %d", c.NumConns) 1428 } 1429 if c.Conns == nil || len(c.Conns) != 0 { 1430 t.Fatalf("Expected 0 connections in array, got %p", c.Conns) 1431 } 1432 } 1433 1434 nc := createClientConnSubscribeAndPublish(t, sc) 1435 defer nc.Close() 1436 1437 nc.Subscribe("hello.bar", func(m *nats.Msg) {}) 1438 nc.Flush() 1439 checkExpectedSubs(t, 1, s, sc) 1440 1441 // Now check routez 1442 urls := []string{"routez", "routez?subs=1", "routez?subs=detail"} 1443 for subs, urlSuffix := range urls { 1444 for mode := 0; mode < 2; mode++ { 1445 rz := pollRoutez(t, s, mode, url+urlSuffix, &RoutezOptions{Subscriptions: subs == 1, SubscriptionsDetail: subs == 2}) 1446 1447 if rz.NumRoutes != DEFAULT_ROUTE_POOL_SIZE { 1448 t.Fatalf("Expected %d route, got %d", DEFAULT_ROUTE_POOL_SIZE, rz.NumRoutes) 1449 } 1450 1451 if len(rz.Routes) != DEFAULT_ROUTE_POOL_SIZE { 1452 t.Fatalf("Expected route array of %d, got %v", DEFAULT_ROUTE_POOL_SIZE, len(rz.Routes)) 1453 } 1454 1455 route := rz.Routes[0] 1456 1457 if route.DidSolicit { 1458 t.Fatalf("Expected unsolicited route, got %v", route.DidSolicit) 1459 } 1460 1461 if route.Start.IsZero() { 1462 t.Fatalf("Expected Start to be set, got %+v", route) 1463 } else if route.Start.Before(start) { 1464 t.Fatalf("Unexpected start time: route was started around %v, got %v", start, route.Start) 1465 } 1466 if route.LastActivity.IsZero() { 1467 t.Fatalf("Expected LastActivity to be set, got %+v", route) 1468 } 1469 if route.Uptime == _EMPTY_ { 1470 t.Fatalf("Expected Uptime to be set, it was not") 1471 } 1472 if route.Idle == _EMPTY_ { 1473 t.Fatalf("Expected Idle to be set, it was not") 1474 } 1475 1476 // Don't ask for subs, so there should not be any 1477 if subs == 0 { 1478 if len(route.Subs) != 0 { 1479 t.Fatalf("There should not be subs, got %v", len(route.Subs)) 1480 } 1481 } else if subs == 1 { 1482 if len(route.Subs) != 1 && len(route.SubsDetail) != 0 { 1483 t.Fatalf("There should be 1 sub, got %v", len(route.Subs)) 1484 } 1485 } else if subs == 2 { 1486 if len(route.SubsDetail) != 1 && len(route.Subs) != 0 { 1487 t.Fatalf("There should be 1 sub, got %v", len(route.SubsDetail)) 1488 } 1489 } 1490 } 1491 } 1492 1493 // Test JSONP 1494 readBodyEx(t, url+"routez?callback=callback", http.StatusOK, appJSContent) 1495 } 1496 1497 func TestRoutezWithBadParams(t *testing.T) { 1498 s := runMonitorServer() 1499 defer s.Shutdown() 1500 1501 url := fmt.Sprintf("http://127.0.0.1:%d/routez?", s.MonitorAddr().Port) 1502 readBodyEx(t, url+"subs=xxx", http.StatusBadRequest, textPlain) 1503 } 1504 1505 func pollSubsz(t *testing.T, s *Server, mode int, url string, opts *SubszOptions) *Subsz { 1506 t.Helper() 1507 if mode == 0 { 1508 body := readBody(t, url) 1509 sz := &Subsz{} 1510 if err := json.Unmarshal(body, sz); err != nil { 1511 t.Fatalf("Got an error unmarshalling the body: %v\n", err) 1512 } 1513 return sz 1514 } 1515 sz, err := s.Subsz(opts) 1516 if err != nil { 1517 t.Fatalf("Error on Subsz: %v", err) 1518 } 1519 return sz 1520 } 1521 1522 func TestSubsz(t *testing.T) { 1523 s := runMonitorServer() 1524 defer s.Shutdown() 1525 1526 nc := createClientConnSubscribeAndPublish(t, s) 1527 defer nc.Close() 1528 1529 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1530 1531 for mode := 0; mode < 2; mode++ { 1532 sl := pollSubsz(t, s, mode, url+"subsz", nil) 1533 if sl.NumSubs != 0 { 1534 t.Fatalf("Expected NumSubs of 0, got %d\n", sl.NumSubs) 1535 } 1536 if sl.NumInserts != 1 { 1537 t.Fatalf("Expected NumInserts of 1, got %d\n", sl.NumInserts) 1538 } 1539 if sl.NumMatches != 1 { 1540 t.Fatalf("Expected NumMatches of 1, got %d\n", sl.NumMatches) 1541 } 1542 } 1543 1544 // Test JSONP 1545 readBodyEx(t, url+"subsz?callback=callback", http.StatusOK, appJSContent) 1546 } 1547 1548 func TestSubszDetails(t *testing.T) { 1549 s := runMonitorServer() 1550 defer s.Shutdown() 1551 1552 nc := createClientConnSubscribeAndPublish(t, s) 1553 defer nc.Close() 1554 1555 nc.Subscribe("foo.*", func(m *nats.Msg) {}) 1556 nc.Subscribe("foo.bar", func(m *nats.Msg) {}) 1557 nc.Subscribe("foo.foo", func(m *nats.Msg) {}) 1558 1559 nc.Publish("foo.bar", []byte("Hello")) 1560 nc.Publish("foo.baz", []byte("Hello")) 1561 nc.Publish("foo.foo", []byte("Hello")) 1562 1563 nc.Flush() 1564 1565 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1566 1567 for mode := 0; mode < 2; mode++ { 1568 sl := pollSubsz(t, s, mode, url+"subsz?subs=1", &SubszOptions{Subscriptions: true}) 1569 if sl.NumSubs != 3 { 1570 t.Fatalf("Expected NumSubs of 3, got %d\n", sl.NumSubs) 1571 } 1572 if sl.Total != 3 { 1573 t.Fatalf("Expected Total of 3, got %d\n", sl.Total) 1574 } 1575 if len(sl.Subs) != 3 { 1576 t.Fatalf("Expected subscription details for 3 subs, got %d\n", len(sl.Subs)) 1577 } 1578 } 1579 } 1580 1581 func TestSubszWithOffsetAndLimit(t *testing.T) { 1582 s := runMonitorServer() 1583 defer s.Shutdown() 1584 1585 nc := createClientConnSubscribeAndPublish(t, s) 1586 defer nc.Close() 1587 1588 for i := 0; i < 200; i++ { 1589 nc.Subscribe(fmt.Sprintf("foo.%d", i), func(m *nats.Msg) {}) 1590 } 1591 nc.Flush() 1592 1593 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1594 for mode := 0; mode < 2; mode++ { 1595 sl := pollSubsz(t, s, mode, url+"subsz?subs=1&offset=10&limit=100", &SubszOptions{Subscriptions: true, Offset: 10, Limit: 100}) 1596 if sl.NumSubs != 200 { 1597 t.Fatalf("Expected NumSubs of 200, got %d\n", sl.NumSubs) 1598 } 1599 if sl.Total != 100 { 1600 t.Fatalf("Expected Total of 100, got %d\n", sl.Total) 1601 } 1602 if sl.Offset != 10 { 1603 t.Fatalf("Expected Offset of 10, got %d\n", sl.Offset) 1604 } 1605 if sl.Limit != 100 { 1606 t.Fatalf("Expected Total of 100, got %d\n", sl.Limit) 1607 } 1608 if len(sl.Subs) != 100 { 1609 t.Fatalf("Expected subscription details for 100 subs, got %d\n", len(sl.Subs)) 1610 } 1611 } 1612 } 1613 1614 func TestSubszTestPubSubject(t *testing.T) { 1615 s := runMonitorServer() 1616 defer s.Shutdown() 1617 1618 nc := createClientConnSubscribeAndPublish(t, s) 1619 defer nc.Close() 1620 1621 nc.Subscribe("foo.*", func(m *nats.Msg) {}) 1622 nc.Subscribe("foo.bar", func(m *nats.Msg) {}) 1623 nc.Subscribe("foo.foo", func(m *nats.Msg) {}) 1624 nc.Flush() 1625 1626 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1627 for mode := 0; mode < 2; mode++ { 1628 sl := pollSubsz(t, s, mode, url+"subsz?subs=1&test=foo.foo", &SubszOptions{Subscriptions: true, Test: "foo.foo"}) 1629 if sl.Total != 2 { 1630 t.Fatalf("Expected Total of 2 match, got %d\n", sl.Total) 1631 } 1632 if len(sl.Subs) != 2 { 1633 t.Fatalf("Expected subscription details for 2 matching subs, got %d\n", len(sl.Subs)) 1634 } 1635 sl = pollSubsz(t, s, mode, url+"subsz?subs=1&test=foo", &SubszOptions{Subscriptions: true, Test: "foo"}) 1636 if len(sl.Subs) != 0 { 1637 t.Fatalf("Expected no matching subs, got %d\n", len(sl.Subs)) 1638 } 1639 } 1640 // Make sure we get an error with invalid test subject. 1641 testUrl := url + "subsz?subs=1&" 1642 readBodyEx(t, testUrl+"test=*", http.StatusBadRequest, textPlain) 1643 readBodyEx(t, testUrl+"test=foo.*", http.StatusBadRequest, textPlain) 1644 readBodyEx(t, testUrl+"test=foo.>", http.StatusBadRequest, textPlain) 1645 readBodyEx(t, testUrl+"test=foo..bar", http.StatusBadRequest, textPlain) 1646 } 1647 1648 func TestSubszMultiAccount(t *testing.T) { 1649 s := runMonitorServerWithAccounts() 1650 defer s.Shutdown() 1651 1652 ncA := createClientConnWithUserSubscribeAndPublish(t, s, "a", "a") 1653 defer ncA.Close() 1654 1655 ncA.Subscribe("foo.*", func(m *nats.Msg) {}) 1656 ncA.Subscribe("foo.bar", func(m *nats.Msg) {}) 1657 ncA.Subscribe("foo.foo", func(m *nats.Msg) {}) 1658 1659 ncA.Publish("foo.bar", []byte("Hello")) 1660 ncA.Publish("foo.baz", []byte("Hello")) 1661 ncA.Publish("foo.foo", []byte("Hello")) 1662 1663 ncA.Flush() 1664 1665 ncB := createClientConnWithUserSubscribeAndPublish(t, s, "b", "b") 1666 defer ncB.Close() 1667 1668 ncB.Subscribe("foo.*", func(m *nats.Msg) {}) 1669 ncB.Subscribe("foo.bar", func(m *nats.Msg) {}) 1670 ncB.Subscribe("foo.foo", func(m *nats.Msg) {}) 1671 1672 ncB.Publish("foo.bar", []byte("Hello")) 1673 ncB.Publish("foo.baz", []byte("Hello")) 1674 ncB.Publish("foo.foo", []byte("Hello")) 1675 1676 ncB.Flush() 1677 1678 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1679 1680 for mode := 0; mode < 2; mode++ { 1681 sl := pollSubsz(t, s, mode, url+"subsz?subs=1", &SubszOptions{Subscriptions: true}) 1682 if sl.NumSubs != 6 { 1683 t.Fatalf("Expected NumSubs of 6, got %d\n", sl.NumSubs) 1684 } 1685 if sl.Total != 6 { 1686 t.Fatalf("Expected Total of 6, got %d\n", sl.Total) 1687 } 1688 if len(sl.Subs) != 6 { 1689 t.Fatalf("Expected subscription details for 6 subs, got %d\n", len(sl.Subs)) 1690 } 1691 for _, sd := range sl.Subs { 1692 if sd.Account != "A" && sd.Account != "B" { 1693 t.Fatalf("Expected account information to be present and be 'A' or 'B', got %q", sd.Account) 1694 } 1695 } 1696 1697 // Now make sure we can filter on account. 1698 sl = pollSubsz(t, s, mode, url+"subsz?subs=1&acc=A", &SubszOptions{Account: "A", Subscriptions: true}) 1699 if sl.NumSubs != 3 { 1700 t.Fatalf("Expected NumSubs of 3, got %d\n", sl.NumSubs) 1701 } 1702 if sl.Total != 3 { 1703 t.Fatalf("Expected Total of 6, got %d\n", sl.Total) 1704 } 1705 if len(sl.Subs) != 3 { 1706 t.Fatalf("Expected subscription details for 6 subs, got %d\n", len(sl.Subs)) 1707 } 1708 for _, sd := range sl.Subs { 1709 if sd.Account != "A" { 1710 t.Fatalf("Expected account information to be present and be 'A', got %q", sd.Account) 1711 } 1712 } 1713 } 1714 } 1715 1716 func TestSubszMultiAccountWithOffsetAndLimit(t *testing.T) { 1717 s := runMonitorServer() 1718 defer s.Shutdown() 1719 1720 ncA := createClientConnWithUserSubscribeAndPublish(t, s, "a", "a") 1721 defer ncA.Close() 1722 1723 for i := 0; i < 200; i++ { 1724 ncA.Subscribe(fmt.Sprintf("foo.%d", i), func(m *nats.Msg) {}) 1725 } 1726 ncA.Flush() 1727 1728 ncB := createClientConnWithUserSubscribeAndPublish(t, s, "b", "b") 1729 defer ncB.Close() 1730 1731 for i := 0; i < 200; i++ { 1732 ncB.Subscribe(fmt.Sprintf("foo.%d", i), func(m *nats.Msg) {}) 1733 } 1734 ncB.Flush() 1735 1736 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1737 for mode := 0; mode < 2; mode++ { 1738 sl := pollSubsz(t, s, mode, url+"subsz?subs=1&offset=10&limit=100", &SubszOptions{Subscriptions: true, Offset: 10, Limit: 100}) 1739 if sl.NumSubs != 400 { 1740 t.Fatalf("Expected NumSubs of 200, got %d\n", sl.NumSubs) 1741 } 1742 if sl.Total != 100 { 1743 t.Fatalf("Expected Total of 100, got %d\n", sl.Total) 1744 } 1745 if sl.Offset != 10 { 1746 t.Fatalf("Expected Offset of 10, got %d\n", sl.Offset) 1747 } 1748 if sl.Limit != 100 { 1749 t.Fatalf("Expected Total of 100, got %d\n", sl.Limit) 1750 } 1751 if len(sl.Subs) != 100 { 1752 t.Fatalf("Expected subscription details for 100 subs, got %d\n", len(sl.Subs)) 1753 } 1754 } 1755 } 1756 1757 // Tests handle root 1758 func TestHandleRoot(t *testing.T) { 1759 s := runMonitorServer() 1760 defer s.Shutdown() 1761 1762 nc := createClientConnSubscribeAndPublish(t, s) 1763 defer nc.Close() 1764 1765 resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port)) 1766 if err != nil { 1767 t.Fatalf("Expected no error: Got %v\n", err) 1768 } 1769 defer resp.Body.Close() 1770 if resp.StatusCode != http.StatusOK { 1771 t.Fatalf("Expected a %d response, got %d\n", http.StatusOK, resp.StatusCode) 1772 } 1773 1774 body, err := io.ReadAll(resp.Body) 1775 if err != nil { 1776 t.Fatalf("Expected no error reading body: Got %v\n", err) 1777 } 1778 for _, b := range body { 1779 if b > unicode.MaxASCII { 1780 t.Fatalf("Expected body to contain only ASCII characters, but got %v\n", b) 1781 } 1782 } 1783 1784 ct := resp.Header.Get("Content-Type") 1785 if !strings.Contains(ct, "text/html") { 1786 t.Fatalf("Expected text/html response, got %s\n", ct) 1787 } 1788 } 1789 1790 func TestConnzWithNamedClient(t *testing.T) { 1791 s := runMonitorServer() 1792 defer s.Shutdown() 1793 1794 clientName := "test-client" 1795 nc := createClientConnWithName(t, clientName, s) 1796 defer nc.Close() 1797 1798 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1799 for mode := 0; mode < 2; mode++ { 1800 // Confirm server is exposing client name in monitoring endpoint. 1801 c := pollConz(t, s, mode, url+"connz", nil) 1802 got := len(c.Conns) 1803 expected := 1 1804 if got != expected { 1805 t.Fatalf("Expected %d connection in array, got %d\n", expected, got) 1806 } 1807 1808 conn := c.Conns[0] 1809 if conn.Name != clientName { 1810 t.Fatalf("Expected client to have name %q. got %q", clientName, conn.Name) 1811 } 1812 } 1813 } 1814 1815 func TestConnzWithStateForClosedConns(t *testing.T) { 1816 s := runMonitorServer() 1817 defer s.Shutdown() 1818 1819 numEach := 10 1820 // Create 10 closed, and 10 to leave open. 1821 for i := 0; i < numEach; i++ { 1822 nc := createClientConnSubscribeAndPublish(t, s) 1823 nc.Subscribe("hello.closed.conns", func(m *nats.Msg) {}) 1824 nc.Close() 1825 nc = createClientConnSubscribeAndPublish(t, s) 1826 nc.Subscribe("hello.open.conns", func(m *nats.Msg) {}) 1827 defer nc.Close() 1828 } 1829 1830 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 1831 1832 for mode := 0; mode < 2; mode++ { 1833 checkFor(t, 2*time.Second, 10*time.Millisecond, func() error { 1834 // Look at all open 1835 c := pollConz(t, s, mode, url+"connz?state=open", &ConnzOptions{State: ConnOpen}) 1836 if lc := len(c.Conns); lc != numEach { 1837 return fmt.Errorf("Expected %d connections in array, got %d", numEach, lc) 1838 } 1839 // Look at all closed 1840 c = pollConz(t, s, mode, url+"connz?state=closed", &ConnzOptions{State: ConnClosed}) 1841 if lc := len(c.Conns); lc != numEach { 1842 return fmt.Errorf("Expected %d connections in array, got %d", numEach, lc) 1843 } 1844 // Look at all 1845 c = pollConz(t, s, mode, url+"connz?state=ALL", &ConnzOptions{State: ConnAll}) 1846 if lc := len(c.Conns); lc != numEach*2 { 1847 return fmt.Errorf("Expected %d connections in array, got %d", 2*numEach, lc) 1848 } 1849 // Look at CID #1, which is in closed. 1850 c = pollConz(t, s, mode, url+"connz?cid=1&state=open", &ConnzOptions{CID: 1, State: ConnOpen}) 1851 if lc := len(c.Conns); lc != 0 { 1852 return fmt.Errorf("Expected no connections in open array, got %d", lc) 1853 } 1854 c = pollConz(t, s, mode, url+"connz?cid=1&state=closed", &ConnzOptions{CID: 1, State: ConnClosed}) 1855 if lc := len(c.Conns); lc != 1 { 1856 return fmt.Errorf("Expected a connection in closed array, got %d", lc) 1857 } 1858 c = pollConz(t, s, mode, url+"connz?cid=1&state=ALL", &ConnzOptions{CID: 1, State: ConnAll}) 1859 if lc := len(c.Conns); lc != 1 { 1860 return fmt.Errorf("Expected a connection in closed array, got %d", lc) 1861 } 1862 c = pollConz(t, s, mode, url+"connz?cid=1&state=closed&subs=true", 1863 &ConnzOptions{CID: 1, State: ConnClosed, Subscriptions: true}) 1864 if lc := len(c.Conns); lc != 1 { 1865 return fmt.Errorf("Expected a connection in closed array, got %d", lc) 1866 } 1867 ci := c.Conns[0] 1868 if ci.NumSubs != 1 { 1869 return fmt.Errorf("Expected NumSubs to be 1, got %d", ci.NumSubs) 1870 } 1871 if len(ci.Subs) != 1 { 1872 return fmt.Errorf("Expected len(ci.Subs) to be 1 also, got %d", len(ci.Subs)) 1873 } 1874 // Now ask for same thing without subs and make sure they are not returned. 1875 c = pollConz(t, s, mode, url+"connz?cid=1&state=closed&subs=false", 1876 &ConnzOptions{CID: 1, State: ConnClosed, Subscriptions: false}) 1877 if lc := len(c.Conns); lc != 1 { 1878 return fmt.Errorf("Expected a connection in closed array, got %d", lc) 1879 } 1880 ci = c.Conns[0] 1881 if ci.NumSubs != 1 { 1882 return fmt.Errorf("Expected NumSubs to be 1, got %d", ci.NumSubs) 1883 } 1884 if len(ci.Subs) != 0 { 1885 return fmt.Errorf("Expected len(ci.Subs) to be 0 since subs=false, got %d", len(ci.Subs)) 1886 } 1887 1888 // CID #2 is in open 1889 c = pollConz(t, s, mode, url+"connz?cid=2&state=open", &ConnzOptions{CID: 2, State: ConnOpen}) 1890 if lc := len(c.Conns); lc != 1 { 1891 return fmt.Errorf("Expected a connection in open array, got %d", lc) 1892 } 1893 c = pollConz(t, s, mode, url+"connz?cid=2&state=closed", &ConnzOptions{CID: 2, State: ConnClosed}) 1894 if lc := len(c.Conns); lc != 0 { 1895 return fmt.Errorf("Expected no connections in closed array, got %d", lc) 1896 } 1897 return nil 1898 }) 1899 } 1900 } 1901 1902 // Make sure options for ConnInfo like subs=1, authuser, etc do not cause a race. 1903 func TestConnzClosedConnsRace(t *testing.T) { 1904 s := runMonitorServer() 1905 defer s.Shutdown() 1906 1907 // Create 100 closed connections. 1908 for i := 0; i < 100; i++ { 1909 nc := createClientConnSubscribeAndPublish(t, s) 1910 nc.Close() 1911 } 1912 1913 urlWithoutSubs := fmt.Sprintf("http://127.0.0.1:%d/connz?state=closed", s.MonitorAddr().Port) 1914 urlWithSubs := urlWithoutSubs + "&subs=true" 1915 1916 checkClosedConns(t, s, 100, 2*time.Second) 1917 1918 wg := &sync.WaitGroup{} 1919 1920 fn := func(url string) { 1921 deadline := time.Now().Add(1 * time.Second) 1922 for time.Now().Before(deadline) { 1923 c := pollConz(t, s, 0, url, nil) 1924 if len(c.Conns) != 100 { 1925 t.Errorf("Incorrect Results: %+v\n", c) 1926 } 1927 } 1928 wg.Done() 1929 } 1930 1931 wg.Add(2) 1932 go fn(urlWithSubs) 1933 go fn(urlWithoutSubs) 1934 wg.Wait() 1935 } 1936 1937 // Make sure a bad client that is disconnected right away has proper values. 1938 func TestConnzClosedConnsBadClient(t *testing.T) { 1939 s := runMonitorServer() 1940 defer s.Shutdown() 1941 1942 opts := s.getOpts() 1943 1944 rc, err := net.Dial("tcp", fmt.Sprintf("%s:%d", opts.Host, opts.Port)) 1945 if err != nil { 1946 t.Fatalf("Error on dial: %v", err) 1947 } 1948 rc.Close() 1949 1950 checkClosedConns(t, s, 1, 2*time.Second) 1951 1952 c := pollConz(t, s, 1, "", &ConnzOptions{State: ConnClosed}) 1953 if len(c.Conns) != 1 { 1954 t.Errorf("Incorrect Results: %+v\n", c) 1955 } 1956 ci := c.Conns[0] 1957 1958 uptime := ci.Stop.Sub(ci.Start) 1959 idle, err := time.ParseDuration(ci.Idle) 1960 if err != nil { 1961 t.Fatalf("Could not parse Idle: %v\n", err) 1962 } 1963 if idle > uptime { 1964 t.Fatalf("Idle can't be larger then uptime, %v vs %v\n", idle, uptime) 1965 } 1966 if ci.LastActivity.IsZero() { 1967 t.Fatalf("LastActivity should not be Zero\n") 1968 } 1969 } 1970 1971 // Make sure a bad client that tries to connect plain to TLS has proper values. 1972 func TestConnzClosedConnsBadTLSClient(t *testing.T) { 1973 resetPreviousHTTPConnections() 1974 1975 tc := &TLSConfigOpts{} 1976 tc.CertFile = "configs/certs/server.pem" 1977 tc.KeyFile = "configs/certs/key.pem" 1978 1979 var err error 1980 opts := DefaultMonitorOptions() 1981 opts.NoSystemAccount = true 1982 opts.TLSTimeout = 1.5 // 1.5 seconds 1983 opts.TLSConfig, err = GenTLSConfig(tc) 1984 if err != nil { 1985 t.Fatalf("Error creating TSL config: %v", err) 1986 } 1987 1988 s := RunServer(opts) 1989 defer s.Shutdown() 1990 1991 opts = s.getOpts() 1992 1993 rc, err := net.Dial("tcp", fmt.Sprintf("%s:%d", opts.Host, opts.Port)) 1994 if err != nil { 1995 t.Fatalf("Error on dial: %v", err) 1996 } 1997 rc.Write([]byte("CONNECT {}\r\n")) 1998 rc.Close() 1999 2000 checkClosedConns(t, s, 1, 2*time.Second) 2001 2002 c := pollConz(t, s, 1, "", &ConnzOptions{State: ConnClosed}) 2003 if len(c.Conns) != 1 { 2004 t.Errorf("Incorrect Results: %+v\n", c) 2005 } 2006 ci := c.Conns[0] 2007 2008 uptime := ci.Stop.Sub(ci.Start) 2009 idle, err := time.ParseDuration(ci.Idle) 2010 if err != nil { 2011 t.Fatalf("Could not parse Idle: %v\n", err) 2012 } 2013 if idle > uptime { 2014 t.Fatalf("Idle can't be larger then uptime, %v vs %v\n", idle, uptime) 2015 } 2016 if ci.LastActivity.IsZero() { 2017 t.Fatalf("LastActivity should not be Zero\n") 2018 } 2019 } 2020 2021 // Create a connection to test ConnInfo 2022 func createClientConnWithUserSubscribeAndPublish(t *testing.T, s *Server, user, pwd string) *nats.Conn { 2023 natsURL := "" 2024 if user == "" { 2025 natsURL = fmt.Sprintf("nats://127.0.0.1:%d", s.Addr().(*net.TCPAddr).Port) 2026 } else { 2027 natsURL = fmt.Sprintf("nats://%s:%s@127.0.0.1:%d", user, pwd, s.Addr().(*net.TCPAddr).Port) 2028 } 2029 client := nats.DefaultOptions 2030 client.Servers = []string{natsURL} 2031 nc, err := client.Connect() 2032 if err != nil { 2033 t.Fatalf("Error creating client: %v to: %s\n", err, natsURL) 2034 } 2035 2036 ch := make(chan bool) 2037 inbox := nats.NewInbox() 2038 sub, err := nc.Subscribe(inbox, func(m *nats.Msg) { ch <- true }) 2039 if err != nil { 2040 t.Fatalf("Error subscribing to `%s`: %v\n", inbox, err) 2041 } 2042 nc.Publish(inbox, []byte("Hello")) 2043 // Wait for message 2044 <-ch 2045 sub.Unsubscribe() 2046 close(ch) 2047 nc.Flush() 2048 return nc 2049 } 2050 2051 func createClientConnSubscribeAndPublish(t *testing.T, s *Server) *nats.Conn { 2052 return createClientConnWithUserSubscribeAndPublish(t, s, "", "") 2053 } 2054 2055 func createClientConnWithName(t *testing.T, name string, s *Server) *nats.Conn { 2056 natsURI := fmt.Sprintf("nats://127.0.0.1:%d", s.Addr().(*net.TCPAddr).Port) 2057 2058 client := nats.DefaultOptions 2059 client.Servers = []string{natsURI} 2060 client.Name = name 2061 nc, err := client.Connect() 2062 if err != nil { 2063 t.Fatalf("Error creating client: %v\n", err) 2064 } 2065 return nc 2066 } 2067 2068 func TestStacksz(t *testing.T) { 2069 s := runMonitorServer() 2070 defer s.Shutdown() 2071 2072 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 2073 body := readBody(t, url+"stacksz") 2074 // Check content 2075 str := string(body) 2076 if !strings.Contains(str, "HandleStacksz") { 2077 t.Fatalf("Result does not seem to contain server's stacks:\n%v", str) 2078 } 2079 } 2080 2081 func TestConcurrentMonitoring(t *testing.T) { 2082 s := runMonitorServer() 2083 defer s.Shutdown() 2084 2085 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 2086 // Get some endpoints. Make sure we have at least varz, 2087 // and the more the merrier. 2088 endpoints := []string{"varz", "varz", "varz", "connz", "connz", "subsz", "subsz", "routez", "routez"} 2089 wg := &sync.WaitGroup{} 2090 wg.Add(len(endpoints)) 2091 ech := make(chan string, len(endpoints)) 2092 2093 for _, e := range endpoints { 2094 go func(endpoint string) { 2095 defer wg.Done() 2096 for i := 0; i < 50; i++ { 2097 resp, err := http.Get(url + endpoint) 2098 if err != nil { 2099 ech <- fmt.Sprintf("Expected no error: Got %v\n", err) 2100 return 2101 } 2102 defer resp.Body.Close() 2103 if resp.StatusCode != http.StatusOK { 2104 ech <- fmt.Sprintf("Expected a %v response, got %d\n", http.StatusOK, resp.StatusCode) 2105 return 2106 } 2107 ct := resp.Header.Get("Content-Type") 2108 if ct != "application/json" { 2109 ech <- fmt.Sprintf("Expected application/json content-type, got %s\n", ct) 2110 return 2111 } 2112 if _, err := io.ReadAll(resp.Body); err != nil { 2113 ech <- fmt.Sprintf("Got an error reading the body: %v\n", err) 2114 return 2115 } 2116 resp.Body.Close() 2117 } 2118 }(e) 2119 } 2120 wg.Wait() 2121 // Check for any errors 2122 select { 2123 case err := <-ech: 2124 t.Fatal(err) 2125 default: 2126 } 2127 } 2128 2129 func TestMonitorHandler(t *testing.T) { 2130 s := runMonitorServer() 2131 defer s.Shutdown() 2132 handler := s.HTTPHandler() 2133 if handler == nil { 2134 t.Fatal("HTTP Handler should be set") 2135 } 2136 s.Shutdown() 2137 handler = s.HTTPHandler() 2138 if handler != nil { 2139 t.Fatal("HTTP Handler should be nil") 2140 } 2141 } 2142 2143 func TestMonitorRoutezRace(t *testing.T) { 2144 resetPreviousHTTPConnections() 2145 srvAOpts := DefaultMonitorOptions() 2146 srvAOpts.NoSystemAccount = true 2147 srvAOpts.Cluster.Name = "B" 2148 srvAOpts.Cluster.Port = -1 2149 srvA := RunServer(srvAOpts) 2150 defer srvA.Shutdown() 2151 2152 srvBOpts := nextServerOpts(srvAOpts) 2153 srvBOpts.Routes = RoutesFromStr(fmt.Sprintf("nats://127.0.0.1:%d", srvA.ClusterAddr().Port)) 2154 2155 doneCh := make(chan struct{}) 2156 go func() { 2157 defer func() { 2158 doneCh <- struct{}{} 2159 }() 2160 for i := 0; i < 10; i++ { 2161 time.Sleep(10 * time.Millisecond) 2162 // Reset ports 2163 srvBOpts.Port = -1 2164 srvBOpts.Cluster.Port = -1 2165 srvB := RunServer(srvBOpts) 2166 time.Sleep(20 * time.Millisecond) 2167 srvB.Shutdown() 2168 } 2169 }() 2170 done := false 2171 for !done { 2172 if _, err := srvA.Routez(nil); err != nil { 2173 time.Sleep(10 * time.Millisecond) 2174 } 2175 select { 2176 case <-doneCh: 2177 done = true 2178 default: 2179 } 2180 } 2181 } 2182 2183 func TestConnzTLSInHandshake(t *testing.T) { 2184 resetPreviousHTTPConnections() 2185 2186 tc := &TLSConfigOpts{} 2187 tc.CertFile = "configs/certs/server.pem" 2188 tc.KeyFile = "configs/certs/key.pem" 2189 2190 var err error 2191 opts := DefaultMonitorOptions() 2192 opts.NoSystemAccount = true 2193 opts.TLSTimeout = 1.5 // 1.5 seconds 2194 opts.TLSConfig, err = GenTLSConfig(tc) 2195 if err != nil { 2196 t.Fatalf("Error creating TSL config: %v", err) 2197 } 2198 2199 s := RunServer(opts) 2200 defer s.Shutdown() 2201 2202 // Create bare TCP connection to delay client TLS handshake 2203 c, err := net.Dial("tcp", fmt.Sprintf("%s:%d", opts.Host, opts.Port)) 2204 if err != nil { 2205 t.Fatalf("Error on dial: %v", err) 2206 } 2207 defer c.Close() 2208 2209 // Wait for the connection to be registered 2210 checkClientsCount(t, s, 1) 2211 2212 start := time.Now() 2213 endpoint := fmt.Sprintf("http://%s:%d/connz", opts.HTTPHost, s.MonitorAddr().Port) 2214 for mode := 0; mode < 2; mode++ { 2215 connz := pollConz(t, s, mode, endpoint, nil) 2216 duration := time.Since(start) 2217 if duration >= 1500*time.Millisecond { 2218 t.Fatalf("Looks like connz blocked on handshake, took %v", duration) 2219 } 2220 if len(connz.Conns) != 1 { 2221 t.Fatalf("Expected 1 conn, got %v", len(connz.Conns)) 2222 } 2223 conn := connz.Conns[0] 2224 // TLS fields should be not set 2225 if conn.TLSVersion != "" || conn.TLSCipher != "" { 2226 t.Fatalf("Expected TLS fields to not be set, got version:%v cipher:%v", conn.TLSVersion, conn.TLSCipher) 2227 } 2228 } 2229 } 2230 2231 func TestConnzTLSCfg(t *testing.T) { 2232 resetPreviousHTTPConnections() 2233 2234 tc := &TLSConfigOpts{} 2235 tc.CertFile = "configs/certs/server.pem" 2236 tc.KeyFile = "configs/certs/key.pem" 2237 2238 var err error 2239 opts := DefaultMonitorOptions() 2240 opts.NoSystemAccount = true 2241 opts.TLSTimeout = 1.5 // 1.5 seconds 2242 opts.TLSConfig, err = GenTLSConfig(tc) 2243 require_NoError(t, err) 2244 opts.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert 2245 opts.Gateway.TLSConfig, err = GenTLSConfig(tc) 2246 require_NoError(t, err) 2247 opts.Gateway.TLSTimeout = 1.5 2248 opts.LeafNode.TLSConfig, err = GenTLSConfig(tc) 2249 require_NoError(t, err) 2250 opts.LeafNode.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert 2251 opts.LeafNode.TLSTimeout = 1.5 2252 opts.Cluster.TLSConfig, err = GenTLSConfig(tc) 2253 require_NoError(t, err) 2254 opts.Cluster.TLSTimeout = 1.5 2255 2256 s := RunServer(opts) 2257 defer s.Shutdown() 2258 2259 check := func(verify, required bool, timeout float64) { 2260 t.Helper() 2261 if !verify { 2262 t.Fatalf("Expected tls_verify to be true") 2263 } 2264 if !required { 2265 t.Fatalf("Expected tls_required to be true") 2266 } 2267 if timeout != 1.5 { 2268 t.Fatalf("Expected tls_timeout to be 1.5") 2269 } 2270 } 2271 2272 start := time.Now() 2273 endpoint := fmt.Sprintf("http://%s:%d/varz", opts.HTTPHost, s.MonitorAddr().Port) 2274 for mode := 0; mode < 2; mode++ { 2275 varz := pollVarz(t, s, mode, endpoint, nil) 2276 duration := time.Since(start) 2277 if duration >= 1500*time.Millisecond { 2278 t.Fatalf("Looks like varz blocked on handshake, took %v", duration) 2279 } 2280 check(varz.TLSVerify, varz.TLSRequired, varz.TLSTimeout) 2281 check(varz.Cluster.TLSVerify, varz.Cluster.TLSRequired, varz.Cluster.TLSTimeout) 2282 check(varz.Gateway.TLSVerify, varz.Gateway.TLSRequired, varz.Gateway.TLSTimeout) 2283 check(varz.LeafNode.TLSVerify, varz.LeafNode.TLSRequired, varz.LeafNode.TLSTimeout) 2284 } 2285 } 2286 2287 func TestConnzTLSPeerCerts(t *testing.T) { 2288 resetPreviousHTTPConnections() 2289 2290 tc := &TLSConfigOpts{} 2291 tc.CertFile = "../test/configs/certs/server-cert.pem" 2292 tc.KeyFile = "../test/configs/certs/server-key.pem" 2293 tc.CaFile = "../test/configs/certs/ca.pem" 2294 tc.Verify = true 2295 tc.Timeout = 2.0 2296 2297 var err error 2298 opts := DefaultMonitorOptions() 2299 opts.TLSConfig, err = GenTLSConfig(tc) 2300 require_NoError(t, err) 2301 2302 s := RunServer(opts) 2303 defer s.Shutdown() 2304 2305 nc := natsConnect(t, s.ClientURL(), 2306 nats.ClientCert("../test/configs/certs/client-cert.pem", "../test/configs/certs/client-key.pem"), 2307 nats.RootCAs("../test/configs/certs/ca.pem")) 2308 defer nc.Close() 2309 2310 endpoint := fmt.Sprintf("http://%s:%d/connz", opts.HTTPHost, s.MonitorAddr().Port) 2311 for mode := 0; mode < 2; mode++ { 2312 // Without "auth" option, we should not get the details 2313 connz := pollConz(t, s, mode, endpoint, nil) 2314 require_True(t, len(connz.Conns) == 1) 2315 c := connz.Conns[0] 2316 if c.TLSPeerCerts != nil { 2317 t.Fatalf("Did not expect TLSPeerCerts when auth is not specified: %+v", c.TLSPeerCerts) 2318 } 2319 // Now specify "auth" option 2320 connz = pollConz(t, s, mode, endpoint+"?auth=1", &ConnzOptions{Username: true}) 2321 require_True(t, len(connz.Conns) == 1) 2322 c = connz.Conns[0] 2323 if c.TLSPeerCerts == nil { 2324 t.Fatal("Expected TLSPeerCerts to be set, was not") 2325 } else if len(c.TLSPeerCerts) != 1 { 2326 t.Fatalf("Unexpected peer certificates: %+v", c.TLSPeerCerts) 2327 } else { 2328 for _, d := range c.TLSPeerCerts { 2329 if d.Subject != "CN=localhost,OU=nats.io,O=Synadia,ST=California,C=US" { 2330 t.Fatalf("Unexpected subject: %s", d.Subject) 2331 } 2332 if len(d.SubjectPKISha256) != 64 { 2333 t.Fatalf("Unexpected spki_sha256: %s", d.SubjectPKISha256) 2334 } 2335 if len(d.CertSha256) != 64 { 2336 t.Fatalf("Unexpected cert_sha256: %s", d.CertSha256) 2337 } 2338 } 2339 } 2340 } 2341 } 2342 2343 func TestServerIDs(t *testing.T) { 2344 s := runMonitorServer() 2345 defer s.Shutdown() 2346 2347 murl := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 2348 2349 for mode := 0; mode < 2; mode++ { 2350 v := pollVarz(t, s, mode, murl+"varz", nil) 2351 if v.ID == _EMPTY_ { 2352 t.Fatal("Varz ID is empty") 2353 } 2354 c := pollConz(t, s, mode, murl+"connz", nil) 2355 if c.ID == _EMPTY_ { 2356 t.Fatal("Connz ID is empty") 2357 } 2358 r := pollRoutez(t, s, mode, murl+"routez", nil) 2359 if r.ID == _EMPTY_ { 2360 t.Fatal("Routez ID is empty") 2361 } 2362 if v.ID != c.ID || v.ID != r.ID { 2363 t.Fatalf("Varz ID [%s] is not equal to Connz ID [%s] or Routez ID [%s]", v.ID, c.ID, r.ID) 2364 } 2365 } 2366 } 2367 2368 func TestHttpStatsNoUpdatedWhenUsingServerFuncs(t *testing.T) { 2369 s := runMonitorServer() 2370 defer s.Shutdown() 2371 2372 for i := 0; i < 10; i++ { 2373 s.Varz(nil) 2374 s.Connz(nil) 2375 s.Routez(nil) 2376 s.Subsz(nil) 2377 } 2378 2379 v, _ := s.Varz(nil) 2380 endpoints := []string{VarzPath, ConnzPath, RoutezPath, SubszPath} 2381 for _, e := range endpoints { 2382 stats := v.HTTPReqStats[e] 2383 if stats != 0 { 2384 t.Fatalf("Expected HTTPReqStats for %q to be 0, got %v", e, stats) 2385 } 2386 } 2387 } 2388 2389 func TestClusterEmptyWhenNotDefined(t *testing.T) { 2390 s := runMonitorServer() 2391 defer s.Shutdown() 2392 2393 body := readBody(t, fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port)) 2394 var v map[string]any 2395 if err := json.Unmarshal(body, &v); err != nil { 2396 t.Fatalf("Got an error unmarshalling the body: %v\n", err) 2397 } 2398 // Cluster can empty, or be defined but that needs to be empty. 2399 c, ok := v["cluster"] 2400 if !ok { 2401 return 2402 } 2403 if len(c.(map[string]any)) != 0 { 2404 t.Fatalf("Expected an empty cluster definition, instead got %+v\n", c) 2405 } 2406 } 2407 2408 func TestRoutezPermissions(t *testing.T) { 2409 resetPreviousHTTPConnections() 2410 opts := DefaultMonitorOptions() 2411 opts.NoSystemAccount = true 2412 opts.Cluster.Name = "A" 2413 opts.Cluster.Host = "127.0.0.1" 2414 opts.Cluster.Port = -1 2415 opts.Cluster.Permissions = &RoutePermissions{ 2416 Import: &SubjectPermission{ 2417 Allow: []string{"foo"}, 2418 }, 2419 Export: &SubjectPermission{ 2420 Allow: []string{"*"}, 2421 Deny: []string{"foo", "nats"}, 2422 }, 2423 } 2424 2425 s1 := RunServer(opts) 2426 defer s1.Shutdown() 2427 2428 opts = DefaultMonitorOptions() 2429 opts.NoSystemAccount = true 2430 opts.ServerName = "monitor_server_2" 2431 opts.Cluster.Host = "127.0.0.1" 2432 opts.Cluster.Name = "A" 2433 opts.Cluster.Port = -1 2434 routeURL, _ := url.Parse(fmt.Sprintf("nats-route://127.0.0.1:%d", s1.ClusterAddr().Port)) 2435 opts.Routes = []*url.URL{routeURL} 2436 opts.HTTPPort = -1 2437 2438 s2 := RunServer(opts) 2439 defer s2.Shutdown() 2440 2441 checkClusterFormed(t, s1, s2) 2442 2443 urls := []string{ 2444 fmt.Sprintf("http://127.0.0.1:%d/routez", s1.MonitorAddr().Port), 2445 fmt.Sprintf("http://127.0.0.1:%d/routez", s2.MonitorAddr().Port), 2446 } 2447 servers := []*Server{s1, s2} 2448 2449 for i, url := range urls { 2450 for mode := 0; mode < 2; mode++ { 2451 rz := pollRoutez(t, servers[i], mode, url, nil) 2452 // For server 1, we expect to see imports and exports 2453 if i == 0 { 2454 if rz.Import == nil || rz.Import.Allow == nil || 2455 len(rz.Import.Allow) != 1 || rz.Import.Allow[0] != "foo" || 2456 rz.Import.Deny != nil { 2457 t.Fatalf("Unexpected Import %v", rz.Import) 2458 } 2459 if rz.Export == nil || rz.Export.Allow == nil || rz.Export.Deny == nil || 2460 len(rz.Export.Allow) != 1 || rz.Export.Allow[0] != "*" || 2461 len(rz.Export.Deny) != 2 || rz.Export.Deny[0] != "foo" || rz.Export.Deny[1] != "nats" { 2462 t.Fatalf("Unexpected Export %v", rz.Export) 2463 } 2464 } else { 2465 // We expect to see NO imports and exports for server B by default. 2466 if rz.Import != nil { 2467 t.Fatal("Routez body should NOT contain \"import\" information.") 2468 } 2469 if rz.Export != nil { 2470 t.Fatal("Routez body should NOT contain \"export\" information.") 2471 } 2472 // We do expect to see them show up for the information we have on Server A though. 2473 if len(rz.Routes) != DEFAULT_ROUTE_POOL_SIZE { 2474 t.Fatalf("Expected route array of %d, got %v\n", DEFAULT_ROUTE_POOL_SIZE, len(rz.Routes)) 2475 } 2476 route := rz.Routes[0] 2477 if route.Import == nil || route.Import.Allow == nil || 2478 len(route.Import.Allow) != 1 || route.Import.Allow[0] != "foo" || 2479 route.Import.Deny != nil { 2480 t.Fatalf("Unexpected Import %v", route.Import) 2481 } 2482 if route.Export == nil || route.Export.Allow == nil || route.Export.Deny == nil || 2483 len(route.Export.Allow) != 1 || route.Export.Allow[0] != "*" || 2484 len(route.Export.Deny) != 2 || route.Export.Deny[0] != "foo" || route.Export.Deny[1] != "nats" { 2485 t.Fatalf("Unexpected Export %v", route.Export) 2486 } 2487 } 2488 } 2489 } 2490 } 2491 2492 // Benchmark our Connz generation. Don't use HTTP here, just measure server endpoint. 2493 func Benchmark_Connz(b *testing.B) { 2494 runtime.MemProfileRate = 0 2495 2496 s := runMonitorServerNoHTTPPort() 2497 defer s.Shutdown() 2498 2499 opts := s.getOpts() 2500 url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) 2501 2502 // Create 250 connections with 100 subs each. 2503 for i := 0; i < 250; i++ { 2504 nc, err := nats.Connect(url) 2505 if err != nil { 2506 b.Fatalf("Error on connection[%d] to %s: %v", i, url, err) 2507 } 2508 for x := 0; x < 100; x++ { 2509 subj := fmt.Sprintf("foo.%d", x) 2510 nc.Subscribe(subj, func(m *nats.Msg) {}) 2511 } 2512 nc.Flush() 2513 defer nc.Close() 2514 } 2515 2516 b.ResetTimer() 2517 runtime.MemProfileRate = 1 2518 2519 copts := &ConnzOptions{Subscriptions: false} 2520 for i := 0; i < b.N; i++ { 2521 _, err := s.Connz(copts) 2522 if err != nil { 2523 b.Fatalf("Error on Connz(): %v", err) 2524 } 2525 } 2526 } 2527 2528 func Benchmark_Varz(b *testing.B) { 2529 runtime.MemProfileRate = 0 2530 2531 s := runMonitorServerNoHTTPPort() 2532 defer s.Shutdown() 2533 2534 b.ResetTimer() 2535 runtime.MemProfileRate = 1 2536 2537 for i := 0; i < b.N; i++ { 2538 _, err := s.Varz(nil) 2539 if err != nil { 2540 b.Fatalf("Error on Connz(): %v", err) 2541 } 2542 } 2543 } 2544 2545 func Benchmark_VarzHttp(b *testing.B) { 2546 runtime.MemProfileRate = 0 2547 2548 s := runMonitorServer() 2549 defer s.Shutdown() 2550 2551 murl := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 2552 2553 b.ResetTimer() 2554 runtime.MemProfileRate = 1 2555 2556 for i := 0; i < b.N; i++ { 2557 v := &Varz{} 2558 resp, err := http.Get(murl) 2559 if err != nil { 2560 b.Fatalf("Expected no error: Got %v\n", err) 2561 } 2562 defer resp.Body.Close() 2563 body, err := io.ReadAll(resp.Body) 2564 if err != nil { 2565 b.Fatalf("Got an error reading the body: %v\n", err) 2566 } 2567 if err := json.Unmarshal(body, v); err != nil { 2568 b.Fatalf("Got an error unmarshalling the body: %v\n", err) 2569 } 2570 resp.Body.Close() 2571 } 2572 } 2573 2574 func TestVarzRaces(t *testing.T) { 2575 s := runMonitorServer() 2576 defer s.Shutdown() 2577 2578 murl := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 2579 done := make(chan struct{}) 2580 wg := sync.WaitGroup{} 2581 wg.Add(1) 2582 go func() { 2583 defer wg.Done() 2584 for { 2585 for i := 0; i < 2; i++ { 2586 v := pollVarz(t, s, i, murl, nil) 2587 // Check the field that we are setting in main thread 2588 // to ensure that we have a copy and there is no 2589 // race with fields set in s.info and s.opts 2590 if v.ID == "abc" || v.MaxConn == -1 { 2591 // We will not get there. Need to have something 2592 // otherwise staticcheck will report empty branch 2593 return 2594 } 2595 2596 select { 2597 case <-done: 2598 return 2599 default: 2600 } 2601 } 2602 } 2603 }() 2604 2605 for i := 0; i < 1000; i++ { 2606 // Simulate a change in server's info and options 2607 // by changing something. 2608 s.mu.Lock() 2609 s.info.ID = fmt.Sprintf("serverid_%d", i) 2610 s.opts.MaxConn = 100 + i 2611 s.mu.Unlock() 2612 time.Sleep(time.Nanosecond) 2613 } 2614 close(done) 2615 wg.Wait() 2616 2617 // Now check that there is no race doing parallel polling 2618 wg.Add(3) 2619 done = make(chan struct{}) 2620 poll := func() { 2621 defer wg.Done() 2622 for { 2623 for mode := 0; mode < 2; mode++ { 2624 pollVarz(t, s, mode, murl, nil) 2625 } 2626 select { 2627 case <-done: 2628 return 2629 default: 2630 } 2631 } 2632 } 2633 for i := 0; i < 3; i++ { 2634 go poll() 2635 } 2636 time.Sleep(500 * time.Millisecond) 2637 close(done) 2638 wg.Wait() 2639 } 2640 2641 func testMonitorStructPresent(t *testing.T, tag string) { 2642 t.Helper() 2643 2644 resetPreviousHTTPConnections() 2645 opts := DefaultMonitorOptions() 2646 opts.NoSystemAccount = true 2647 s := RunServer(opts) 2648 defer s.Shutdown() 2649 2650 varzURL := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 2651 body := readBody(t, varzURL) 2652 if !bytes.Contains(body, []byte(`"`+tag+`": {}`)) { 2653 t.Fatalf("%s should be present and empty, got %s", tag, body) 2654 } 2655 } 2656 2657 func TestMonitorCluster(t *testing.T) { 2658 testMonitorStructPresent(t, "cluster") 2659 2660 resetPreviousHTTPConnections() 2661 opts := DefaultMonitorOptions() 2662 opts.NoSystemAccount = true 2663 opts.Cluster.Name = "A" 2664 opts.Cluster.Port = -1 2665 opts.Cluster.AuthTimeout = 1 2666 opts.Routes = RoutesFromStr("nats://127.0.0.1:1234") 2667 s := RunServer(opts) 2668 defer s.Shutdown() 2669 2670 expected := ClusterOptsVarz{ 2671 "A", 2672 opts.Cluster.Host, 2673 opts.Cluster.Port, 2674 opts.Cluster.AuthTimeout, 2675 []string{"127.0.0.1:1234"}, 2676 opts.Cluster.TLSTimeout, 2677 opts.Cluster.TLSConfig != nil, 2678 opts.Cluster.TLSConfig != nil, 2679 DEFAULT_ROUTE_POOL_SIZE, 2680 } 2681 2682 varzURL := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 2683 for mode := 0; mode < 2; mode++ { 2684 check := func(t *testing.T, v *Varz) { 2685 t.Helper() 2686 if !reflect.DeepEqual(v.Cluster, expected) { 2687 t.Fatalf("mode=%v - expected %+v, got %+v", mode, expected, v.Cluster) 2688 } 2689 } 2690 v := pollVarz(t, s, mode, varzURL, nil) 2691 check(t, v) 2692 2693 // Having this here to make sure that if fields are added in ClusterOptsVarz, 2694 // we make sure to update this test (compiler will report an error if we don't) 2695 _ = ClusterOptsVarz{"", "", 0, 0, nil, 2, false, false, 0} 2696 2697 // Alter the fields to make sure that we have a proper deep copy 2698 // of what may be stored in the server. Anything we change here 2699 // should not affect the next returned value. 2700 v.Cluster.Name = "wrong" 2701 v.Cluster.Host = "wrong" 2702 v.Cluster.Port = 0 2703 v.Cluster.AuthTimeout = 0 2704 v.Cluster.URLs = []string{"wrong"} 2705 v = pollVarz(t, s, mode, varzURL, nil) 2706 check(t, v) 2707 } 2708 } 2709 2710 func TestMonitorClusterURLs(t *testing.T) { 2711 resetPreviousHTTPConnections() 2712 2713 o2 := DefaultOptions() 2714 o2.Cluster.Host = "127.0.0.1" 2715 o2.Cluster.Name = "A" 2716 2717 s2 := RunServer(o2) 2718 defer s2.Shutdown() 2719 2720 s2ClusterHostPort := fmt.Sprintf("127.0.0.1:%d", s2.ClusterAddr().Port) 2721 2722 template := ` 2723 port: -1 2724 http: -1 2725 cluster: { 2726 name: "A" 2727 port: -1 2728 routes [ 2729 %s 2730 %s 2731 ] 2732 } 2733 ` 2734 conf := createConfFile(t, []byte(fmt.Sprintf(template, "nats://"+s2ClusterHostPort, ""))) 2735 s1, _ := RunServerWithConfig(conf) 2736 defer s1.Shutdown() 2737 2738 checkClusterFormed(t, s1, s2) 2739 2740 // Check /varz cluster{} to see the URLs from s1 to s2 2741 varzURL := fmt.Sprintf("http://127.0.0.1:%d/varz", s1.MonitorAddr().Port) 2742 for mode := 0; mode < 2; mode++ { 2743 v := pollVarz(t, s1, mode, varzURL, nil) 2744 if n := len(v.Cluster.URLs); n != 1 { 2745 t.Fatalf("mode=%v - Expected 1 URL, got %v", mode, n) 2746 } 2747 if v.Cluster.URLs[0] != s2ClusterHostPort { 2748 t.Fatalf("mode=%v - Expected url %q, got %q", mode, s2ClusterHostPort, v.Cluster.URLs[0]) 2749 } 2750 } 2751 2752 otherClusterHostPort := "127.0.0.1:1234" 2753 // Now update the config and add a route 2754 changeCurrentConfigContentWithNewContent(t, conf, []byte(fmt.Sprintf(template, "nats://"+s2ClusterHostPort, "nats://"+otherClusterHostPort))) 2755 2756 if err := s1.Reload(); err != nil { 2757 t.Fatalf("Error on reload: %v", err) 2758 } 2759 2760 // Verify cluster still ok 2761 checkClusterFormed(t, s1, s2) 2762 2763 // Now verify that s1 reports in /varz the new URL 2764 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 2765 for mode := 0; mode < 2; mode++ { 2766 v := pollVarz(t, s1, mode, varzURL, nil) 2767 if n := len(v.Cluster.URLs); n != 2 { 2768 t.Fatalf("mode=%v - Expected 2 URL, got %v", mode, n) 2769 } 2770 gotS2 := false 2771 gotOther := false 2772 for _, u := range v.Cluster.URLs { 2773 if u == s2ClusterHostPort { 2774 gotS2 = true 2775 } else if u == otherClusterHostPort { 2776 gotOther = true 2777 } else { 2778 t.Fatalf("mode=%v - Incorrect url: %q", mode, u) 2779 } 2780 } 2781 if !gotS2 { 2782 t.Fatalf("mode=%v - Did not get cluster URL for s2", mode) 2783 } 2784 if !gotOther { 2785 t.Fatalf("mode=%v - Did not get the new cluster URL", mode) 2786 } 2787 } 2788 return nil 2789 }) 2790 2791 // Remove all routes from config 2792 changeCurrentConfigContentWithNewContent(t, conf, []byte(fmt.Sprintf(template, "", ""))) 2793 2794 if err := s1.Reload(); err != nil { 2795 t.Fatalf("Error on reload: %v", err) 2796 } 2797 2798 // Now verify that s1 reports no ULRs in /varz 2799 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 2800 for mode := 0; mode < 2; mode++ { 2801 v := pollVarz(t, s1, mode, varzURL, nil) 2802 if n := len(v.Cluster.URLs); n != 0 { 2803 t.Fatalf("mode=%v - Expected 0 URL, got %v", mode, n) 2804 } 2805 } 2806 return nil 2807 }) 2808 } 2809 2810 func TestMonitorGateway(t *testing.T) { 2811 testMonitorStructPresent(t, "gateway") 2812 2813 resetPreviousHTTPConnections() 2814 opts := DefaultMonitorOptions() 2815 opts.NoSystemAccount = true 2816 opts.Gateway.Name = "A" 2817 opts.Gateway.Port = -1 2818 opts.Gateway.AuthTimeout = 1 2819 opts.Gateway.TLSTimeout = 1 2820 opts.Gateway.Advertise = "127.0.0.1" 2821 opts.Gateway.ConnectRetries = 1 2822 opts.Gateway.RejectUnknown = false 2823 u1, _ := url.Parse("nats://ivan:pwd@localhost:1234") 2824 u2, _ := url.Parse("nats://localhost:1235") 2825 opts.Gateway.Gateways = []*RemoteGatewayOpts{ 2826 { 2827 Name: "B", 2828 TLSTimeout: 1, 2829 URLs: []*url.URL{ 2830 u1, 2831 u2, 2832 }, 2833 }, 2834 } 2835 s := RunServer(opts) 2836 defer s.Shutdown() 2837 2838 expected := GatewayOptsVarz{ 2839 "A", 2840 opts.Gateway.Host, 2841 opts.Gateway.Port, 2842 opts.Gateway.AuthTimeout, 2843 opts.Gateway.TLSTimeout, 2844 opts.Gateway.TLSConfig != nil, 2845 opts.Gateway.TLSConfig != nil, 2846 opts.Gateway.Advertise, 2847 opts.Gateway.ConnectRetries, 2848 []RemoteGatewayOptsVarz{{"B", 1, nil}}, 2849 opts.Gateway.RejectUnknown, 2850 } 2851 // Since URLs array is not guaranteed to be always the same order, 2852 // we don't add it in the expected GatewayOptsVarz, instead we 2853 // maintain here. 2854 expectedURLs := []string{"localhost:1234", "localhost:1235"} 2855 2856 varzURL := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 2857 for mode := 0; mode < 2; mode++ { 2858 check := func(t *testing.T, v *Varz) { 2859 t.Helper() 2860 var urls []string 2861 if len(v.Gateway.Gateways) == 1 { 2862 urls = v.Gateway.Gateways[0].URLs 2863 v.Gateway.Gateways[0].URLs = nil 2864 } 2865 if !reflect.DeepEqual(v.Gateway, expected) { 2866 t.Fatalf("mode=%v - expected %+v, got %+v", mode, expected, v.Gateway) 2867 } 2868 // Now compare urls 2869 for _, u := range expectedURLs { 2870 ok := false 2871 for _, u2 := range urls { 2872 if u == u2 { 2873 ok = true 2874 break 2875 } 2876 } 2877 if !ok { 2878 t.Fatalf("mode=%v - expected urls to be %v, got %v", mode, expected.Gateways[0].URLs, urls) 2879 } 2880 } 2881 } 2882 v := pollVarz(t, s, mode, varzURL, nil) 2883 check(t, v) 2884 2885 // Having this here to make sure that if fields are added in GatewayOptsVarz, 2886 // we make sure to update this test (compiler will report an error if we don't) 2887 _ = GatewayOptsVarz{"", "", 0, 0, 0, false, false, "", 0, []RemoteGatewayOptsVarz{{"", 0, nil}}, false} 2888 2889 // Alter the fields to make sure that we have a proper deep copy 2890 // of what may be stored in the server. Anything we change here 2891 // should not affect the next returned value. 2892 v.Gateway.Name = "wrong" 2893 v.Gateway.Host = "wrong" 2894 v.Gateway.Port = 0 2895 v.Gateway.AuthTimeout = 1234.5 2896 v.Gateway.TLSTimeout = 1234.5 2897 v.Gateway.Advertise = "wrong" 2898 v.Gateway.ConnectRetries = 1234 2899 v.Gateway.Gateways[0].Name = "wrong" 2900 v.Gateway.Gateways[0].TLSTimeout = 1234.5 2901 v.Gateway.Gateways[0].URLs = []string{"wrong"} 2902 v.Gateway.RejectUnknown = true 2903 v = pollVarz(t, s, mode, varzURL, nil) 2904 check(t, v) 2905 } 2906 } 2907 2908 func TestMonitorGatewayURLsUpdated(t *testing.T) { 2909 resetPreviousHTTPConnections() 2910 2911 ob1 := testDefaultOptionsForGateway("B") 2912 sb1 := runGatewayServer(ob1) 2913 defer sb1.Shutdown() 2914 2915 // Start a1 that has a single URL to sb1. 2916 oa := testGatewayOptionsFromToWithServers(t, "A", "B", sb1) 2917 oa.HTTPHost = "127.0.0.1" 2918 oa.HTTPPort = MONITOR_PORT 2919 sa := runGatewayServer(oa) 2920 defer sa.Shutdown() 2921 2922 waitForOutboundGateways(t, sa, 1, 2*time.Second) 2923 2924 varzURL := fmt.Sprintf("http://127.0.0.1:%d/varz", sa.MonitorAddr().Port) 2925 // Check the /varz gateway's URLs 2926 for mode := 0; mode < 2; mode++ { 2927 v := pollVarz(t, sa, mode, varzURL, nil) 2928 if n := len(v.Gateway.Gateways); n != 1 { 2929 t.Fatalf("mode=%v - Expected 1 remote gateway, got %v", mode, n) 2930 } 2931 gw := v.Gateway.Gateways[0] 2932 if n := len(gw.URLs); n != 1 { 2933 t.Fatalf("mode=%v - Expected 1 url, got %v", mode, n) 2934 } 2935 expected := oa.Gateway.Gateways[0].URLs[0].Host 2936 if u := gw.URLs[0]; u != expected { 2937 t.Fatalf("mode=%v - Expected URL %q, got %q", mode, expected, u) 2938 } 2939 } 2940 2941 // Now start sb2 that clusters with sb1. sa should add to its list of URLs 2942 // sb2 gateway's connect URL. 2943 ob2 := testDefaultOptionsForGateway("B") 2944 ob2.Routes = RoutesFromStr(fmt.Sprintf("nats://127.0.0.1:%d", sb1.ClusterAddr().Port)) 2945 sb2 := runGatewayServer(ob2) 2946 defer sb2.Shutdown() 2947 2948 // Wait for sb1 and sb2 to connect 2949 checkClusterFormed(t, sb1, sb2) 2950 // sb2 should be made aware of gateway A and connect to sa 2951 waitForInboundGateways(t, sa, 2, 2*time.Second) 2952 // Now check that URLs in /varz get updated 2953 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 2954 for mode := 0; mode < 2; mode++ { 2955 v := pollVarz(t, sa, mode, varzURL, nil) 2956 if n := len(v.Gateway.Gateways); n != 1 { 2957 return fmt.Errorf("mode=%v - Expected 1 remote gateway, got %v", mode, n) 2958 } 2959 gw := v.Gateway.Gateways[0] 2960 if n := len(gw.URLs); n != 2 { 2961 return fmt.Errorf("mode=%v - Expected 2 urls, got %v", mode, n) 2962 } 2963 2964 gotSB1 := false 2965 gotSB2 := false 2966 for _, u := range gw.URLs { 2967 if u == fmt.Sprintf("127.0.0.1:%d", sb1.GatewayAddr().Port) { 2968 gotSB1 = true 2969 } else if u == fmt.Sprintf("127.0.0.1:%d", sb2.GatewayAddr().Port) { 2970 gotSB2 = true 2971 } else { 2972 return fmt.Errorf("mode=%v - Incorrect URL to gateway B: %v", mode, u) 2973 } 2974 } 2975 if !gotSB1 { 2976 return fmt.Errorf("mode=%v - Did not get URL to sb1", mode) 2977 } 2978 if !gotSB2 { 2979 return fmt.Errorf("mode=%v - Did not get URL to sb2", mode) 2980 } 2981 } 2982 return nil 2983 }) 2984 2985 // Now stop sb2 and make sure that its removal is reflected in varz. 2986 sb2.Shutdown() 2987 // Wait for it to disappear from sa. 2988 waitForInboundGateways(t, sa, 1, 2*time.Second) 2989 // Now check that URLs in /varz get updated. 2990 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 2991 for mode := 0; mode < 2; mode++ { 2992 v := pollVarz(t, sa, mode, varzURL, nil) 2993 if n := len(v.Gateway.Gateways); n != 1 { 2994 return fmt.Errorf("mode=%v - Expected 1 remote gateway, got %v", mode, n) 2995 } 2996 gw := v.Gateway.Gateways[0] 2997 if n := len(gw.URLs); n != 1 { 2998 return fmt.Errorf("mode=%v - Expected 1 url, got %v", mode, n) 2999 } 3000 u := gw.URLs[0] 3001 if u != fmt.Sprintf("127.0.0.1:%d", sb1.GatewayAddr().Port) { 3002 return fmt.Errorf("mode=%v - Did not get URL to sb1", mode) 3003 } 3004 } 3005 return nil 3006 }) 3007 } 3008 3009 func TestMonitorGatewayReportItsOwnURLs(t *testing.T) { 3010 resetPreviousHTTPConnections() 3011 3012 // In this test, we show that if a server has its own gateway information 3013 // as a remote (which is the case when remote gateway definitions is copied 3014 // on all clusters), we display the defined URLs. 3015 oa := testGatewayOptionsFromToWithURLs(t, "A", "A", []string{"nats://127.0.0.1:1234", "nats://127.0.0.1:1235"}) 3016 oa.HTTPHost = "127.0.0.1" 3017 oa.HTTPPort = MONITOR_PORT 3018 sa := runGatewayServer(oa) 3019 defer sa.Shutdown() 3020 3021 varzURL := fmt.Sprintf("http://127.0.0.1:%d/varz", sa.MonitorAddr().Port) 3022 // Check the /varz gateway's URLs 3023 for mode := 0; mode < 2; mode++ { 3024 v := pollVarz(t, sa, mode, varzURL, nil) 3025 if n := len(v.Gateway.Gateways); n != 1 { 3026 t.Fatalf("mode=%v - Expected 1 remote gateway, got %v", mode, n) 3027 } 3028 gw := v.Gateway.Gateways[0] 3029 if n := len(gw.URLs); n != 2 { 3030 t.Fatalf("mode=%v - Expected 2 urls, got %v", mode, gw.URLs) 3031 } 3032 expected := []string{"127.0.0.1:1234", "127.0.0.1:1235"} 3033 if !reflect.DeepEqual(gw.URLs, expected) { 3034 t.Fatalf("mode=%v - Expected URLs %q, got %q", mode, expected, gw.URLs) 3035 } 3036 } 3037 } 3038 3039 func TestMonitorLeafNode(t *testing.T) { 3040 testMonitorStructPresent(t, "leaf") 3041 3042 resetPreviousHTTPConnections() 3043 opts := DefaultMonitorOptions() 3044 opts.NoSystemAccount = true 3045 opts.LeafNode.Port = -1 3046 opts.LeafNode.AuthTimeout = 1 3047 opts.LeafNode.TLSTimeout = 1 3048 opts.Accounts = []*Account{NewAccount("acc")} 3049 u, _ := url.Parse("nats://ivan:pwd@localhost:1234") 3050 opts.LeafNode.Remotes = []*RemoteLeafOpts{ 3051 { 3052 LocalAccount: "acc", 3053 URLs: []*url.URL{u}, 3054 TLSTimeout: 1, 3055 }, 3056 } 3057 s := RunServer(opts) 3058 defer s.Shutdown() 3059 3060 expected := LeafNodeOptsVarz{ 3061 opts.LeafNode.Host, 3062 opts.LeafNode.Port, 3063 opts.LeafNode.AuthTimeout, 3064 opts.LeafNode.TLSTimeout, 3065 opts.LeafNode.TLSConfig != nil, 3066 opts.LeafNode.TLSConfig != nil, 3067 []RemoteLeafOptsVarz{ 3068 { 3069 "acc", 1, []string{"localhost:1234"}, nil, false, 3070 }, 3071 }, 3072 false, 3073 } 3074 3075 varzURL := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 3076 3077 for mode := 0; mode < 2; mode++ { 3078 check := func(t *testing.T, v *Varz) { 3079 t.Helper() 3080 if !reflect.DeepEqual(v.LeafNode, expected) { 3081 t.Fatalf("mode=%v - expected %+v, got %+v", mode, expected, v.LeafNode) 3082 } 3083 } 3084 v := pollVarz(t, s, mode, varzURL, nil) 3085 check(t, v) 3086 3087 // Having this here to make sure that if fields are added in ClusterOptsVarz, 3088 // we make sure to update this test (compiler will report an error if we don't) 3089 _ = LeafNodeOptsVarz{"", 0, 0, 0, false, false, []RemoteLeafOptsVarz{{"", 0, nil, nil, false}}, false} 3090 3091 // Alter the fields to make sure that we have a proper deep copy 3092 // of what may be stored in the server. Anything we change here 3093 // should not affect the next returned value. 3094 v.LeafNode.Host = "wrong" 3095 v.LeafNode.Port = 0 3096 v.LeafNode.AuthTimeout = 1234.5 3097 v.LeafNode.TLSTimeout = 1234.5 3098 v.LeafNode.Remotes[0].LocalAccount = "wrong" 3099 v.LeafNode.Remotes[0].URLs = append(v.LeafNode.Remotes[0].URLs, "wrong") 3100 v.LeafNode.Remotes[0].TLSTimeout = 1234.5 3101 v = pollVarz(t, s, mode, varzURL, nil) 3102 check(t, v) 3103 } 3104 } 3105 3106 func pollGatewayz(t *testing.T, s *Server, mode int, url string, opts *GatewayzOptions) *Gatewayz { 3107 t.Helper() 3108 if mode == 0 { 3109 g := &Gatewayz{} 3110 body := readBody(t, url) 3111 if err := json.Unmarshal(body, g); err != nil { 3112 t.Fatalf("Got an error unmarshalling the body: %v\n", err) 3113 } 3114 return g 3115 } 3116 g, err := s.Gatewayz(opts) 3117 if err != nil { 3118 t.Fatalf("Error on Gatewayz: %v", err) 3119 } 3120 return g 3121 } 3122 3123 func TestMonitorGatewayz(t *testing.T) { 3124 resetPreviousHTTPConnections() 3125 3126 // First check that without gateway configured 3127 s := runMonitorServer() 3128 defer s.Shutdown() 3129 url := fmt.Sprintf("http://127.0.0.1:%d/gatewayz", s.MonitorAddr().Port) 3130 for pollMode := 0; pollMode < 2; pollMode++ { 3131 g := pollGatewayz(t, s, pollMode, url, nil) 3132 // Expect Name and port to be empty 3133 if g.Name != _EMPTY_ || g.Port != 0 { 3134 t.Fatalf("Expected no gateway, got %+v", g) 3135 } 3136 } 3137 s.Shutdown() 3138 3139 ob1 := testDefaultOptionsForGateway("B") 3140 sb1 := runGatewayServer(ob1) 3141 defer sb1.Shutdown() 3142 3143 // Start a1 that has a single URL to sb1. 3144 oa := testGatewayOptionsFromToWithServers(t, "A", "B", sb1) 3145 oa.HTTPHost = "127.0.0.1" 3146 oa.HTTPPort = MONITOR_PORT 3147 sa := runGatewayServer(oa) 3148 defer sa.Shutdown() 3149 3150 waitForOutboundGateways(t, sa, 1, 2*time.Second) 3151 waitForInboundGateways(t, sa, 1, 2*time.Second) 3152 3153 waitForOutboundGateways(t, sb1, 1, 2*time.Second) 3154 waitForInboundGateways(t, sb1, 1, 2*time.Second) 3155 3156 gatewayzURL := fmt.Sprintf("http://127.0.0.1:%d/gatewayz", sa.MonitorAddr().Port) 3157 for pollMode := 0; pollMode < 2; pollMode++ { 3158 g := pollGatewayz(t, sa, pollMode, gatewayzURL, nil) 3159 if g.Host != oa.Gateway.Host { 3160 t.Fatalf("mode=%v - Expected host to be %q, got %q", pollMode, oa.Gateway.Host, g.Host) 3161 } 3162 if g.Port != oa.Gateway.Port { 3163 t.Fatalf("mode=%v - Expected port to be %v, got %v", pollMode, oa.Gateway.Port, g.Port) 3164 } 3165 if n := len(g.OutboundGateways); n != 1 { 3166 t.Fatalf("mode=%v - Expected outbound to 1 gateway, got %v", pollMode, n) 3167 } 3168 if n := len(g.InboundGateways); n != 1 { 3169 t.Fatalf("mode=%v - Expected inbound from 1 gateway, got %v", pollMode, n) 3170 } 3171 og := g.OutboundGateways["B"] 3172 if og == nil { 3173 t.Fatalf("mode=%v - Expected to find outbound connection to B, got none", pollMode) 3174 } 3175 if !og.IsConfigured { 3176 t.Fatalf("mode=%v - Expected gw connection to be configured, was not", pollMode) 3177 } 3178 if og.Connection == nil { 3179 t.Fatalf("mode=%v - Expected outbound connection to B to be set, wat not", pollMode) 3180 } 3181 if og.Connection.Name != sb1.ID() { 3182 t.Fatalf("mode=%v - Expected outbound connection to B to have name %q, got %q", pollMode, sb1.ID(), og.Connection.Name) 3183 } 3184 if n := len(og.Accounts); n != 0 { 3185 t.Fatalf("mode=%v - Expected no account, got %v", pollMode, n) 3186 } 3187 ig := g.InboundGateways["B"] 3188 if ig == nil { 3189 t.Fatalf("mode=%v - Expected to find inbound connection from B, got none", pollMode) 3190 } 3191 if n := len(ig); n != 1 { 3192 t.Fatalf("mode=%v - Expected 1 inbound connection, got %v", pollMode, n) 3193 } 3194 igc := ig[0] 3195 if igc.Connection == nil { 3196 t.Fatalf("mode=%v - Expected inbound connection to B to be set, wat not", pollMode) 3197 } 3198 if igc.Connection.Name != sb1.ID() { 3199 t.Fatalf("mode=%v - Expected inbound connection to B to have name %q, got %q", pollMode, sb1.ID(), igc.Connection.Name) 3200 } 3201 } 3202 3203 // Now start sb2 that clusters with sb1. sa should add to its list of URLs 3204 // sb2 gateway's connect URL. 3205 ob2 := testDefaultOptionsForGateway("B") 3206 ob2.Routes = RoutesFromStr(fmt.Sprintf("nats://127.0.0.1:%d", sb1.ClusterAddr().Port)) 3207 sb2 := runGatewayServer(ob2) 3208 defer sb2.Shutdown() 3209 3210 // Wait for sb1 and sb2 to connect 3211 checkClusterFormed(t, sb1, sb2) 3212 // sb2 should be made aware of gateway A and connect to sa 3213 waitForInboundGateways(t, sa, 2, 2*time.Second) 3214 // Now check that URLs in /varz get updated 3215 checkGatewayB := func(t *testing.T, url string, opts *GatewayzOptions) { 3216 t.Helper() 3217 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 3218 for pollMode := 0; pollMode < 2; pollMode++ { 3219 g := pollGatewayz(t, sa, pollMode, url, opts) 3220 if n := len(g.OutboundGateways); n != 1 { 3221 t.Fatalf("mode=%v - Expected outbound to 1 gateway, got %v", pollMode, n) 3222 } 3223 // The InboundGateways is a map with key the gateway names, 3224 // then value is array of connections. So should be 1 here. 3225 if n := len(g.InboundGateways); n != 1 { 3226 t.Fatalf("mode=%v - Expected inbound from 1 gateway, got %v", pollMode, n) 3227 } 3228 ig := g.InboundGateways["B"] 3229 if ig == nil { 3230 t.Fatalf("mode=%v - Expected to find inbound connection from B, got none", pollMode) 3231 } 3232 if n := len(ig); n != 2 { 3233 t.Fatalf("mode=%v - Expected 2 inbound connections from gateway B, got %v", pollMode, n) 3234 } 3235 gotSB1 := false 3236 gotSB2 := false 3237 for _, rg := range ig { 3238 if rg.Connection != nil { 3239 if rg.Connection.Name == sb1.ID() { 3240 gotSB1 = true 3241 } else if rg.Connection.Name == sb2.ID() { 3242 gotSB2 = true 3243 } 3244 } 3245 } 3246 if !gotSB1 { 3247 t.Fatalf("mode=%v - Missing inbound connection from sb1", pollMode) 3248 } 3249 if !gotSB2 { 3250 t.Fatalf("mode=%v - Missing inbound connection from sb2", pollMode) 3251 } 3252 } 3253 return nil 3254 }) 3255 } 3256 checkGatewayB(t, gatewayzURL, nil) 3257 3258 // Start a new cluser C that connects to B. A should see it as 3259 // a non-configured gateway. 3260 oc := testGatewayOptionsFromToWithServers(t, "C", "B", sb1) 3261 sc := runGatewayServer(oc) 3262 defer sc.Shutdown() 3263 3264 // All servers should have 2 outbound connections (one for each other cluster) 3265 waitForOutboundGateways(t, sa, 2, 2*time.Second) 3266 waitForOutboundGateways(t, sb1, 2, 2*time.Second) 3267 waitForOutboundGateways(t, sb2, 2, 2*time.Second) 3268 waitForOutboundGateways(t, sc, 2, 2*time.Second) 3269 3270 // Server sa should have 3 inbounds now 3271 waitForInboundGateways(t, sa, 3, 2*time.Second) 3272 3273 // Check gatewayz again to see that we have C now. 3274 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 3275 for pollMode := 0; pollMode < 2; pollMode++ { 3276 g := pollGatewayz(t, sa, pollMode, gatewayzURL, nil) 3277 if n := len(g.OutboundGateways); n != 2 { 3278 t.Fatalf("mode=%v - Expected outbound to 2 gateways, got %v", pollMode, n) 3279 } 3280 // The InboundGateways is a map with key the gateway names, 3281 // then value is array of connections. So should be 2 here. 3282 if n := len(g.InboundGateways); n != 2 { 3283 t.Fatalf("mode=%v - Expected inbound from 2 gateways, got %v", pollMode, n) 3284 } 3285 og := g.OutboundGateways["C"] 3286 if og == nil { 3287 t.Fatalf("mode=%v - Expected to find outbound connection to C, got none", pollMode) 3288 } 3289 if og.IsConfigured { 3290 t.Fatalf("mode=%v - Expected IsConfigured for gateway C to be false, was true", pollMode) 3291 } 3292 if og.Connection == nil { 3293 t.Fatalf("mode=%v - Expected connection to C, got none", pollMode) 3294 } 3295 if og.Connection.Name != sc.ID() { 3296 t.Fatalf("mode=%v - Expected outbound connection to C to have name %q, got %q", pollMode, sc.ID(), og.Connection.Name) 3297 } 3298 ig := g.InboundGateways["C"] 3299 if ig == nil { 3300 t.Fatalf("mode=%v - Expected to find inbound connection from C, got none", pollMode) 3301 } 3302 if n := len(ig); n != 1 { 3303 t.Fatalf("mode=%v - Expected 1 inbound connections from gateway C, got %v", pollMode, n) 3304 } 3305 igc := ig[0] 3306 if igc.Connection == nil { 3307 t.Fatalf("mode=%v - Expected connection to C, got none", pollMode) 3308 } 3309 if igc.Connection.Name != sc.ID() { 3310 t.Fatalf("mode=%v - Expected outbound connection to C to have name %q, got %q", pollMode, sc.ID(), og.Connection.Name) 3311 } 3312 } 3313 return nil 3314 }) 3315 3316 // Select only 1 gateway by passing the name to option/url 3317 opts := &GatewayzOptions{Name: "B"} 3318 checkGatewayB(t, gatewayzURL+"?gw_name=B", opts) 3319 3320 // Stop gateway C and check that we have only B, with and without filter. 3321 sc.Shutdown() 3322 checkGatewayB(t, gatewayzURL+"?gw_name=B", opts) 3323 checkGatewayB(t, gatewayzURL, nil) 3324 } 3325 3326 func TestMonitorGatewayzAccounts(t *testing.T) { 3327 GatewayDoNotForceInterestOnlyMode(true) 3328 defer GatewayDoNotForceInterestOnlyMode(false) 3329 3330 resetPreviousHTTPConnections() 3331 3332 // Create bunch of Accounts 3333 totalAccounts := 15 3334 accounts := "" 3335 for i := 0; i < totalAccounts; i++ { 3336 acc := fmt.Sprintf(" acc_%d: { users=[{user:user_%d, password: pwd}] }\n", i, i) 3337 accounts += acc 3338 } 3339 3340 bConf := createConfFile(t, []byte(fmt.Sprintf(` 3341 accounts { 3342 %s 3343 } 3344 port: -1 3345 http: -1 3346 gateway: { 3347 name: "B" 3348 port: -1 3349 } 3350 no_sys_acc = true 3351 `, accounts))) 3352 3353 sb, ob := RunServerWithConfig(bConf) 3354 defer sb.Shutdown() 3355 sb.SetLogger(&DummyLogger{}, true, true) 3356 3357 // Start a1 that has a single URL to sb1. 3358 aConf := createConfFile(t, []byte(fmt.Sprintf(` 3359 accounts { 3360 %s 3361 } 3362 port: -1 3363 http: -1 3364 gateway: { 3365 name: "A" 3366 port: -1 3367 gateways [ 3368 { 3369 name: "B" 3370 url: "nats://127.0.0.1:%d" 3371 } 3372 ] 3373 } 3374 no_sys_acc = true 3375 `, accounts, sb.GatewayAddr().Port))) 3376 3377 sa, oa := RunServerWithConfig(aConf) 3378 defer sa.Shutdown() 3379 sa.SetLogger(&DummyLogger{}, true, true) 3380 3381 waitForOutboundGateways(t, sa, 1, 2*time.Second) 3382 waitForInboundGateways(t, sa, 1, 2*time.Second) 3383 waitForOutboundGateways(t, sb, 1, 2*time.Second) 3384 waitForInboundGateways(t, sb, 1, 2*time.Second) 3385 3386 // Create clients for each account on A and publish a message 3387 // so that list of accounts appear in gatewayz 3388 produceMsgsFromA := func(t *testing.T) { 3389 t.Helper() 3390 for i := 0; i < totalAccounts; i++ { 3391 nc, err := nats.Connect(fmt.Sprintf("nats://user_%d:pwd@%s:%d", i, oa.Host, oa.Port)) 3392 if err != nil { 3393 t.Fatalf("Error on connect: %v", err) 3394 } 3395 nc.Publish("foo", []byte("hello")) 3396 nc.Flush() 3397 nc.Close() 3398 } 3399 } 3400 produceMsgsFromA(t) 3401 3402 // Wait for A- for all accounts 3403 gwc := sa.getOutboundGatewayConnection("B") 3404 for i := 0; i < totalAccounts; i++ { 3405 checkForAccountNoInterest(t, gwc, fmt.Sprintf("acc_%d", i), true, 2*time.Second) 3406 } 3407 3408 // Check accounts... 3409 gatewayzURL := fmt.Sprintf("http://127.0.0.1:%d/gatewayz", sa.MonitorAddr().Port) 3410 for pollMode := 0; pollMode < 2; pollMode++ { 3411 // First, without asking for it, they should not be present. 3412 g := pollGatewayz(t, sa, pollMode, gatewayzURL, nil) 3413 og := g.OutboundGateways["B"] 3414 if og == nil { 3415 t.Fatalf("mode=%v - Expected outbound gateway to B, got none", pollMode) 3416 } 3417 if n := len(og.Accounts); n != 0 { 3418 t.Fatalf("mode=%v - Expected accounts list to not be present by default, got %v", pollMode, n) 3419 } 3420 // Now ask for the accounts 3421 g = pollGatewayz(t, sa, pollMode, gatewayzURL+"?accs=1", &GatewayzOptions{Accounts: true}) 3422 og = g.OutboundGateways["B"] 3423 if og == nil { 3424 t.Fatalf("mode=%v - Expected outbound gateway to B, got none", pollMode) 3425 } 3426 if n := len(og.Accounts); n != totalAccounts { 3427 t.Fatalf("mode=%v - Expected to get all %d accounts, got %v", pollMode, totalAccounts, n) 3428 } 3429 // Now account details 3430 for _, acc := range og.Accounts { 3431 if acc.InterestMode != Optimistic.String() { 3432 t.Fatalf("mode=%v - Expected optimistic mode, got %q", pollMode, acc.InterestMode) 3433 } 3434 // Since there is no interest at all on B, the publish 3435 // will have resulted in total account no interest, so 3436 // the number of no interest (subject wise) should be 0 3437 if acc.NoInterestCount != 0 { 3438 t.Fatalf("mode=%v - Expected 0 no-interest, got %v", pollMode, acc.NoInterestCount) 3439 } 3440 if acc.NumQueueSubscriptions != 0 || acc.TotalSubscriptions != 0 { 3441 t.Fatalf("mode=%v - Expected total subs to be 0, got %v - and num queue subs to be 0, got %v", 3442 pollMode, acc.TotalSubscriptions, acc.NumQueueSubscriptions) 3443 } 3444 } 3445 } 3446 3447 // Check inbound on B 3448 gwURLServerB := fmt.Sprintf("http://127.0.0.1:%d/gatewayz", sb.MonitorAddr().Port) 3449 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 3450 for pollMode := 0; pollMode < 2; pollMode++ { 3451 // First, without asking for it, they should not be present. 3452 g := pollGatewayz(t, sb, pollMode, gwURLServerB, nil) 3453 igs := g.InboundGateways["A"] 3454 if igs == nil { 3455 return fmt.Errorf("mode=%v - Expected inbound gateway to A, got none", pollMode) 3456 } 3457 if len(igs) != 1 { 3458 return fmt.Errorf("mode=%v - Expected single inbound, got %v", pollMode, len(igs)) 3459 } 3460 ig := igs[0] 3461 if n := len(ig.Accounts); n != 0 { 3462 return fmt.Errorf("mode=%v - Expected no account, got %v", pollMode, n) 3463 } 3464 // Check that list of accounts 3465 g = pollGatewayz(t, sb, pollMode, gwURLServerB+"?accs=1", &GatewayzOptions{Accounts: true}) 3466 igs = g.InboundGateways["A"] 3467 if igs == nil { 3468 return fmt.Errorf("mode=%v - Expected inbound gateway to A, got none", pollMode) 3469 } 3470 if len(igs) != 1 { 3471 return fmt.Errorf("mode=%v - Expected single inbound, got %v", pollMode, len(igs)) 3472 } 3473 ig = igs[0] 3474 if ig.Connection == nil { 3475 return fmt.Errorf("mode=%v - Expected inbound connection from A to be set, wat not", pollMode) 3476 } 3477 if ig.Connection.Name != sa.ID() { 3478 t.Fatalf("mode=%v - Expected inbound connection from A to have name %q, got %q", pollMode, sa.ID(), ig.Connection.Name) 3479 } 3480 if n := len(ig.Accounts); n != totalAccounts { 3481 return fmt.Errorf("mode=%v - Expected to get all %d accounts, got %v", pollMode, totalAccounts, n) 3482 } 3483 // Now account details 3484 for _, acc := range ig.Accounts { 3485 if acc.InterestMode != Optimistic.String() { 3486 return fmt.Errorf("mode=%v - Expected optimistic mode, got %q", pollMode, acc.InterestMode) 3487 } 3488 // Since there is no interest at all on B, the publish 3489 // will have resulted in total account no interest, so 3490 // the number of no interest (subject wise) should be 0 3491 if acc.NoInterestCount != 0 { 3492 t.Fatalf("mode=%v - Expected 0 no-interest, got %v", pollMode, acc.NoInterestCount) 3493 } 3494 // For inbound gateway, NumQueueSubscriptions and TotalSubscriptions 3495 // are not relevant. 3496 if acc.NumQueueSubscriptions != 0 || acc.TotalSubscriptions != 0 { 3497 return fmt.Errorf("mode=%v - For inbound connection, expected num queue subs and total subs to be 0, got %v and %v", 3498 pollMode, acc.TotalSubscriptions, acc.NumQueueSubscriptions) 3499 } 3500 } 3501 } 3502 return nil 3503 }) 3504 3505 // Now create subscriptions on B to prevent A- and check on subject no interest 3506 for i := 0; i < totalAccounts; i++ { 3507 nc, err := nats.Connect(fmt.Sprintf("nats://user_%d:pwd@%s:%d", i, ob.Host, ob.Port)) 3508 if err != nil { 3509 t.Fatalf("Error on connect: %v", err) 3510 } 3511 defer nc.Close() 3512 // Create a queue sub so it shows up in gatewayz 3513 nc.QueueSubscribeSync("bar", "queue") 3514 // Create plain subscriptions on baz.0, baz.1 and baz.2. 3515 // Create to for each subject. Since gateways will send 3516 // only once per subject, the number of subs should be 3, not 6. 3517 for j := 0; j < 3; j++ { 3518 subj := fmt.Sprintf("baz.%d", j) 3519 nc.SubscribeSync(subj) 3520 nc.SubscribeSync(subj) 3521 } 3522 nc.Flush() 3523 } 3524 3525 for i := 0; i < totalAccounts; i++ { 3526 accName := fmt.Sprintf("acc_%d", i) 3527 checkForRegisteredQSubInterest(t, sa, "B", accName, "bar", 1, 2*time.Second) 3528 } 3529 3530 // Resend msgs from A on foo, on all accounts. There will be no interest on this subject. 3531 produceMsgsFromA(t) 3532 3533 for i := 0; i < totalAccounts; i++ { 3534 accName := fmt.Sprintf("acc_%d", i) 3535 checkForSubjectNoInterest(t, gwc, accName, "foo", true, 2*time.Second) 3536 // Verify that we still have the queue interest registered 3537 checkForRegisteredQSubInterest(t, sa, "B", accName, "bar", 1, 2*time.Second) 3538 } 3539 3540 // Check accounts... 3541 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 3542 for pollMode := 0; pollMode < 2; pollMode++ { 3543 g := pollGatewayz(t, sa, pollMode, gatewayzURL+"?accs=1", &GatewayzOptions{Accounts: true}) 3544 og := g.OutboundGateways["B"] 3545 if og == nil { 3546 return fmt.Errorf("mode=%v - Expected outbound gateway to B, got none", pollMode) 3547 } 3548 if n := len(og.Accounts); n != totalAccounts { 3549 return fmt.Errorf("mode=%v - Expected to get all %d accounts, got %v", pollMode, totalAccounts, n) 3550 } 3551 // Now account details 3552 for _, acc := range og.Accounts { 3553 if acc.InterestMode != Optimistic.String() { 3554 return fmt.Errorf("mode=%v - Expected optimistic mode, got %q", pollMode, acc.InterestMode) 3555 } 3556 if acc.NoInterestCount != 1 { 3557 return fmt.Errorf("mode=%v - Expected 1 no-interest, got %v", pollMode, acc.NoInterestCount) 3558 } 3559 if acc.NumQueueSubscriptions != 1 || acc.TotalSubscriptions != 1 { 3560 return fmt.Errorf("mode=%v - Expected total subs to be 1, got %v - and num queue subs to be 1, got %v", 3561 pollMode, acc.TotalSubscriptions, acc.NumQueueSubscriptions) 3562 } 3563 } 3564 } 3565 return nil 3566 }) 3567 3568 // Check inbound on server B 3569 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 3570 for pollMode := 0; pollMode < 2; pollMode++ { 3571 // Ask for accounts list 3572 g := pollGatewayz(t, sb, pollMode, gwURLServerB+"?accs=1", &GatewayzOptions{Accounts: true}) 3573 igs := g.InboundGateways["A"] 3574 if igs == nil { 3575 return fmt.Errorf("mode=%v - Expected inbound gateway to A, got none", pollMode) 3576 } 3577 if len(igs) != 1 { 3578 return fmt.Errorf("mode=%v - Expected single inbound, got %v", pollMode, len(igs)) 3579 } 3580 ig := igs[0] 3581 if ig.Connection == nil { 3582 return fmt.Errorf("mode=%v - Expected inbound connection from A to be set, wat not", pollMode) 3583 } 3584 if ig.Connection.Name != sa.ID() { 3585 t.Fatalf("mode=%v - Expected inbound connection from A to have name %q, got %q", pollMode, sa.ID(), ig.Connection.Name) 3586 } 3587 if n := len(ig.Accounts); n != totalAccounts { 3588 return fmt.Errorf("mode=%v - Expected to get all %d accounts, got %v", pollMode, totalAccounts, n) 3589 } 3590 // Now account details 3591 for _, acc := range ig.Accounts { 3592 if acc.InterestMode != Optimistic.String() { 3593 return fmt.Errorf("mode=%v - Expected optimistic mode, got %q", pollMode, acc.InterestMode) 3594 } 3595 if acc.NoInterestCount != 1 { 3596 return fmt.Errorf("mode=%v - Expected 1 no-interest, got %v", pollMode, acc.NoInterestCount) 3597 } 3598 // For inbound gateway, NumQueueSubscriptions and TotalSubscriptions 3599 // are not relevant. 3600 if acc.NumQueueSubscriptions != 0 || acc.TotalSubscriptions != 0 { 3601 return fmt.Errorf("mode=%v - For inbound connection, expected num queue subs and total subs to be 0, got %v and %v", 3602 pollMode, acc.TotalSubscriptions, acc.NumQueueSubscriptions) 3603 } 3604 } 3605 } 3606 return nil 3607 }) 3608 3609 // Make one of the account to switch to interest only 3610 nc, err := nats.Connect(fmt.Sprintf("nats://user_1:pwd@%s:%d", oa.Host, oa.Port)) 3611 if err != nil { 3612 t.Fatalf("Error on connect: %v", err) 3613 } 3614 defer nc.Close() 3615 for i := 0; i < 1100; i++ { 3616 nc.Publish(fmt.Sprintf("foo.%d", i), []byte("hello")) 3617 } 3618 nc.Flush() 3619 nc.Close() 3620 3621 // Check that we can select single account 3622 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 3623 for pollMode := 0; pollMode < 2; pollMode++ { 3624 g := pollGatewayz(t, sa, pollMode, gatewayzURL+"?gw_name=B&acc_name=acc_1", &GatewayzOptions{Name: "B", AccountName: "acc_1"}) 3625 og := g.OutboundGateways["B"] 3626 if og == nil { 3627 return fmt.Errorf("mode=%v - Expected outbound gateway to B, got none", pollMode) 3628 } 3629 if n := len(og.Accounts); n != 1 { 3630 return fmt.Errorf("mode=%v - Expected to get 1 account, got %v", pollMode, n) 3631 } 3632 // Now account details 3633 acc := og.Accounts[0] 3634 if acc.InterestMode != InterestOnly.String() { 3635 return fmt.Errorf("mode=%v - Expected interest-only mode, got %q", pollMode, acc.InterestMode) 3636 } 3637 // Since we switched, this should be set to 0 3638 if acc.NoInterestCount != 0 { 3639 return fmt.Errorf("mode=%v - Expected 0 no-interest, got %v", pollMode, acc.NoInterestCount) 3640 } 3641 // We have created 3 subs on that account on B, and 1 queue sub. 3642 // So total should be 4 and 1 for queue sub. 3643 if acc.NumQueueSubscriptions != 1 { 3644 return fmt.Errorf("mode=%v - Expected num queue subs to be 1, got %v", 3645 pollMode, acc.NumQueueSubscriptions) 3646 } 3647 if acc.TotalSubscriptions != 4 { 3648 return fmt.Errorf("mode=%v - Expected total subs to be 4, got %v", 3649 pollMode, acc.TotalSubscriptions) 3650 } 3651 } 3652 return nil 3653 }) 3654 3655 // Check inbound on B now... 3656 checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { 3657 for pollMode := 0; pollMode < 2; pollMode++ { 3658 g := pollGatewayz(t, sb, pollMode, gwURLServerB+"?gw_name=A&acc_name=acc_1", &GatewayzOptions{Name: "A", AccountName: "acc_1"}) 3659 igs := g.InboundGateways["A"] 3660 if igs == nil { 3661 return fmt.Errorf("mode=%v - Expected inbound gateway from A, got none", pollMode) 3662 } 3663 if len(igs) != 1 { 3664 return fmt.Errorf("mode=%v - Expected single inbound, got %v", pollMode, len(igs)) 3665 } 3666 ig := igs[0] 3667 if n := len(ig.Accounts); n != 1 { 3668 return fmt.Errorf("mode=%v - Expected to get 1 account, got %v", pollMode, n) 3669 } 3670 // Now account details 3671 acc := ig.Accounts[0] 3672 if acc.InterestMode != InterestOnly.String() { 3673 return fmt.Errorf("mode=%v - Expected interest-only mode, got %q", pollMode, acc.InterestMode) 3674 } 3675 if acc.InterestMode != InterestOnly.String() { 3676 return fmt.Errorf("Should be in %q mode, got %q", InterestOnly.String(), acc.InterestMode) 3677 } 3678 // Since we switched, this should be set to 0 3679 if acc.NoInterestCount != 0 { 3680 return fmt.Errorf("mode=%v - Expected 0 no-interest, got %v", pollMode, acc.NoInterestCount) 3681 } 3682 // Again, for inbound, these should be always 0. 3683 if acc.NumQueueSubscriptions != 0 || acc.TotalSubscriptions != 0 { 3684 return fmt.Errorf("mode=%v - For inbound connection, expected num queue subs and total subs to be 0, got %v and %v", 3685 pollMode, acc.TotalSubscriptions, acc.NumQueueSubscriptions) 3686 } 3687 } 3688 return nil 3689 }) 3690 } 3691 3692 func TestMonitorRouteRTT(t *testing.T) { 3693 // Do not change default PingInterval and expect RTT to still be reported 3694 3695 ob := DefaultOptions() 3696 sb := RunServer(ob) 3697 defer sb.Shutdown() 3698 3699 oa := DefaultOptions() 3700 oa.Routes = RoutesFromStr(fmt.Sprintf("nats://%s:%d", ob.Cluster.Host, ob.Cluster.Port)) 3701 sa := RunServer(oa) 3702 defer sa.Shutdown() 3703 3704 checkClusterFormed(t, sa, sb) 3705 3706 checkRouteInfo := func(t *testing.T, s *Server) { 3707 t.Helper() 3708 routezURL := fmt.Sprintf("http://127.0.0.1:%d/routez", s.MonitorAddr().Port) 3709 for pollMode := 0; pollMode < 2; pollMode++ { 3710 checkFor(t, 2*firstPingInterval, 15*time.Millisecond, func() error { 3711 rz := pollRoutez(t, s, pollMode, routezURL, nil) 3712 // Pool size + 1 for system account 3713 if len(rz.Routes) != DEFAULT_ROUTE_POOL_SIZE+1 { 3714 return fmt.Errorf("Expected %d route, got %v", DEFAULT_ROUTE_POOL_SIZE+1, len(rz.Routes)) 3715 } 3716 for _, ri := range rz.Routes { 3717 if ri.RTT == _EMPTY_ { 3718 return fmt.Errorf("Route's RTT not reported") 3719 } 3720 } 3721 return nil 3722 }) 3723 } 3724 } 3725 checkRouteInfo(t, sa) 3726 checkRouteInfo(t, sb) 3727 } 3728 3729 func pollLeafz(t *testing.T, s *Server, mode int, url string, opts *LeafzOptions) *Leafz { 3730 t.Helper() 3731 if mode == 0 { 3732 l := &Leafz{} 3733 body := readBody(t, url) 3734 if err := json.Unmarshal(body, l); err != nil { 3735 t.Fatalf("Got an error unmarshalling the body: %v\n", err) 3736 } 3737 return l 3738 } 3739 l, err := s.Leafz(opts) 3740 if err != nil { 3741 t.Fatalf("Error on Leafz: %v", err) 3742 } 3743 return l 3744 } 3745 3746 func TestMonitorOpJWT(t *testing.T) { 3747 content := ` 3748 listen: "127.0.0.1:-1" 3749 http: "127.0.0.1:-1" 3750 operator = "../test/configs/nkeys/op.jwt" 3751 resolver = MEMORY 3752 ` 3753 conf := createConfFile(t, []byte(content)) 3754 sa, _ := RunServerWithConfig(conf) 3755 defer sa.Shutdown() 3756 3757 theJWT, err := os.ReadFile("../test/configs/nkeys/op.jwt") 3758 require_NoError(t, err) 3759 theJWT = []byte(strings.Split(string(theJWT), "\n")[1]) 3760 claim, err := jwt.DecodeOperatorClaims(string(theJWT)) 3761 require_NoError(t, err) 3762 3763 pollURL := fmt.Sprintf("http://127.0.0.1:%d/varz", sa.MonitorAddr().Port) 3764 for pollMode := 1; pollMode < 2; pollMode++ { 3765 l := pollVarz(t, sa, pollMode, pollURL, nil) 3766 3767 if len(l.TrustedOperatorsJwt) != 1 { 3768 t.Fatalf("Expected one operator jwt") 3769 } 3770 if len(l.TrustedOperatorsClaim) != 1 { 3771 t.Fatalf("Expected one operator claim") 3772 } 3773 if l.TrustedOperatorsJwt[0] != string(theJWT) { 3774 t.Fatalf("Expected operator to be identical to configuration") 3775 } 3776 if !reflect.DeepEqual(l.TrustedOperatorsClaim[0], claim) { 3777 t.Fatal("claims need to be equal") 3778 } 3779 } 3780 } 3781 3782 func TestMonitorLeafz(t *testing.T) { 3783 content := ` 3784 server_name: "hub" 3785 listen: "127.0.0.1:-1" 3786 http: "127.0.0.1:-1" 3787 operator = "../test/configs/nkeys/op.jwt" 3788 resolver = MEMORY 3789 ping_interval = 1 3790 leafnodes { 3791 listen: "127.0.0.1:-1" 3792 } 3793 ` 3794 conf := createConfFile(t, []byte(content)) 3795 sb, ob := RunServerWithConfig(conf) 3796 defer sb.Shutdown() 3797 3798 createAcc := func(t *testing.T) (*Account, string) { 3799 t.Helper() 3800 acc, akp := createAccount(sb) 3801 kp, _ := nkeys.CreateUser() 3802 pub, _ := kp.PublicKey() 3803 nuc := jwt.NewUserClaims(pub) 3804 ujwt, err := nuc.Encode(akp) 3805 if err != nil { 3806 t.Fatalf("Error generating user JWT: %v", err) 3807 } 3808 seed, _ := kp.Seed() 3809 creds := genCredsFile(t, ujwt, seed) 3810 return acc, creds 3811 } 3812 acc1, mycreds1 := createAcc(t) 3813 acc2, mycreds2 := createAcc(t) 3814 leafName := "my-leaf-node" 3815 3816 content = ` 3817 port: -1 3818 http: "127.0.0.1:-1" 3819 ping_interval = 1 3820 server_name: %s 3821 accounts { 3822 %s { 3823 users [ 3824 {user: user1, password: pwd} 3825 ] 3826 } 3827 %s { 3828 users [ 3829 {user: user2, password: pwd} 3830 ] 3831 } 3832 } 3833 leafnodes { 3834 remotes = [ 3835 { 3836 account: "%s" 3837 url: nats-leaf://127.0.0.1:%d 3838 credentials: '%s' 3839 } 3840 { 3841 account: "%s" 3842 url: nats-leaf://127.0.0.1:%d 3843 credentials: '%s' 3844 } 3845 ] 3846 } 3847 ` 3848 config := fmt.Sprintf(content, 3849 leafName, 3850 acc1.Name, acc2.Name, 3851 acc1.Name, ob.LeafNode.Port, mycreds1, 3852 acc2.Name, ob.LeafNode.Port, mycreds2) 3853 conf = createConfFile(t, []byte(config)) 3854 sa, oa := RunServerWithConfig(conf) 3855 defer sa.Shutdown() 3856 3857 checkFor(t, time.Second, 15*time.Millisecond, func() error { 3858 if n := sa.NumLeafNodes(); n != 2 { 3859 return fmt.Errorf("Expected 2 leaf connections, got %v", n) 3860 } 3861 return nil 3862 }) 3863 3864 // Wait for initial RTT to be computed 3865 time.Sleep(firstPingInterval + 500*time.Millisecond) 3866 3867 ch := make(chan bool, 1) 3868 nc1B := natsConnect(t, fmt.Sprintf("nats://127.0.0.1:%d", ob.Port), nats.UserCredentials(mycreds1)) 3869 defer nc1B.Close() 3870 natsSub(t, nc1B, "foo", func(_ *nats.Msg) { ch <- true }) 3871 natsSub(t, nc1B, "bar", func(_ *nats.Msg) {}) 3872 natsFlush(t, nc1B) 3873 3874 nc2B := natsConnect(t, fmt.Sprintf("nats://127.0.0.1:%d", ob.Port), nats.UserCredentials(mycreds2)) 3875 defer nc2B.Close() 3876 natsSub(t, nc2B, "bar", func(_ *nats.Msg) { ch <- true }) 3877 natsSub(t, nc2B, "foo", func(_ *nats.Msg) {}) 3878 natsFlush(t, nc2B) 3879 3880 nc1A := natsConnect(t, fmt.Sprintf("nats://user1:pwd@127.0.0.1:%d", oa.Port)) 3881 defer nc1A.Close() 3882 natsPub(t, nc1A, "foo", []byte("hello")) 3883 natsFlush(t, nc1A) 3884 3885 waitCh(t, ch, "Did not get the message") 3886 3887 nc2A := natsConnect(t, fmt.Sprintf("nats://user2:pwd@127.0.0.1:%d", oa.Port)) 3888 defer nc2A.Close() 3889 natsPub(t, nc2A, "bar", []byte("hello")) 3890 natsPub(t, nc2A, "bar", []byte("hello")) 3891 natsFlush(t, nc2A) 3892 3893 waitCh(t, ch, "Did not get the message") 3894 waitCh(t, ch, "Did not get the message") 3895 3896 // Let's poll server A 3897 pollURL := fmt.Sprintf("http://127.0.0.1:%d/leafz?subs=1", sa.MonitorAddr().Port) 3898 for pollMode := 1; pollMode < 2; pollMode++ { 3899 l := pollLeafz(t, sa, pollMode, pollURL, &LeafzOptions{Subscriptions: true}) 3900 if l.ID != sa.ID() { 3901 t.Fatalf("Expected ID to be %q, got %q", sa.ID(), l.ID) 3902 } 3903 if l.Now.IsZero() { 3904 t.Fatalf("Expected Now to be set, was not") 3905 } 3906 if l.NumLeafs != 2 { 3907 t.Fatalf("Expected NumLeafs to be 2, got %v", l.NumLeafs) 3908 } 3909 if len(l.Leafs) != 2 { 3910 t.Fatalf("Expected array to be len 2, got %v", len(l.Leafs)) 3911 } 3912 for _, ln := range l.Leafs { 3913 if ln.Account == acc1.Name { 3914 if ln.OutMsgs != 1 || ln.OutBytes == 0 || ln.InMsgs != 0 || ln.InBytes != 0 { 3915 t.Fatalf("Expected 1 OutMsgs/Bytes and 0 InMsgs/Bytes, got %+v", ln) 3916 } 3917 } else if ln.Account == acc2.Name { 3918 if ln.OutMsgs != 2 || ln.OutBytes == 0 || ln.InMsgs != 0 || ln.InBytes != 0 { 3919 t.Fatalf("Expected 2 OutMsgs/Bytes and 0 InMsgs/Bytes, got %+v", ln) 3920 } 3921 } else { 3922 t.Fatalf("Expected account to be %q or %q, got %q", acc1.Name, acc2.Name, ln.Account) 3923 } 3924 if ln.Name != "hub" { 3925 t.Fatalf("Expected name to be %q, got %q", "hub", ln.Name) 3926 } 3927 if !ln.IsSpoke { 3928 t.Fatal("Expected leafnode connection to be spoke") 3929 } 3930 if ln.RTT == "" { 3931 t.Fatalf("RTT not tracked?") 3932 } 3933 if ln.NumSubs != 3 { 3934 t.Fatalf("Expected 3 subs, got %v", ln.NumSubs) 3935 } 3936 if len(ln.Subs) != 3 { 3937 t.Fatalf("Expected subs to be returned, got %v", len(ln.Subs)) 3938 } 3939 var foundFoo bool 3940 var foundBar bool 3941 for _, sub := range ln.Subs { 3942 if sub == "foo" { 3943 foundFoo = true 3944 } else if sub == "bar" { 3945 foundBar = true 3946 } 3947 } 3948 if !foundFoo { 3949 t.Fatal("Did not find subject foo") 3950 } 3951 if !foundBar { 3952 t.Fatal("Did not find subject bar") 3953 } 3954 } 3955 } 3956 // Make sure that if we don't ask for subs, we don't get them 3957 pollURL = fmt.Sprintf("http://127.0.0.1:%d/leafz", sa.MonitorAddr().Port) 3958 for pollMode := 1; pollMode < 2; pollMode++ { 3959 l := pollLeafz(t, sa, pollMode, pollURL, nil) 3960 for _, ln := range l.Leafs { 3961 if ln.NumSubs != 3 { 3962 t.Fatalf("Number of subs should be 3, got %v", ln.NumSubs) 3963 } 3964 if len(ln.Subs) != 0 { 3965 t.Fatalf("Subs should not have been returned, got %v", ln.Subs) 3966 } 3967 } 3968 } 3969 // Make sure that we can request per account - existing account 3970 pollURL = fmt.Sprintf("http://127.0.0.1:%d/leafz?acc=%s", sa.MonitorAddr().Port, acc1.Name) 3971 for pollMode := 1; pollMode < 2; pollMode++ { 3972 l := pollLeafz(t, sa, pollMode, pollURL, &LeafzOptions{Account: acc1.Name}) 3973 for _, ln := range l.Leafs { 3974 if ln.Account != acc1.Name { 3975 t.Fatalf("Expected leaf node to be from account %s, got: %v", acc1.Name, ln) 3976 } 3977 } 3978 if len(l.Leafs) != 1 { 3979 t.Fatalf("Expected only two leaf node for this account, got: %v", len(l.Leafs)) 3980 } 3981 } 3982 // Make sure that we can request per account - non existing account 3983 pollURL = fmt.Sprintf("http://127.0.0.1:%d/leafz?acc=%s", sa.MonitorAddr().Port, "DOESNOTEXIST") 3984 for pollMode := 1; pollMode < 2; pollMode++ { 3985 l := pollLeafz(t, sa, pollMode, pollURL, &LeafzOptions{Account: "DOESNOTEXIST"}) 3986 if len(l.Leafs) != 0 { 3987 t.Fatalf("Expected no leaf node for this account, got: %v", len(l.Leafs)) 3988 } 3989 } 3990 // Now polling server B. 3991 pollURL = fmt.Sprintf("http://127.0.0.1:%d/leafz?subs=1", sb.MonitorAddr().Port) 3992 for pollMode := 1; pollMode < 2; pollMode++ { 3993 l := pollLeafz(t, sb, pollMode, pollURL, &LeafzOptions{Subscriptions: true}) 3994 if l.ID != sb.ID() { 3995 t.Fatalf("Expected ID to be %q, got %q", sb.ID(), l.ID) 3996 } 3997 if l.Now.IsZero() { 3998 t.Fatalf("Expected Now to be set, was not") 3999 } 4000 if l.NumLeafs != 2 { 4001 t.Fatalf("Expected NumLeafs to be 1, got %v", l.NumLeafs) 4002 } 4003 if len(l.Leafs) != 2 { 4004 t.Fatalf("Expected array to be len 2, got %v", len(l.Leafs)) 4005 } 4006 for _, ln := range l.Leafs { 4007 if ln.Account == acc1.Name { 4008 if ln.OutMsgs != 0 || ln.OutBytes != 0 || ln.InMsgs != 1 || ln.InBytes == 0 { 4009 t.Fatalf("Expected 1 InMsgs/Bytes and 0 OutMsgs/Bytes, got %+v", ln) 4010 } 4011 } else if ln.Account == acc2.Name { 4012 if ln.OutMsgs != 0 || ln.OutBytes != 0 || ln.InMsgs != 2 || ln.InBytes == 0 { 4013 t.Fatalf("Expected 2 InMsgs/Bytes and 0 OutMsgs/Bytes, got %+v", ln) 4014 } 4015 } else { 4016 t.Fatalf("Expected account to be %q or %q, got %q", acc1.Name, acc2.Name, ln.Account) 4017 } 4018 if ln.Name != leafName { 4019 t.Fatalf("Expected name to be %q, got %q", leafName, ln.Name) 4020 } 4021 if ln.IsSpoke { 4022 t.Fatal("Expected leafnode connection to be hub") 4023 } 4024 if ln.RTT == "" { 4025 t.Fatalf("RTT not tracked?") 4026 } 4027 // LDS should be only one. 4028 if ln.NumSubs != 5 || len(ln.Subs) != 5 { 4029 t.Fatalf("Expected 5 subs, got %v (%v)", ln.NumSubs, ln.Subs) 4030 } 4031 } 4032 } 4033 } 4034 4035 func TestMonitorAccountz(t *testing.T) { 4036 s := RunServer(DefaultMonitorOptions()) 4037 defer s.Shutdown() 4038 body := string(readBody(t, fmt.Sprintf("http://127.0.0.1:%d%s", s.MonitorAddr().Port, AccountzPath))) 4039 require_Contains(t, body, `$G`) 4040 require_Contains(t, body, `$SYS`) 4041 require_Contains(t, body, `"accounts": [`) 4042 require_Contains(t, body, `"system_account": "$SYS"`) 4043 4044 body = string(readBody(t, fmt.Sprintf("http://127.0.0.1:%d%s?acc=$SYS", s.MonitorAddr().Port, AccountzPath))) 4045 require_Contains(t, body, `"account_detail": {`) 4046 require_Contains(t, body, `"account_name": "$SYS",`) 4047 require_Contains(t, body, `"subscriptions": 50,`) 4048 require_Contains(t, body, `"is_system": true,`) 4049 require_Contains(t, body, `"system_account": "$SYS"`) 4050 4051 body = string(readBody(t, fmt.Sprintf("http://127.0.0.1:%d%s?unused=1", s.MonitorAddr().Port, AccountStatzPath))) 4052 require_Contains(t, body, `"acc": "$G"`) 4053 require_Contains(t, body, `"name": "$G"`) 4054 require_Contains(t, body, `"acc": "$SYS"`) 4055 require_Contains(t, body, `"name": "$SYS"`) 4056 require_Contains(t, body, `"sent": {`) 4057 require_Contains(t, body, `"received": {`) 4058 require_Contains(t, body, `"total_conns": 0,`) 4059 require_Contains(t, body, `"leafnodes": 0,`) 4060 } 4061 4062 func TestMonitorAccountzOperatorMode(t *testing.T) { 4063 _, sysPub := createKey(t) 4064 sysClaim := jwt.NewAccountClaims(sysPub) 4065 sysClaim.Name = "SYS" 4066 sysJwt := encodeClaim(t, sysClaim, sysPub) 4067 4068 accKp, accPub := createKey(t) 4069 accClaim := jwt.NewAccountClaims(accPub) 4070 accClaim.Name = "APP" 4071 accJwt := encodeClaim(t, accClaim, accPub) 4072 4073 conf := createConfFile(t, []byte(fmt.Sprintf(` 4074 listen: 127.0.0.1:-1 4075 http: 127.0.0.1:-1 4076 operator = %s 4077 resolver = MEMORY 4078 system_account: %s 4079 resolver_preload = { 4080 %s : %s 4081 %s : %s 4082 } 4083 `, ojwt, sysPub, accPub, accJwt, sysPub, sysJwt))) 4084 4085 s, _ := RunServerWithConfig(conf) 4086 defer s.Shutdown() 4087 4088 createUser := func() (string, string) { 4089 ukp, _ := nkeys.CreateUser() 4090 seed, _ := ukp.Seed() 4091 upub, _ := ukp.PublicKey() 4092 uclaim := newJWTTestUserClaims() 4093 uclaim.Subject = upub 4094 ujwt, err := uclaim.Encode(accKp) 4095 require_NoError(t, err) 4096 return upub, genCredsFile(t, ujwt, seed) 4097 } 4098 4099 _, aCreds := createUser() 4100 4101 nc, err := nats.Connect(s.ClientURL(), nats.UserCredentials(aCreds)) 4102 require_NoError(t, err) 4103 defer nc.Close() 4104 4105 body := string(readBody(t, fmt.Sprintf("http://127.0.0.1:%d%s", s.MonitorAddr().Port, AccountzPath))) 4106 require_Contains(t, body, accPub) 4107 require_Contains(t, body, sysPub) 4108 require_Contains(t, body, `"accounts": [`) 4109 require_Contains(t, body, fmt.Sprintf(`"system_account": "%s"`, sysPub)) 4110 4111 body = string(readBody(t, fmt.Sprintf("http://127.0.0.1:%d%s?acc=%s", s.MonitorAddr().Port, AccountzPath, sysPub))) 4112 require_Contains(t, body, `"account_detail": {`) 4113 require_Contains(t, body, fmt.Sprintf(`"account_name": "%s",`, sysPub)) 4114 require_Contains(t, body, `"subscriptions": 50,`) 4115 require_Contains(t, body, `"is_system": true,`) 4116 require_Contains(t, body, fmt.Sprintf(`"system_account": "%s"`, sysPub)) 4117 4118 // TODO: understand why the APP account did not show up in the accountz detail 4119 // even though unused is set. It required a connection to be made to show up. 4120 body = string(readBody(t, fmt.Sprintf("http://127.0.0.1:%d%s?unused=1", s.MonitorAddr().Port, AccountStatzPath))) 4121 require_Contains(t, body, fmt.Sprintf(`"acc": "%s"`, accPub)) 4122 require_Contains(t, body, fmt.Sprintf(`"name": "%s"`, accClaim.Name)) 4123 require_Contains(t, body, fmt.Sprintf(`"acc": "%s"`, sysPub)) 4124 require_Contains(t, body, fmt.Sprintf(`"name": "%s"`, sysClaim.Name)) 4125 require_Contains(t, body, `"sent": {`) 4126 require_Contains(t, body, `"received": {`) 4127 require_Contains(t, body, `"total_conns": 0,`) 4128 require_Contains(t, body, `"leafnodes": 0,`) 4129 } 4130 4131 func TestMonitorAuthorizedUsers(t *testing.T) { 4132 kp, _ := nkeys.FromSeed(seed) 4133 usrNKey, _ := kp.PublicKey() 4134 opts := DefaultMonitorOptions() 4135 opts.Nkeys = []*NkeyUser{{Nkey: string(usrNKey)}} 4136 opts.Users = []*User{{Username: "user", Password: "pwd"}} 4137 s := RunServer(opts) 4138 defer s.Shutdown() 4139 4140 checkAuthUser := func(expected string) { 4141 t.Helper() 4142 resetPreviousHTTPConnections() 4143 url := fmt.Sprintf("http://127.0.0.1:%d/connz?auth=true", s.MonitorAddr().Port) 4144 for mode := 0; mode < 2; mode++ { 4145 connz := pollConz(t, s, mode, url, &ConnzOptions{Username: true}) 4146 if l := len(connz.Conns); l != 1 { 4147 t.Fatalf("Expected 1, got %v", l) 4148 } 4149 conn := connz.Conns[0] 4150 au := conn.AuthorizedUser 4151 if au == _EMPTY_ { 4152 t.Fatal("AuthorizedUser is empty!") 4153 } 4154 if au != expected { 4155 t.Fatalf("Expected %q, got %q", expected, au) 4156 } 4157 } 4158 } 4159 4160 c := natsConnect(t, fmt.Sprintf("nats://user:pwd@127.0.0.1:%d", opts.Port)) 4161 defer c.Close() 4162 checkAuthUser("user") 4163 c.Close() 4164 4165 c = natsConnect(t, fmt.Sprintf("nats://127.0.0.1:%d", opts.Port), 4166 nats.Nkey(usrNKey, func(nonce []byte) ([]byte, error) { 4167 return kp.Sign(nonce) 4168 })) 4169 defer c.Close() 4170 // we should get the user's NKey 4171 checkAuthUser(usrNKey) 4172 c.Close() 4173 4174 s.Shutdown() 4175 opts = DefaultMonitorOptions() 4176 opts.Authorization = "sometoken" 4177 s = RunServer(opts) 4178 defer s.Shutdown() 4179 4180 c = natsConnect(t, fmt.Sprintf("nats://127.0.0.1:%d", opts.Port), 4181 nats.Token("sometoken")) 4182 defer c.Close() 4183 // We should get the token specified by the user 4184 checkAuthUser("sometoken") 4185 c.Close() 4186 s.Shutdown() 4187 4188 opts = DefaultMonitorOptions() 4189 // User an operator seed 4190 kp, _ = nkeys.FromSeed(oSeed) 4191 pub, _ := kp.PublicKey() 4192 opts.TrustedKeys = []string{pub} 4193 s = RunServer(opts) 4194 defer s.Shutdown() 4195 4196 akp, _ := nkeys.CreateAccount() 4197 apub, _ := akp.PublicKey() 4198 nac := jwt.NewAccountClaims(apub) 4199 ajwt, err := nac.Encode(oKp) 4200 if err != nil { 4201 t.Fatalf("Error generating account JWT: %v", err) 4202 } 4203 4204 nkp, _ := nkeys.CreateUser() 4205 upub, _ := nkp.PublicKey() 4206 nuc := jwt.NewUserClaims(upub) 4207 jwt, err := nuc.Encode(akp) 4208 if err != nil { 4209 t.Fatalf("Error generating user JWT: %v", err) 4210 } 4211 4212 buildMemAccResolver(s) 4213 addAccountToMemResolver(s, apub, ajwt) 4214 4215 c = natsConnect(t, fmt.Sprintf("nats://127.0.0.1:%d", opts.Port), 4216 nats.UserJWT( 4217 func() (string, error) { return jwt, nil }, 4218 func(nonce []byte) ([]byte, error) { return nkp.Sign(nonce) })) 4219 defer c.Close() 4220 // we should get the user's pubkey 4221 checkAuthUser(upub) 4222 } 4223 4224 // Helper function to check that a JS cluster is formed 4225 func checkForJSClusterUp(t *testing.T, servers ...*Server) { 4226 t.Helper() 4227 // We will use the other JetStream helpers here. 4228 c := &cluster{t: t, servers: servers} 4229 c.checkClusterFormed() 4230 c.waitOnClusterReady() 4231 } 4232 4233 func TestMonitorJszNonJszServer(t *testing.T) { 4234 srv := RunServer(DefaultOptions()) 4235 defer srv.Shutdown() 4236 4237 if !srv.ReadyForConnections(5 * time.Second) { 4238 t.Fatalf("server did not become ready") 4239 } 4240 4241 jsi, err := srv.Jsz(&JSzOptions{}) 4242 if err != nil { 4243 t.Fatalf("jsi failed: %v", err) 4244 } 4245 if jsi.ID != srv.ID() { 4246 t.Fatalf("did not receive valid info") 4247 } 4248 4249 jsi, err = srv.Jsz(&JSzOptions{LeaderOnly: true}) 4250 if !errors.Is(err, errSkipZreq) { 4251 t.Fatalf("expected a skip z req error: %v", err) 4252 } 4253 if jsi != nil { 4254 t.Fatalf("expected no jsi: %v", jsi) 4255 } 4256 } 4257 4258 func TestMonitorJsz(t *testing.T) { 4259 readJsInfo := func(url string) *JSInfo { 4260 t.Helper() 4261 body := readBody(t, url) 4262 info := &JSInfo{} 4263 err := json.Unmarshal(body, info) 4264 require_NoError(t, err) 4265 return info 4266 } 4267 srvs := []*Server{} 4268 for _, test := range []struct { 4269 port int 4270 mport int 4271 cport int 4272 routed int 4273 }{ 4274 {7500, 7501, 7502, 5502}, 4275 {5500, 5501, 5502, 7502}, 4276 } { 4277 tmpDir := t.TempDir() 4278 cf := createConfFile(t, []byte(fmt.Sprintf(` 4279 listen: 127.0.0.1:%d 4280 http: 127.0.0.1:%d 4281 system_account: SYS 4282 accounts { 4283 SYS { 4284 users [{user: sys, password: pwd}] 4285 } 4286 ACC { 4287 users [{user: usr, password: pwd}] 4288 // In clustered mode, these reservations will not impact any one server. 4289 jetstream: {max_store: 4Mb, max_memory: 5Mb} 4290 } 4291 BCC_TO_HAVE_ONE_EXTRA { 4292 users [{user: usr2, password: pwd}] 4293 jetstream: enabled 4294 } 4295 } 4296 jetstream: { 4297 max_mem_store: 10Mb 4298 max_file_store: 10Mb 4299 store_dir: '%s' 4300 unique_tag: az 4301 } 4302 cluster { 4303 name: cluster_name 4304 listen: 127.0.0.1:%d 4305 routes: [nats-route://127.0.0.1:%d] 4306 } 4307 server_name: server_%d 4308 server_tags: [ "az:%d" ] `, test.port, test.mport, tmpDir, test.cport, test.routed, test.port, test.port))) 4309 4310 s, _ := RunServerWithConfig(cf) 4311 defer s.Shutdown() 4312 srvs = append(srvs, s) 4313 } 4314 checkClusterFormed(t, srvs...) 4315 checkForJSClusterUp(t, srvs...) 4316 4317 nc := natsConnect(t, "nats://usr:pwd@127.0.0.1:7500") 4318 defer nc.Close() 4319 js, err := nc.JetStream(nats.MaxWait(5 * time.Second)) 4320 require_NoError(t, err) 4321 _, err = js.AddStream(&nats.StreamConfig{ 4322 Name: "my-stream-replicated", 4323 Subjects: []string{"foo", "bar"}, 4324 Replicas: 2, 4325 }) 4326 require_NoError(t, err) 4327 _, err = js.AddStream(&nats.StreamConfig{ 4328 Name: "my-stream-non-replicated", 4329 Subjects: []string{"baz"}, 4330 Replicas: 1, 4331 }) 4332 require_NoError(t, err) 4333 _, err = js.AddStream(&nats.StreamConfig{ 4334 Name: "my-stream-mirror", 4335 Replicas: 2, 4336 Mirror: &nats.StreamSource{ 4337 Name: "my-stream-replicated", 4338 }, 4339 }) 4340 require_NoError(t, err) 4341 _, err = js.AddConsumer("my-stream-replicated", &nats.ConsumerConfig{ 4342 Durable: "my-consumer-replicated", 4343 AckPolicy: nats.AckExplicitPolicy, 4344 }) 4345 require_NoError(t, err) 4346 _, err = js.AddConsumer("my-stream-non-replicated", &nats.ConsumerConfig{ 4347 Durable: "my-consumer-non-replicated", 4348 AckPolicy: nats.AckExplicitPolicy, 4349 }) 4350 require_NoError(t, err) 4351 _, err = js.AddConsumer("my-stream-mirror", &nats.ConsumerConfig{ 4352 Durable: "my-consumer-mirror", 4353 AckPolicy: nats.AckExplicitPolicy, 4354 }) 4355 require_NoError(t, err) 4356 nc.Flush() 4357 _, err = js.Publish("foo", nil) 4358 require_NoError(t, err) 4359 // Wait for mirror replication 4360 time.Sleep(200 * time.Millisecond) 4361 4362 monUrl1 := fmt.Sprintf("http://127.0.0.1:%d/jsz", 7501) 4363 monUrl2 := fmt.Sprintf("http://127.0.0.1:%d/jsz", 5501) 4364 4365 t.Run("default", func(t *testing.T) { 4366 for _, url := range []string{monUrl1, monUrl2} { 4367 info := readJsInfo(url) 4368 if len(info.AccountDetails) != 0 { 4369 t.Fatalf("expected no account to be returned by %s but got %v", url, info) 4370 } 4371 if info.Streams == 0 { 4372 t.Fatalf("expected stream count to be 3 but got %d", info.Streams) 4373 } 4374 if info.Consumers == 0 { 4375 t.Fatalf("expected consumer count to be 3 but got %d", info.Consumers) 4376 } 4377 if info.Messages != 2 { 4378 t.Fatalf("expected two message but got %d", info.Messages) 4379 } 4380 } 4381 }) 4382 t.Run("accounts", func(t *testing.T) { 4383 for _, url := range []string{monUrl1, monUrl2} { 4384 info := readJsInfo(url + "?accounts=true") 4385 if len(info.AccountDetails) != 2 { 4386 t.Fatalf("expected both accounts to be returned by %s but got %v", url, info) 4387 } 4388 } 4389 }) 4390 t.Run("accounts reserved metrics", func(t *testing.T) { 4391 for _, url := range []string{monUrl1, monUrl2} { 4392 info := readJsInfo(url + "?accounts=true&acc=ACC") 4393 if len(info.AccountDetails) != 1 { 4394 t.Fatalf("expected single account") 4395 } 4396 acc := info.AccountDetails[0] 4397 got := int(acc.ReservedMemory) 4398 expected := 5242880 4399 if got != expected { 4400 t.Errorf("Expected: %v, got: %v", expected, got) 4401 } 4402 got = int(acc.ReservedStore) 4403 expected = 4194304 4404 if got != expected { 4405 t.Errorf("Expected: %v, got: %v", expected, got) 4406 } 4407 4408 info = readJsInfo(url + "?accounts=true&acc=BCC_TO_HAVE_ONE_EXTRA") 4409 if len(info.AccountDetails) != 1 { 4410 t.Fatalf("expected single account") 4411 } 4412 acc = info.AccountDetails[0] 4413 got = int(acc.ReservedMemory) 4414 expected = -1 4415 if got != expected { 4416 t.Errorf("Expected: %v, got: %v", expected, got) 4417 } 4418 got = int(acc.ReservedStore) 4419 expected = -1 4420 if got != expected { 4421 t.Errorf("Expected: %v, got: %v", expected, got) 4422 } 4423 } 4424 }) 4425 t.Run("offset-too-big", func(t *testing.T) { 4426 for _, url := range []string{monUrl1, monUrl2} { 4427 info := readJsInfo(url + "?accounts=true&offset=10") 4428 if len(info.AccountDetails) != 0 { 4429 t.Fatalf("expected no accounts to be returned by %s but got %v", url, info) 4430 } 4431 } 4432 }) 4433 t.Run("limit", func(t *testing.T) { 4434 for _, url := range []string{monUrl1, monUrl2} { 4435 info := readJsInfo(url + "?accounts=true&limit=1") 4436 if len(info.AccountDetails) != 1 { 4437 t.Fatalf("expected one account to be returned by %s but got %v", url, info) 4438 } 4439 if info := readJsInfo(url + "?accounts=true&offset=1&limit=1"); len(info.AccountDetails) != 1 { 4440 t.Fatalf("expected one account to be returned by %s but got %v", url, info) 4441 } 4442 } 4443 }) 4444 t.Run("offset-stable", func(t *testing.T) { 4445 for _, url := range []string{monUrl1, monUrl2} { 4446 info1 := readJsInfo(url + "?accounts=true&offset=1&limit=1") 4447 if len(info1.AccountDetails) != 1 { 4448 t.Fatalf("expected one account to be returned by %s but got %v", url, info1) 4449 } 4450 info2 := readJsInfo(url + "?accounts=true&offset=1&limit=1") 4451 if len(info2.AccountDetails) != 1 { 4452 t.Fatalf("expected one account to be returned by %s but got %v", url, info2) 4453 } 4454 if info1.AccountDetails[0].Name != info2.AccountDetails[0].Name { 4455 t.Fatalf("absent changes, same offset should result in same account but gut: %v %v", 4456 info1.AccountDetails[0].Name, info2.AccountDetails[0].Name) 4457 } 4458 } 4459 }) 4460 t.Run("filter-account", func(t *testing.T) { 4461 for _, url := range []string{monUrl1, monUrl2} { 4462 info := readJsInfo(url + "?acc=ACC") 4463 if len(info.AccountDetails) != 1 { 4464 t.Fatalf("expected account ACC to be returned by %s but got %v", url, info) 4465 } 4466 if info.AccountDetails[0].Name != "ACC" { 4467 t.Fatalf("expected account ACC to be returned by %s but got %v", url, info) 4468 } 4469 if len(info.AccountDetails[0].Streams) != 0 { 4470 t.Fatalf("expected account ACC to be returned by %s but got %v", url, info) 4471 } 4472 } 4473 }) 4474 t.Run("streams", func(t *testing.T) { 4475 for _, url := range []string{monUrl1, monUrl2} { 4476 info := readJsInfo(url + "?acc=ACC&streams=true") 4477 if len(info.AccountDetails) != 1 { 4478 t.Fatalf("expected account ACC to be returned by %s but got %v", url, info) 4479 } 4480 if len(info.AccountDetails[0].Streams) == 0 { 4481 t.Fatalf("expected streams to be returned by %s but got %v", url, info) 4482 } 4483 if len(info.AccountDetails[0].Streams[0].Consumer) != 0 { 4484 t.Fatalf("expected no consumers to be returned by %s but got %v", url, info) 4485 } 4486 } 4487 }) 4488 t.Run("consumers", func(t *testing.T) { 4489 for _, url := range []string{monUrl1, monUrl2} { 4490 info := readJsInfo(url + "?acc=ACC&consumers=true") 4491 if len(info.AccountDetails) != 1 { 4492 t.Fatalf("expected account ACC to be returned by %s but got %v", url, info) 4493 } 4494 if len(info.AccountDetails[0].Streams[0].Consumer) == 0 { 4495 t.Fatalf("expected consumers to be returned by %s but got %v", url, info) 4496 } 4497 if info.AccountDetails[0].Streams[0].Config != nil { 4498 t.Fatal("Config expected to not be present") 4499 } 4500 if info.AccountDetails[0].Streams[0].Consumer[0].Config != nil { 4501 t.Fatal("Config expected to not be present") 4502 } 4503 if len(info.AccountDetails[0].Streams[0].ConsumerRaftGroups) != 0 { 4504 t.Fatalf("expected consumer raft groups to not be returned by %s but got %v", url, info) 4505 } 4506 } 4507 }) 4508 t.Run("config", func(t *testing.T) { 4509 for _, url := range []string{monUrl1, monUrl2} { 4510 info := readJsInfo(url + "?acc=ACC&consumers=true&config=true") 4511 if len(info.AccountDetails) != 1 { 4512 t.Fatalf("expected account ACC to be returned by %s but got %v", url, info) 4513 } 4514 if info.AccountDetails[0].Streams[0].Config == nil { 4515 t.Fatal("Config expected to be present") 4516 } 4517 if info.AccountDetails[0].Streams[0].Consumer[0].Config == nil { 4518 t.Fatal("Config expected to be present") 4519 } 4520 } 4521 }) 4522 t.Run("replication", func(t *testing.T) { 4523 // The replication lag may only be present on the leader 4524 replicationFound := false 4525 for _, url := range []string{monUrl1, monUrl2} { 4526 info := readJsInfo(url + "?acc=ACC&streams=true") 4527 if len(info.AccountDetails) != 1 { 4528 t.Fatalf("expected account ACC to be returned by %s but got %v", url, info) 4529 } 4530 streamFound := false 4531 for _, stream := range info.AccountDetails[0].Streams { 4532 if stream.Name == "my-stream-mirror" { 4533 streamFound = true 4534 if stream.Mirror != nil { 4535 replicationFound = true 4536 } 4537 } 4538 } 4539 if !streamFound { 4540 t.Fatalf("Did not locate my-stream-mirror stream in results") 4541 } 4542 } 4543 if !replicationFound { 4544 t.Fatal("ReplicationLag expected to be present for my-stream-mirror stream") 4545 } 4546 }) 4547 t.Run("cluster-info", func(t *testing.T) { 4548 found := 0 4549 for i, url := range []string{monUrl1, monUrl2} { 4550 info := readJsInfo(url + "") 4551 if info.Meta.Peer != getHash(info.Meta.Leader) { 4552 t.Fatalf("Invalid Peer: %+v", info.Meta) 4553 } 4554 if info.Meta.Replicas != nil { 4555 found++ 4556 for _, r := range info.Meta.Replicas { 4557 if r.Peer == _EMPTY_ { 4558 t.Fatalf("Replicas' Peer is empty: %+v", r) 4559 } 4560 } 4561 if info.Meta.Leader != srvs[i].Name() { 4562 t.Fatalf("received cluster info from non leader: leader %s, server: %s", info.Meta.Leader, srvs[i].Name()) 4563 } 4564 } 4565 } 4566 if found == 0 { 4567 t.Fatalf("did not receive cluster info from any node") 4568 } 4569 if found > 1 { 4570 t.Fatalf("received cluster info from multiple nodes") 4571 } 4572 }) 4573 t.Run("account-non-existing", func(t *testing.T) { 4574 for _, url := range []string{monUrl1, monUrl2} { 4575 info := readJsInfo(url + "?acc=DOES_NOT_EXIST") 4576 if len(info.AccountDetails) != 0 { 4577 t.Fatalf("expected no account to be returned by %s but got %v", url, info) 4578 } 4579 } 4580 }) 4581 t.Run("account-non-existing-with-stream-details", func(t *testing.T) { 4582 for _, url := range []string{monUrl1, monUrl2} { 4583 info := readJsInfo(url + "?acc=DOES_NOT_EXIST&streams=true") 4584 if len(info.AccountDetails) != 0 { 4585 t.Fatalf("expected no account to be returned by %s but got %v", url, info) 4586 } 4587 } 4588 }) 4589 t.Run("unique-tag-exists", func(t *testing.T) { 4590 for _, url := range []string{monUrl1, monUrl2} { 4591 info := readJsInfo(url) 4592 if len(info.Config.UniqueTag) == 0 { 4593 t.Fatalf("expected unique_tag to be returned by %s but got %v", url, info) 4594 } 4595 } 4596 }) 4597 t.Run("raftgroups", func(t *testing.T) { 4598 for _, url := range []string{monUrl1, monUrl2} { 4599 info := readJsInfo(url + "?acc=ACC&consumers=true&raft=true") 4600 if len(info.AccountDetails) != 1 { 4601 t.Fatalf("expected account ACC to be returned by %s but got %v", url, info) 4602 } 4603 4604 // We will have two streams and order is not guaranteed. So grab the one we want. 4605 var si StreamDetail 4606 if info.AccountDetails[0].Streams[0].Name == "my-stream-replicated" { 4607 si = info.AccountDetails[0].Streams[0] 4608 } else { 4609 si = info.AccountDetails[0].Streams[1] 4610 } 4611 4612 if len(si.Consumer) == 0 { 4613 t.Fatalf("expected consumers to be returned by %s but got %v", url, info) 4614 } 4615 if len(si.ConsumerRaftGroups) == 0 { 4616 t.Fatalf("expected consumer raft groups to be returned by %s but got %v", url, info) 4617 } 4618 if len(si.RaftGroup) == 0 { 4619 t.Fatal("expected stream raft group info to be included") 4620 } 4621 crgroup := si.ConsumerRaftGroups[0] 4622 if crgroup.Name != "my-consumer-replicated" && crgroup.Name != "my-consumer-mirror" { 4623 t.Fatalf("expected consumer name to be included in raft group info, got: %v", crgroup.Name) 4624 } 4625 if len(crgroup.RaftGroup) == 0 { 4626 t.Fatal("expected consumer raft group info to be included") 4627 } 4628 } 4629 }) 4630 } 4631 4632 func TestMonitorReloadTLSConfig(t *testing.T) { 4633 template := ` 4634 listen: "127.0.0.1:-1" 4635 https: "127.0.0.1:-1" 4636 tls { 4637 cert_file: '%s' 4638 key_file: '%s' 4639 ca_file: '../test/configs/certs/ca.pem' 4640 4641 # Set this to make sure that it does not impact secure monitoring 4642 # (which it did, see issue: https://github.com/nats-io/nats-server/issues/2980) 4643 verify_and_map: true 4644 } 4645 ` 4646 conf := createConfFile(t, []byte(fmt.Sprintf(template, 4647 "../test/configs/certs/server-noip.pem", 4648 "../test/configs/certs/server-key-noip.pem"))) 4649 4650 s, _ := RunServerWithConfig(conf) 4651 defer s.Shutdown() 4652 4653 addr := fmt.Sprintf("127.0.0.1:%d", s.MonitorAddr().Port) 4654 c, err := net.Dial("tcp", addr) 4655 if err != nil { 4656 t.Fatalf("Error creating ws connection: %v", err) 4657 } 4658 defer c.Close() 4659 4660 tc := &TLSConfigOpts{CaFile: "../test/configs/certs/ca.pem"} 4661 tlsConfig, err := GenTLSConfig(tc) 4662 if err != nil { 4663 t.Fatalf("Error generating TLS config: %v", err) 4664 } 4665 tlsConfig.ServerName = "127.0.0.1" 4666 tlsConfig.RootCAs = tlsConfig.ClientCAs 4667 tlsConfig.ClientCAs = nil 4668 c = tls.Client(c, tlsConfig.Clone()) 4669 if err := c.(*tls.Conn).Handshake(); err == nil || !strings.Contains(err.Error(), "SAN") { 4670 t.Fatalf("Unexpected error: %v", err) 4671 } 4672 c.Close() 4673 4674 reloadUpdateConfig(t, s, conf, fmt.Sprintf(template, 4675 "../test/configs/certs/server-cert.pem", 4676 "../test/configs/certs/server-key.pem")) 4677 4678 c, err = net.Dial("tcp", addr) 4679 if err != nil { 4680 t.Fatalf("Error creating ws connection: %v", err) 4681 } 4682 defer c.Close() 4683 4684 c = tls.Client(c, tlsConfig.Clone()) 4685 if err := c.(*tls.Conn).Handshake(); err != nil { 4686 t.Fatalf("Error on TLS handshake: %v", err) 4687 } 4688 4689 // Need to read something to see if there is a problem with the certificate or not. 4690 var buf [64]byte 4691 c.SetReadDeadline(time.Now().Add(250 * time.Millisecond)) 4692 _, err = c.Read(buf[:]) 4693 if ne, ok := err.(net.Error); !ok || !ne.Timeout() { 4694 t.Fatalf("Error: %v", err) 4695 } 4696 } 4697 4698 func TestMonitorMQTT(t *testing.T) { 4699 o := DefaultOptions() 4700 o.HTTPHost = "127.0.0.1" 4701 o.HTTPPort = -1 4702 o.ServerName = "mqtt_server" 4703 o.Users = []*User{{Username: "someuser"}} 4704 pinnedCerts := make(PinnedCertSet) 4705 pinnedCerts["7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"] = struct{}{} 4706 o.MQTT = MQTTOpts{ 4707 Host: "127.0.0.1", 4708 Port: -1, 4709 NoAuthUser: "someuser", 4710 JsDomain: "js", 4711 AuthTimeout: 2.0, 4712 TLSMap: true, 4713 TLSTimeout: 3.0, 4714 TLSPinnedCerts: pinnedCerts, 4715 AckWait: 4 * time.Second, 4716 MaxAckPending: 256, 4717 } 4718 s := RunServer(o) 4719 defer s.Shutdown() 4720 4721 expected := &MQTTOptsVarz{ 4722 Host: "127.0.0.1", 4723 Port: o.MQTT.Port, 4724 NoAuthUser: "someuser", 4725 JsDomain: "js", 4726 AuthTimeout: 2.0, 4727 TLSMap: true, 4728 TLSTimeout: 3.0, 4729 TLSPinnedCerts: []string{"7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"}, 4730 AckWait: 4 * time.Second, 4731 MaxAckPending: 256, 4732 } 4733 url := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 4734 for mode := 0; mode < 2; mode++ { 4735 v := pollVarz(t, s, mode, url, nil) 4736 vm := &v.MQTT 4737 if !reflect.DeepEqual(vm, expected) { 4738 t.Fatalf("Expected\n%+v\nGot:\n%+v", expected, vm) 4739 } 4740 } 4741 } 4742 4743 func TestMonitorWebsocket(t *testing.T) { 4744 o := DefaultOptions() 4745 o.HTTPHost = "127.0.0.1" 4746 o.HTTPPort = -1 4747 kp, _ := nkeys.FromSeed(oSeed) 4748 pub, _ := kp.PublicKey() 4749 o.TrustedKeys = []string{pub} 4750 o.Users = []*User{{Username: "someuser"}} 4751 pinnedCerts := make(PinnedCertSet) 4752 pinnedCerts["7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"] = struct{}{} 4753 o.Websocket = WebsocketOpts{ 4754 Host: "127.0.0.1", 4755 Port: -1, 4756 Advertise: "somehost:8080", 4757 NoAuthUser: "someuser", 4758 JWTCookie: "somecookiename", 4759 AuthTimeout: 2.0, 4760 NoTLS: true, 4761 TLSMap: true, 4762 TLSPinnedCerts: pinnedCerts, 4763 SameOrigin: true, 4764 AllowedOrigins: []string{"origin1", "origin2"}, 4765 Compression: true, 4766 HandshakeTimeout: 4 * time.Second, 4767 } 4768 s := RunServer(o) 4769 defer s.Shutdown() 4770 4771 expected := &WebsocketOptsVarz{ 4772 Host: "127.0.0.1", 4773 Port: o.Websocket.Port, 4774 Advertise: "somehost:8080", 4775 NoAuthUser: "someuser", 4776 JWTCookie: "somecookiename", 4777 AuthTimeout: 2.0, 4778 NoTLS: true, 4779 TLSMap: true, 4780 TLSPinnedCerts: []string{"7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"}, 4781 SameOrigin: true, 4782 AllowedOrigins: []string{"origin1", "origin2"}, 4783 Compression: true, 4784 HandshakeTimeout: 4 * time.Second, 4785 } 4786 url := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 4787 for mode := 0; mode < 2; mode++ { 4788 v := pollVarz(t, s, mode, url, nil) 4789 vw := &v.Websocket 4790 if !reflect.DeepEqual(vw, expected) { 4791 t.Fatalf("Expected\n%+v\nGot:\n%+v", expected, vw) 4792 } 4793 } 4794 } 4795 4796 func TestServerIDZRequest(t *testing.T) { 4797 conf := createConfFile(t, []byte(` 4798 listen: 127.0.0.1:-1 4799 server_name: TEST22 4800 # For access to system account. 4801 accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } 4802 `)) 4803 defer removeFile(t, conf) 4804 4805 s, _ := RunServerWithConfig(conf) 4806 defer s.Shutdown() 4807 4808 nc, err := nats.Connect(s.ClientURL(), nats.UserInfo("admin", "s3cr3t!")) 4809 require_NoError(t, err) 4810 4811 subject := fmt.Sprintf(serverPingReqSubj, "IDZ") 4812 resp, err := nc.Request(subject, nil, time.Second) 4813 require_NoError(t, err) 4814 4815 var sid ServerID 4816 err = json.Unmarshal(resp.Data, &sid) 4817 require_NoError(t, err) 4818 4819 require_True(t, sid.Name == "TEST22") 4820 require_True(t, strings.HasPrefix(sid.ID, "N")) 4821 } 4822 4823 func TestMonitorProfilez(t *testing.T) { 4824 s := RunServer(DefaultOptions()) 4825 defer s.Shutdown() 4826 4827 // Then start profiling. 4828 s.StartProfiler() 4829 4830 // Now check that all of the profiles that we expect are 4831 // returning instead of erroring. 4832 for _, try := range []*ProfilezOptions{ 4833 {Name: "allocs", Debug: 0}, 4834 {Name: "allocs", Debug: 1}, 4835 {Name: "block", Debug: 0}, 4836 {Name: "goroutine", Debug: 0}, 4837 {Name: "goroutine", Debug: 1}, 4838 {Name: "goroutine", Debug: 2}, 4839 {Name: "heap", Debug: 0}, 4840 {Name: "heap", Debug: 1}, 4841 {Name: "mutex", Debug: 0}, 4842 {Name: "threadcreate", Debug: 0}, 4843 } { 4844 if ps := s.profilez(try); ps.Error != _EMPTY_ { 4845 t.Fatalf("Unexpected error on %v: %s", try, ps.Error) 4846 } 4847 } 4848 } 4849 4850 func TestMonitorRoutePoolSize(t *testing.T) { 4851 conf1 := createConfFile(t, []byte(` 4852 port: -1 4853 http: -1 4854 cluster { 4855 port: -1 4856 name: "local" 4857 pool_size: 5 4858 } 4859 no_sys_acc: true 4860 `)) 4861 defer removeFile(t, conf1) 4862 s1, o1 := RunServerWithConfig(conf1) 4863 defer s1.Shutdown() 4864 4865 conf23 := createConfFile(t, []byte(fmt.Sprintf(` 4866 port: -1 4867 http: -1 4868 cluster { 4869 port: -1 4870 name: "local" 4871 routes: ["nats://127.0.0.1:%d"] 4872 pool_size: 5 4873 } 4874 no_sys_acc: true 4875 `, o1.Cluster.Port))) 4876 defer removeFile(t, conf23) 4877 4878 s2, _ := RunServerWithConfig(conf23) 4879 defer s2.Shutdown() 4880 s3, _ := RunServerWithConfig(conf23) 4881 defer s3.Shutdown() 4882 4883 checkClusterFormed(t, s1, s2, s3) 4884 4885 for i, s := range []*Server{s1, s2, s3} { 4886 url := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 4887 for mode := 0; mode < 2; mode++ { 4888 v := pollVarz(t, s, mode, url, nil) 4889 if v.Cluster.PoolSize != 5 { 4890 t.Fatalf("Expected Cluster.PoolSize==5, got %v", v.Cluster.PoolSize) 4891 } 4892 if v.Remotes != 2 { 4893 t.Fatalf("Expected Remotes==2, got %v", v.Remotes) 4894 } 4895 if v.Routes != 10 { 4896 t.Fatalf("Expected NumRoutes==10, got %v", v.Routes) 4897 } 4898 } 4899 4900 url = fmt.Sprintf("http://127.0.0.1:%d/routez", s.MonitorAddr().Port) 4901 for mode := 0; mode < 2; mode++ { 4902 v := pollRoutez(t, s, mode, url, nil) 4903 if v.NumRoutes != 10 { 4904 t.Fatalf("Expected NumRoutes==10, got %v", v.NumRoutes) 4905 } 4906 if n := len(v.Routes); n != 10 { 4907 t.Fatalf("Expected len(Routes)==10, got %v", n) 4908 } 4909 remotes := make(map[string]int) 4910 for _, r := range v.Routes { 4911 remotes[r.RemoteID]++ 4912 } 4913 if n := len(remotes); n != 2 { 4914 t.Fatalf("Expected routes for 2 different servers, got %v", n) 4915 } 4916 switch i { 4917 case 0: 4918 if n := remotes[s2.ID()]; n != 5 { 4919 t.Fatalf("Expected 5 routes from S1 to S2, got %v", n) 4920 } 4921 if n := remotes[s3.ID()]; n != 5 { 4922 t.Fatalf("Expected 5 routes from S1 to S3, got %v", n) 4923 } 4924 case 1: 4925 if n := remotes[s1.ID()]; n != 5 { 4926 t.Fatalf("Expected 5 routes from S2 to S1, got %v", n) 4927 } 4928 if n := remotes[s3.ID()]; n != 5 { 4929 t.Fatalf("Expected 5 routes from S2 to S3, got %v", n) 4930 } 4931 case 2: 4932 if n := remotes[s1.ID()]; n != 5 { 4933 t.Fatalf("Expected 5 routes from S3 to S1, got %v", n) 4934 } 4935 if n := remotes[s2.ID()]; n != 5 { 4936 t.Fatalf("Expected 5 routes from S3 to S2, got %v", n) 4937 } 4938 } 4939 } 4940 } 4941 } 4942 4943 func TestMonitorRoutePerAccount(t *testing.T) { 4944 conf1 := createConfFile(t, []byte(` 4945 port: -1 4946 http: -1 4947 accounts { 4948 A { users: [{user: "a", password: "pwd"}] } 4949 } 4950 cluster { 4951 port: -1 4952 name: "local" 4953 accounts: ["A"] 4954 } 4955 `)) 4956 defer removeFile(t, conf1) 4957 s1, o1 := RunServerWithConfig(conf1) 4958 defer s1.Shutdown() 4959 4960 conf23 := createConfFile(t, []byte(fmt.Sprintf(` 4961 port: -1 4962 http: -1 4963 accounts { 4964 A { users: [{user: "a", password: "pwd"}] } 4965 } 4966 cluster { 4967 port: -1 4968 name: "local" 4969 routes: ["nats://127.0.0.1:%d"] 4970 accounts: ["A"] 4971 } 4972 `, o1.Cluster.Port))) 4973 defer removeFile(t, conf23) 4974 4975 s2, _ := RunServerWithConfig(conf23) 4976 defer s2.Shutdown() 4977 s3, _ := RunServerWithConfig(conf23) 4978 defer s3.Shutdown() 4979 4980 checkClusterFormed(t, s1, s2, s3) 4981 4982 for _, s := range []*Server{s1, s2, s3} { 4983 // Default pool size + account "A" + system account (added by default) 4984 enr := 2 * (DEFAULT_ROUTE_POOL_SIZE + 1 + 1) 4985 url := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 4986 for mode := 0; mode < 2; mode++ { 4987 v := pollVarz(t, s, mode, url, nil) 4988 if v.Remotes != 2 { 4989 t.Fatalf("Expected Remotes==2, got %v", v.Remotes) 4990 } 4991 if v.Routes != enr { 4992 t.Fatalf("Expected NumRoutes==%d, got %v", enr, v.Routes) 4993 } 4994 } 4995 4996 url = fmt.Sprintf("http://127.0.0.1:%d/routez", s.MonitorAddr().Port) 4997 for mode := 0; mode < 2; mode++ { 4998 v := pollRoutez(t, s, mode, url, nil) 4999 if v.NumRoutes != enr { 5000 t.Fatalf("Expected NumRoutes==%d, got %v", enr, v.NumRoutes) 5001 } 5002 if n := len(v.Routes); n != enr { 5003 t.Fatalf("Expected len(Routes)==%d, got %v", enr, n) 5004 } 5005 remotes := make(map[string]int) 5006 for _, r := range v.Routes { 5007 var acc int 5008 if r.Account == "A" { 5009 acc = 1 5010 } 5011 remotes[r.RemoteID] += acc 5012 } 5013 if n := len(remotes); n != 2 { 5014 t.Fatalf("Expected routes for 2 different servers, got %v", n) 5015 } 5016 for remoteID, v := range remotes { 5017 if v != 1 { 5018 t.Fatalf("Expected one and only one connection for account A for remote %q, got %v", remoteID, v) 5019 } 5020 } 5021 } 5022 } 5023 } 5024 5025 func TestMonitorConnzOperatorModeFilterByUser(t *testing.T) { 5026 accKp, accPub := createKey(t) 5027 accClaim := jwt.NewAccountClaims(accPub) 5028 accJwt := encodeClaim(t, accClaim, accPub) 5029 5030 conf := createConfFile(t, []byte(fmt.Sprintf(` 5031 listen: 127.0.0.1:-1 5032 http: 127.0.0.1:-1 5033 operator = %s 5034 resolver = MEMORY 5035 resolver_preload = { 5036 %s : %s 5037 } 5038 `, ojwt, accPub, accJwt))) 5039 5040 s, _ := RunServerWithConfig(conf) 5041 defer s.Shutdown() 5042 5043 createUser := func() (string, string) { 5044 ukp, _ := nkeys.CreateUser() 5045 seed, _ := ukp.Seed() 5046 upub, _ := ukp.PublicKey() 5047 uclaim := newJWTTestUserClaims() 5048 uclaim.Subject = upub 5049 ujwt, err := uclaim.Encode(accKp) 5050 require_NoError(t, err) 5051 return upub, genCredsFile(t, ujwt, seed) 5052 } 5053 5054 // Now create 2 users. 5055 aUser, aCreds := createUser() 5056 bUser, bCreds := createUser() 5057 5058 var users []*nats.Conn 5059 5060 // Create 2 for A 5061 for i := 0; i < 2; i++ { 5062 nc, err := nats.Connect(s.ClientURL(), nats.UserCredentials(aCreds)) 5063 require_NoError(t, err) 5064 defer nc.Close() 5065 users = append(users, nc) 5066 } 5067 // Create 5 for B 5068 for i := 0; i < 5; i++ { 5069 nc, err := nats.Connect(s.ClientURL(), nats.UserCredentials(bCreds)) 5070 require_NoError(t, err) 5071 defer nc.Close() 5072 users = append(users, nc) 5073 } 5074 5075 // Test A 5076 connz := pollConz(t, s, 1, _EMPTY_, &ConnzOptions{User: aUser, Username: true}) 5077 require_True(t, connz.NumConns == 2) 5078 for _, ci := range connz.Conns { 5079 require_True(t, ci.AuthorizedUser == aUser) 5080 } 5081 // Test B 5082 connz = pollConz(t, s, 1, _EMPTY_, &ConnzOptions{User: bUser, Username: true}) 5083 require_True(t, connz.NumConns == 5) 5084 for _, ci := range connz.Conns { 5085 require_True(t, ci.AuthorizedUser == bUser) 5086 } 5087 5088 // Make sure URL access is the same. 5089 url := fmt.Sprintf("http://127.0.0.1:%d/", s.MonitorAddr().Port) 5090 urlFull := url + fmt.Sprintf("connz?auth=true&user=%s", aUser) 5091 connz = pollConz(t, s, 0, urlFull, nil) 5092 require_True(t, connz.NumConns == 2) 5093 for _, ci := range connz.Conns { 5094 require_True(t, ci.AuthorizedUser == aUser) 5095 } 5096 5097 // Now test closed filtering as well. 5098 for _, nc := range users { 5099 nc.Close() 5100 } 5101 // Let them process and be moved to closed ring buffer in server. 5102 time.Sleep(100 * time.Millisecond) 5103 5104 connz = pollConz(t, s, 1, _EMPTY_, &ConnzOptions{User: aUser, Username: true, State: ConnClosed}) 5105 require_True(t, connz.NumConns == 2) 5106 for _, ci := range connz.Conns { 5107 require_True(t, ci.AuthorizedUser == aUser) 5108 } 5109 } 5110 5111 func TestMonitorConnzSortByRTT(t *testing.T) { 5112 s := runMonitorServer() 5113 defer s.Shutdown() 5114 5115 for i := 0; i < 10; i++ { 5116 nc, err := nats.Connect(s.ClientURL()) 5117 require_NoError(t, err) 5118 defer nc.Close() 5119 } 5120 5121 connz := pollConz(t, s, 1, _EMPTY_, &ConnzOptions{Sort: ByRTT}) 5122 require_True(t, connz.NumConns == 10) 5123 5124 var rtt int64 5125 for _, ci := range connz.Conns { 5126 if rtt == 0 { 5127 rtt = ci.rtt 5128 } else { 5129 if ci.rtt > rtt { 5130 t.Fatalf("RTT not in descending order: %v vs %v", 5131 time.Duration(rtt), time.Duration(ci.rtt)) 5132 } 5133 rtt = ci.rtt 5134 } 5135 } 5136 5137 // Make sure url works as well. 5138 url := fmt.Sprintf("http://127.0.0.1:%d/connz?sort=rtt", s.MonitorAddr().Port) 5139 connz = pollConz(t, s, 0, url, nil) 5140 require_True(t, connz.NumConns == 10) 5141 5142 rtt = 0 5143 for _, ci := range connz.Conns { 5144 crttd, err := time.ParseDuration(ci.RTT) 5145 require_NoError(t, err) 5146 crtt := int64(crttd) 5147 if rtt == 0 { 5148 rtt = crtt 5149 } else { 5150 if crtt > rtt { 5151 t.Fatalf("RTT not in descending order: %v vs %v", 5152 time.Duration(rtt), time.Duration(crtt)) 5153 } 5154 rtt = ci.rtt 5155 } 5156 } 5157 } 5158 5159 // https://github.com/nats-io/nats-server/issues/4144 5160 func TestMonitorAccountszMappingOrderReporting(t *testing.T) { 5161 conf := createConfFile(t, []byte(` 5162 listen: 127.0.0.1:-1 5163 server_name: SR22 5164 accounts { 5165 CLOUD { 5166 exports [ { service: "downlink.>" } ] 5167 } 5168 APP { 5169 imports [ { service: { account: CLOUD, subject: "downlink.>"}, to: "event.>"} ] 5170 } 5171 }`)) 5172 5173 s, _ := RunServerWithConfig(conf) 5174 defer s.Shutdown() 5175 5176 az, err := s.Accountz(&AccountzOptions{"APP"}) 5177 require_NoError(t, err) 5178 require_NotNil(t, az.Account) 5179 require_True(t, len(az.Account.Imports) > 0) 5180 5181 var found bool 5182 for _, si := range az.Account.Imports { 5183 if si.Import.Subject == "downlink.>" { 5184 found = true 5185 require_True(t, si.Import.LocalSubject == "event.>") 5186 break 5187 } 5188 } 5189 require_True(t, found) 5190 } 5191 5192 // createCallbackURL adds a callback query parameter for JSONP requests. 5193 func createCallbackURL(t *testing.T, endpoint string) string { 5194 t.Helper() 5195 5196 u, err := url.Parse(endpoint) 5197 if err != nil { 5198 t.Fatal(err) 5199 } 5200 5201 params := u.Query() 5202 params.Set("callback", "callback") 5203 5204 u.RawQuery = params.Encode() 5205 5206 return u.String() 5207 } 5208 5209 // stripCallback removes the JSONP callback function from the response. 5210 // Returns the JSON body without the wrapping callback function. 5211 // If there's no callback function, the data is returned as is. 5212 func stripCallback(data []byte) []byte { 5213 // Cut the JSONP callback function with the opening parentheses. 5214 _, after, found := bytes.Cut(data, []byte("(")) 5215 5216 if found { 5217 return bytes.TrimSuffix(after, []byte(")")) 5218 } 5219 5220 return data 5221 } 5222 5223 // expectHealthStatus makes 1 regular and 1 JSONP request to the URL and checks the 5224 // HTTP status code, Content-Type header and health status string. 5225 func expectHealthStatus(t *testing.T, url string, statusCode int, wantStatus string) { 5226 t.Helper() 5227 5228 // First check for regular requests. 5229 body := readBodyEx(t, url, statusCode, appJSONContent) 5230 checkHealthStatus(t, body, wantStatus) 5231 5232 // Another check for JSONP requests. 5233 jsonpURL := createCallbackURL(t, url) // Adds a callback query param. 5234 jsonpBody := readBodyEx(t, jsonpURL, statusCode, appJSContent) 5235 checkHealthStatus(t, stripCallback(jsonpBody), wantStatus) 5236 } 5237 5238 // checkHealthStatus checks the health status from a JSON response. 5239 func checkHealthStatus(t *testing.T, body []byte, wantStatus string) { 5240 t.Helper() 5241 5242 h := &HealthStatus{} 5243 5244 if err := json.Unmarshal(body, h); err != nil { 5245 t.Fatalf("error unmarshalling the body: %v", err) 5246 } 5247 5248 if h.Status != wantStatus { 5249 t.Errorf("want health status %q, got %q", wantStatus, h.Status) 5250 } 5251 } 5252 5253 // checkHealthzEndpoint makes requests to the /healthz endpoint and checks the health status. 5254 func checkHealthzEndpoint(t *testing.T, address string, statusCode int, wantStatus string) { 5255 t.Helper() 5256 5257 cases := map[string]string{ 5258 "healthz": fmt.Sprintf("http://%s/healthz", address), 5259 "js-enabled-only": fmt.Sprintf("http://%s/healthz?js-enabled-only=true", address), 5260 "js-server-only": fmt.Sprintf("http://%s/healthz?js-server-only=true", address), 5261 } 5262 5263 for name, url := range cases { 5264 t.Run(name, func(t *testing.T) { 5265 expectHealthStatus(t, url, statusCode, wantStatus) 5266 }) 5267 } 5268 } 5269 5270 func TestHealthzStatusOK(t *testing.T) { 5271 s := runMonitorServer() 5272 defer s.Shutdown() 5273 5274 checkHealthzEndpoint(t, s.MonitorAddr().String(), http.StatusOK, "ok") 5275 } 5276 5277 func TestHealthzStatusError(t *testing.T) { 5278 s := runMonitorServer() 5279 defer s.Shutdown() 5280 5281 // Intentionally causing an error in readyForConnections(). 5282 // Note: Private field access, taking advantage of having the tests in the same package. 5283 s.listener = nil 5284 5285 checkHealthzEndpoint(t, s.MonitorAddr().String(), http.StatusInternalServerError, "error") 5286 } 5287 5288 func TestHealthzStatusUnavailable(t *testing.T) { 5289 opts := DefaultMonitorOptions() 5290 opts.JetStream = true 5291 5292 s := RunServer(opts) 5293 defer s.Shutdown() 5294 5295 if !s.JetStreamEnabled() { 5296 t.Fatalf("want JetStream to be enabled first") 5297 } 5298 5299 err := s.DisableJetStream() 5300 5301 if err != nil { 5302 t.Fatalf("got an error disabling JetStream: %v", err) 5303 } 5304 5305 for _, test := range []struct { 5306 name string 5307 url string 5308 statusCode int 5309 wantStatus string 5310 }{ 5311 { 5312 "healthz", 5313 fmt.Sprintf("http://%s/healthz", s.MonitorAddr().String()), 5314 http.StatusServiceUnavailable, 5315 "unavailable", 5316 }, 5317 { 5318 "js-enabled-only", 5319 fmt.Sprintf("http://%s/healthz?js-enabled-only=true", s.MonitorAddr().String()), 5320 http.StatusServiceUnavailable, 5321 "unavailable", 5322 }, 5323 { 5324 "js-server-only", 5325 fmt.Sprintf("http://%s/healthz?js-server-only=true", s.MonitorAddr().String()), 5326 http.StatusOK, 5327 "ok", 5328 }, 5329 } { 5330 t.Run(test.name, func(t *testing.T) { 5331 expectHealthStatus(t, test.url, test.statusCode, test.wantStatus) 5332 }) 5333 } 5334 } 5335 5336 // When we converted ipq to use generics we still were using sync.Map. Currently you can not convert 5337 // any or any to a generic parameterized type. So this stopped working and panics. 5338 func TestIpqzWithGenerics(t *testing.T) { 5339 opts := DefaultMonitorOptions() 5340 opts.JetStream = true 5341 5342 s := RunServer(opts) 5343 defer s.Shutdown() 5344 5345 url := fmt.Sprintf("http://%s/ipqueuesz?all=1", s.MonitorAddr().String()) 5346 body := readBody(t, url) 5347 require_True(t, len(body) > 0) 5348 5349 queues := map[string]*monitorIPQueue{} 5350 require_NoError(t, json.Unmarshal(body, &queues)) 5351 require_True(t, len(queues) >= 4) 5352 require_True(t, queues["SendQ"] != nil) 5353 } 5354 5355 func TestVarzSyncInterval(t *testing.T) { 5356 resetPreviousHTTPConnections() 5357 opts := DefaultMonitorOptions() 5358 opts.JetStream = true 5359 opts.SyncInterval = 22 * time.Second 5360 opts.SyncAlways = true 5361 5362 s := RunServer(opts) 5363 defer s.Shutdown() 5364 5365 url := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port) 5366 5367 jscfg := pollVarz(t, s, 0, url, nil).JetStream.Config 5368 require_True(t, jscfg.SyncInterval == opts.SyncInterval) 5369 require_True(t, jscfg.SyncAlways) 5370 }