github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/base/addr_validation_test.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package base_test
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  	"net"
    17  	"os"
    18  	"strings"
    19  	"testing"
    20  
    21  	"github.com/cockroachdb/cockroach/pkg/base"
    22  	"github.com/cockroachdb/cockroach/pkg/testutils"
    23  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    24  )
    25  
    26  type addrs struct{ listen, adv, http, advhttp, sql, advsql string }
    27  
    28  func (a *addrs) String() string {
    29  	return fmt.Sprintf("--listen-addr=%s --advertise-addr=%s --http-addr=%s (http adv: %s) --sql-addr=%s (sql adv: %s)",
    30  		a.listen, a.adv, a.http, a.advhttp, a.sql, a.advsql)
    31  }
    32  
    33  func TestValidateAddrs(t *testing.T) {
    34  	defer leaktest.AfterTest(t)()
    35  
    36  	// Prepare some reference strings that will be checked in the
    37  	// test below.
    38  	hostname, err := os.Hostname()
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	hostAddr, err := base.LookupAddr(context.Background(), net.DefaultResolver, hostname)
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	if strings.Contains(hostAddr, ":") {
    47  		hostAddr = "[" + hostAddr + "]"
    48  	}
    49  	localAddr, err := base.LookupAddr(context.Background(), net.DefaultResolver, "localhost")
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  	if strings.Contains(localAddr, ":") {
    54  		localAddr = "[" + localAddr + "]"
    55  	}
    56  
    57  	// We need to know what a port name resolution error look like,
    58  	// because they may be different across systems/libcs.
    59  	_, err = net.DefaultResolver.LookupPort(context.Background(), "tcp", "nonexistent")
    60  	if err == nil {
    61  		t.Fatal("expected port resolution failure, got no error")
    62  	}
    63  	portExpectedErr := err.Error()
    64  	// For the host name resolution error we can reliably expect "no such host"
    65  	// below, but before we test anything we need to ensure we indeed have
    66  	// a reliably non-resolvable host name.
    67  	_, err = net.DefaultResolver.LookupIPAddr(context.Background(), "nonexistent.example.com")
    68  	if err == nil {
    69  		t.Fatal("expected host resolution failure, got no error")
    70  	}
    71  
    72  	// The test cases.
    73  	testData := []struct {
    74  		in          addrs
    75  		expectedErr string
    76  		expected    addrs
    77  	}{
    78  		// Common case: no server flags, all defaults.
    79  		{addrs{":26257", "", ":8080", "", ":5432", ""}, "",
    80  			addrs{":26257", hostname + ":26257", ":8080", hostname + ":8080", ":5432", hostname + ":5432"}},
    81  
    82  		// Another common case: --listen-addr=<somehost>
    83  		{addrs{hostname + ":26257", "", ":8080", "", ":5432", ""}, "",
    84  			addrs{hostAddr + ":26257", hostname + ":26257", hostAddr + ":8080", hostname + ":8080", hostAddr + ":5432", hostname + ":5432"}},
    85  
    86  		// Another common case: --listen-addr=localhost
    87  		{addrs{"localhost:26257", "", ":8080", "", ":5432", ""}, "",
    88  			addrs{localAddr + ":26257", "localhost:26257", localAddr + ":8080", "localhost:8080", localAddr + ":5432", "localhost:5432"}},
    89  
    90  		// Correct use: --listen-addr=<someaddr> --advertise-host=<somehost>
    91  		{addrs{hostAddr + ":26257", hostname + ":", ":8080", "", ":5432", ""}, "",
    92  			addrs{hostAddr + ":26257", hostname + ":26257", hostAddr + ":8080", hostname + ":8080", hostAddr + ":5432", hostname + ":5432"}},
    93  
    94  		// Explicit port number in advertise addr.
    95  		{addrs{hostAddr + ":26257", hostname + ":12345", ":8080", "", ":5432", ""}, "",
    96  			addrs{hostAddr + ":26257", hostname + ":12345", hostAddr + ":8080", hostname + ":8080", hostAddr + ":5432", hostname + ":5432"}},
    97  
    98  		// Use a non-numeric port number.
    99  		{addrs{":postgresql", "", ":http", "", ":postgresql", ""}, "",
   100  			addrs{":5432", hostname + ":5432", ":80", hostname + ":80", ":5432", hostname + ":5432"}},
   101  
   102  		// Make HTTP local only.
   103  		{addrs{":26257", "", "localhost:8080", "", ":5432", ""}, "",
   104  			addrs{":26257", hostname + ":26257", localAddr + ":8080", "localhost:8080", ":5432", hostname + ":5432"}},
   105  
   106  		// Local server but public HTTP.
   107  		{addrs{"localhost:26257", "", hostname + ":8080", "", ":5432", ""}, "",
   108  			addrs{localAddr + ":26257", "localhost:26257", hostAddr + ":8080", hostname + ":8080", localAddr + ":5432", "localhost:5432"}},
   109  
   110  		// Make SQL local only.
   111  		{addrs{":26257", "", ":8080", "", "localhost:5432", ""}, "",
   112  			addrs{":26257", hostname + ":26257", ":8080", hostname + ":8080", localAddr + ":5432", "localhost:5432"}},
   113  
   114  		// Not-unreasonable case: addresses set empty. Means using port 0.
   115  		{addrs{"", "", "", "", "", ""}, "",
   116  			addrs{":0", hostname + ":0", ":0", hostname + ":0", ":0", hostname + ":0"}},
   117  		// A colon means "all-addr, auto-port".
   118  		{addrs{":", "", "", "", "", ""}, "",
   119  			addrs{":0", hostname + ":0", ":0", hostname + ":0", ":0", hostname + ":0"}},
   120  		{addrs{"", ":", "", "", "", ""}, "",
   121  			addrs{":0", hostname + ":0", ":0", hostname + ":0", ":0", hostname + ":0"}},
   122  		{addrs{"", "", ":", "", "", ""}, "",
   123  			addrs{":0", hostname + ":0", ":0", hostname + ":0", ":0", hostname + ":0"}},
   124  		{addrs{"", "", "", "", ":", ""}, "",
   125  			addrs{":0", hostname + ":0", ":0", hostname + ":0", ":0", hostname + ":0"}},
   126  		{addrs{"", "", "", "", "", ":"}, "",
   127  			addrs{":0", hostname + ":0", ":0", hostname + ":0", ":0", hostname + ":0"}},
   128  
   129  		// Advertise port 0 means reuse listen port. We don't
   130  		// auto-allocate ports for advertised addresses.
   131  		{addrs{":12345", ":0", "", "", ":5432", ""}, "",
   132  			addrs{":12345", hostname + ":12345", ":0", hostname + ":0", ":5432", hostname + ":5432"}},
   133  		{addrs{":12345", "", "", "", ":5432", ":0"}, "",
   134  			addrs{":12345", hostname + ":12345", ":0", hostname + ":0", ":5432", hostname + ":5432"}},
   135  
   136  		// Expected errors.
   137  
   138  		// Missing port number.
   139  		{addrs{"localhost", "", "", "", "", ""}, "invalid --listen-addr.*missing port in address", addrs{}},
   140  		{addrs{":26257", "", "localhost", "", "", ""}, "invalid --http-addr.*missing port in address", addrs{}},
   141  		// Invalid port number.
   142  		{addrs{"localhost:-1231", "", "", "", "", ""}, "invalid port", addrs{}},
   143  		{addrs{"localhost:nonexistent", "", "", "", "", ""}, portExpectedErr, addrs{}},
   144  		// Invalid address.
   145  		{addrs{"nonexistent.example.com:26257", "", "", "", "", ""}, "no such host", addrs{}},
   146  		{addrs{"333.333.333.333:26257", "", "", "", "", ""}, "no such host", addrs{}},
   147  	}
   148  
   149  	for i, test := range testData {
   150  		t.Run(fmt.Sprintf("%d/%s", i, test.in), func(t *testing.T) {
   151  			cfg := base.Config{
   152  				Addr:             test.in.listen,
   153  				AdvertiseAddr:    test.in.adv,
   154  				HTTPAddr:         test.in.http,
   155  				SQLAddr:          test.in.sql,
   156  				SQLAdvertiseAddr: test.in.advsql,
   157  			}
   158  
   159  			if err := cfg.ValidateAddrs(context.Background()); err != nil {
   160  				if !testutils.IsError(err, test.expectedErr) {
   161  					t.Fatalf("expected error %q, got %v", test.expectedErr, err)
   162  				}
   163  				return
   164  			}
   165  			if test.expectedErr != "" {
   166  				t.Fatalf("expected error %q, got success", test.expectedErr)
   167  			}
   168  
   169  			got := addrs{cfg.Addr, cfg.AdvertiseAddr, cfg.HTTPAddr, cfg.HTTPAdvertiseAddr, cfg.SQLAddr, cfg.SQLAdvertiseAddr}
   170  			gotStr := got.String()
   171  			expStr := test.expected.String()
   172  
   173  			if gotStr != expStr {
   174  				t.Fatalf("expected %q,\ngot %q", expStr, gotStr)
   175  			}
   176  		})
   177  	}
   178  }