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

     1  // Copyright 2012-2020 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package test
    15  
    16  import (
    17  	"crypto/tls"
    18  	"crypto/x509"
    19  	"encoding/json"
    20  	"fmt"
    21  	"io"
    22  	"net"
    23  	"net/http"
    24  	"os"
    25  	"strings"
    26  	"sync"
    27  	"sync/atomic"
    28  	"testing"
    29  	"time"
    30  
    31  	"get.pme.sh/pnats/server"
    32  	"github.com/nats-io/nats.go"
    33  )
    34  
    35  const CLIENT_PORT = 11422
    36  const MONITOR_PORT = 11522
    37  
    38  func runMonitorServer() *server.Server {
    39  	resetPreviousHTTPConnections()
    40  	opts := DefaultTestOptions
    41  	opts.Port = CLIENT_PORT
    42  	opts.HTTPPort = MONITOR_PORT
    43  	opts.HTTPHost = "127.0.0.1"
    44  	opts.NoSystemAccount = true
    45  	return RunServer(&opts)
    46  }
    47  
    48  // Runs a clustered pair of monitor servers for testing the /routez endpoint
    49  func runMonitorServerClusteredPair(t *testing.T) (*server.Server, *server.Server) {
    50  	resetPreviousHTTPConnections()
    51  	opts := DefaultTestOptions
    52  	opts.Port = CLIENT_PORT
    53  	opts.HTTPPort = MONITOR_PORT
    54  	opts.HTTPHost = "127.0.0.1"
    55  	opts.Cluster = server.ClusterOpts{Name: "M", Host: "127.0.0.1", Port: 10223}
    56  	opts.Routes = server.RoutesFromStr("nats-route://127.0.0.1:10222")
    57  	opts.NoSystemAccount = true
    58  
    59  	s1 := RunServer(&opts)
    60  
    61  	opts2 := DefaultTestOptions
    62  	opts2.Port = CLIENT_PORT + 1
    63  	opts2.HTTPPort = MONITOR_PORT + 1
    64  	opts2.HTTPHost = "127.0.0.1"
    65  	opts2.Cluster = server.ClusterOpts{Name: "M", Host: "127.0.0.1", Port: 10222}
    66  	opts2.Routes = server.RoutesFromStr("nats-route://127.0.0.1:10223")
    67  	opts2.NoSystemAccount = true
    68  
    69  	s2 := RunServer(&opts2)
    70  
    71  	checkClusterFormed(t, s1, s2)
    72  
    73  	return s1, s2
    74  }
    75  
    76  func runMonitorServerNoHTTPPort() *server.Server {
    77  	resetPreviousHTTPConnections()
    78  	opts := DefaultTestOptions
    79  	opts.Port = CLIENT_PORT
    80  	opts.HTTPPort = 0
    81  	opts.NoSystemAccount = true
    82  
    83  	return RunServer(&opts)
    84  }
    85  
    86  func resetPreviousHTTPConnections() {
    87  	http.DefaultTransport.(*http.Transport).CloseIdleConnections()
    88  }
    89  
    90  // Make sure that we do not run the http server for monitoring unless asked.
    91  func TestNoMonitorPort(t *testing.T) {
    92  	s := runMonitorServerNoHTTPPort()
    93  	defer s.Shutdown()
    94  
    95  	url := fmt.Sprintf("http://127.0.0.1:%d/", MONITOR_PORT)
    96  	if resp, err := http.Get(url + "varz"); err == nil {
    97  		t.Fatalf("Expected error: Got %+v\n", resp)
    98  	}
    99  	if resp, err := http.Get(url + "healthz"); err == nil {
   100  		t.Fatalf("Expected error: Got %+v\n", resp)
   101  	}
   102  	if resp, err := http.Get(url + "connz"); err == nil {
   103  		t.Fatalf("Expected error: Got %+v\n", resp)
   104  	}
   105  }
   106  
   107  // testEndpointDataRace tests a monitoring endpoint for data races by polling
   108  // while client code acts to ensure statistics are updated. It is designed to
   109  // run under the -race flag to catch violations. The caller must start the
   110  // NATS server.
   111  func testEndpointDataRace(endpoint string, t *testing.T) {
   112  	var doneWg sync.WaitGroup
   113  
   114  	url := fmt.Sprintf("http://127.0.0.1:%d/", MONITOR_PORT)
   115  
   116  	// Poll as fast as we can, while creating connections, publishing,
   117  	// and subscribing.
   118  	clientDone := int64(0)
   119  	doneWg.Add(1)
   120  	go func() {
   121  		for atomic.LoadInt64(&clientDone) == 0 {
   122  			resp, err := http.Get(url + endpoint)
   123  			if err != nil {
   124  				t.Errorf("Expected no error: Got %v\n", err)
   125  			} else {
   126  				resp.Body.Close()
   127  			}
   128  		}
   129  		doneWg.Done()
   130  	}()
   131  
   132  	// create connections, subscriptions, and publish messages to
   133  	// update the monitor variables.
   134  	var conns []net.Conn
   135  	for i := 0; i < 50; i++ {
   136  		cl := createClientConnSubscribeAndPublish(t)
   137  		// keep a few connections around to test monitor variables.
   138  		if i%10 == 0 {
   139  			conns = append(conns, cl)
   140  		} else {
   141  			cl.Close()
   142  		}
   143  	}
   144  	atomic.AddInt64(&clientDone, 1)
   145  
   146  	// wait for the endpoint polling goroutine to exit
   147  	doneWg.Wait()
   148  
   149  	// cleanup the conns
   150  	for _, cl := range conns {
   151  		cl.Close()
   152  	}
   153  }
   154  
   155  func TestEndpointDataRaces(t *testing.T) {
   156  	// setup a small cluster to test /routez
   157  	s1, s2 := runMonitorServerClusteredPair(t)
   158  	defer s1.Shutdown()
   159  	defer s2.Shutdown()
   160  
   161  	// test all of our endpoints
   162  	testEndpointDataRace("varz", t)
   163  	testEndpointDataRace("connz", t)
   164  	testEndpointDataRace("routez", t)
   165  	testEndpointDataRace("subsz", t)
   166  	testEndpointDataRace("stacksz", t)
   167  }
   168  
   169  func TestVarz(t *testing.T) {
   170  	s := runMonitorServer()
   171  	defer s.Shutdown()
   172  
   173  	url := fmt.Sprintf("http://127.0.0.1:%d/", MONITOR_PORT)
   174  	resp, err := http.Get(url + "varz")
   175  	if err != nil {
   176  		t.Fatalf("Expected no error: Got %v\n", err)
   177  	}
   178  	if resp.StatusCode != 200 {
   179  		t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   180  	}
   181  	defer resp.Body.Close()
   182  	body, err := io.ReadAll(resp.Body)
   183  	if err != nil {
   184  		t.Fatalf("Got an error reading the body: %v\n", err)
   185  	}
   186  
   187  	v := server.Varz{}
   188  	if err := json.Unmarshal(body, &v); err != nil {
   189  		t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   190  	}
   191  
   192  	// Do some sanity checks on values
   193  	if time.Since(v.Start) > 10*time.Second {
   194  		t.Fatal("Expected start time to be within 10 seconds.")
   195  	}
   196  
   197  	cl := createClientConnSubscribeAndPublish(t)
   198  	defer cl.Close()
   199  
   200  	resp, err = http.Get(url + "varz")
   201  	if err != nil {
   202  		t.Fatalf("Expected no error: Got %v\n", err)
   203  	}
   204  	if resp.StatusCode != 200 {
   205  		t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   206  	}
   207  	defer resp.Body.Close()
   208  	body, err = io.ReadAll(resp.Body)
   209  	if err != nil {
   210  		t.Fatalf("Got an error reading the body: %v\n", err)
   211  	}
   212  
   213  	if strings.Contains(string(body), "cluster_port") {
   214  		t.Fatal("Varz body contains cluster information when no cluster is defined.")
   215  	}
   216  
   217  	v = server.Varz{}
   218  	if err := json.Unmarshal(body, &v); err != nil {
   219  		t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   220  	}
   221  
   222  	if v.Connections != 1 {
   223  		t.Fatalf("Expected Connections of 1, got %v\n", v.Connections)
   224  	}
   225  	if v.InMsgs != 1 {
   226  		t.Fatalf("Expected InMsgs of 1, got %v\n", v.InMsgs)
   227  	}
   228  	if v.OutMsgs != 1 {
   229  		t.Fatalf("Expected OutMsgs of 1, got %v\n", v.OutMsgs)
   230  	}
   231  	if v.InBytes != 5 {
   232  		t.Fatalf("Expected InBytes of 5, got %v\n", v.InBytes)
   233  	}
   234  	if v.OutBytes != 5 {
   235  		t.Fatalf("Expected OutBytes of 5, got %v\n", v.OutBytes)
   236  	}
   237  	if v.MaxPending != server.MAX_PENDING_SIZE {
   238  		t.Fatalf("Expected MaxPending of %d, got %v\n",
   239  			server.MAX_PENDING_SIZE, v.MaxPending)
   240  	}
   241  	if v.WriteDeadline != server.DEFAULT_FLUSH_DEADLINE {
   242  		t.Fatalf("Expected WriteDeadline of %d, got %v\n",
   243  			server.DEFAULT_FLUSH_DEADLINE, v.WriteDeadline)
   244  	}
   245  }
   246  
   247  func TestConnz(t *testing.T) {
   248  	s := runMonitorServer()
   249  	defer s.Shutdown()
   250  
   251  	url := fmt.Sprintf("http://127.0.0.1:%d/", MONITOR_PORT)
   252  	resp, err := http.Get(url + "connz")
   253  	if err != nil {
   254  		t.Fatalf("Expected no error: Got %v\n", err)
   255  	}
   256  	if resp.StatusCode != 200 {
   257  		t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   258  	}
   259  	defer resp.Body.Close()
   260  	body, err := io.ReadAll(resp.Body)
   261  	if err != nil {
   262  		t.Fatalf("Got an error reading the body: %v\n", err)
   263  	}
   264  
   265  	c := server.Connz{}
   266  	if err := json.Unmarshal(body, &c); err != nil {
   267  		t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   268  	}
   269  
   270  	// Test contents..
   271  	if c.NumConns != 0 {
   272  		t.Fatalf("Expected 0 connections, got %d\n", c.NumConns)
   273  	}
   274  	if c.Total != 0 {
   275  		t.Fatalf("Expected 0 live connections, got %d\n", c.Total)
   276  	}
   277  	if c.Conns == nil || len(c.Conns) != 0 {
   278  		t.Fatalf("Expected 0 connections in array, got %p\n", c.Conns)
   279  	}
   280  
   281  	cl := createClientConnSubscribeAndPublish(t)
   282  	defer cl.Close()
   283  
   284  	resp, err = http.Get(url + "connz")
   285  	if err != nil {
   286  		t.Fatalf("Expected no error: Got %v\n", err)
   287  	}
   288  	if resp.StatusCode != 200 {
   289  		t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   290  	}
   291  	defer resp.Body.Close()
   292  	body, err = io.ReadAll(resp.Body)
   293  	if err != nil {
   294  		t.Fatalf("Got an error reading the body: %v\n", err)
   295  	}
   296  	if err := json.Unmarshal(body, &c); err != nil {
   297  		t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   298  	}
   299  
   300  	if c.NumConns != 1 {
   301  		t.Fatalf("Expected 1 connection, got %d\n", c.NumConns)
   302  	}
   303  	if c.Total != 1 {
   304  		t.Fatalf("Expected 1 live connection, got %d\n", c.Total)
   305  	}
   306  	if c.Conns == nil || len(c.Conns) != 1 {
   307  		t.Fatalf("Expected 1 connection in array, got %p\n", c.Conns)
   308  	}
   309  
   310  	if c.Limit != server.DefaultConnListSize {
   311  		t.Fatalf("Expected limit of %d, got %v\n", server.DefaultConnListSize, c.Limit)
   312  	}
   313  
   314  	if c.Offset != 0 {
   315  		t.Fatalf("Expected offset of 0, got %v\n", c.Offset)
   316  	}
   317  
   318  	// Test inside details of each connection
   319  	ci := c.Conns[0]
   320  
   321  	if ci.Cid == 0 {
   322  		t.Fatalf("Expected non-zero cid, got %v\n", ci.Cid)
   323  	}
   324  	if ci.IP != "127.0.0.1" {
   325  		t.Fatalf("Expected \"127.0.0.1\" for IP, got %v\n", ci.IP)
   326  	}
   327  	if ci.Port == 0 {
   328  		t.Fatalf("Expected non-zero port, got %v\n", ci.Port)
   329  	}
   330  	if ci.NumSubs != 1 {
   331  		t.Fatalf("Expected num_subs of 1, got %v\n", ci.NumSubs)
   332  	}
   333  	if len(ci.Subs) != 0 {
   334  		t.Fatalf("Expected subs of 0, got %v\n", ci.Subs)
   335  	}
   336  	if ci.InMsgs != 1 {
   337  		t.Fatalf("Expected InMsgs of 1, got %v\n", ci.InMsgs)
   338  	}
   339  	if ci.OutMsgs != 1 {
   340  		t.Fatalf("Expected OutMsgs of 1, got %v\n", ci.OutMsgs)
   341  	}
   342  	if ci.InBytes != 5 {
   343  		t.Fatalf("Expected InBytes of 1, got %v\n", ci.InBytes)
   344  	}
   345  	if ci.OutBytes != 5 {
   346  		t.Fatalf("Expected OutBytes of 1, got %v\n", ci.OutBytes)
   347  	}
   348  }
   349  
   350  func TestTLSConnz(t *testing.T) {
   351  	srv, opts := RunServerWithConfig("./configs/tls.conf")
   352  	defer srv.Shutdown()
   353  	rootCAFile := "./configs/certs/ca.pem"
   354  	clientCertFile := "./configs/certs/client-cert.pem"
   355  	clientKeyFile := "./configs/certs/client-key.pem"
   356  
   357  	// Test with secure connection
   358  	endpoint := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
   359  	nurl := fmt.Sprintf("tls://%s:%s@%s/", opts.Username, opts.Password, endpoint)
   360  	nc, err := nats.Connect(nurl, nats.RootCAs(rootCAFile))
   361  	if err != nil {
   362  		t.Fatalf("Got an error on Connect with Secure Options: %+v\n", err)
   363  	}
   364  	defer nc.Close()
   365  	ch := make(chan struct{})
   366  	nc.Subscribe("foo", func(m *nats.Msg) { ch <- struct{}{} })
   367  	nc.Publish("foo", []byte("Hello"))
   368  
   369  	// Wait for message
   370  	<-ch
   371  
   372  	url := fmt.Sprintf("https://127.0.0.1:%d/", opts.HTTPSPort)
   373  	tlsConfig := &tls.Config{}
   374  	caCert, err := os.ReadFile(rootCAFile)
   375  	if err != nil {
   376  		t.Fatalf("Got error reading RootCA file: %s", err)
   377  	}
   378  	caCertPool := x509.NewCertPool()
   379  	caCertPool.AppendCertsFromPEM(caCert)
   380  	tlsConfig.RootCAs = caCertPool
   381  
   382  	cert, err := tls.LoadX509KeyPair(clientCertFile, clientKeyFile)
   383  	if err != nil {
   384  		t.Fatalf("Got error reading client certificates: %s", err)
   385  	}
   386  	tlsConfig.Certificates = []tls.Certificate{cert}
   387  	transport := &http.Transport{TLSClientConfig: tlsConfig}
   388  	httpClient := &http.Client{Transport: transport}
   389  
   390  	resp, err := httpClient.Get(url + "connz")
   391  	if err != nil {
   392  		t.Fatalf("Expected no error: Got %v\n", err)
   393  	}
   394  	if resp.StatusCode != 200 {
   395  		t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   396  	}
   397  	defer resp.Body.Close()
   398  	body, err := io.ReadAll(resp.Body)
   399  
   400  	if err != nil {
   401  		t.Fatalf("Got an error reading the body: %v\n", err)
   402  	}
   403  	c := server.Connz{}
   404  	if err := json.Unmarshal(body, &c); err != nil {
   405  		t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   406  	}
   407  
   408  	if c.NumConns != 1 {
   409  		t.Fatalf("Expected 1 connection, got %d\n", c.NumConns)
   410  	}
   411  	if c.Total != 1 {
   412  		t.Fatalf("Expected 1 live connection, got %d\n", c.Total)
   413  	}
   414  	if c.Conns == nil || len(c.Conns) != 1 {
   415  		t.Fatalf("Expected 1 connection in array, got %d\n", len(c.Conns))
   416  	}
   417  
   418  	// Test inside details of each connection
   419  	ci := c.Conns[0]
   420  
   421  	if ci.Cid == 0 {
   422  		t.Fatalf("Expected non-zero cid, got %v\n", ci.Cid)
   423  	}
   424  	if ci.IP != "127.0.0.1" {
   425  		t.Fatalf("Expected \"127.0.0.1\" for IP, got %v\n", ci.IP)
   426  	}
   427  	if ci.Port == 0 {
   428  		t.Fatalf("Expected non-zero port, got %v\n", ci.Port)
   429  	}
   430  	if ci.NumSubs != 1 {
   431  		t.Fatalf("Expected num_subs of 1, got %v\n", ci.NumSubs)
   432  	}
   433  	if len(ci.Subs) != 0 {
   434  		t.Fatalf("Expected subs of 0, got %v\n", ci.Subs)
   435  	}
   436  	if ci.InMsgs != 1 {
   437  		t.Fatalf("Expected InMsgs of 1, got %v\n", ci.InMsgs)
   438  	}
   439  	if ci.OutMsgs != 1 {
   440  		t.Fatalf("Expected OutMsgs of 1, got %v\n", ci.OutMsgs)
   441  	}
   442  	if ci.InBytes != 5 {
   443  		t.Fatalf("Expected InBytes of 1, got %v\n", ci.InBytes)
   444  	}
   445  	if ci.OutBytes != 5 {
   446  		t.Fatalf("Expected OutBytes of 1, got %v\n", ci.OutBytes)
   447  	}
   448  	if ci.Start.IsZero() {
   449  		t.Fatalf("Expected Start to be valid\n")
   450  	}
   451  	if ci.Uptime == "" {
   452  		t.Fatalf("Expected Uptime to be valid\n")
   453  	}
   454  	if ci.LastActivity.IsZero() {
   455  		t.Fatalf("Expected LastActivity to be valid\n")
   456  	}
   457  	if ci.LastActivity.UnixNano() < ci.Start.UnixNano() {
   458  		t.Fatalf("Expected LastActivity [%v] to be > Start [%v]\n", ci.LastActivity, ci.Start)
   459  	}
   460  	if ci.Idle == "" {
   461  		t.Fatalf("Expected Idle to be valid\n")
   462  	}
   463  }
   464  
   465  func TestConnzWithSubs(t *testing.T) {
   466  	s := runMonitorServer()
   467  	defer s.Shutdown()
   468  
   469  	cl := createClientConnSubscribeAndPublish(t)
   470  	defer cl.Close()
   471  
   472  	url := fmt.Sprintf("http://127.0.0.1:%d/", MONITOR_PORT)
   473  	resp, err := http.Get(url + "connz?subs=1")
   474  	if err != nil {
   475  		t.Fatalf("Expected no error: Got %v\n", err)
   476  	}
   477  	if resp.StatusCode != 200 {
   478  		t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   479  	}
   480  	defer resp.Body.Close()
   481  	body, err := io.ReadAll(resp.Body)
   482  	if err != nil {
   483  		t.Fatalf("Got an error reading the body: %v\n", err)
   484  	}
   485  
   486  	c := server.Connz{}
   487  	if err := json.Unmarshal(body, &c); err != nil {
   488  		t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   489  	}
   490  
   491  	// Test inside details of each connection
   492  	ci := c.Conns[0]
   493  	if len(ci.Subs) != 1 || ci.Subs[0] != "foo" {
   494  		t.Fatalf("Expected subs of 1, got %v\n", ci.Subs)
   495  	}
   496  }
   497  
   498  func TestConnzWithAuth(t *testing.T) {
   499  	srv, opts := RunServerWithConfig("./configs/multi_user.conf")
   500  	defer srv.Shutdown()
   501  
   502  	endpoint := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
   503  	curl := fmt.Sprintf("nats://%s:%s@%s/", opts.Users[0].Username, opts.Users[0].Password, endpoint)
   504  	nc, err := nats.Connect(curl)
   505  	if err != nil {
   506  		t.Fatalf("Got an error on Connect: %+v\n", err)
   507  	}
   508  	defer nc.Close()
   509  
   510  	ch := make(chan struct{})
   511  	nc.Subscribe("foo", func(m *nats.Msg) { ch <- struct{}{} })
   512  	nc.Publish("foo", []byte("Hello"))
   513  
   514  	// Wait for message
   515  	<-ch
   516  
   517  	url := fmt.Sprintf("http://127.0.0.1:%d/", opts.HTTPPort)
   518  
   519  	resp, err := http.Get(url + "connz?auth=1")
   520  	if err != nil {
   521  		t.Fatalf("Expected no error: Got %v\n", err)
   522  	}
   523  	if resp.StatusCode != 200 {
   524  		t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   525  	}
   526  	defer resp.Body.Close()
   527  	body, err := io.ReadAll(resp.Body)
   528  	if err != nil {
   529  		t.Fatalf("Got an error reading the body: %v\n", err)
   530  	}
   531  
   532  	c := server.Connz{}
   533  	if err := json.Unmarshal(body, &c); err != nil {
   534  		t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   535  	}
   536  
   537  	// Test that we have authorized_user and its Alice.
   538  	ci := c.Conns[0]
   539  	if ci.AuthorizedUser != opts.Users[0].Username {
   540  		t.Fatalf("Expected authorized_user to be %q, got %q\n",
   541  			opts.Users[0].Username, ci.AuthorizedUser)
   542  	}
   543  }
   544  
   545  func TestConnzWithAccounts(t *testing.T) {
   546  	resetPreviousHTTPConnections()
   547  	s, opts := RunServerWithConfig("./configs/multi_accounts.conf")
   548  	defer s.Shutdown()
   549  
   550  	endpoint := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
   551  
   552  	// Connect all the users. Tests depend on knowing users, accounts.
   553  	if len(opts.Users) != 6 {
   554  		t.Fatalf("Expected 6 total users, got %d", len(opts.Users))
   555  	}
   556  	if len(opts.Accounts) != 3 {
   557  		t.Fatalf("Expected 3 total accounts, got %d", len(opts.Accounts))
   558  	}
   559  
   560  	// Map from user to account name.
   561  	utoa := make(map[string]string)
   562  	conns := make([]*nats.Conn, len(opts.Users))
   563  	for _, u := range opts.Users {
   564  		nc, err := nats.Connect(fmt.Sprintf("nats://%s:%s@%s/", u.Username, u.Password, endpoint))
   565  		if err != nil {
   566  			t.Fatalf("Got an error on Connect: %+v\n", err)
   567  		}
   568  		defer nc.Close()
   569  		utoa[u.Username] = u.Account.Name
   570  		conns = append(conns, nc)
   571  	}
   572  
   573  	url := fmt.Sprintf("http://127.0.0.1:%d/", opts.HTTPPort)
   574  
   575  	grabConnz := func(args string) *server.Connz {
   576  		t.Helper()
   577  		if args != "" {
   578  			args = "&" + args
   579  		}
   580  		resp, err := http.Get(url + "connz?auth=1" + args)
   581  		if err != nil {
   582  			t.Fatalf("Expected no error: Got %v\n", err)
   583  		}
   584  		if resp.StatusCode != 200 {
   585  			t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   586  		}
   587  		defer resp.Body.Close()
   588  		body, err := io.ReadAll(resp.Body)
   589  		if err != nil {
   590  			t.Fatalf("Got an error reading the body: %v\n", err)
   591  		}
   592  		c := server.Connz{}
   593  		if err := json.Unmarshal(body, &c); err != nil {
   594  			t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   595  		}
   596  		return &c
   597  	}
   598  
   599  	c := grabConnz("")
   600  	if c.NumConns != 6 {
   601  		t.Fatalf("Expected 6 connection entries, got %d", c.NumConns)
   602  	}
   603  
   604  	checkConn := func(ci *server.ConnInfo) {
   605  		t.Helper()
   606  		user := ci.AuthorizedUser
   607  		account := utoa[user]
   608  		if user == "" || account == "" {
   609  			t.Fatalf("Empty user or account: %q - %q", user, account)
   610  		}
   611  		if ci.Account != account {
   612  			t.Fatalf("Expected account of %q, got %q", account, ci.Account)
   613  		}
   614  	}
   615  
   616  	for i, ci := range c.Conns {
   617  		if ci.Cid != uint64(i+1) {
   618  			t.Fatalf("Expected CID of %d, got %d", i+1, ci.Cid)
   619  		}
   620  		checkConn(ci)
   621  	}
   622  
   623  	// Now make sure we can pull connections by account and user
   624  	pullByAccount := func(accName, state string) {
   625  		t.Helper()
   626  		c = grabConnz("acc=" + accName + "&state=" + state)
   627  		if c.NumConns != 2 {
   628  			t.Fatalf("Expected 2 connection entries, got %d", c.NumConns)
   629  		}
   630  		for _, ci := range c.Conns {
   631  			if ci.Account != accName {
   632  				t.Fatalf("Expected %q account, go %q", accName, ci.Account)
   633  			}
   634  		}
   635  	}
   636  
   637  	pullByUser := func(user, state string) {
   638  		t.Helper()
   639  		c = grabConnz("user=" + user + "&state=" + state)
   640  		if c.NumConns != 1 {
   641  			t.Fatalf("Expected 1 connection, got %d", c.NumConns)
   642  		}
   643  		if c.Conns[0].AuthorizedUser != user {
   644  			t.Fatalf("Expected user %q, got %q", user, c.Conns[0].AuthorizedUser)
   645  		}
   646  	}
   647  
   648  	pullByAccount("engineering", "open")
   649  	pullByAccount("finance", "open")
   650  	pullByAccount("legal", "open")
   651  
   652  	pullByUser("alice", "open")
   653  	pullByUser("bob", "open")
   654  
   655  	pullByUser("john", "open")
   656  	pullByUser("mary", "open")
   657  
   658  	pullByUser("peter", "open")
   659  	pullByUser("paul", "open")
   660  
   661  	// Now closed and make sure these work on closed as well.
   662  	for _, nc := range conns {
   663  		nc.Close()
   664  	}
   665  
   666  	checkFor(t, time.Second, 10*time.Millisecond, func() error {
   667  		if numClients := s.NumClients(); numClients != 0 {
   668  			return fmt.Errorf("Number of client is %d", numClients)
   669  		}
   670  		return nil
   671  	})
   672  
   673  	pullByAccount("engineering", "closed")
   674  	pullByAccount("finance", "closed")
   675  	pullByAccount("legal", "closed")
   676  
   677  	pullByUser("alice", "closed")
   678  	pullByUser("bob", "closed")
   679  
   680  	pullByUser("john", "closed")
   681  	pullByUser("mary", "closed")
   682  
   683  	pullByUser("peter", "closed")
   684  	pullByUser("paul", "closed")
   685  }
   686  
   687  func TestConnzWithOffsetAndLimit(t *testing.T) {
   688  	s := runMonitorServer()
   689  	defer s.Shutdown()
   690  
   691  	cl1 := createClientConnSubscribeAndPublish(t)
   692  	defer cl1.Close()
   693  
   694  	cl2 := createClientConnSubscribeAndPublish(t)
   695  	defer cl2.Close()
   696  
   697  	url := fmt.Sprintf("http://127.0.0.1:%d/", MONITOR_PORT)
   698  	resp, err := http.Get(url + "connz?offset=1&limit=1")
   699  	if err != nil {
   700  		t.Fatalf("Expected no error: Got %v\n", err)
   701  	}
   702  	if resp.StatusCode != 200 {
   703  		t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   704  	}
   705  	defer resp.Body.Close()
   706  	body, err := io.ReadAll(resp.Body)
   707  	if err != nil {
   708  		t.Fatalf("Got an error reading the body: %v\n", err)
   709  	}
   710  
   711  	c := server.Connz{}
   712  	if err := json.Unmarshal(body, &c); err != nil {
   713  		t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   714  	}
   715  
   716  	if c.Limit != 1 {
   717  		t.Fatalf("Expected limit of 1, got %v\n", c.Limit)
   718  	}
   719  
   720  	if c.Offset != 1 {
   721  		t.Fatalf("Expected offset of 1, got %v\n", c.Offset)
   722  	}
   723  
   724  	if len(c.Conns) != 1 {
   725  		t.Fatalf("Expected conns of 1, got %v\n", len(c.Conns))
   726  	}
   727  }
   728  
   729  func TestSubsz(t *testing.T) {
   730  	s := runMonitorServer()
   731  	defer s.Shutdown()
   732  
   733  	cl := createClientConnSubscribeAndPublish(t)
   734  	defer cl.Close()
   735  
   736  	url := fmt.Sprintf("http://127.0.0.1:%d/", MONITOR_PORT)
   737  	resp, err := http.Get(url + "subscriptionsz")
   738  	if err != nil {
   739  		t.Fatalf("Expected no error: Got %v\n", err)
   740  	}
   741  	if resp.StatusCode != 200 {
   742  		t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
   743  	}
   744  	defer resp.Body.Close()
   745  	body, err := io.ReadAll(resp.Body)
   746  	if err != nil {
   747  		t.Fatalf("Got an error reading the body: %v\n", err)
   748  	}
   749  
   750  	su := server.Subsz{}
   751  	if err := json.Unmarshal(body, &su); err != nil {
   752  		t.Fatalf("Got an error unmarshalling the body: %v\n", err)
   753  	}
   754  
   755  	// Do some sanity checks on values
   756  	if su.NumSubs != 1 {
   757  		t.Fatalf("Expected num_subs of 1, got %v\n", su.NumSubs)
   758  	}
   759  }
   760  
   761  func TestHTTPHost(t *testing.T) {
   762  	s := runMonitorServer()
   763  	defer s.Shutdown()
   764  
   765  	// Grab non-127.0.0.1 address and try to use that to connect.
   766  	// Should fail.
   767  	var ip net.IP
   768  	ifaces, _ := net.Interfaces()
   769  	for _, i := range ifaces {
   770  		addrs, _ := i.Addrs()
   771  		for _, addr := range addrs {
   772  			switch v := addr.(type) {
   773  			case *net.IPNet:
   774  				ip = v.IP
   775  			case *net.IPAddr:
   776  				ip = v.IP
   777  			}
   778  			// Skip loopback/127.0.0.1 or any ipv6 for now.
   779  			if ip.IsLoopback() || ip.To4() == nil {
   780  				ip = nil
   781  				continue
   782  			}
   783  			break
   784  		}
   785  		if ip != nil {
   786  			break
   787  		}
   788  	}
   789  	if ip == nil {
   790  		t.Fatalf("Could not find non-loopback IPV4 address")
   791  	}
   792  	url := fmt.Sprintf("http://%v:%d/", ip, MONITOR_PORT)
   793  	if resp, err := http.Get(url + "varz"); err == nil {
   794  		t.Fatalf("Expected error: Got %+v\n", resp)
   795  	}
   796  }
   797  
   798  // Create a connection to test ConnInfo
   799  func createClientConnSubscribeAndPublish(t *testing.T) net.Conn {
   800  	cl := createClientConn(t, "127.0.0.1", CLIENT_PORT)
   801  	send, expect := setupConn(t, cl)
   802  	expectMsgs := expectMsgsCommand(t, expect)
   803  
   804  	send("SUB foo 1\r\nPUB foo 5\r\nhello\r\n")
   805  	expectMsgs(1)
   806  
   807  	return cl
   808  }
   809  
   810  func TestMonitorNoTLSConfig(t *testing.T) {
   811  	opts := DefaultTestOptions
   812  	opts.Port = CLIENT_PORT
   813  	opts.HTTPHost = "127.0.0.1"
   814  	opts.HTTPSPort = MONITOR_PORT
   815  	s := server.New(&opts)
   816  	defer s.Shutdown()
   817  	// Check with manually starting the monitoring, which should return an error
   818  	if err := s.StartMonitoring(); err == nil || !strings.Contains(err.Error(), "TLS") {
   819  		t.Fatalf("Expected error about missing TLS config, got %v", err)
   820  	}
   821  	// Also check by calling Start(), which should produce a fatal error
   822  	dl := &dummyLogger{}
   823  	s.SetLogger(dl, false, false)
   824  	defer s.SetLogger(nil, false, false)
   825  	s.Start()
   826  	if !strings.Contains(dl.msg, "TLS") {
   827  		t.Fatalf("Expected error about missing TLS config, got %v", dl.msg)
   828  	}
   829  }
   830  
   831  func TestMonitorErrorOnListen(t *testing.T) {
   832  	s := runMonitorServer()
   833  	defer s.Shutdown()
   834  
   835  	opts := DefaultTestOptions
   836  	opts.Port = CLIENT_PORT + 1
   837  	opts.HTTPHost = "127.0.0.1"
   838  	opts.HTTPPort = MONITOR_PORT
   839  	s2 := server.New(&opts)
   840  	defer s2.Shutdown()
   841  	if err := s2.StartMonitoring(); err == nil || !strings.Contains(err.Error(), "listen") {
   842  		t.Fatalf("Expected error about not able to start listener, got %v", err)
   843  	}
   844  }
   845  
   846  func TestMonitorBothPortsConfigured(t *testing.T) {
   847  	opts := DefaultTestOptions
   848  	opts.Port = CLIENT_PORT
   849  	opts.HTTPHost = "127.0.0.1"
   850  	opts.HTTPPort = MONITOR_PORT
   851  	opts.HTTPSPort = MONITOR_PORT + 1
   852  	s := server.New(&opts)
   853  	defer s.Shutdown()
   854  	if err := s.StartMonitoring(); err == nil || !strings.Contains(err.Error(), "specify both") {
   855  		t.Fatalf("Expected error about ports configured, got %v", err)
   856  	}
   857  }
   858  
   859  func TestMonitorStop(t *testing.T) {
   860  	resetPreviousHTTPConnections()
   861  	opts := DefaultTestOptions
   862  	opts.Port = CLIENT_PORT
   863  	opts.HTTPHost = "127.0.0.1"
   864  	opts.HTTPPort = MONITOR_PORT
   865  	url := fmt.Sprintf("http://%v:%d/", opts.HTTPHost, MONITOR_PORT)
   866  	// Create a server instance and start only the monitoring http server.
   867  	s := server.New(&opts)
   868  	if err := s.StartMonitoring(); err != nil {
   869  		t.Fatalf("Error starting monitoring: %v", err)
   870  	}
   871  	// Make sure http server is started
   872  	resp, err := http.Get(url + "varz")
   873  	if err != nil {
   874  		t.Fatalf("Error on http request: %v", err)
   875  	}
   876  	resp.Body.Close()
   877  	// Although the server itself was not started (we did not call s.Start()),
   878  	// Shutdown() should stop the http server.
   879  	s.Shutdown()
   880  	// HTTP request should now fail
   881  	if resp, err := http.Get(url + "varz"); err == nil {
   882  		t.Fatalf("Expected error: Got %+v\n", resp)
   883  	}
   884  }