Home | History | Annotate | Download | only in net
      1 // Copyright 2013 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package net
      6 
      7 import (
      8 	"reflect"
      9 	"testing"
     10 )
     11 
     12 var testInetaddr = func(ip IPAddr) Addr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} }
     13 
     14 var addrListTests = []struct {
     15 	filter    func(IPAddr) bool
     16 	ips       []IPAddr
     17 	inetaddr  func(IPAddr) Addr
     18 	first     Addr
     19 	primaries addrList
     20 	fallbacks addrList
     21 	err       error
     22 }{
     23 	{
     24 		nil,
     25 		[]IPAddr{
     26 			{IP: IPv4(127, 0, 0, 1)},
     27 			{IP: IPv6loopback},
     28 		},
     29 		testInetaddr,
     30 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
     31 		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
     32 		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
     33 		nil,
     34 	},
     35 	{
     36 		nil,
     37 		[]IPAddr{
     38 			{IP: IPv6loopback},
     39 			{IP: IPv4(127, 0, 0, 1)},
     40 		},
     41 		testInetaddr,
     42 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
     43 		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
     44 		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
     45 		nil,
     46 	},
     47 	{
     48 		nil,
     49 		[]IPAddr{
     50 			{IP: IPv4(127, 0, 0, 1)},
     51 			{IP: IPv4(192, 168, 0, 1)},
     52 		},
     53 		testInetaddr,
     54 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
     55 		addrList{
     56 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
     57 			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
     58 		},
     59 		nil,
     60 		nil,
     61 	},
     62 	{
     63 		nil,
     64 		[]IPAddr{
     65 			{IP: IPv6loopback},
     66 			{IP: ParseIP("fe80::1"), Zone: "eth0"},
     67 		},
     68 		testInetaddr,
     69 		&TCPAddr{IP: IPv6loopback, Port: 5682},
     70 		addrList{
     71 			&TCPAddr{IP: IPv6loopback, Port: 5682},
     72 			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
     73 		},
     74 		nil,
     75 		nil,
     76 	},
     77 	{
     78 		nil,
     79 		[]IPAddr{
     80 			{IP: IPv4(127, 0, 0, 1)},
     81 			{IP: IPv4(192, 168, 0, 1)},
     82 			{IP: IPv6loopback},
     83 			{IP: ParseIP("fe80::1"), Zone: "eth0"},
     84 		},
     85 		testInetaddr,
     86 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
     87 		addrList{
     88 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
     89 			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
     90 		},
     91 		addrList{
     92 			&TCPAddr{IP: IPv6loopback, Port: 5682},
     93 			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
     94 		},
     95 		nil,
     96 	},
     97 	{
     98 		nil,
     99 		[]IPAddr{
    100 			{IP: IPv6loopback},
    101 			{IP: ParseIP("fe80::1"), Zone: "eth0"},
    102 			{IP: IPv4(127, 0, 0, 1)},
    103 			{IP: IPv4(192, 168, 0, 1)},
    104 		},
    105 		testInetaddr,
    106 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    107 		addrList{
    108 			&TCPAddr{IP: IPv6loopback, Port: 5682},
    109 			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
    110 		},
    111 		addrList{
    112 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    113 			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
    114 		},
    115 		nil,
    116 	},
    117 	{
    118 		nil,
    119 		[]IPAddr{
    120 			{IP: IPv4(127, 0, 0, 1)},
    121 			{IP: IPv6loopback},
    122 			{IP: IPv4(192, 168, 0, 1)},
    123 			{IP: ParseIP("fe80::1"), Zone: "eth0"},
    124 		},
    125 		testInetaddr,
    126 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    127 		addrList{
    128 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    129 			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
    130 		},
    131 		addrList{
    132 			&TCPAddr{IP: IPv6loopback, Port: 5682},
    133 			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
    134 		},
    135 		nil,
    136 	},
    137 	{
    138 		nil,
    139 		[]IPAddr{
    140 			{IP: IPv6loopback},
    141 			{IP: IPv4(127, 0, 0, 1)},
    142 			{IP: ParseIP("fe80::1"), Zone: "eth0"},
    143 			{IP: IPv4(192, 168, 0, 1)},
    144 		},
    145 		testInetaddr,
    146 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    147 		addrList{
    148 			&TCPAddr{IP: IPv6loopback, Port: 5682},
    149 			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
    150 		},
    151 		addrList{
    152 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    153 			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
    154 		},
    155 		nil,
    156 	},
    157 
    158 	{
    159 		ipv4only,
    160 		[]IPAddr{
    161 			{IP: IPv4(127, 0, 0, 1)},
    162 			{IP: IPv6loopback},
    163 		},
    164 		testInetaddr,
    165 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    166 		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
    167 		nil,
    168 		nil,
    169 	},
    170 	{
    171 		ipv4only,
    172 		[]IPAddr{
    173 			{IP: IPv6loopback},
    174 			{IP: IPv4(127, 0, 0, 1)},
    175 		},
    176 		testInetaddr,
    177 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    178 		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
    179 		nil,
    180 		nil,
    181 	},
    182 
    183 	{
    184 		ipv6only,
    185 		[]IPAddr{
    186 			{IP: IPv4(127, 0, 0, 1)},
    187 			{IP: IPv6loopback},
    188 		},
    189 		testInetaddr,
    190 		&TCPAddr{IP: IPv6loopback, Port: 5682},
    191 		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
    192 		nil,
    193 		nil,
    194 	},
    195 	{
    196 		ipv6only,
    197 		[]IPAddr{
    198 			{IP: IPv6loopback},
    199 			{IP: IPv4(127, 0, 0, 1)},
    200 		},
    201 		testInetaddr,
    202 		&TCPAddr{IP: IPv6loopback, Port: 5682},
    203 		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
    204 		nil,
    205 		nil,
    206 	},
    207 
    208 	{nil, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
    209 
    210 	{ipv4only, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
    211 	{ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
    212 
    213 	{ipv6only, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
    214 	{ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
    215 }
    216 
    217 func TestAddrList(t *testing.T) {
    218 	if !supportsIPv4() || !supportsIPv6() {
    219 		t.Skip("both IPv4 and IPv6 are required")
    220 	}
    221 
    222 	for i, tt := range addrListTests {
    223 		addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr, "ADDR")
    224 		if !reflect.DeepEqual(err, tt.err) {
    225 			t.Errorf("#%v: got %v; want %v", i, err, tt.err)
    226 		}
    227 		if tt.err != nil {
    228 			if len(addrs) != 0 {
    229 				t.Errorf("#%v: got %v; want 0", i, len(addrs))
    230 			}
    231 			continue
    232 		}
    233 		first := addrs.first(isIPv4)
    234 		if !reflect.DeepEqual(first, tt.first) {
    235 			t.Errorf("#%v: got %v; want %v", i, first, tt.first)
    236 		}
    237 		primaries, fallbacks := addrs.partition(isIPv4)
    238 		if !reflect.DeepEqual(primaries, tt.primaries) {
    239 			t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
    240 		}
    241 		if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
    242 			t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
    243 		}
    244 		expectedLen := len(primaries) + len(fallbacks)
    245 		if len(addrs) != expectedLen {
    246 			t.Errorf("#%v: got %v; want %v", i, len(addrs), expectedLen)
    247 		}
    248 	}
    249 }
    250 
    251 func TestAddrListPartition(t *testing.T) {
    252 	addrs := addrList{
    253 		&IPAddr{IP: ParseIP("fe80::"), Zone: "eth0"},
    254 		&IPAddr{IP: ParseIP("fe80::1"), Zone: "eth0"},
    255 		&IPAddr{IP: ParseIP("fe80::2"), Zone: "eth0"},
    256 	}
    257 	cases := []struct {
    258 		lastByte  byte
    259 		primaries addrList
    260 		fallbacks addrList
    261 	}{
    262 		{0, addrList{addrs[0]}, addrList{addrs[1], addrs[2]}},
    263 		{1, addrList{addrs[0], addrs[2]}, addrList{addrs[1]}},
    264 		{2, addrList{addrs[0], addrs[1]}, addrList{addrs[2]}},
    265 		{3, addrList{addrs[0], addrs[1], addrs[2]}, nil},
    266 	}
    267 	for i, tt := range cases {
    268 		// Inverting the function's output should not affect the outcome.
    269 		for _, invert := range []bool{false, true} {
    270 			primaries, fallbacks := addrs.partition(func(a Addr) bool {
    271 				ip := a.(*IPAddr).IP
    272 				return (ip[len(ip)-1] == tt.lastByte) != invert
    273 			})
    274 			if !reflect.DeepEqual(primaries, tt.primaries) {
    275 				t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
    276 			}
    277 			if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
    278 				t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
    279 			}
    280 		}
    281 	}
    282 }
    283