123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- /*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- package naming
- import (
- "context"
- "fmt"
- "net"
- "reflect"
- "sync"
- "testing"
- "time"
- )
- func newUpdateWithMD(op Operation, addr, lb string) *Update {
- return &Update{
- Op: op,
- Addr: addr,
- Metadata: AddrMetadataGRPCLB{AddrType: GRPCLB, ServerName: lb},
- }
- }
- func toMap(u []*Update) map[string]*Update {
- m := make(map[string]*Update)
- for _, v := range u {
- m[v.Addr] = v
- }
- return m
- }
- func TestCompileUpdate(t *testing.T) {
- tests := []struct {
- oldAddrs []string
- newAddrs []string
- want []*Update
- }{
- {
- []string{},
- []string{"1.0.0.1"},
- []*Update{{Op: Add, Addr: "1.0.0.1"}},
- },
- {
- []string{"1.0.0.1"},
- []string{"1.0.0.1"},
- []*Update{},
- },
- {
- []string{"1.0.0.0"},
- []string{"1.0.0.1"},
- []*Update{{Op: Delete, Addr: "1.0.0.0"}, {Op: Add, Addr: "1.0.0.1"}},
- },
- {
- []string{"1.0.0.1"},
- []string{"1.0.0.0"},
- []*Update{{Op: Add, Addr: "1.0.0.0"}, {Op: Delete, Addr: "1.0.0.1"}},
- },
- {
- []string{"1.0.0.1"},
- []string{"1.0.0.1", "1.0.0.2", "1.0.0.3"},
- []*Update{{Op: Add, Addr: "1.0.0.2"}, {Op: Add, Addr: "1.0.0.3"}},
- },
- {
- []string{"1.0.0.1", "1.0.0.2", "1.0.0.3"},
- []string{"1.0.0.0"},
- []*Update{{Op: Add, Addr: "1.0.0.0"}, {Op: Delete, Addr: "1.0.0.1"}, {Op: Delete, Addr: "1.0.0.2"}, {Op: Delete, Addr: "1.0.0.3"}},
- },
- {
- []string{"1.0.0.1", "1.0.0.3", "1.0.0.5"},
- []string{"1.0.0.2", "1.0.0.3", "1.0.0.6"},
- []*Update{{Op: Delete, Addr: "1.0.0.1"}, {Op: Add, Addr: "1.0.0.2"}, {Op: Delete, Addr: "1.0.0.5"}, {Op: Add, Addr: "1.0.0.6"}},
- },
- {
- []string{"1.0.0.1", "1.0.0.1", "1.0.0.2"},
- []string{"1.0.0.1"},
- []*Update{{Op: Delete, Addr: "1.0.0.2"}},
- },
- }
- var w dnsWatcher
- for _, c := range tests {
- w.curAddrs = make(map[string]*Update)
- newUpdates := make(map[string]*Update)
- for _, a := range c.oldAddrs {
- w.curAddrs[a] = &Update{Addr: a}
- }
- for _, a := range c.newAddrs {
- newUpdates[a] = &Update{Addr: a}
- }
- r := w.compileUpdate(newUpdates)
- if !reflect.DeepEqual(toMap(c.want), toMap(r)) {
- t.Errorf("w(%+v).compileUpdate(%+v) = %+v, want %+v", c.oldAddrs, c.newAddrs, updatesToSlice(r), updatesToSlice(c.want))
- }
- }
- }
- func TestResolveFunc(t *testing.T) {
- tests := []struct {
- addr string
- want error
- }{
- // TODO(yuxuanli): More false cases?
- {"www.google.com", nil},
- {"foo.bar:12345", nil},
- {"127.0.0.1", nil},
- {"127.0.0.1:12345", nil},
- {"[::1]:80", nil},
- {"[2001:db8:a0b:12f0::1]:21", nil},
- {":80", nil},
- {"127.0.0...1:12345", nil},
- {"[fe80::1%lo0]:80", nil},
- {"golang.org:http", nil},
- {"[2001:db8::1]:http", nil},
- {":", nil},
- {"", errMissingAddr},
- {"[2001:db8:a0b:12f0::1", fmt.Errorf("invalid target address %v", "[2001:db8:a0b:12f0::1")},
- }
- r, err := NewDNSResolver()
- if err != nil {
- t.Errorf("%v", err)
- }
- for _, v := range tests {
- _, err := r.Resolve(v.addr)
- if !reflect.DeepEqual(err, v.want) {
- t.Errorf("Resolve(%q) = %v, want %v", v.addr, err, v.want)
- }
- }
- }
- var hostLookupTbl = map[string][]string{
- "foo.bar.com": {"1.2.3.4", "5.6.7.8"},
- "ipv4.single.fake": {"1.2.3.4"},
- "ipv4.multi.fake": {"1.2.3.4", "5.6.7.8", "9.10.11.12"},
- "ipv6.single.fake": {"2607:f8b0:400a:801::1001"},
- "ipv6.multi.fake": {"2607:f8b0:400a:801::1001", "2607:f8b0:400a:801::1002", "2607:f8b0:400a:801::1003"},
- }
- func hostLookup(host string) ([]string, error) {
- if addrs, ok := hostLookupTbl[host]; ok {
- return addrs, nil
- }
- return nil, fmt.Errorf("failed to lookup host:%s resolution in hostLookupTbl", host)
- }
- var srvLookupTbl = map[string][]*net.SRV{
- "_grpclb._tcp.srv.ipv4.single.fake": {&net.SRV{Target: "ipv4.single.fake", Port: 1234}},
- "_grpclb._tcp.srv.ipv4.multi.fake": {&net.SRV{Target: "ipv4.multi.fake", Port: 1234}},
- "_grpclb._tcp.srv.ipv6.single.fake": {&net.SRV{Target: "ipv6.single.fake", Port: 1234}},
- "_grpclb._tcp.srv.ipv6.multi.fake": {&net.SRV{Target: "ipv6.multi.fake", Port: 1234}},
- }
- func srvLookup(service, proto, name string) (string, []*net.SRV, error) {
- cname := "_" + service + "._" + proto + "." + name
- if srvs, ok := srvLookupTbl[cname]; ok {
- return cname, srvs, nil
- }
- return "", nil, fmt.Errorf("failed to lookup srv record for %s in srvLookupTbl", cname)
- }
- func updatesToSlice(updates []*Update) []Update {
- res := make([]Update, len(updates))
- for i, u := range updates {
- res[i] = *u
- }
- return res
- }
- func testResolver(t *testing.T, freq time.Duration, slp time.Duration) {
- tests := []struct {
- target string
- want []*Update
- }{
- {
- "foo.bar.com",
- []*Update{{Op: Add, Addr: "1.2.3.4" + colonDefaultPort}, {Op: Add, Addr: "5.6.7.8" + colonDefaultPort}},
- },
- {
- "foo.bar.com:1234",
- []*Update{{Op: Add, Addr: "1.2.3.4:1234"}, {Op: Add, Addr: "5.6.7.8:1234"}},
- },
- {
- "srv.ipv4.single.fake",
- []*Update{newUpdateWithMD(Add, "1.2.3.4:1234", "ipv4.single.fake")},
- },
- {
- "srv.ipv4.multi.fake",
- []*Update{
- newUpdateWithMD(Add, "1.2.3.4:1234", "ipv4.multi.fake"),
- newUpdateWithMD(Add, "5.6.7.8:1234", "ipv4.multi.fake"),
- newUpdateWithMD(Add, "9.10.11.12:1234", "ipv4.multi.fake")},
- },
- {
- "srv.ipv6.single.fake",
- []*Update{newUpdateWithMD(Add, "[2607:f8b0:400a:801::1001]:1234", "ipv6.single.fake")},
- },
- {
- "srv.ipv6.multi.fake",
- []*Update{
- newUpdateWithMD(Add, "[2607:f8b0:400a:801::1001]:1234", "ipv6.multi.fake"),
- newUpdateWithMD(Add, "[2607:f8b0:400a:801::1002]:1234", "ipv6.multi.fake"),
- newUpdateWithMD(Add, "[2607:f8b0:400a:801::1003]:1234", "ipv6.multi.fake"),
- },
- },
- }
- for _, a := range tests {
- r, err := NewDNSResolverWithFreq(freq)
- if err != nil {
- t.Fatalf("%v\n", err)
- }
- w, err := r.Resolve(a.target)
- if err != nil {
- t.Fatalf("%v\n", err)
- }
- updates, err := w.Next()
- if err != nil {
- t.Fatalf("%v\n", err)
- }
- if !reflect.DeepEqual(toMap(a.want), toMap(updates)) {
- t.Errorf("Resolve(%q) = %+v, want %+v\n", a.target, updatesToSlice(updates), updatesToSlice(a.want))
- }
- var wg sync.WaitGroup
- wg.Add(1)
- go func() {
- defer wg.Done()
- for {
- _, err := w.Next()
- if err != nil {
- return
- }
- t.Error("Execution shouldn't reach here, since w.Next() should be blocked until close happen.")
- }
- }()
- // Sleep for sometime to let watcher do more than one lookup
- time.Sleep(slp)
- w.Close()
- wg.Wait()
- }
- }
- func replaceNetFunc() func() {
- oldLookupHost := lookupHost
- oldLookupSRV := lookupSRV
- lookupHost = func(ctx context.Context, host string) ([]string, error) {
- return hostLookup(host)
- }
- lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) {
- return srvLookup(service, proto, name)
- }
- return func() {
- lookupHost = oldLookupHost
- lookupSRV = oldLookupSRV
- }
- }
- func TestResolve(t *testing.T) {
- defer replaceNetFunc()()
- testResolver(t, time.Millisecond*5, time.Millisecond*10)
- }
- const colonDefaultPort = ":" + defaultPort
- func TestIPWatcher(t *testing.T) {
- tests := []struct {
- target string
- want []*Update
- }{
- {"127.0.0.1", []*Update{{Op: Add, Addr: "127.0.0.1" + colonDefaultPort}}},
- {"127.0.0.1:12345", []*Update{{Op: Add, Addr: "127.0.0.1:12345"}}},
- {"::1", []*Update{{Op: Add, Addr: "[::1]" + colonDefaultPort}}},
- {"[::1]:12345", []*Update{{Op: Add, Addr: "[::1]:12345"}}},
- {"[::1]:", []*Update{{Op: Add, Addr: "[::1]:443"}}},
- {"2001:db8:85a3::8a2e:370:7334", []*Update{{Op: Add, Addr: "[2001:db8:85a3::8a2e:370:7334]" + colonDefaultPort}}},
- {"[2001:db8:85a3::8a2e:370:7334]", []*Update{{Op: Add, Addr: "[2001:db8:85a3::8a2e:370:7334]" + colonDefaultPort}}},
- {"[2001:db8:85a3::8a2e:370:7334]:12345", []*Update{{Op: Add, Addr: "[2001:db8:85a3::8a2e:370:7334]:12345"}}},
- {"[2001:db8::1]:http", []*Update{{Op: Add, Addr: "[2001:db8::1]:http"}}},
- // TODO(yuxuanli): zone support?
- }
- for _, v := range tests {
- r, err := NewDNSResolverWithFreq(time.Millisecond * 5)
- if err != nil {
- t.Fatalf("%v\n", err)
- }
- w, err := r.Resolve(v.target)
- if err != nil {
- t.Fatalf("%v\n", err)
- }
- var updates []*Update
- var wg sync.WaitGroup
- wg.Add(1)
- count := 0
- go func() {
- defer wg.Done()
- for {
- u, err := w.Next()
- if err != nil {
- return
- }
- updates = u
- count++
- }
- }()
- // Sleep for sometime to let watcher do more than one lookup
- time.Sleep(time.Millisecond * 10)
- w.Close()
- wg.Wait()
- if !reflect.DeepEqual(v.want, updates) {
- t.Errorf("Resolve(%q) = %v, want %+v\n", v.target, updatesToSlice(updates), updatesToSlice(v.want))
- }
- if count != 1 {
- t.Errorf("IPWatcher Next() should return only once, not %d times\n", count)
- }
- }
- }
|