pkg/netutil: return error from "URLStringsEqual"

Signed-off-by: Gyuho Lee <gyuhox@gmail.com>
release-3.4
Gyuho Lee 2018-01-25 10:31:59 -08:00
parent 2b10bcccee
commit e1de74913d
2 changed files with 51 additions and 17 deletions

View File

@ -17,6 +17,7 @@ package netutil
import ( import (
"context" "context"
"fmt"
"net" "net"
"net/url" "net/url"
"reflect" "reflect"
@ -73,14 +74,14 @@ func resolveTCPAddrs(ctx context.Context, urls [][]url.URL) ([][]url.URL, error)
for i, u := range us { for i, u := range us {
nu, err := url.Parse(u.String()) nu, err := url.Parse(u.String())
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("failed to parse %q (%v)", u.String(), err)
} }
nus[i] = *nu nus[i] = *nu
} }
for i, u := range nus { for i, u := range nus {
h, err := resolveURL(ctx, u) h, err := resolveURL(ctx, u)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("failed to resolve %q (%v)", u.String(), err)
} }
if h != "" { if h != "" {
nus[i].Host = h nus[i].Host = h
@ -123,35 +124,41 @@ func resolveURL(ctx context.Context, u url.URL) (string, error) {
// urlsEqual checks equality of url.URLS between two arrays. // urlsEqual checks equality of url.URLS between two arrays.
// This check pass even if an URL is in hostname and opposite is in IP address. // This check pass even if an URL is in hostname and opposite is in IP address.
func urlsEqual(ctx context.Context, a []url.URL, b []url.URL) bool { func urlsEqual(ctx context.Context, a []url.URL, b []url.URL) (bool, error) {
if len(a) != len(b) { if len(a) != len(b) {
return false return false, fmt.Errorf("len(%q) != len(%q)", urlsToStrings(a), urlsToStrings(b))
} }
urls, err := resolveTCPAddrs(ctx, [][]url.URL{a, b}) urls, err := resolveTCPAddrs(ctx, [][]url.URL{a, b})
if err != nil { if err != nil {
return false return false, err
} }
preva, prevb := a, b
a, b = urls[0], urls[1] a, b = urls[0], urls[1]
sort.Sort(types.URLs(a)) sort.Sort(types.URLs(a))
sort.Sort(types.URLs(b)) sort.Sort(types.URLs(b))
for i := range a { for i := range a {
if !reflect.DeepEqual(a[i], b[i]) { if !reflect.DeepEqual(a[i], b[i]) {
return false return false, fmt.Errorf("%q(resolved from %q) != %q(resolved from %q)",
a[i].String(), preva[i].String(),
b[i].String(), prevb[i].String(),
)
} }
} }
return true, nil
return true
} }
func URLStringsEqual(ctx context.Context, a []string, b []string) bool { // URLStringsEqual returns "true" if given URLs are valid
// and resolved to same IP addresses. Otherwise, return "false"
// and error, if any.
func URLStringsEqual(ctx context.Context, a []string, b []string) (bool, error) {
if len(a) != len(b) { if len(a) != len(b) {
return false return false, fmt.Errorf("len(%q) != len(%q)", a, b)
} }
urlsA := make([]url.URL, 0) urlsA := make([]url.URL, 0)
for _, str := range a { for _, str := range a {
u, err := url.Parse(str) u, err := url.Parse(str)
if err != nil { if err != nil {
return false return false, fmt.Errorf("failed to parse %q", str)
} }
urlsA = append(urlsA, *u) urlsA = append(urlsA, *u)
} }
@ -159,14 +166,21 @@ func URLStringsEqual(ctx context.Context, a []string, b []string) bool {
for _, str := range b { for _, str := range b {
u, err := url.Parse(str) u, err := url.Parse(str)
if err != nil { if err != nil {
return false return false, fmt.Errorf("failed to parse %q", str)
} }
urlsB = append(urlsB, *u) urlsB = append(urlsB, *u)
} }
return urlsEqual(ctx, urlsA, urlsB) return urlsEqual(ctx, urlsA, urlsB)
} }
func urlsToStrings(us []url.URL) []string {
rs := make([]string, len(us))
for i := range us {
rs[i] = us[i].String()
}
return rs
}
func IsNetworkTimeoutError(err error) bool { func IsNetworkTimeoutError(err error) bool {
nerr, ok := err.(net.Error) nerr, ok := err.(net.Error)
return ok && nerr.Timeout() return ok && nerr.Timeout()

View File

@ -167,6 +167,7 @@ func TestURLsEqual(t *testing.T) {
a []url.URL a []url.URL
b []url.URL b []url.URL
expect bool expect bool
err error
}{ }{
{ {
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}}, a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
@ -182,11 +183,13 @@ func TestURLsEqual(t *testing.T) {
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}}, a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
b: []url.URL{{Scheme: "https", Host: "10.0.10.1:2379"}}, b: []url.URL{{Scheme: "https", Host: "10.0.10.1:2379"}},
expect: false, expect: false,
err: errors.New(`"http://10.0.10.1:2379"(resolved from "http://example.com:2379") != "https://10.0.10.1:2379"(resolved from "https://10.0.10.1:2379")`),
}, },
{ {
a: []url.URL{{Scheme: "https", Host: "example.com:2379"}}, a: []url.URL{{Scheme: "https", Host: "example.com:2379"}},
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}}, b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
expect: false, expect: false,
err: errors.New(`"https://10.0.10.1:2379"(resolved from "https://example.com:2379") != "http://10.0.10.1:2379"(resolved from "http://10.0.10.1:2379")`),
}, },
{ {
a: []url.URL{{Scheme: "unix", Host: "abc:2379"}}, a: []url.URL{{Scheme: "unix", Host: "abc:2379"}},
@ -212,46 +215,55 @@ func TestURLsEqual(t *testing.T) {
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}}, a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}}, b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false, expect: false,
err: errors.New(`"http://127.0.0.1:2379"(resolved from "http://127.0.0.1:2379") != "http://127.0.0.1:2380"(resolved from "http://127.0.0.1:2380")`),
}, },
{ {
a: []url.URL{{Scheme: "http", Host: "example.com:2380"}}, a: []url.URL{{Scheme: "http", Host: "example.com:2380"}},
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}}, b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
expect: false, expect: false,
err: errors.New(`"http://10.0.10.1:2380"(resolved from "http://example.com:2380") != "http://10.0.10.1:2379"(resolved from "http://10.0.10.1:2379")`),
}, },
{ {
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}}, a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}}, b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
expect: false, expect: false,
err: errors.New(`"http://127.0.0.1:2379"(resolved from "http://127.0.0.1:2379") != "http://10.0.0.1:2379"(resolved from "http://10.0.0.1:2379")`),
}, },
{ {
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}}, a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}}, b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
expect: false, expect: false,
err: errors.New(`"http://10.0.10.1:2379"(resolved from "http://example.com:2379") != "http://10.0.0.1:2379"(resolved from "http://10.0.0.1:2379")`),
}, },
{ {
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}}, a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}}, b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false, expect: false,
err: errors.New(`"http://127.0.0.1:2379"(resolved from "http://127.0.0.1:2379") != "http://127.0.0.1:2380"(resolved from "http://127.0.0.1:2380")`),
}, },
{ {
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}}, a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}}, b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false, expect: false,
err: errors.New(`"http://10.0.10.1:2379"(resolved from "http://example.com:2379") != "http://127.0.0.1:2380"(resolved from "http://127.0.0.1:2380")`),
}, },
{ {
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}}, a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}}, b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false, expect: false,
err: errors.New(`"http://127.0.0.1:2379"(resolved from "http://127.0.0.1:2379") != "http://10.0.0.1:2379"(resolved from "http://10.0.0.1:2379")`),
}, },
{ {
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}}, a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}}, b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false, expect: false,
err: errors.New(`"http://10.0.10.1:2379"(resolved from "http://example.com:2379") != "http://10.0.0.1:2379"(resolved from "http://10.0.0.1:2379")`),
}, },
{ {
a: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}}, a: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}}, b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
expect: false, expect: false,
err: errors.New(`len(["http://10.0.0.1:2379"]) != len(["http://10.0.0.1:2379" "http://127.0.0.1:2380"])`),
}, },
{ {
a: []url.URL{{Scheme: "http", Host: "first.com:2379"}, {Scheme: "http", Host: "second.com:2380"}}, a: []url.URL{{Scheme: "http", Host: "first.com:2379"}, {Scheme: "http", Host: "second.com:2380"}},
@ -265,16 +277,24 @@ func TestURLsEqual(t *testing.T) {
}, },
} }
for _, test := range tests { for i, test := range tests {
result := urlsEqual(context.TODO(), test.a, test.b) result, err := urlsEqual(context.TODO(), test.a, test.b)
if result != test.expect { if result != test.expect {
t.Errorf("a:%v b:%v, expected %v but %v", test.a, test.b, test.expect, result) t.Errorf("#%d: a:%v b:%v, expected %v but %v", i, test.a, test.b, test.expect, result)
}
if test.err != nil {
if err.Error() != test.err.Error() {
t.Errorf("#%d: err expected %v but %v", i, test.err, err)
}
} }
} }
} }
func TestURLStringsEqual(t *testing.T) { func TestURLStringsEqual(t *testing.T) {
result := URLStringsEqual(context.TODO(), []string{"http://127.0.0.1:8080"}, []string{"http://127.0.0.1:8080"}) result, err := URLStringsEqual(context.TODO(), []string{"http://127.0.0.1:8080"}, []string{"http://127.0.0.1:8080"})
if !result { if !result {
t.Errorf("unexpected result %v", result) t.Errorf("unexpected result %v", result)
} }
if err != nil {
t.Errorf("unexpected error %v", err)
}
} }