...

Source file src/go.etcd.io/etcd/pkg/v3/netutil/netutil_test.go

Documentation: go.etcd.io/etcd/pkg/v3/netutil

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package netutil
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"fmt"
    21  	"net"
    22  	"net/url"
    23  	"reflect"
    24  	"strconv"
    25  	"testing"
    26  	"time"
    27  
    28  	"go.uber.org/zap"
    29  )
    30  
    31  func TestResolveTCPAddrs(t *testing.T) {
    32  	defer func() { resolveTCPAddr = resolveTCPAddrDefault }()
    33  	tests := []struct {
    34  		urls     [][]url.URL
    35  		expected [][]url.URL
    36  		hostMap  map[string]string
    37  		hasError bool
    38  	}{
    39  		{
    40  			urls: [][]url.URL{
    41  				{
    42  					{Scheme: "http", Host: "127.0.0.1:4001"},
    43  					{Scheme: "http", Host: "127.0.0.1:2379"},
    44  				},
    45  				{
    46  					{Scheme: "http", Host: "127.0.0.1:7001"},
    47  					{Scheme: "http", Host: "127.0.0.1:2380"},
    48  				},
    49  			},
    50  			expected: [][]url.URL{
    51  				{
    52  					{Scheme: "http", Host: "127.0.0.1:4001"},
    53  					{Scheme: "http", Host: "127.0.0.1:2379"},
    54  				},
    55  				{
    56  					{Scheme: "http", Host: "127.0.0.1:7001"},
    57  					{Scheme: "http", Host: "127.0.0.1:2380"},
    58  				},
    59  			},
    60  		},
    61  		{
    62  			urls: [][]url.URL{
    63  				{
    64  					{Scheme: "http", Host: "infra0.example.com:4001"},
    65  					{Scheme: "http", Host: "infra0.example.com:2379"},
    66  				},
    67  				{
    68  					{Scheme: "http", Host: "infra0.example.com:7001"},
    69  					{Scheme: "http", Host: "infra0.example.com:2380"},
    70  				},
    71  			},
    72  			expected: [][]url.URL{
    73  				{
    74  					{Scheme: "http", Host: "10.0.1.10:4001"},
    75  					{Scheme: "http", Host: "10.0.1.10:2379"},
    76  				},
    77  				{
    78  					{Scheme: "http", Host: "10.0.1.10:7001"},
    79  					{Scheme: "http", Host: "10.0.1.10:2380"},
    80  				},
    81  			},
    82  			hostMap: map[string]string{
    83  				"infra0.example.com": "10.0.1.10",
    84  			},
    85  			hasError: false,
    86  		},
    87  		{
    88  			urls: [][]url.URL{
    89  				{
    90  					{Scheme: "http", Host: "infra0.example.com:4001"},
    91  					{Scheme: "http", Host: "infra0.example.com:2379"},
    92  				},
    93  				{
    94  					{Scheme: "http", Host: "infra0.example.com:7001"},
    95  					{Scheme: "http", Host: "infra0.example.com:2380"},
    96  				},
    97  			},
    98  			hostMap: map[string]string{
    99  				"infra0.example.com": "",
   100  			},
   101  			hasError: true,
   102  		},
   103  		{
   104  			urls: [][]url.URL{
   105  				{
   106  					{Scheme: "http", Host: "ssh://infra0.example.com:4001"},
   107  					{Scheme: "http", Host: "ssh://infra0.example.com:2379"},
   108  				},
   109  				{
   110  					{Scheme: "http", Host: "ssh://infra0.example.com:7001"},
   111  					{Scheme: "http", Host: "ssh://infra0.example.com:2380"},
   112  				},
   113  			},
   114  			hasError: true,
   115  		},
   116  	}
   117  	for _, tt := range tests {
   118  		resolveTCPAddr = func(ctx context.Context, addr string) (*net.TCPAddr, error) {
   119  			host, port, err := net.SplitHostPort(addr)
   120  			if err != nil {
   121  				return nil, err
   122  			}
   123  			i, err := strconv.Atoi(port)
   124  			if err != nil {
   125  				return nil, err
   126  			}
   127  			if ip := net.ParseIP(host); ip != nil {
   128  				return &net.TCPAddr{IP: ip, Port: i, Zone: ""}, nil
   129  			}
   130  			if tt.hostMap[host] == "" {
   131  				return nil, errors.New("cannot resolve host")
   132  			}
   133  			return &net.TCPAddr{IP: net.ParseIP(tt.hostMap[host]), Port: i, Zone: ""}, nil
   134  		}
   135  		ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
   136  		urls, err := resolveTCPAddrs(ctx, zap.NewExample(), tt.urls)
   137  		cancel()
   138  		if tt.hasError {
   139  			if err == nil {
   140  				t.Errorf("expected error")
   141  			}
   142  			continue
   143  		}
   144  		if !reflect.DeepEqual(urls, tt.expected) {
   145  			t.Errorf("expected: %v, got %v", tt.expected, urls)
   146  		}
   147  	}
   148  }
   149  
   150  func TestURLsEqual(t *testing.T) {
   151  	defer func() { resolveTCPAddr = resolveTCPAddrDefault }()
   152  	hostm := map[string]string{
   153  		"example.com": "10.0.10.1",
   154  		"first.com":   "10.0.11.1",
   155  		"second.com":  "10.0.11.2",
   156  	}
   157  	resolveTCPAddr = func(ctx context.Context, addr string) (*net.TCPAddr, error) {
   158  		host, port, err := net.SplitHostPort(addr)
   159  		if err != nil {
   160  			return nil, err
   161  		}
   162  		i, err := strconv.Atoi(port)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  		if ip := net.ParseIP(host); ip != nil {
   167  			return &net.TCPAddr{IP: ip, Port: i, Zone: ""}, nil
   168  		}
   169  		if hostm[host] == "" {
   170  			return nil, errors.New("cannot resolve host")
   171  		}
   172  		return &net.TCPAddr{IP: net.ParseIP(hostm[host]), Port: i, Zone: ""}, nil
   173  	}
   174  
   175  	tests := []struct {
   176  		n      int
   177  		a      []url.URL
   178  		b      []url.URL
   179  		expect bool
   180  		err    error
   181  	}{
   182  		{
   183  			n:      0,
   184  			a:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
   185  			b:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
   186  			expect: true,
   187  		},
   188  		{
   189  			n:      1,
   190  			a:      []url.URL{{Scheme: "http", Host: "example.com:2379"}},
   191  			b:      []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
   192  			expect: true,
   193  		},
   194  		{
   195  			n:      2,
   196  			a:      []url.URL{{Scheme: "http", Host: "example.com:2379"}},
   197  			b:      []url.URL{{Scheme: "https", Host: "10.0.10.1:2379"}},
   198  			expect: false,
   199  			err:    errors.New(`resolved urls: "http://10.0.10.1:2379" != "https://10.0.10.1:2379"`),
   200  		},
   201  		{
   202  			n:      3,
   203  			a:      []url.URL{{Scheme: "https", Host: "example.com:2379"}},
   204  			b:      []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
   205  			expect: false,
   206  			err:    errors.New(`resolved urls: "https://10.0.10.1:2379" != "http://10.0.10.1:2379"`),
   207  		},
   208  		{
   209  			n:      4,
   210  			a:      []url.URL{{Scheme: "unix", Host: "abc:2379"}},
   211  			b:      []url.URL{{Scheme: "unix", Host: "abc:2379"}},
   212  			expect: true,
   213  		},
   214  		{
   215  			n:      5,
   216  			a:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   217  			b:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   218  			expect: true,
   219  		},
   220  		{
   221  			n:      6,
   222  			a:      []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   223  			b:      []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   224  			expect: true,
   225  		},
   226  		{
   227  			n:      7,
   228  			a:      []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   229  			b:      []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   230  			expect: true,
   231  		},
   232  		{
   233  			n:      8,
   234  			a:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
   235  			b:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}},
   236  			expect: false,
   237  			err:    errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://127.0.0.1:2380"`),
   238  		},
   239  		{
   240  			n:      9,
   241  			a:      []url.URL{{Scheme: "http", Host: "example.com:2380"}},
   242  			b:      []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
   243  			expect: false,
   244  			err:    errors.New(`resolved urls: "http://10.0.10.1:2380" != "http://10.0.10.1:2379"`),
   245  		},
   246  		{
   247  			n:      10,
   248  			a:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
   249  			b:      []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
   250  			expect: false,
   251  			err:    errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://10.0.0.1:2379"`),
   252  		},
   253  		{
   254  			n:      11,
   255  			a:      []url.URL{{Scheme: "http", Host: "example.com:2379"}},
   256  			b:      []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
   257  			expect: false,
   258  			err:    errors.New(`resolved urls: "http://10.0.10.1:2379" != "http://10.0.0.1:2379"`),
   259  		},
   260  		{
   261  			n:      12,
   262  			a:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   263  			b:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   264  			expect: false,
   265  			err:    errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://127.0.0.1:2380"`),
   266  		},
   267  		{
   268  			n:      13,
   269  			a:      []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   270  			b:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   271  			expect: false,
   272  			err:    errors.New(`resolved urls: "http://10.0.10.1:2379" != "http://127.0.0.1:2380"`),
   273  		},
   274  		{
   275  			n:      14,
   276  			a:      []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   277  			b:      []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   278  			expect: false,
   279  			err:    errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://10.0.0.1:2379"`),
   280  		},
   281  		{
   282  			n:      15,
   283  			a:      []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   284  			b:      []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   285  			expect: false,
   286  			err:    errors.New(`resolved urls: "http://10.0.10.1:2379" != "http://10.0.0.1:2379"`),
   287  		},
   288  		{
   289  			n:      16,
   290  			a:      []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
   291  			b:      []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
   292  			expect: false,
   293  			err:    errors.New(`len(["http://10.0.0.1:2379"]) != len(["http://10.0.0.1:2379" "http://127.0.0.1:2380"])`),
   294  		},
   295  		{
   296  			n:      17,
   297  			a:      []url.URL{{Scheme: "http", Host: "first.com:2379"}, {Scheme: "http", Host: "second.com:2380"}},
   298  			b:      []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
   299  			expect: true,
   300  		},
   301  		{
   302  			n:      18,
   303  			a:      []url.URL{{Scheme: "http", Host: "second.com:2380"}, {Scheme: "http", Host: "first.com:2379"}},
   304  			b:      []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
   305  			expect: true,
   306  		},
   307  	}
   308  
   309  	for i, test := range tests {
   310  		result, err := urlsEqual(context.TODO(), zap.NewExample(), test.a, test.b)
   311  		if result != test.expect {
   312  			t.Errorf("idx=%d #%d: a:%v b:%v, expected %v but %v", i, test.n, test.a, test.b, test.expect, result)
   313  		}
   314  		if test.err != nil {
   315  			if err.Error() != test.err.Error() {
   316  				t.Errorf("idx=%d #%d: err expected %v but %v", i, test.n, test.err, err)
   317  			}
   318  		}
   319  	}
   320  }
   321  func TestURLStringsEqual(t *testing.T) {
   322  	defer func() { resolveTCPAddr = resolveTCPAddrDefault }()
   323  	errOnResolve := func(ctx context.Context, addr string) (*net.TCPAddr, error) {
   324  		return nil, fmt.Errorf("unexpected attempt to resolve: %q", addr)
   325  	}
   326  	cases := []struct {
   327  		urlsA    []string
   328  		urlsB    []string
   329  		resolver func(ctx context.Context, addr string) (*net.TCPAddr, error)
   330  	}{
   331  		{[]string{"http://127.0.0.1:8080"}, []string{"http://127.0.0.1:8080"}, resolveTCPAddrDefault},
   332  		{[]string{
   333  			"http://host1:8080",
   334  			"http://host2:8080",
   335  		}, []string{
   336  			"http://host1:8080",
   337  			"http://host2:8080",
   338  		}, errOnResolve},
   339  		{
   340  			urlsA:    []string{"https://[c262:266f:fa53:0ee6:966e:e3f0:d68f:b046]:2380"},
   341  			urlsB:    []string{"https://[c262:266f:fa53:ee6:966e:e3f0:d68f:b046]:2380"},
   342  			resolver: resolveTCPAddrDefault,
   343  		},
   344  	}
   345  	for idx, c := range cases {
   346  		t.Logf("TestURLStringsEqual, case #%d", idx)
   347  		resolveTCPAddr = c.resolver
   348  		result, err := URLStringsEqual(context.TODO(), zap.NewExample(), c.urlsA, c.urlsB)
   349  		if !result {
   350  			t.Errorf("unexpected result %v", result)
   351  		}
   352  		if err != nil {
   353  			t.Errorf("unexpected error %v", err)
   354  		}
   355  	}
   356  }
   357  

View as plain text