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

     1  // Copyright 2015-2019 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package test
    15  
    16  import (
    17  	"bufio"
    18  	"encoding/json"
    19  	"fmt"
    20  	"io"
    21  	"net"
    22  	"net/http"
    23  	"runtime"
    24  	"strconv"
    25  	"strings"
    26  	"testing"
    27  	"time"
    28  
    29  	"get.pme.sh/pnats/server"
    30  )
    31  
    32  func runSeedServer(t *testing.T) (*server.Server, *server.Options) {
    33  	return RunServerWithConfig("./configs/seed.conf")
    34  }
    35  
    36  func runAuthSeedServer(t *testing.T) (*server.Server, *server.Options) {
    37  	return RunServerWithConfig("./configs/auth_seed.conf")
    38  }
    39  
    40  func TestSeedFirstRouteInfo(t *testing.T) {
    41  	s, opts := runSeedServer(t)
    42  	defer s.Shutdown()
    43  
    44  	rc := createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port)
    45  	defer rc.Close()
    46  
    47  	_, routeExpect := setupRoute(t, rc, opts)
    48  	buf := routeExpect(infoRe)
    49  
    50  	info := server.Info{}
    51  	if err := json.Unmarshal(buf[4:], &info); err != nil {
    52  		t.Fatalf("Could not unmarshal route info: %v", err)
    53  	}
    54  
    55  	if info.ID != s.ID() {
    56  		t.Fatalf("Expected seed's ID %q, got %q", s.ID(), info.ID)
    57  	}
    58  }
    59  
    60  func TestSeedMultipleRouteInfo(t *testing.T) {
    61  	s, opts := runSeedServer(t)
    62  	defer s.Shutdown()
    63  
    64  	rc1 := createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port)
    65  	defer rc1.Close()
    66  
    67  	rc1ID := "2222"
    68  	rc1Port := 22
    69  	rc1Host := "127.0.0.1"
    70  
    71  	routeSend1, route1Expect := setupRouteEx(t, rc1, opts, rc1ID)
    72  	route1Expect(infoRe)
    73  
    74  	// register ourselves via INFO
    75  	r1Info := server.Info{ID: rc1ID, Host: rc1Host, Port: rc1Port}
    76  	b, _ := json.Marshal(r1Info)
    77  	infoJSON := fmt.Sprintf(server.InfoProto, b)
    78  	routeSend1(infoJSON)
    79  	routeSend1("PING\r\n")
    80  	route1Expect(pongRe)
    81  
    82  	rc2 := createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port)
    83  	defer rc2.Close()
    84  
    85  	rc2ID := "2224"
    86  	rc2Port := 24
    87  	rc2Host := "127.0.0.1"
    88  
    89  	routeSend2, route2Expect := setupRouteEx(t, rc2, opts, rc2ID)
    90  
    91  	hp2 := fmt.Sprintf("nats-route://%s/", net.JoinHostPort(rc2Host, strconv.Itoa(rc2Port)))
    92  
    93  	// register ourselves via INFO
    94  	r2Info := server.Info{ID: rc2ID, Host: rc2Host, Port: rc2Port}
    95  	b, _ = json.Marshal(r2Info)
    96  	infoJSON = fmt.Sprintf(server.InfoProto, b)
    97  	routeSend2(infoJSON)
    98  
    99  	// Now read back the second INFO route1 should receive letting
   100  	// it know about route2
   101  	buf := route1Expect(infoRe)
   102  
   103  	info := server.Info{}
   104  	if err := json.Unmarshal(buf[4:], &info); err != nil {
   105  		t.Fatalf("Could not unmarshal route info: %v", err)
   106  	}
   107  
   108  	if info.ID != rc2ID {
   109  		t.Fatalf("Expected info.ID to be %q, got %q", rc2ID, info.ID)
   110  	}
   111  	if info.IP == "" {
   112  		t.Fatalf("Expected a IP for the implicit route")
   113  	}
   114  	if info.IP != hp2 {
   115  		t.Fatalf("Expected IP Host of %s, got %s\n", hp2, info.IP)
   116  	}
   117  
   118  	route2Expect(infoRe)
   119  	routeSend2("PING\r\n")
   120  	route2Expect(pongRe)
   121  
   122  	// Now let's do a third.
   123  	rc3 := createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port)
   124  	defer rc3.Close()
   125  
   126  	rc3ID := "2226"
   127  	rc3Port := 26
   128  	rc3Host := "127.0.0.1"
   129  
   130  	routeSend3, _ := setupRouteEx(t, rc3, opts, rc3ID)
   131  
   132  	// register ourselves via INFO
   133  	r3Info := server.Info{ID: rc3ID, Host: rc3Host, Port: rc3Port}
   134  	b, _ = json.Marshal(r3Info)
   135  	infoJSON = fmt.Sprintf(server.InfoProto, b)
   136  	routeSend3(infoJSON)
   137  
   138  	// Now read back out the info from the seed route
   139  	buf = route1Expect(infoRe)
   140  
   141  	info = server.Info{}
   142  	if err := json.Unmarshal(buf[4:], &info); err != nil {
   143  		t.Fatalf("Could not unmarshal route info: %v", err)
   144  	}
   145  
   146  	if info.ID != rc3ID {
   147  		t.Fatalf("Expected info.ID to be %q, got %q", rc3ID, info.ID)
   148  	}
   149  
   150  	// Now read back out the info from the seed route
   151  	buf = route2Expect(infoRe)
   152  
   153  	info = server.Info{}
   154  	if err := json.Unmarshal(buf[4:], &info); err != nil {
   155  		t.Fatalf("Could not unmarshal route info: %v", err)
   156  	}
   157  
   158  	if info.ID != rc3ID {
   159  		t.Fatalf("Expected info.ID to be %q, got %q", rc3ID, info.ID)
   160  	}
   161  }
   162  
   163  func TestSeedSolicitWorks(t *testing.T) {
   164  	s1, opts := runSeedServer(t)
   165  	defer s1.Shutdown()
   166  
   167  	// Create the routes string for others to connect to the seed.
   168  	routesStr := fmt.Sprintf("nats-route://%s:%d/", opts.Cluster.Host, opts.Cluster.Port)
   169  
   170  	// Run Server #2
   171  	s2Opts := nextServerOpts(opts)
   172  	s2Opts.Routes = server.RoutesFromStr(routesStr)
   173  
   174  	s2 := RunServer(s2Opts)
   175  	defer s2.Shutdown()
   176  
   177  	// Run Server #3
   178  	s3Opts := nextServerOpts(s2Opts)
   179  
   180  	s3 := RunServer(s3Opts)
   181  	defer s3.Shutdown()
   182  
   183  	// Wait for a bit for graph to connect
   184  	time.Sleep(500 * time.Millisecond)
   185  
   186  	// Grab Routez from monitor ports, make sure we are fully connected.
   187  	url := fmt.Sprintf("http://%s:%d/", opts.Host, opts.HTTPPort)
   188  	rz := readHTTPRoutez(t, url)
   189  	for _, route := range rz.Routes {
   190  		if route.LastActivity.IsZero() {
   191  			t.Error("Expected LastActivity to be valid\n")
   192  		}
   193  	}
   194  	ris := expectRids(t, rz, []string{s2.ID(), s3.ID()})
   195  	if ris[s2.ID()].IsConfigured {
   196  		t.Fatalf("Expected server not to be configured\n")
   197  	}
   198  	if ris[s3.ID()].IsConfigured {
   199  		t.Fatalf("Expected server not to be configured\n")
   200  	}
   201  
   202  	// Server 2 did solicit routes to Server 1.
   203  	url = fmt.Sprintf("http://%s:%d/", s2Opts.Host, s2Opts.HTTPPort)
   204  	rz = readHTTPRoutez(t, url)
   205  	for _, route := range rz.Routes {
   206  		if route.LastActivity.IsZero() {
   207  			t.Error("Expected LastActivity to be valid")
   208  		}
   209  	}
   210  	ris = expectRids(t, rz, []string{s1.ID(), s3.ID()})
   211  	if !ris[s1.ID()].IsConfigured {
   212  		t.Fatalf("Expected seed server to be configured\n")
   213  	}
   214  	if ris[s3.ID()].IsConfigured {
   215  		t.Fatalf("Expected server not to be configured\n")
   216  	}
   217  
   218  	url = fmt.Sprintf("http://%s:%d/", s3Opts.Host, s3Opts.HTTPPort)
   219  	rz = readHTTPRoutez(t, url)
   220  	for _, route := range rz.Routes {
   221  		if route.LastActivity.IsZero() {
   222  			t.Error("Expected LastActivity to be valid")
   223  		}
   224  	}
   225  	ris = expectRids(t, rz, []string{s1.ID(), s2.ID()})
   226  	if !ris[s1.ID()].IsConfigured {
   227  		t.Fatalf("Expected seed server to be configured\n")
   228  	}
   229  	if ris[s2.ID()].IsConfigured {
   230  		t.Fatalf("Expected server not to be configured\n")
   231  	}
   232  }
   233  
   234  type serverInfo struct {
   235  	server *server.Server
   236  	opts   *server.Options
   237  }
   238  
   239  func checkConnected(t *testing.T, servers []serverInfo, current int, oneSeed bool) error {
   240  	s := servers[current]
   241  
   242  	// Grab Routez from monitor ports, make sure we are fully connected
   243  	url := fmt.Sprintf("http://%s:%d/", s.opts.Host, s.opts.HTTPPort)
   244  	rz := readHTTPRoutez(t, url)
   245  	total := len(servers)
   246  	var ids []string
   247  	for i := 0; i < total; i++ {
   248  		if i == current {
   249  			continue
   250  		}
   251  		ids = append(ids, servers[i].server.ID())
   252  	}
   253  	ris, err := expectRidsNoFatal(t, true, rz, ids)
   254  	if err != nil {
   255  		return err
   256  	}
   257  	for i := 0; i < total; i++ {
   258  		if i == current {
   259  			continue
   260  		}
   261  		s := servers[i]
   262  		if current == 0 || ((oneSeed && i > 0) || (!oneSeed && (i != current-1))) {
   263  			if ris[s.server.ID()].IsConfigured {
   264  				return fmt.Errorf("Expected server %s:%d not to be configured", s.opts.Host, s.opts.Port)
   265  			}
   266  		} else if oneSeed || (i == current-1) {
   267  			if !ris[s.server.ID()].IsConfigured {
   268  				return fmt.Errorf("Expected server %s:%d to be configured", s.opts.Host, s.opts.Port)
   269  			}
   270  		}
   271  	}
   272  	return nil
   273  }
   274  
   275  func TestStressSeedSolicitWorks(t *testing.T) {
   276  	s1, opts := runSeedServer(t)
   277  	defer s1.Shutdown()
   278  
   279  	// Create the routes string for others to connect to the seed.
   280  	routesStr := fmt.Sprintf("nats-route://%s:%d/", opts.Cluster.Host, opts.Cluster.Port)
   281  
   282  	s2Opts := nextServerOpts(opts)
   283  	s2Opts.Routes = server.RoutesFromStr(routesStr)
   284  
   285  	s3Opts := nextServerOpts(s2Opts)
   286  	s4Opts := nextServerOpts(s3Opts)
   287  
   288  	for i := 0; i < 10; i++ {
   289  		func() {
   290  			// Run these servers manually, because we want them to start and
   291  			// connect to s1 as fast as possible.
   292  
   293  			s2 := server.New(s2Opts)
   294  			if s2 == nil {
   295  				panic("No NATS Server object returned.")
   296  			}
   297  			defer s2.Shutdown()
   298  			go s2.Start()
   299  
   300  			s3 := server.New(s3Opts)
   301  			if s3 == nil {
   302  				panic("No NATS Server object returned.")
   303  			}
   304  			defer s3.Shutdown()
   305  			go s3.Start()
   306  
   307  			s4 := server.New(s4Opts)
   308  			if s4 == nil {
   309  				panic("No NATS Server object returned.")
   310  			}
   311  			defer s4.Shutdown()
   312  			go s4.Start()
   313  
   314  			serversInfo := []serverInfo{{s1, opts}, {s2, s2Opts}, {s3, s3Opts}, {s4, s4Opts}}
   315  
   316  			checkFor(t, 5*time.Second, 100*time.Millisecond, func() error {
   317  				for j := 0; j < len(serversInfo); j++ {
   318  					if err := checkConnected(t, serversInfo, j, true); err != nil {
   319  						return err
   320  					}
   321  				}
   322  				return nil
   323  			})
   324  		}()
   325  		checkNumRoutes(t, s1, 0)
   326  	}
   327  }
   328  
   329  func TestChainedSolicitWorks(t *testing.T) {
   330  	s1, opts := runSeedServer(t)
   331  	defer s1.Shutdown()
   332  
   333  	// Create the routes string for others to connect to the seed.
   334  	routesStr := fmt.Sprintf("nats-route://%s:%d/", opts.Cluster.Host, opts.Cluster.Port)
   335  
   336  	// Run Server #2
   337  	s2Opts := nextServerOpts(opts)
   338  	s2Opts.Routes = server.RoutesFromStr(routesStr)
   339  
   340  	s2 := RunServer(s2Opts)
   341  	defer s2.Shutdown()
   342  
   343  	// Run Server #3
   344  	s3Opts := nextServerOpts(s2Opts)
   345  	// We will have s3 connect to s2, not the seed.
   346  	routesStr = fmt.Sprintf("nats-route://%s:%d/", s2Opts.Cluster.Host, s2Opts.Cluster.Port)
   347  	s3Opts.Routes = server.RoutesFromStr(routesStr)
   348  
   349  	s3 := RunServer(s3Opts)
   350  	defer s3.Shutdown()
   351  
   352  	// Wait for a bit for graph to connect
   353  	time.Sleep(500 * time.Millisecond)
   354  
   355  	// Grab Routez from monitor ports, make sure we are fully connected
   356  	url := fmt.Sprintf("http://%s:%d/", opts.Host, opts.HTTPPort)
   357  	rz := readHTTPRoutez(t, url)
   358  	ris := expectRids(t, rz, []string{s2.ID(), s3.ID()})
   359  	if ris[s2.ID()].IsConfigured {
   360  		t.Fatalf("Expected server not to be configured\n")
   361  	}
   362  	if ris[s3.ID()].IsConfigured {
   363  		t.Fatalf("Expected server not to be configured\n")
   364  	}
   365  
   366  	url = fmt.Sprintf("http://%s:%d/", s2Opts.Host, s2Opts.HTTPPort)
   367  	rz = readHTTPRoutez(t, url)
   368  	ris = expectRids(t, rz, []string{s1.ID(), s3.ID()})
   369  	if !ris[s1.ID()].IsConfigured {
   370  		t.Fatalf("Expected seed server to be configured\n")
   371  	}
   372  	if ris[s3.ID()].IsConfigured {
   373  		t.Fatalf("Expected server not to be configured\n")
   374  	}
   375  
   376  	url = fmt.Sprintf("http://%s:%d/", s3Opts.Host, s3Opts.HTTPPort)
   377  	rz = readHTTPRoutez(t, url)
   378  	ris = expectRids(t, rz, []string{s1.ID(), s2.ID()})
   379  	if !ris[s2.ID()].IsConfigured {
   380  		t.Fatalf("Expected s2 server to be configured\n")
   381  	}
   382  	if ris[s1.ID()].IsConfigured {
   383  		t.Fatalf("Expected seed server not to be configured\n")
   384  	}
   385  }
   386  
   387  func TestStressChainedSolicitWorks(t *testing.T) {
   388  	s1, opts := runSeedServer(t)
   389  	defer s1.Shutdown()
   390  
   391  	// Create the routes string for s2 to connect to the seed
   392  	routesStr := fmt.Sprintf("nats-route://%s:%d/", opts.Cluster.Host, opts.Cluster.Port)
   393  	s2Opts := nextServerOpts(opts)
   394  	s2Opts.Routes = server.RoutesFromStr(routesStr)
   395  
   396  	s3Opts := nextServerOpts(s2Opts)
   397  	// Create the routes string for s3 to connect to s2
   398  	routesStr = fmt.Sprintf("nats-route://%s:%d/", s2Opts.Cluster.Host, s2Opts.Cluster.Port)
   399  	s3Opts.Routes = server.RoutesFromStr(routesStr)
   400  
   401  	s4Opts := nextServerOpts(s3Opts)
   402  	// Create the routes string for s4 to connect to s3
   403  	routesStr = fmt.Sprintf("nats-route://%s:%d/", s3Opts.Cluster.Host, s3Opts.Cluster.Port)
   404  	s4Opts.Routes = server.RoutesFromStr(routesStr)
   405  
   406  	for i := 0; i < 10; i++ {
   407  		func() {
   408  			// Run these servers manually, because we want them to start and
   409  			// connect to s1 as fast as possible.
   410  
   411  			s2 := server.New(s2Opts)
   412  			if s2 == nil {
   413  				panic("No NATS Server object returned.")
   414  			}
   415  			defer s2.Shutdown()
   416  			go s2.Start()
   417  
   418  			s3 := server.New(s3Opts)
   419  			if s3 == nil {
   420  				panic("No NATS Server object returned.")
   421  			}
   422  			defer s3.Shutdown()
   423  			go s3.Start()
   424  
   425  			s4 := server.New(s4Opts)
   426  			if s4 == nil {
   427  				panic("No NATS Server object returned.")
   428  			}
   429  			defer s4.Shutdown()
   430  			go s4.Start()
   431  
   432  			serversInfo := []serverInfo{{s1, opts}, {s2, s2Opts}, {s3, s3Opts}, {s4, s4Opts}}
   433  
   434  			checkFor(t, 5*time.Second, 100*time.Millisecond, func() error {
   435  				for j := 0; j < len(serversInfo); j++ {
   436  					if err := checkConnected(t, serversInfo, j, false); err != nil {
   437  						return err
   438  					}
   439  				}
   440  				return nil
   441  			})
   442  		}()
   443  		checkNumRoutes(t, s1, 0)
   444  	}
   445  }
   446  
   447  func TestAuthSeedSolicitWorks(t *testing.T) {
   448  	s1, opts := runAuthSeedServer(t)
   449  	defer s1.Shutdown()
   450  
   451  	// Create the routes string for others to connect to the seed.
   452  	routesStr := fmt.Sprintf("nats-route://%s:%s@%s:%d/", opts.Cluster.Username, opts.Cluster.Password, opts.Cluster.Host, opts.Cluster.Port)
   453  
   454  	// Run Server #2
   455  	s2Opts := nextServerOpts(opts)
   456  	s2Opts.Routes = server.RoutesFromStr(routesStr)
   457  
   458  	s2 := RunServer(s2Opts)
   459  	defer s2.Shutdown()
   460  
   461  	// Run Server #3
   462  	s3Opts := nextServerOpts(s2Opts)
   463  
   464  	s3 := RunServer(s3Opts)
   465  	defer s3.Shutdown()
   466  
   467  	// Wait for a bit for graph to connect
   468  	time.Sleep(500 * time.Millisecond)
   469  
   470  	// Grab Routez from monitor ports, make sure we are fully connected
   471  	url := fmt.Sprintf("http://%s:%d/", opts.Host, opts.HTTPPort)
   472  	rz := readHTTPRoutez(t, url)
   473  	ris := expectRids(t, rz, []string{s2.ID(), s3.ID()})
   474  	if ris[s2.ID()].IsConfigured {
   475  		t.Fatalf("Expected server not to be configured\n")
   476  	}
   477  	if ris[s3.ID()].IsConfigured {
   478  		t.Fatalf("Expected server not to be configured\n")
   479  	}
   480  
   481  	url = fmt.Sprintf("http://%s:%d/", s2Opts.Host, s2Opts.HTTPPort)
   482  	rz = readHTTPRoutez(t, url)
   483  	ris = expectRids(t, rz, []string{s1.ID(), s3.ID()})
   484  	if !ris[s1.ID()].IsConfigured {
   485  		t.Fatalf("Expected seed server to be configured\n")
   486  	}
   487  	if ris[s3.ID()].IsConfigured {
   488  		t.Fatalf("Expected server not to be configured\n")
   489  	}
   490  
   491  	url = fmt.Sprintf("http://%s:%d/", s3Opts.Host, s3Opts.HTTPPort)
   492  	rz = readHTTPRoutez(t, url)
   493  	ris = expectRids(t, rz, []string{s1.ID(), s2.ID()})
   494  	if !ris[s1.ID()].IsConfigured {
   495  		t.Fatalf("Expected seed server to be configured\n")
   496  	}
   497  	if ris[s2.ID()].IsConfigured {
   498  		t.Fatalf("Expected server not to be configured\n")
   499  	}
   500  }
   501  
   502  // Helper to check for correct route memberships
   503  func expectRids(t *testing.T, rz *server.Routez, rids []string) map[string]*server.RouteInfo {
   504  	ri, err := expectRidsNoFatal(t, false, rz, rids)
   505  	if err != nil {
   506  		t.Fatalf("%v", err)
   507  	}
   508  	return ri
   509  }
   510  
   511  func expectRidsNoFatal(t *testing.T, direct bool, rz *server.Routez, rids []string) (map[string]*server.RouteInfo, error) {
   512  	caller := 1
   513  	if !direct {
   514  		caller++
   515  	}
   516  	if len(rids) != rz.NumRoutes {
   517  		_, fn, line, _ := runtime.Caller(caller)
   518  		return nil, fmt.Errorf("[%s:%d] Expecting %d routes, got %d\n", fn, line, len(rids), rz.NumRoutes)
   519  	}
   520  	set := make(map[string]bool)
   521  	for _, v := range rids {
   522  		set[v] = true
   523  	}
   524  	// Make result map for additional checking
   525  	ri := make(map[string]*server.RouteInfo)
   526  	for _, r := range rz.Routes {
   527  		if !set[r.RemoteID] {
   528  			_, fn, line, _ := runtime.Caller(caller)
   529  			return nil, fmt.Errorf("[%s:%d] Route with rid %s unexpected, expected %+v\n", fn, line, r.RemoteID, rids)
   530  		}
   531  		ri[r.RemoteID] = r
   532  	}
   533  	return ri, nil
   534  }
   535  
   536  // Helper to easily grab routez info.
   537  func readHTTPRoutez(t *testing.T, url string) *server.Routez {
   538  	resetPreviousHTTPConnections()
   539  	resp, err := http.Get(url + "routez")
   540  	if err != nil {
   541  		stackFatalf(t, "Expected no error: Got %v\n", err)
   542  	}
   543  	defer resp.Body.Close()
   544  	if resp.StatusCode != 200 {
   545  		stackFatalf(t, "Expected a 200 response, got %d\n", resp.StatusCode)
   546  	}
   547  	body, err := io.ReadAll(resp.Body)
   548  	if err != nil {
   549  		stackFatalf(t, "Got an error reading the body: %v\n", err)
   550  	}
   551  	r := server.Routez{}
   552  	if err := json.Unmarshal(body, &r); err != nil {
   553  		stackFatalf(t, "Got an error unmarshalling the body: %v\n", err)
   554  	}
   555  	return &r
   556  }
   557  
   558  func TestSeedReturnIPInInfo(t *testing.T) {
   559  	s, opts := runSeedServer(t)
   560  	defer s.Shutdown()
   561  
   562  	rc1 := createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port)
   563  	defer rc1.Close()
   564  
   565  	rc1ID := "2222"
   566  	rc1Port := 22
   567  	rc1Host := "127.0.0.1"
   568  
   569  	routeSend1, route1Expect := setupRouteEx(t, rc1, opts, rc1ID)
   570  	route1Expect(infoRe)
   571  
   572  	// register ourselves via INFO
   573  	r1Info := server.Info{ID: rc1ID, Host: rc1Host, Port: rc1Port}
   574  	b, _ := json.Marshal(r1Info)
   575  	infoJSON := fmt.Sprintf(server.InfoProto, b)
   576  	routeSend1(infoJSON)
   577  	routeSend1("PING\r\n")
   578  	route1Expect(pongRe)
   579  
   580  	rc2 := createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port)
   581  	defer rc2.Close()
   582  
   583  	rc2ID := "2224"
   584  	rc2Port := 24
   585  	rc2Host := "127.0.0.1"
   586  
   587  	routeSend2, _ := setupRouteEx(t, rc2, opts, rc2ID)
   588  
   589  	// register ourselves via INFO
   590  	r2Info := server.Info{ID: rc2ID, Host: rc2Host, Port: rc2Port}
   591  	b, _ = json.Marshal(r2Info)
   592  	infoJSON = fmt.Sprintf(server.InfoProto, b)
   593  	routeSend2(infoJSON)
   594  
   595  	// Now read info that route1 should have received from the seed
   596  	buf := route1Expect(infoRe)
   597  
   598  	info := server.Info{}
   599  	if err := json.Unmarshal(buf[4:], &info); err != nil {
   600  		t.Fatalf("Could not unmarshal route info: %v", err)
   601  	}
   602  
   603  	if info.IP == "" {
   604  		t.Fatal("Expected to have IP in INFO")
   605  	}
   606  	rip, _, err := net.SplitHostPort(strings.TrimPrefix(info.IP, "nats-route://"))
   607  	if err != nil {
   608  		t.Fatalf("Error parsing url: %v", err)
   609  	}
   610  	addr, ok := rc1.RemoteAddr().(*net.TCPAddr)
   611  	if !ok {
   612  		t.Fatal("Unable to get IP address from route")
   613  	}
   614  	s1 := strings.ToLower(addr.IP.String())
   615  	s2 := strings.ToLower(rip)
   616  	if s1 != s2 {
   617  		t.Fatalf("Expected IP %s, got %s", s1, s2)
   618  	}
   619  }
   620  
   621  func TestImplicitRouteRetry(t *testing.T) {
   622  	srvSeed, optsSeed := runSeedServer(t)
   623  	defer srvSeed.Shutdown()
   624  
   625  	optsA := nextServerOpts(optsSeed)
   626  	optsA.Routes = server.RoutesFromStr(fmt.Sprintf("nats://%s:%d", optsSeed.Cluster.Host, optsSeed.Cluster.Port))
   627  	optsA.Cluster.ConnectRetries = 5
   628  	srvA := RunServer(optsA)
   629  	defer srvA.Shutdown()
   630  
   631  	optsB := nextServerOpts(optsA)
   632  	rcb := createRouteConn(t, optsSeed.Cluster.Host, optsSeed.Cluster.Port)
   633  	defer rcb.Close()
   634  	rcbID := "ServerB"
   635  	routeBSend, routeBExpect := setupRouteEx(t, rcb, optsB, rcbID)
   636  	routeBExpect(infoRe)
   637  	// register ourselves via INFO
   638  	rbInfo := server.Info{ID: rcbID, Host: optsB.Cluster.Host, Port: optsB.Cluster.Port}
   639  	b, _ := json.Marshal(rbInfo)
   640  	infoJSON := fmt.Sprintf(server.InfoProto, b)
   641  	routeBSend(infoJSON)
   642  	routeBSend("PING\r\n")
   643  	routeBExpect(pongRe)
   644  
   645  	// srvA should try to connect. Wait to make sure that it fails.
   646  	time.Sleep(1200 * time.Millisecond)
   647  
   648  	// Setup a fake route listen for routeB
   649  	rbListen, err := net.Listen("tcp", fmt.Sprintf("%s:%d", optsB.Cluster.Host, optsB.Cluster.Port))
   650  	if err != nil {
   651  		t.Fatalf("Error during listen: %v", err)
   652  	}
   653  	defer rbListen.Close()
   654  	c, err := rbListen.Accept()
   655  	if err != nil {
   656  		t.Fatalf("Error during accept: %v", err)
   657  	}
   658  	defer c.Close()
   659  
   660  	br := bufio.NewReaderSize(c, 32768)
   661  	// Consume CONNECT and INFO
   662  	for i := 0; i < 2; i++ {
   663  		c.SetReadDeadline(time.Now().Add(2 * time.Second))
   664  		buf, _, err := br.ReadLine()
   665  		c.SetReadDeadline(time.Time{})
   666  		if err != nil {
   667  			t.Fatalf("Error reading: %v", err)
   668  		}
   669  		if i == 0 {
   670  			continue
   671  		}
   672  		buf = buf[len("INFO "):]
   673  		info := &server.Info{}
   674  		if err := json.Unmarshal(buf, info); err != nil {
   675  			t.Fatalf("Error during unmarshal: %v", err)
   676  		}
   677  		// Check INFO is from server A.
   678  		if info.ID != srvA.ID() {
   679  			t.Fatalf("Expected CONNECT from %v, got CONNECT from %v", srvA.ID(), info.ID)
   680  		}
   681  	}
   682  }