github.com/thanos-io/thanos@v0.32.5/pkg/discovery/dns/resolver_test.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package dns 5 6 import ( 7 "context" 8 "net" 9 "sort" 10 "testing" 11 12 "github.com/go-kit/log" 13 14 "github.com/pkg/errors" 15 16 "github.com/efficientgo/core/testutil" 17 ) 18 19 type mockHostnameResolver struct { 20 resultIPs map[string][]net.IPAddr 21 resultSRVs map[string][]*net.SRV 22 err error 23 } 24 25 func (m mockHostnameResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error) { 26 if m.err != nil { 27 return nil, m.err 28 } 29 return m.resultIPs[host], nil 30 } 31 32 func (m mockHostnameResolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error) { 33 if m.err != nil { 34 return "", nil, m.err 35 } 36 return "", m.resultSRVs[name], nil 37 } 38 39 func (m mockHostnameResolver) IsNotFound(err error) bool { 40 return false 41 } 42 43 type DNSSDTest struct { 44 testName string 45 addr string 46 qtype QType 47 expectedResult []string 48 expectedErr error 49 resolver *mockHostnameResolver 50 } 51 52 var ( 53 errorFromResolver = errors.New("error from resolver") 54 55 dnsSDTests = []DNSSDTest{ 56 { 57 testName: "single ip from dns lookup of host port", 58 addr: "test.mycompany.com:8080", 59 qtype: A, 60 expectedResult: []string{"192.168.0.1:8080"}, 61 expectedErr: nil, 62 resolver: &mockHostnameResolver{ 63 resultIPs: map[string][]net.IPAddr{ 64 "test.mycompany.com": {net.IPAddr{IP: net.ParseIP("192.168.0.1")}}, 65 }, 66 }, 67 }, 68 // Scheme is preserved. 69 { 70 testName: "single ip from dns lookup of host port with scheme", 71 addr: "http://test.mycompany.com:8080", 72 qtype: A, 73 expectedResult: []string{"http://192.168.0.1:8080"}, 74 expectedErr: nil, 75 resolver: &mockHostnameResolver{ 76 resultIPs: map[string][]net.IPAddr{ 77 "test.mycompany.com": {net.IPAddr{IP: net.ParseIP("192.168.0.1")}}, 78 }, 79 }, 80 }, 81 { 82 testName: "error on dns lookup when no port is specified", 83 addr: "test.mycompany.com", 84 qtype: A, 85 expectedResult: nil, 86 expectedErr: errors.New("missing port in address given for dns lookup: test.mycompany.com"), 87 resolver: &mockHostnameResolver{}, 88 }, 89 { 90 testName: "multiple SRV records from SRV lookup", 91 addr: "_test._tcp.mycompany.com", 92 qtype: SRV, 93 expectedResult: []string{"192.168.0.1:8080", "192.168.0.2:8081"}, 94 expectedErr: nil, 95 resolver: &mockHostnameResolver{ 96 resultSRVs: map[string][]*net.SRV{ 97 "_test._tcp.mycompany.com": { 98 &net.SRV{Target: "alt1.mycompany.com.", Port: 8080}, 99 &net.SRV{Target: "alt2.mycompany.com.", Port: 8081}, 100 }, 101 }, 102 resultIPs: map[string][]net.IPAddr{ 103 "alt1.mycompany.com.": {net.IPAddr{IP: net.ParseIP("192.168.0.1")}}, 104 "alt2.mycompany.com.": {net.IPAddr{IP: net.ParseIP("192.168.0.2")}}, 105 }, 106 }, 107 }, 108 { 109 testName: "multiple SRV records from SRV lookup with specified port", 110 addr: "_test._tcp.mycompany.com:8082", 111 qtype: SRV, 112 expectedResult: []string{"192.168.0.1:8082", "192.168.0.2:8082"}, 113 expectedErr: nil, 114 resolver: &mockHostnameResolver{ 115 resultSRVs: map[string][]*net.SRV{ 116 "_test._tcp.mycompany.com": { 117 &net.SRV{Target: "alt1.mycompany.com.", Port: 8080}, 118 &net.SRV{Target: "alt2.mycompany.com.", Port: 8081}, 119 }, 120 }, 121 resultIPs: map[string][]net.IPAddr{ 122 "alt1.mycompany.com.": {net.IPAddr{IP: net.ParseIP("192.168.0.1")}}, 123 "alt2.mycompany.com.": {net.IPAddr{IP: net.ParseIP("192.168.0.2")}}, 124 }, 125 }, 126 }, 127 { 128 testName: "error from SRV resolver", 129 addr: "_test._tcp.mycompany.com", 130 qtype: SRV, 131 expectedResult: nil, 132 expectedErr: errors.Wrapf(errorFromResolver, "lookup SRV records \"_test._tcp.mycompany.com\""), 133 resolver: &mockHostnameResolver{err: errorFromResolver}, 134 }, 135 { 136 testName: "multiple SRV records from SRV no A lookup", 137 addr: "_test._tcp.mycompany.com", 138 qtype: SRVNoA, 139 expectedResult: []string{"192.168.0.1:8080", "192.168.0.2:8081"}, 140 expectedErr: nil, 141 resolver: &mockHostnameResolver{ 142 resultSRVs: map[string][]*net.SRV{ 143 "_test._tcp.mycompany.com": { 144 &net.SRV{Target: "192.168.0.1", Port: 8080}, 145 &net.SRV{Target: "192.168.0.2", Port: 8081}, 146 }, 147 }, 148 }, 149 }, 150 { 151 testName: "multiple SRV records from SRV no A lookup with specified port", 152 addr: "_test._tcp.mycompany.com:8082", 153 qtype: SRVNoA, 154 expectedResult: []string{"192.168.0.1:8082", "192.168.0.2:8082"}, 155 expectedErr: nil, 156 resolver: &mockHostnameResolver{ 157 resultSRVs: map[string][]*net.SRV{ 158 "_test._tcp.mycompany.com": { 159 &net.SRV{Target: "192.168.0.1", Port: 8080}, 160 &net.SRV{Target: "192.168.0.2", Port: 8081}, 161 }, 162 }, 163 }, 164 }, 165 { 166 testName: "error from SRV no A lookup", 167 addr: "_test._tcp.mycompany.com", 168 qtype: SRV, 169 expectedResult: nil, 170 expectedErr: errors.Wrapf(errorFromResolver, "lookup SRV records \"_test._tcp.mycompany.com\""), 171 resolver: &mockHostnameResolver{err: errorFromResolver}, 172 }, 173 { 174 testName: "error on bad qtype", 175 addr: "test.mycompany.com", 176 qtype: "invalid", 177 expectedResult: nil, 178 expectedErr: errors.New("invalid lookup scheme \"invalid\""), 179 resolver: &mockHostnameResolver{}, 180 }, 181 } 182 ) 183 184 func TestDnsSD_Resolve(t *testing.T) { 185 for _, tt := range dnsSDTests { 186 t.Run(tt.testName, func(t *testing.T) { 187 testDnsSd(t, tt) 188 }) 189 } 190 } 191 192 func testDnsSd(t *testing.T, tt DNSSDTest) { 193 ctx := context.TODO() 194 dnsSD := dnsSD{tt.resolver, log.NewNopLogger()} 195 196 result, err := dnsSD.Resolve(ctx, tt.addr, tt.qtype) 197 if tt.expectedErr != nil { 198 testutil.NotOk(t, err) 199 testutil.Assert(t, tt.expectedErr.Error() == err.Error(), "expected error '%v', but got '%v'", tt.expectedErr.Error(), err.Error()) 200 } else { 201 testutil.Ok(t, err) 202 } 203 sort.Strings(result) 204 testutil.Equals(t, tt.expectedResult, result) 205 }