3 * Copyright 2017 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
30 func newUpdateWithMD(op Operation, addr, lb string) *Update {
34 Metadata: AddrMetadataGRPCLB{AddrType: GRPCLB, ServerName: lb},
38 func toMap(u []*Update) map[string]*Update {
39 m := make(map[string]*Update)
46 func TestCompileUpdate(t *testing.T) {
55 []*Update{{Op: Add, Addr: "1.0.0.1"}},
65 []*Update{{Op: Delete, Addr: "1.0.0.0"}, {Op: Add, Addr: "1.0.0.1"}},
70 []*Update{{Op: Add, Addr: "1.0.0.0"}, {Op: Delete, Addr: "1.0.0.1"}},
74 []string{"1.0.0.1", "1.0.0.2", "1.0.0.3"},
75 []*Update{{Op: Add, Addr: "1.0.0.2"}, {Op: Add, Addr: "1.0.0.3"}},
78 []string{"1.0.0.1", "1.0.0.2", "1.0.0.3"},
80 []*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"}},
83 []string{"1.0.0.1", "1.0.0.3", "1.0.0.5"},
84 []string{"1.0.0.2", "1.0.0.3", "1.0.0.6"},
85 []*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"}},
88 []string{"1.0.0.1", "1.0.0.1", "1.0.0.2"},
90 []*Update{{Op: Delete, Addr: "1.0.0.2"}},
95 for _, c := range tests {
96 w.curAddrs = make(map[string]*Update)
97 newUpdates := make(map[string]*Update)
98 for _, a := range c.oldAddrs {
99 w.curAddrs[a] = &Update{Addr: a}
101 for _, a := range c.newAddrs {
102 newUpdates[a] = &Update{Addr: a}
104 r := w.compileUpdate(newUpdates)
105 if !reflect.DeepEqual(toMap(c.want), toMap(r)) {
106 t.Errorf("w(%+v).compileUpdate(%+v) = %+v, want %+v", c.oldAddrs, c.newAddrs, updatesToSlice(r), updatesToSlice(c.want))
111 func TestResolveFunc(t *testing.T) {
116 // TODO(yuxuanli): More false cases?
117 {"www.google.com", nil},
118 {"foo.bar:12345", nil},
120 {"127.0.0.1:12345", nil},
122 {"[2001:db8:a0b:12f0::1]:21", nil},
124 {"127.0.0...1:12345", nil},
125 {"[fe80::1%lo0]:80", nil},
126 {"golang.org:http", nil},
127 {"[2001:db8::1]:http", nil},
129 {"", errMissingAddr},
130 {"[2001:db8:a0b:12f0::1", fmt.Errorf("invalid target address %v", "[2001:db8:a0b:12f0::1")},
133 r, err := NewDNSResolver()
137 for _, v := range tests {
138 _, err := r.Resolve(v.addr)
139 if !reflect.DeepEqual(err, v.want) {
140 t.Errorf("Resolve(%q) = %v, want %v", v.addr, err, v.want)
145 var hostLookupTbl = map[string][]string{
146 "foo.bar.com": {"1.2.3.4", "5.6.7.8"},
147 "ipv4.single.fake": {"1.2.3.4"},
148 "ipv4.multi.fake": {"1.2.3.4", "5.6.7.8", "9.10.11.12"},
149 "ipv6.single.fake": {"2607:f8b0:400a:801::1001"},
150 "ipv6.multi.fake": {"2607:f8b0:400a:801::1001", "2607:f8b0:400a:801::1002", "2607:f8b0:400a:801::1003"},
153 func hostLookup(host string) ([]string, error) {
154 if addrs, ok := hostLookupTbl[host]; ok {
157 return nil, fmt.Errorf("failed to lookup host:%s resolution in hostLookupTbl", host)
160 var srvLookupTbl = map[string][]*net.SRV{
161 "_grpclb._tcp.srv.ipv4.single.fake": {&net.SRV{Target: "ipv4.single.fake", Port: 1234}},
162 "_grpclb._tcp.srv.ipv4.multi.fake": {&net.SRV{Target: "ipv4.multi.fake", Port: 1234}},
163 "_grpclb._tcp.srv.ipv6.single.fake": {&net.SRV{Target: "ipv6.single.fake", Port: 1234}},
164 "_grpclb._tcp.srv.ipv6.multi.fake": {&net.SRV{Target: "ipv6.multi.fake", Port: 1234}},
167 func srvLookup(service, proto, name string) (string, []*net.SRV, error) {
168 cname := "_" + service + "._" + proto + "." + name
169 if srvs, ok := srvLookupTbl[cname]; ok {
170 return cname, srvs, nil
172 return "", nil, fmt.Errorf("failed to lookup srv record for %s in srvLookupTbl", cname)
175 func updatesToSlice(updates []*Update) []Update {
176 res := make([]Update, len(updates))
177 for i, u := range updates {
183 func testResolver(t *testing.T, freq time.Duration, slp time.Duration) {
190 []*Update{{Op: Add, Addr: "1.2.3.4" + colonDefaultPort}, {Op: Add, Addr: "5.6.7.8" + colonDefaultPort}},
194 []*Update{{Op: Add, Addr: "1.2.3.4:1234"}, {Op: Add, Addr: "5.6.7.8:1234"}},
197 "srv.ipv4.single.fake",
198 []*Update{newUpdateWithMD(Add, "1.2.3.4:1234", "ipv4.single.fake")},
201 "srv.ipv4.multi.fake",
203 newUpdateWithMD(Add, "1.2.3.4:1234", "ipv4.multi.fake"),
204 newUpdateWithMD(Add, "5.6.7.8:1234", "ipv4.multi.fake"),
205 newUpdateWithMD(Add, "9.10.11.12:1234", "ipv4.multi.fake")},
208 "srv.ipv6.single.fake",
209 []*Update{newUpdateWithMD(Add, "[2607:f8b0:400a:801::1001]:1234", "ipv6.single.fake")},
212 "srv.ipv6.multi.fake",
214 newUpdateWithMD(Add, "[2607:f8b0:400a:801::1001]:1234", "ipv6.multi.fake"),
215 newUpdateWithMD(Add, "[2607:f8b0:400a:801::1002]:1234", "ipv6.multi.fake"),
216 newUpdateWithMD(Add, "[2607:f8b0:400a:801::1003]:1234", "ipv6.multi.fake"),
221 for _, a := range tests {
222 r, err := NewDNSResolverWithFreq(freq)
224 t.Fatalf("%v\n", err)
226 w, err := r.Resolve(a.target)
228 t.Fatalf("%v\n", err)
230 updates, err := w.Next()
232 t.Fatalf("%v\n", err)
234 if !reflect.DeepEqual(toMap(a.want), toMap(updates)) {
235 t.Errorf("Resolve(%q) = %+v, want %+v\n", a.target, updatesToSlice(updates), updatesToSlice(a.want))
237 var wg sync.WaitGroup
246 t.Error("Execution shouldn't reach here, since w.Next() should be blocked until close happen.")
249 // Sleep for sometime to let watcher do more than one lookup
256 func TestResolve(t *testing.T) {
257 defer replaceNetFunc()()
258 testResolver(t, time.Millisecond*5, time.Millisecond*10)
261 const colonDefaultPort = ":" + defaultPort
263 func TestIPWatcher(t *testing.T) {
268 {"127.0.0.1", []*Update{{Op: Add, Addr: "127.0.0.1" + colonDefaultPort}}},
269 {"127.0.0.1:12345", []*Update{{Op: Add, Addr: "127.0.0.1:12345"}}},
270 {"::1", []*Update{{Op: Add, Addr: "[::1]" + colonDefaultPort}}},
271 {"[::1]:12345", []*Update{{Op: Add, Addr: "[::1]:12345"}}},
272 {"[::1]:", []*Update{{Op: Add, Addr: "[::1]:443"}}},
273 {"2001:db8:85a3::8a2e:370:7334", []*Update{{Op: Add, Addr: "[2001:db8:85a3::8a2e:370:7334]" + colonDefaultPort}}},
274 {"[2001:db8:85a3::8a2e:370:7334]", []*Update{{Op: Add, Addr: "[2001:db8:85a3::8a2e:370:7334]" + colonDefaultPort}}},
275 {"[2001:db8:85a3::8a2e:370:7334]:12345", []*Update{{Op: Add, Addr: "[2001:db8:85a3::8a2e:370:7334]:12345"}}},
276 {"[2001:db8::1]:http", []*Update{{Op: Add, Addr: "[2001:db8::1]:http"}}},
277 // TODO(yuxuanli): zone support?
280 for _, v := range tests {
281 r, err := NewDNSResolverWithFreq(time.Millisecond * 5)
283 t.Fatalf("%v\n", err)
285 w, err := r.Resolve(v.target)
287 t.Fatalf("%v\n", err)
289 var updates []*Update
290 var wg sync.WaitGroup
304 // Sleep for sometime to let watcher do more than one lookup
305 time.Sleep(time.Millisecond * 10)
308 if !reflect.DeepEqual(v.want, updates) {
309 t.Errorf("Resolve(%q) = %v, want %+v\n", v.target, updatesToSlice(updates), updatesToSlice(v.want))
312 t.Errorf("IPWatcher Next() should return only once, not %d times\n", count)