1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package srv
16
17 import (
18 "errors"
19 "fmt"
20 "net"
21 "reflect"
22 "strings"
23 "testing"
24
25 "go.etcd.io/etcd/client/pkg/v3/testutil"
26 )
27
28 func notFoundErr(service, proto, domain string) error {
29 name := fmt.Sprintf("_%s._%s.%s", service, proto, domain)
30 return &net.DNSError{Err: "no such host", Name: name, Server: "10.0.0.53:53", IsTimeout: false, IsTemporary: false, IsNotFound: true}
31 }
32
33 func TestSRVGetCluster(t *testing.T) {
34 defer func() {
35 lookupSRV = net.LookupSRV
36 resolveTCPAddr = net.ResolveTCPAddr
37 }()
38
39 hasErr := func(err error) bool {
40 return err != nil
41 }
42
43 name := "dnsClusterTest"
44 dns := map[string]string{
45 "1.example.com.:2480": "10.0.0.1:2480",
46 "2.example.com.:2480": "10.0.0.2:2480",
47 "3.example.com.:2480": "10.0.0.3:2480",
48 "4.example.com.:2380": "10.0.0.3:2380",
49 }
50 srvAll := []*net.SRV{
51 {Target: "1.example.com.", Port: 2480},
52 {Target: "2.example.com.", Port: 2480},
53 {Target: "3.example.com.", Port: 2480},
54 }
55 srvNone := []*net.SRV{}
56
57 tests := []struct {
58 service string
59 scheme string
60 withSSL []*net.SRV
61 withoutSSL []*net.SRV
62 urls []string
63 expected string
64 werr bool
65 }{
66 {
67 "etcd-server-ssl",
68 "https",
69 srvNone,
70 srvNone,
71 nil,
72 "",
73 true,
74 },
75 {
76 "etcd-server-ssl",
77 "https",
78 srvAll,
79 srvNone,
80 nil,
81 "0=https://1.example.com:2480,1=https://2.example.com:2480,2=https://3.example.com:2480",
82 false,
83 },
84 {
85 "etcd-server",
86 "http",
87 srvNone,
88 srvAll,
89 nil,
90 "0=http://1.example.com:2480,1=http://2.example.com:2480,2=http://3.example.com:2480",
91 false,
92 },
93 {
94 "etcd-server-ssl",
95 "https",
96 srvAll,
97 srvNone,
98 []string{"https://10.0.0.1:2480"},
99 "dnsClusterTest=https://1.example.com:2480,0=https://2.example.com:2480,1=https://3.example.com:2480",
100 false,
101 },
102
103 {
104 "etcd-server-ssl",
105 "https",
106 srvAll,
107 srvNone,
108 []string{"https://10.0.0.1:2480"},
109 "dnsClusterTest=https://1.example.com:2480,0=https://2.example.com:2480,1=https://3.example.com:2480",
110 false,
111 },
112
113 {
114 "etcd-server",
115 "http",
116 srvNone,
117 srvAll,
118 []string{"https://10.0.0.1:2480"},
119 "0=http://2.example.com:2480,1=http://3.example.com:2480",
120 false,
121 },
122 }
123
124 resolveTCPAddr = func(network, addr string) (*net.TCPAddr, error) {
125 if strings.Contains(addr, "10.0.0.") {
126
127 return net.ResolveTCPAddr(network, addr)
128 }
129 if dns[addr] == "" {
130 return nil, errors.New("missing dns record")
131 }
132 return net.ResolveTCPAddr(network, dns[addr])
133 }
134
135 for i, tt := range tests {
136 lookupSRV = func(service string, proto string, domain string) (string, []*net.SRV, error) {
137 if service == "etcd-server-ssl" {
138 if len(tt.withSSL) > 0 {
139 return "", tt.withSSL, nil
140 }
141 return "", nil, notFoundErr(service, proto, domain)
142 }
143 if service == "etcd-server" {
144 if len(tt.withoutSSL) > 0 {
145 return "", tt.withoutSSL, nil
146 }
147 return "", nil, notFoundErr(service, proto, domain)
148 }
149 return "", nil, errors.New("unknown service in mock")
150 }
151
152 urls := testutil.MustNewURLs(t, tt.urls)
153 str, err := GetCluster(tt.scheme, tt.service, name, "example.com", urls)
154
155 if hasErr(err) != tt.werr {
156 t.Fatalf("%d: err = %#v, want = %#v", i, err, tt.werr)
157 }
158 if strings.Join(str, ",") != tt.expected {
159 t.Errorf("#%d: cluster = %s, want %s", i, str, tt.expected)
160 }
161 }
162 }
163
164 func TestSRVDiscover(t *testing.T) {
165 defer func() { lookupSRV = net.LookupSRV }()
166
167 hasErr := func(err error) bool {
168 return err != nil
169 }
170
171 tests := []struct {
172 withSSL []*net.SRV
173 withoutSSL []*net.SRV
174 expected []string
175 werr bool
176 }{
177 {
178 []*net.SRV{},
179 []*net.SRV{},
180 []string{},
181 true,
182 },
183 {
184 []*net.SRV{},
185 []*net.SRV{
186 {Target: "10.0.0.1", Port: 2480},
187 {Target: "10.0.0.2", Port: 2480},
188 {Target: "10.0.0.3", Port: 2480},
189 },
190 []string{"http://10.0.0.1:2480", "http://10.0.0.2:2480", "http://10.0.0.3:2480"},
191 false,
192 },
193 {
194 []*net.SRV{
195 {Target: "10.0.0.1", Port: 2480},
196 {Target: "10.0.0.2", Port: 2480},
197 {Target: "10.0.0.3", Port: 2480},
198 },
199 []*net.SRV{},
200 []string{"https://10.0.0.1:2480", "https://10.0.0.2:2480", "https://10.0.0.3:2480"},
201 false,
202 },
203 {
204 []*net.SRV{
205 {Target: "10.0.0.1", Port: 2480},
206 {Target: "10.0.0.2", Port: 2480},
207 {Target: "10.0.0.3", Port: 2480},
208 },
209 []*net.SRV{
210 {Target: "10.0.0.1", Port: 7001},
211 },
212 []string{"https://10.0.0.1:2480", "https://10.0.0.2:2480", "https://10.0.0.3:2480", "http://10.0.0.1:7001"},
213 false,
214 },
215 {
216 []*net.SRV{
217 {Target: "10.0.0.1", Port: 2480},
218 {Target: "10.0.0.2", Port: 2480},
219 {Target: "10.0.0.3", Port: 2480},
220 },
221 []*net.SRV{
222 {Target: "10.0.0.1", Port: 7001},
223 },
224 []string{"https://10.0.0.1:2480", "https://10.0.0.2:2480", "https://10.0.0.3:2480", "http://10.0.0.1:7001"},
225 false,
226 },
227 {
228 []*net.SRV{
229 {Target: "a.example.com", Port: 2480},
230 {Target: "b.example.com", Port: 2480},
231 {Target: "c.example.com.", Port: 2480},
232 },
233 []*net.SRV{},
234 []string{"https://a.example.com:2480", "https://b.example.com:2480", "https://c.example.com.:2480"},
235 false,
236 },
237 }
238
239 for i, tt := range tests {
240 lookupSRV = func(service string, proto string, domain string) (string, []*net.SRV, error) {
241 if service == "etcd-client-ssl" {
242 if len(tt.withSSL) > 0 {
243 return "", tt.withSSL, nil
244 }
245 return "", nil, notFoundErr(service, proto, domain)
246 }
247 if service == "etcd-client" {
248 if len(tt.withoutSSL) > 0 {
249 return "", tt.withoutSSL, nil
250 }
251 return "", nil, notFoundErr(service, proto, domain)
252 }
253 return "", nil, errors.New("unknown service in mock")
254 }
255
256 srvs, err := GetClient("etcd-client", "example.com", "")
257
258 if hasErr(err) != tt.werr {
259 t.Fatalf("%d: err = %#v, want = %#v", i, err, tt.werr)
260 }
261 if srvs == nil {
262 if len(tt.expected) > 0 {
263 t.Errorf("#%d: srvs = nil, want non-nil", i)
264 }
265 } else {
266 if !reflect.DeepEqual(srvs.Endpoints, tt.expected) {
267 t.Errorf("#%d: endpoints = %v, want = %v", i, srvs.Endpoints, tt.expected)
268 }
269 }
270 }
271 }
272
273 func TestGetSRVService(t *testing.T) {
274 tests := []struct {
275 scheme string
276 serviceName string
277
278 expected string
279 }{
280 {
281 "https",
282 "",
283 "etcd-client-ssl",
284 },
285 {
286 "http",
287 "",
288 "etcd-client",
289 },
290 {
291 "https",
292 "foo",
293 "etcd-client-ssl-foo",
294 },
295 {
296 "http",
297 "bar",
298 "etcd-client-bar",
299 },
300 }
301
302 for i, tt := range tests {
303 service := GetSRVService("etcd-client", tt.serviceName, tt.scheme)
304 if strings.Compare(service, tt.expected) != 0 {
305 t.Errorf("#%d: service = %s, want %s", i, service, tt.expected)
306 }
307 }
308 }
309
View as plain text