OSDN Git Service

new repo
[bytom/vapor.git] / vendor / google.golang.org / grpc / resolver / dns / dns_resolver_test.go
1 /*
2  *
3  * Copyright 2017 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 package dns
20
21 import (
22         "fmt"
23         "net"
24         "os"
25         "reflect"
26         "sync"
27         "testing"
28         "time"
29
30         "google.golang.org/grpc/resolver"
31         "google.golang.org/grpc/test/leakcheck"
32 )
33
34 func TestMain(m *testing.M) {
35         cleanup := replaceNetFunc()
36         code := m.Run()
37         cleanup()
38         os.Exit(code)
39 }
40
41 const (
42         txtBytesLimit = 255
43 )
44
45 type testClientConn struct {
46         target string
47         m1     sync.Mutex
48         addrs  []resolver.Address
49         a      int
50         m2     sync.Mutex
51         sc     string
52         s      int
53 }
54
55 func (t *testClientConn) NewAddress(addresses []resolver.Address) {
56         t.m1.Lock()
57         defer t.m1.Unlock()
58         t.addrs = addresses
59         t.a++
60 }
61
62 func (t *testClientConn) getAddress() ([]resolver.Address, int) {
63         t.m1.Lock()
64         defer t.m1.Unlock()
65         return t.addrs, t.a
66 }
67
68 func (t *testClientConn) NewServiceConfig(serviceConfig string) {
69         t.m2.Lock()
70         defer t.m2.Unlock()
71         t.sc = serviceConfig
72         t.s++
73 }
74
75 func (t *testClientConn) getSc() (string, int) {
76         t.m2.Lock()
77         defer t.m2.Unlock()
78         return t.sc, t.s
79 }
80
81 var hostLookupTbl = struct {
82         sync.Mutex
83         tbl map[string][]string
84 }{
85         tbl: map[string][]string{
86                 "foo.bar.com":          {"1.2.3.4", "5.6.7.8"},
87                 "ipv4.single.fake":     {"1.2.3.4"},
88                 "srv.ipv4.single.fake": {"2.4.6.8"},
89                 "ipv4.multi.fake":      {"1.2.3.4", "5.6.7.8", "9.10.11.12"},
90                 "ipv6.single.fake":     {"2607:f8b0:400a:801::1001"},
91                 "ipv6.multi.fake":      {"2607:f8b0:400a:801::1001", "2607:f8b0:400a:801::1002", "2607:f8b0:400a:801::1003"},
92         },
93 }
94
95 func hostLookup(host string) ([]string, error) {
96         hostLookupTbl.Lock()
97         defer hostLookupTbl.Unlock()
98         if addrs, cnt := hostLookupTbl.tbl[host]; cnt {
99                 return addrs, nil
100         }
101         return nil, fmt.Errorf("failed to lookup host:%s resolution in hostLookupTbl", host)
102 }
103
104 var srvLookupTbl = struct {
105         sync.Mutex
106         tbl map[string][]*net.SRV
107 }{
108         tbl: map[string][]*net.SRV{
109                 "_grpclb._tcp.srv.ipv4.single.fake": {&net.SRV{Target: "ipv4.single.fake", Port: 1234}},
110                 "_grpclb._tcp.srv.ipv4.multi.fake":  {&net.SRV{Target: "ipv4.multi.fake", Port: 1234}},
111                 "_grpclb._tcp.srv.ipv6.single.fake": {&net.SRV{Target: "ipv6.single.fake", Port: 1234}},
112                 "_grpclb._tcp.srv.ipv6.multi.fake":  {&net.SRV{Target: "ipv6.multi.fake", Port: 1234}},
113         },
114 }
115
116 func srvLookup(service, proto, name string) (string, []*net.SRV, error) {
117         cname := "_" + service + "._" + proto + "." + name
118         srvLookupTbl.Lock()
119         defer srvLookupTbl.Unlock()
120         if srvs, cnt := srvLookupTbl.tbl[cname]; cnt {
121                 return cname, srvs, nil
122         }
123         return "", nil, fmt.Errorf("failed to lookup srv record for %s in srvLookupTbl", cname)
124 }
125
126 // div divides a byte slice into a slice of strings, each of which is of maximum
127 // 255 bytes length, which is the length limit per TXT record in DNS.
128 func div(b []byte) []string {
129         var r []string
130         for i := 0; i < len(b); i += txtBytesLimit {
131                 if i+txtBytesLimit > len(b) {
132                         r = append(r, string(b[i:]))
133                 } else {
134                         r = append(r, string(b[i:i+txtBytesLimit]))
135                 }
136         }
137         return r
138 }
139
140 // scfs contains an array of service config file string in JSON format.
141 // Notes about the scfs contents and usage:
142 // scfs contains 4 service config file JSON strings for testing. Inside each
143 // service config file, there are multiple choices. scfs[0:3] each contains 5
144 // choices, and first 3 choices are nonmatching choices based on canarying rule,
145 // while the last two are matched choices. scfs[3] only contains 3 choices, and
146 // all of them are nonmatching based on canarying rule. For each of scfs[0:3],
147 // the eventually returned service config, which is from the first of the two
148 // matched choices, is stored in the corresponding scs element (e.g.
149 // scfs[0]->scs[0]). scfs and scs elements are used in pair to test the dns
150 // resolver functionality, with scfs as the input and scs used for validation of
151 // the output. For scfs[3], it corresponds to empty service config, since there
152 // isn't a matched choice.
153 var scfs = []string{
154         `[
155         {
156                 "clientLanguage": [
157                         "CPP",
158                         "JAVA"
159                 ],
160                 "serviceConfig": {
161                         "loadBalancingPolicy": "grpclb",
162                         "methodConfig": [
163                                 {
164                                         "name": [
165                                                 {
166                                                         "service": "all"
167                                                 }
168                                         ],
169                                         "timeout": "1s"
170                                 }
171                         ]
172                 }
173         },
174         {
175                 "percentage": 0,
176                 "serviceConfig": {
177                         "loadBalancingPolicy": "grpclb",
178                         "methodConfig": [
179                                 {
180                                         "name": [
181                                                 {
182                                                         "service": "all"
183                                                 }
184                                         ],
185                                         "timeout": "1s"
186                                 }
187                         ]
188                 }
189         },
190         {
191                 "clientHostName": [
192                         "localhost"
193                 ],
194                 "serviceConfig": {
195                         "loadBalancingPolicy": "grpclb",
196                         "methodConfig": [
197                                 {
198                                         "name": [
199                                                 {
200                                                         "service": "all"
201                                                 }
202                                         ],
203                                         "timeout": "1s"
204                                 }
205                         ]
206                 }
207         },
208         {
209                 "clientLanguage": [
210                         "GO"
211                 ],
212                 "percentage": 100,
213                 "serviceConfig": {
214                         "methodConfig": [
215                                 {
216                                         "name": [
217                                                 {
218                                                         "method": "bar"
219                                                 }
220                                         ],
221                                         "maxRequestMessageBytes": 1024,
222                                         "maxResponseMessageBytes": 1024
223                                 }
224                         ]
225                 }
226         },
227         {
228                 "serviceConfig": {
229                         "loadBalancingPolicy": "round_robin",
230                         "methodConfig": [
231                                 {
232                                         "name": [
233                                                 {
234                                                         "service": "foo",
235                                                         "method": "bar"
236                                                 }
237                                         ],
238                                         "waitForReady": true
239                                 }
240                         ]
241                 }
242         }
243 ]`,
244         `[
245         {
246                 "clientLanguage": [
247                         "CPP",
248                         "JAVA"
249                 ],
250                 "serviceConfig": {
251                         "loadBalancingPolicy": "grpclb",
252                         "methodConfig": [
253                                 {
254                                         "name": [
255                                                 {
256                                                         "service": "all"
257                                                 }
258                                         ],
259                                         "timeout": "1s"
260                                 }
261                         ]
262                 }
263         },
264         {
265                 "percentage": 0,
266                 "serviceConfig": {
267                         "loadBalancingPolicy": "grpclb",
268                         "methodConfig": [
269                                 {
270                                         "name": [
271                                                 {
272                                                         "service": "all"
273                                                 }
274                                         ],
275                                         "timeout": "1s"
276                                 }
277                         ]
278                 }
279         },
280         {
281                 "clientHostName": [
282                         "localhost"
283                 ],
284                 "serviceConfig": {
285                         "loadBalancingPolicy": "grpclb",
286                         "methodConfig": [
287                                 {
288                                         "name": [
289                                                 {
290                                                         "service": "all"
291                                                 }
292                                         ],
293                                         "timeout": "1s"
294                                 }
295                         ]
296                 }
297         },
298         {
299                 "clientLanguage": [
300                         "GO"
301                 ],
302                 "percentage": 100,
303                 "serviceConfig": {
304                         "methodConfig": [
305                                 {
306                                         "name": [
307                                                 {
308                                                         "service": "foo",
309                                                         "method": "bar"
310                                                 }
311                                         ],
312                                         "waitForReady": true,
313                                         "timeout": "1s",
314                                         "maxRequestMessageBytes": 1024,
315                                         "maxResponseMessageBytes": 1024
316                                 }
317                         ]
318                 }
319         },
320         {
321                 "serviceConfig": {
322                         "loadBalancingPolicy": "round_robin",
323                         "methodConfig": [
324                                 {
325                                         "name": [
326                                                 {
327                                                         "service": "foo",
328                                                         "method": "bar"
329                                                 }
330                                         ],
331                                         "waitForReady": true
332                                 }
333                         ]
334                 }
335         }
336 ]`,
337         `[
338         {
339                 "clientLanguage": [
340                         "CPP",
341                         "JAVA"
342                 ],
343                 "serviceConfig": {
344                         "loadBalancingPolicy": "grpclb",
345                         "methodConfig": [
346                                 {
347                                         "name": [
348                                                 {
349                                                         "service": "all"
350                                                 }
351                                         ],
352                                         "timeout": "1s"
353                                 }
354                         ]
355                 }
356         },
357         {
358                 "percentage": 0,
359                 "serviceConfig": {
360                         "loadBalancingPolicy": "grpclb",
361                         "methodConfig": [
362                                 {
363                                         "name": [
364                                                 {
365                                                         "service": "all"
366                                                 }
367                                         ],
368                                         "timeout": "1s"
369                                 }
370                         ]
371                 }
372         },
373         {
374                 "clientHostName": [
375                         "localhost"
376                 ],
377                 "serviceConfig": {
378                         "loadBalancingPolicy": "grpclb",
379                         "methodConfig": [
380                                 {
381                                         "name": [
382                                                 {
383                                                         "service": "all"
384                                                 }
385                                         ],
386                                         "timeout": "1s"
387                                 }
388                         ]
389                 }
390         },
391         {
392                 "clientLanguage": [
393                         "GO"
394                 ],
395                 "percentage": 100,
396                 "serviceConfig": {
397                         "loadBalancingPolicy": "round_robin",
398                         "methodConfig": [
399                                 {
400                                         "name": [
401                                                 {
402                                                         "service": "foo"
403                                                 }
404                                         ],
405                                         "waitForReady": true,
406                                         "timeout": "1s"
407                                 },
408                                 {
409                                         "name": [
410                                                 {
411                                                         "service": "bar"
412                                                 }
413                                         ],
414                                         "waitForReady": false
415                                 }
416                         ]
417                 }
418         },
419         {
420                 "serviceConfig": {
421                         "loadBalancingPolicy": "round_robin",
422                         "methodConfig": [
423                                 {
424                                         "name": [
425                                                 {
426                                                         "service": "foo",
427                                                         "method": "bar"
428                                                 }
429                                         ],
430                                         "waitForReady": true
431                                 }
432                         ]
433                 }
434         }
435 ]`,
436         `[
437         {
438                 "clientLanguage": [
439                         "CPP",
440                         "JAVA"
441                 ],
442                 "serviceConfig": {
443                         "loadBalancingPolicy": "grpclb",
444                         "methodConfig": [
445                                 {
446                                         "name": [
447                                                 {
448                                                         "service": "all"
449                                                 }
450                                         ],
451                                         "timeout": "1s"
452                                 }
453                         ]
454                 }
455         },
456         {
457                 "percentage": 0,
458                 "serviceConfig": {
459                         "loadBalancingPolicy": "grpclb",
460                         "methodConfig": [
461                                 {
462                                         "name": [
463                                                 {
464                                                         "service": "all"
465                                                 }
466                                         ],
467                                         "timeout": "1s"
468                                 }
469                         ]
470                 }
471         },
472         {
473                 "clientHostName": [
474                         "localhost"
475                 ],
476                 "serviceConfig": {
477                         "loadBalancingPolicy": "grpclb",
478                         "methodConfig": [
479                                 {
480                                         "name": [
481                                                 {
482                                                         "service": "all"
483                                                 }
484                                         ],
485                                         "timeout": "1s"
486                                 }
487                         ]
488                 }
489         }
490 ]`,
491 }
492
493 // scs contains an array of service config string in JSON format.
494 var scs = []string{
495         `{
496                         "methodConfig": [
497                                 {
498                                         "name": [
499                                                 {
500                                                         "method": "bar"
501                                                 }
502                                         ],
503                                         "maxRequestMessageBytes": 1024,
504                                         "maxResponseMessageBytes": 1024
505                                 }
506                         ]
507                 }`,
508         `{
509                         "methodConfig": [
510                                 {
511                                         "name": [
512                                                 {
513                                                         "service": "foo",
514                                                         "method": "bar"
515                                                 }
516                                         ],
517                                         "waitForReady": true,
518                                         "timeout": "1s",
519                                         "maxRequestMessageBytes": 1024,
520                                         "maxResponseMessageBytes": 1024
521                                 }
522                         ]
523                 }`,
524         `{
525                         "loadBalancingPolicy": "round_robin",
526                         "methodConfig": [
527                                 {
528                                         "name": [
529                                                 {
530                                                         "service": "foo"
531                                                 }
532                                         ],
533                                         "waitForReady": true,
534                                         "timeout": "1s"
535                                 },
536                                 {
537                                         "name": [
538                                                 {
539                                                         "service": "bar"
540                                                 }
541                                         ],
542                                         "waitForReady": false
543                                 }
544                         ]
545                 }`,
546 }
547
548 // scLookupTbl is a set, which contains targets that have service config. Target
549 // not in this set should not have service config.
550 var scLookupTbl = map[string]bool{
551         "foo.bar.com":          true,
552         "srv.ipv4.single.fake": true,
553         "srv.ipv4.multi.fake":  true,
554         "no.attribute":         true,
555 }
556
557 // generateSCF generates a slice of strings (aggregately representing a single
558 // service config file) for the input name, which mocks the result from a real
559 // DNS TXT record lookup.
560 func generateSCF(name string) []string {
561         var b []byte
562         switch name {
563         case "foo.bar.com":
564                 b = []byte(scfs[0])
565         case "srv.ipv4.single.fake":
566                 b = []byte(scfs[1])
567         case "srv.ipv4.multi.fake":
568                 b = []byte(scfs[2])
569         default:
570                 b = []byte(scfs[3])
571         }
572         if name == "no.attribute" {
573                 return div(b)
574         }
575         return div(append([]byte(txtAttribute), b...))
576 }
577
578 // generateSC returns a service config string in JSON format for the input name.
579 func generateSC(name string) string {
580         _, cnt := scLookupTbl[name]
581         if !cnt || name == "no.attribute" {
582                 return ""
583         }
584         switch name {
585         case "foo.bar.com":
586                 return scs[0]
587         case "srv.ipv4.single.fake":
588                 return scs[1]
589         case "srv.ipv4.multi.fake":
590                 return scs[2]
591         default:
592                 return ""
593         }
594 }
595
596 var txtLookupTbl = struct {
597         sync.Mutex
598         tbl map[string][]string
599 }{
600         tbl: map[string][]string{
601                 "foo.bar.com":          generateSCF("foo.bar.com"),
602                 "srv.ipv4.single.fake": generateSCF("srv.ipv4.single.fake"),
603                 "srv.ipv4.multi.fake":  generateSCF("srv.ipv4.multi.fake"),
604                 "srv.ipv6.single.fake": generateSCF("srv.ipv6.single.fake"),
605                 "srv.ipv6.multi.fake":  generateSCF("srv.ipv6.multi.fake"),
606                 "no.attribute":         generateSCF("no.attribute"),
607         },
608 }
609
610 func txtLookup(host string) ([]string, error) {
611         txtLookupTbl.Lock()
612         defer txtLookupTbl.Unlock()
613         if scs, cnt := txtLookupTbl.tbl[host]; cnt {
614                 return scs, nil
615         }
616         return nil, fmt.Errorf("failed to lookup TXT:%s resolution in txtLookupTbl", host)
617 }
618
619 func TestResolve(t *testing.T) {
620         testDNSResolver(t)
621         testDNSResolveNow(t)
622         testIPResolver(t)
623 }
624
625 func testDNSResolver(t *testing.T) {
626         defer leakcheck.Check(t)
627         tests := []struct {
628                 target   string
629                 addrWant []resolver.Address
630                 scWant   string
631         }{
632                 {
633                         "foo.bar.com",
634                         []resolver.Address{{Addr: "1.2.3.4" + colonDefaultPort}, {Addr: "5.6.7.8" + colonDefaultPort}},
635                         generateSC("foo.bar.com"),
636                 },
637                 {
638                         "foo.bar.com:1234",
639                         []resolver.Address{{Addr: "1.2.3.4:1234"}, {Addr: "5.6.7.8:1234"}},
640                         generateSC("foo.bar.com"),
641                 },
642                 {
643                         "srv.ipv4.single.fake",
644                         []resolver.Address{{Addr: "1.2.3.4:1234", Type: resolver.GRPCLB, ServerName: "ipv4.single.fake"}, {Addr: "2.4.6.8" + colonDefaultPort}},
645                         generateSC("srv.ipv4.single.fake"),
646                 },
647                 {
648                         "srv.ipv4.multi.fake",
649                         []resolver.Address{
650                                 {Addr: "1.2.3.4:1234", Type: resolver.GRPCLB, ServerName: "ipv4.multi.fake"},
651                                 {Addr: "5.6.7.8:1234", Type: resolver.GRPCLB, ServerName: "ipv4.multi.fake"},
652                                 {Addr: "9.10.11.12:1234", Type: resolver.GRPCLB, ServerName: "ipv4.multi.fake"},
653                         },
654                         generateSC("srv.ipv4.multi.fake"),
655                 },
656                 {
657                         "srv.ipv6.single.fake",
658                         []resolver.Address{{Addr: "[2607:f8b0:400a:801::1001]:1234", Type: resolver.GRPCLB, ServerName: "ipv6.single.fake"}},
659                         generateSC("srv.ipv6.single.fake"),
660                 },
661                 {
662                         "srv.ipv6.multi.fake",
663                         []resolver.Address{
664                                 {Addr: "[2607:f8b0:400a:801::1001]:1234", Type: resolver.GRPCLB, ServerName: "ipv6.multi.fake"},
665                                 {Addr: "[2607:f8b0:400a:801::1002]:1234", Type: resolver.GRPCLB, ServerName: "ipv6.multi.fake"},
666                                 {Addr: "[2607:f8b0:400a:801::1003]:1234", Type: resolver.GRPCLB, ServerName: "ipv6.multi.fake"},
667                         },
668                         generateSC("srv.ipv6.multi.fake"),
669                 },
670                 {
671                         "no.attribute",
672                         nil,
673                         generateSC("no.attribute"),
674                 },
675         }
676
677         for _, a := range tests {
678                 b := NewBuilder()
679                 cc := &testClientConn{target: a.target}
680                 r, err := b.Build(resolver.Target{Endpoint: a.target}, cc, resolver.BuildOption{})
681                 if err != nil {
682                         t.Fatalf("%v\n", err)
683                 }
684                 var addrs []resolver.Address
685                 var cnt int
686                 for {
687                         addrs, cnt = cc.getAddress()
688                         if cnt > 0 {
689                                 break
690                         }
691                         time.Sleep(time.Millisecond)
692                 }
693                 var sc string
694                 for {
695                         sc, cnt = cc.getSc()
696                         if cnt > 0 {
697                                 break
698                         }
699                         time.Sleep(time.Millisecond)
700                 }
701                 if !reflect.DeepEqual(a.addrWant, addrs) {
702                         t.Errorf("Resolved addresses of target: %q = %+v, want %+v\n", a.target, addrs, a.addrWant)
703                 }
704                 if !reflect.DeepEqual(a.scWant, sc) {
705                         t.Errorf("Resolved service config of target: %q = %+v, want %+v\n", a.target, sc, a.scWant)
706                 }
707                 r.Close()
708         }
709 }
710
711 func mutateTbl(target string) func() {
712         hostLookupTbl.Lock()
713         oldHostTblEntry := hostLookupTbl.tbl[target]
714         hostLookupTbl.tbl[target] = hostLookupTbl.tbl[target][:len(oldHostTblEntry)-1]
715         hostLookupTbl.Unlock()
716         txtLookupTbl.Lock()
717         oldTxtTblEntry := txtLookupTbl.tbl[target]
718         txtLookupTbl.tbl[target] = []string{""}
719         txtLookupTbl.Unlock()
720
721         return func() {
722                 hostLookupTbl.Lock()
723                 hostLookupTbl.tbl[target] = oldHostTblEntry
724                 hostLookupTbl.Unlock()
725                 txtLookupTbl.Lock()
726                 txtLookupTbl.tbl[target] = oldTxtTblEntry
727                 txtLookupTbl.Unlock()
728         }
729 }
730
731 func testDNSResolveNow(t *testing.T) {
732         defer leakcheck.Check(t)
733         tests := []struct {
734                 target   string
735                 addrWant []resolver.Address
736                 addrNext []resolver.Address
737                 scWant   string
738                 scNext   string
739         }{
740                 {
741                         "foo.bar.com",
742                         []resolver.Address{{Addr: "1.2.3.4" + colonDefaultPort}, {Addr: "5.6.7.8" + colonDefaultPort}},
743                         []resolver.Address{{Addr: "1.2.3.4" + colonDefaultPort}},
744                         generateSC("foo.bar.com"),
745                         "",
746                 },
747         }
748
749         for _, a := range tests {
750                 b := NewBuilder()
751                 cc := &testClientConn{target: a.target}
752                 r, err := b.Build(resolver.Target{Endpoint: a.target}, cc, resolver.BuildOption{})
753                 if err != nil {
754                         t.Fatalf("%v\n", err)
755                 }
756                 var addrs []resolver.Address
757                 var cnt int
758                 for {
759                         addrs, cnt = cc.getAddress()
760                         if cnt > 0 {
761                                 break
762                         }
763                         time.Sleep(time.Millisecond)
764                 }
765                 var sc string
766                 for {
767                         sc, cnt = cc.getSc()
768                         if cnt > 0 {
769                                 break
770                         }
771                         time.Sleep(time.Millisecond)
772                 }
773                 if !reflect.DeepEqual(a.addrWant, addrs) {
774                         t.Errorf("Resolved addresses of target: %q = %+v, want %+v\n", a.target, addrs, a.addrWant)
775                 }
776                 if !reflect.DeepEqual(a.scWant, sc) {
777                         t.Errorf("Resolved service config of target: %q = %+v, want %+v\n", a.target, sc, a.scWant)
778                 }
779                 revertTbl := mutateTbl(a.target)
780                 r.ResolveNow(resolver.ResolveNowOption{})
781                 for {
782                         addrs, cnt = cc.getAddress()
783                         if cnt == 2 {
784                                 break
785                         }
786                         time.Sleep(time.Millisecond)
787                 }
788                 for {
789                         sc, cnt = cc.getSc()
790                         if cnt == 2 {
791                                 break
792                         }
793                         time.Sleep(time.Millisecond)
794                 }
795                 if !reflect.DeepEqual(a.addrNext, addrs) {
796                         t.Errorf("Resolved addresses of target: %q = %+v, want %+v\n", a.target, addrs, a.addrNext)
797                 }
798                 if !reflect.DeepEqual(a.scNext, sc) {
799                         t.Errorf("Resolved service config of target: %q = %+v, want %+v\n", a.target, sc, a.scNext)
800                 }
801                 revertTbl()
802                 r.Close()
803         }
804 }
805
806 const colonDefaultPort = ":" + defaultPort
807
808 func testIPResolver(t *testing.T) {
809         defer leakcheck.Check(t)
810         tests := []struct {
811                 target string
812                 want   []resolver.Address
813         }{
814                 {"127.0.0.1", []resolver.Address{{Addr: "127.0.0.1" + colonDefaultPort}}},
815                 {"127.0.0.1:12345", []resolver.Address{{Addr: "127.0.0.1:12345"}}},
816                 {"::1", []resolver.Address{{Addr: "[::1]" + colonDefaultPort}}},
817                 {"[::1]:12345", []resolver.Address{{Addr: "[::1]:12345"}}},
818                 {"[::1]:", []resolver.Address{{Addr: "[::1]:443"}}},
819                 {"2001:db8:85a3::8a2e:370:7334", []resolver.Address{{Addr: "[2001:db8:85a3::8a2e:370:7334]" + colonDefaultPort}}},
820                 {"[2001:db8:85a3::8a2e:370:7334]", []resolver.Address{{Addr: "[2001:db8:85a3::8a2e:370:7334]" + colonDefaultPort}}},
821                 {"[2001:db8:85a3::8a2e:370:7334]:12345", []resolver.Address{{Addr: "[2001:db8:85a3::8a2e:370:7334]:12345"}}},
822                 {"[2001:db8::1]:http", []resolver.Address{{Addr: "[2001:db8::1]:http"}}},
823                 // TODO(yuxuanli): zone support?
824         }
825
826         for _, v := range tests {
827                 b := NewBuilder()
828                 cc := &testClientConn{target: v.target}
829                 r, err := b.Build(resolver.Target{Endpoint: v.target}, cc, resolver.BuildOption{})
830                 if err != nil {
831                         t.Fatalf("%v\n", err)
832                 }
833                 var addrs []resolver.Address
834                 var cnt int
835                 for {
836                         addrs, cnt = cc.getAddress()
837                         if cnt > 0 {
838                                 break
839                         }
840                         time.Sleep(time.Millisecond)
841                 }
842                 if !reflect.DeepEqual(v.want, addrs) {
843                         t.Errorf("Resolved addresses of target: %q = %+v, want %+v\n", v.target, addrs, v.want)
844                 }
845                 r.ResolveNow(resolver.ResolveNowOption{})
846                 for {
847                         addrs, cnt = cc.getAddress()
848                         if cnt == 2 {
849                                 break
850                         }
851                         time.Sleep(time.Millisecond)
852                 }
853                 if !reflect.DeepEqual(v.want, addrs) {
854                         t.Errorf("Resolved addresses of target: %q = %+v, want %+v\n", v.target, addrs, v.want)
855                 }
856                 r.Close()
857         }
858 }
859
860 func TestResolveFunc(t *testing.T) {
861         defer leakcheck.Check(t)
862         tests := []struct {
863                 addr string
864                 want error
865         }{
866                 // TODO(yuxuanli): More false cases?
867                 {"www.google.com", nil},
868                 {"foo.bar:12345", nil},
869                 {"127.0.0.1", nil},
870                 {"127.0.0.1:12345", nil},
871                 {"[::1]:80", nil},
872                 {"[2001:db8:a0b:12f0::1]:21", nil},
873                 {":80", nil},
874                 {"127.0.0...1:12345", nil},
875                 {"[fe80::1%lo0]:80", nil},
876                 {"golang.org:http", nil},
877                 {"[2001:db8::1]:http", nil},
878                 {":", nil},
879                 {"", errMissingAddr},
880                 {"[2001:db8:a0b:12f0::1", errForInvalidTarget},
881         }
882
883         b := NewBuilder()
884         for _, v := range tests {
885                 cc := &testClientConn{target: v.addr}
886                 r, err := b.Build(resolver.Target{Endpoint: v.addr}, cc, resolver.BuildOption{})
887                 if err == nil {
888                         r.Close()
889                 }
890                 if !reflect.DeepEqual(err, v.want) {
891                         t.Errorf("Build(%q, cc, resolver.BuildOption{}) = %v, want %v", v.addr, err, v.want)
892                 }
893         }
894 }