Browse Source

pkg/netutil: return error from "URLStringsEqual"

Signed-off-by: Gyuho Lee <gyuhox@gmail.com>
Gyuho Lee 8 years ago
parent
commit
e1de74913d
2 changed files with 51 additions and 17 deletions
  1. 27 13
      pkg/netutil/netutil.go
  2. 24 4
      pkg/netutil/netutil_test.go

+ 27 - 13
pkg/netutil/netutil.go

@@ -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
+	return true, nil
 }
 }
 
 
-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()

+ 24 - 4
pkg/netutil/netutil_test.go

@@ -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 {
-		result := urlsEqual(context.TODO(), test.a, test.b)
+	for i, test := range tests {
+		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)
+	}
 }
 }