1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package netutil
16
17 import (
18 "context"
19 "errors"
20 "fmt"
21 "net"
22 "net/url"
23 "reflect"
24 "strconv"
25 "testing"
26 "time"
27
28 "go.uber.org/zap"
29 )
30
31 func TestResolveTCPAddrs(t *testing.T) {
32 defer func() { resolveTCPAddr = resolveTCPAddrDefault }()
33 tests := []struct {
34 urls [][]url.URL
35 expected [][]url.URL
36 hostMap map[string]string
37 hasError bool
38 }{
39 {
40 urls: [][]url.URL{
41 {
42 {Scheme: "http", Host: "127.0.0.1:4001"},
43 {Scheme: "http", Host: "127.0.0.1:2379"},
44 },
45 {
46 {Scheme: "http", Host: "127.0.0.1:7001"},
47 {Scheme: "http", Host: "127.0.0.1:2380"},
48 },
49 },
50 expected: [][]url.URL{
51 {
52 {Scheme: "http", Host: "127.0.0.1:4001"},
53 {Scheme: "http", Host: "127.0.0.1:2379"},
54 },
55 {
56 {Scheme: "http", Host: "127.0.0.1:7001"},
57 {Scheme: "http", Host: "127.0.0.1:2380"},
58 },
59 },
60 },
61 {
62 urls: [][]url.URL{
63 {
64 {Scheme: "http", Host: "infra0.example.com:4001"},
65 {Scheme: "http", Host: "infra0.example.com:2379"},
66 },
67 {
68 {Scheme: "http", Host: "infra0.example.com:7001"},
69 {Scheme: "http", Host: "infra0.example.com:2380"},
70 },
71 },
72 expected: [][]url.URL{
73 {
74 {Scheme: "http", Host: "10.0.1.10:4001"},
75 {Scheme: "http", Host: "10.0.1.10:2379"},
76 },
77 {
78 {Scheme: "http", Host: "10.0.1.10:7001"},
79 {Scheme: "http", Host: "10.0.1.10:2380"},
80 },
81 },
82 hostMap: map[string]string{
83 "infra0.example.com": "10.0.1.10",
84 },
85 hasError: false,
86 },
87 {
88 urls: [][]url.URL{
89 {
90 {Scheme: "http", Host: "infra0.example.com:4001"},
91 {Scheme: "http", Host: "infra0.example.com:2379"},
92 },
93 {
94 {Scheme: "http", Host: "infra0.example.com:7001"},
95 {Scheme: "http", Host: "infra0.example.com:2380"},
96 },
97 },
98 hostMap: map[string]string{
99 "infra0.example.com": "",
100 },
101 hasError: true,
102 },
103 {
104 urls: [][]url.URL{
105 {
106 {Scheme: "http", Host: "ssh://infra0.example.com:4001"},
107 {Scheme: "http", Host: "ssh://infra0.example.com:2379"},
108 },
109 {
110 {Scheme: "http", Host: "ssh://infra0.example.com:7001"},
111 {Scheme: "http", Host: "ssh://infra0.example.com:2380"},
112 },
113 },
114 hasError: true,
115 },
116 }
117 for _, tt := range tests {
118 resolveTCPAddr = func(ctx context.Context, addr string) (*net.TCPAddr, error) {
119 host, port, err := net.SplitHostPort(addr)
120 if err != nil {
121 return nil, err
122 }
123 i, err := strconv.Atoi(port)
124 if err != nil {
125 return nil, err
126 }
127 if ip := net.ParseIP(host); ip != nil {
128 return &net.TCPAddr{IP: ip, Port: i, Zone: ""}, nil
129 }
130 if tt.hostMap[host] == "" {
131 return nil, errors.New("cannot resolve host")
132 }
133 return &net.TCPAddr{IP: net.ParseIP(tt.hostMap[host]), Port: i, Zone: ""}, nil
134 }
135 ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
136 urls, err := resolveTCPAddrs(ctx, zap.NewExample(), tt.urls)
137 cancel()
138 if tt.hasError {
139 if err == nil {
140 t.Errorf("expected error")
141 }
142 continue
143 }
144 if !reflect.DeepEqual(urls, tt.expected) {
145 t.Errorf("expected: %v, got %v", tt.expected, urls)
146 }
147 }
148 }
149
150 func TestURLsEqual(t *testing.T) {
151 defer func() { resolveTCPAddr = resolveTCPAddrDefault }()
152 hostm := map[string]string{
153 "example.com": "10.0.10.1",
154 "first.com": "10.0.11.1",
155 "second.com": "10.0.11.2",
156 }
157 resolveTCPAddr = func(ctx context.Context, addr string) (*net.TCPAddr, error) {
158 host, port, err := net.SplitHostPort(addr)
159 if err != nil {
160 return nil, err
161 }
162 i, err := strconv.Atoi(port)
163 if err != nil {
164 return nil, err
165 }
166 if ip := net.ParseIP(host); ip != nil {
167 return &net.TCPAddr{IP: ip, Port: i, Zone: ""}, nil
168 }
169 if hostm[host] == "" {
170 return nil, errors.New("cannot resolve host")
171 }
172 return &net.TCPAddr{IP: net.ParseIP(hostm[host]), Port: i, Zone: ""}, nil
173 }
174
175 tests := []struct {
176 n int
177 a []url.URL
178 b []url.URL
179 expect bool
180 err error
181 }{
182 {
183 n: 0,
184 a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
185 b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
186 expect: true,
187 },
188 {
189 n: 1,
190 a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
191 b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
192 expect: true,
193 },
194 {
195 n: 2,
196 a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
197 b: []url.URL{{Scheme: "https", Host: "10.0.10.1:2379"}},
198 expect: false,
199 err: errors.New(`resolved urls: "http://10.0.10.1:2379" != "https://10.0.10.1:2379"`),
200 },
201 {
202 n: 3,
203 a: []url.URL{{Scheme: "https", Host: "example.com:2379"}},
204 b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
205 expect: false,
206 err: errors.New(`resolved urls: "https://10.0.10.1:2379" != "http://10.0.10.1:2379"`),
207 },
208 {
209 n: 4,
210 a: []url.URL{{Scheme: "unix", Host: "abc:2379"}},
211 b: []url.URL{{Scheme: "unix", Host: "abc:2379"}},
212 expect: true,
213 },
214 {
215 n: 5,
216 a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
217 b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
218 expect: true,
219 },
220 {
221 n: 6,
222 a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
223 b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
224 expect: true,
225 },
226 {
227 n: 7,
228 a: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
229 b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
230 expect: true,
231 },
232 {
233 n: 8,
234 a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
235 b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}},
236 expect: false,
237 err: errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://127.0.0.1:2380"`),
238 },
239 {
240 n: 9,
241 a: []url.URL{{Scheme: "http", Host: "example.com:2380"}},
242 b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
243 expect: false,
244 err: errors.New(`resolved urls: "http://10.0.10.1:2380" != "http://10.0.10.1:2379"`),
245 },
246 {
247 n: 10,
248 a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
249 b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
250 expect: false,
251 err: errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://10.0.0.1:2379"`),
252 },
253 {
254 n: 11,
255 a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
256 b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
257 expect: false,
258 err: errors.New(`resolved urls: "http://10.0.10.1:2379" != "http://10.0.0.1:2379"`),
259 },
260 {
261 n: 12,
262 a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
263 b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
264 expect: false,
265 err: errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://127.0.0.1:2380"`),
266 },
267 {
268 n: 13,
269 a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
270 b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
271 expect: false,
272 err: errors.New(`resolved urls: "http://10.0.10.1:2379" != "http://127.0.0.1:2380"`),
273 },
274 {
275 n: 14,
276 a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
277 b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
278 expect: false,
279 err: errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://10.0.0.1:2379"`),
280 },
281 {
282 n: 15,
283 a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
284 b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
285 expect: false,
286 err: errors.New(`resolved urls: "http://10.0.10.1:2379" != "http://10.0.0.1:2379"`),
287 },
288 {
289 n: 16,
290 a: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
291 b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
292 expect: false,
293 err: errors.New(`len(["http://10.0.0.1:2379"]) != len(["http://10.0.0.1:2379" "http://127.0.0.1:2380"])`),
294 },
295 {
296 n: 17,
297 a: []url.URL{{Scheme: "http", Host: "first.com:2379"}, {Scheme: "http", Host: "second.com:2380"}},
298 b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
299 expect: true,
300 },
301 {
302 n: 18,
303 a: []url.URL{{Scheme: "http", Host: "second.com:2380"}, {Scheme: "http", Host: "first.com:2379"}},
304 b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
305 expect: true,
306 },
307 }
308
309 for i, test := range tests {
310 result, err := urlsEqual(context.TODO(), zap.NewExample(), test.a, test.b)
311 if result != test.expect {
312 t.Errorf("idx=%d #%d: a:%v b:%v, expected %v but %v", i, test.n, test.a, test.b, test.expect, result)
313 }
314 if test.err != nil {
315 if err.Error() != test.err.Error() {
316 t.Errorf("idx=%d #%d: err expected %v but %v", i, test.n, test.err, err)
317 }
318 }
319 }
320 }
321 func TestURLStringsEqual(t *testing.T) {
322 defer func() { resolveTCPAddr = resolveTCPAddrDefault }()
323 errOnResolve := func(ctx context.Context, addr string) (*net.TCPAddr, error) {
324 return nil, fmt.Errorf("unexpected attempt to resolve: %q", addr)
325 }
326 cases := []struct {
327 urlsA []string
328 urlsB []string
329 resolver func(ctx context.Context, addr string) (*net.TCPAddr, error)
330 }{
331 {[]string{"http://127.0.0.1:8080"}, []string{"http://127.0.0.1:8080"}, resolveTCPAddrDefault},
332 {[]string{
333 "http://host1:8080",
334 "http://host2:8080",
335 }, []string{
336 "http://host1:8080",
337 "http://host2:8080",
338 }, errOnResolve},
339 {
340 urlsA: []string{"https://[c262:266f:fa53:0ee6:966e:e3f0:d68f:b046]:2380"},
341 urlsB: []string{"https://[c262:266f:fa53:ee6:966e:e3f0:d68f:b046]:2380"},
342 resolver: resolveTCPAddrDefault,
343 },
344 }
345 for idx, c := range cases {
346 t.Logf("TestURLStringsEqual, case #%d", idx)
347 resolveTCPAddr = c.resolver
348 result, err := URLStringsEqual(context.TODO(), zap.NewExample(), c.urlsA, c.urlsB)
349 if !result {
350 t.Errorf("unexpected result %v", result)
351 }
352 if err != nil {
353 t.Errorf("unexpected error %v", err)
354 }
355 }
356 }
357
View as plain text