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 }