diff options
Diffstat (limited to 'vendor/github.com/hashicorp/go-sockaddr/ifaddrs_test.go')
-rw-r--r-- | vendor/github.com/hashicorp/go-sockaddr/ifaddrs_test.go | 1881 |
1 files changed, 1881 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs_test.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs_test.go new file mode 100644 index 000000000..e89dae1ef --- /dev/null +++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs_test.go @@ -0,0 +1,1881 @@ +package sockaddr_test + +import ( + "fmt" + "net" + "reflect" + "testing" + + sockaddr "github.com/hashicorp/go-sockaddr" +) + +// NOTE: A number of these code paths are exercised in template/ and +// cmd/sockaddr/. +// +// TODO(sean@): Add better coverage for filtering functions (e.g. ExcludeBy*, +// IncludeBy*). + +func TestCmpIfAddrFunc(t *testing.T) { + tests := []struct { + name string + t1 sockaddr.IfAddr // must come before t2 according to the ascOp + t2 sockaddr.IfAddr + ascOp sockaddr.CmpIfAddrFunc + ascResult int + descOp sockaddr.CmpIfAddrFunc + descResult int + }{ + { + name: "empty test", + t1: sockaddr.IfAddr{}, + t2: sockaddr.IfAddr{}, + ascOp: sockaddr.AscIfAddress, + descOp: sockaddr.DescIfAddress, + ascResult: 0, + descResult: 0, + }, + { + name: "ipv4 address less", + t1: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.3"), + }, + t2: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + ascOp: sockaddr.AscIfAddress, + descOp: sockaddr.DescIfAddress, + ascResult: -1, + descResult: -1, + }, + { + name: "ipv4 private", + t1: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.1.2.3"), + }, + t2: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("203.0.113.3"), + }, + ascOp: sockaddr.AscIfPrivate, + descOp: sockaddr.DescIfPrivate, + ascResult: 0, // not both private, can't complete the test + descResult: 0, + }, + { + name: "IfAddr name", + t1: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.1.2.3"), + Interface: net.Interface{ + Name: "abc0", + }, + }, + t2: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("203.0.113.3"), + Interface: net.Interface{ + Name: "xyz0", + }, + }, + ascOp: sockaddr.AscIfName, + descOp: sockaddr.DescIfName, + ascResult: -1, + descResult: -1, + }, + { + name: "IfAddr network size", + t1: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.0.0.0/8"), + }, + t2: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.0/24"), + }, + ascOp: sockaddr.AscIfNetworkSize, + descOp: sockaddr.DescIfNetworkSize, + ascResult: -1, + descResult: -1, + }, + { + name: "IfAddr port", + t1: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.0.0.0:80"), + }, + t2: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.0:8600"), + }, + ascOp: sockaddr.AscIfPort, + descOp: sockaddr.DescIfPort, + ascResult: -1, + descResult: -1, + }, + { + name: "IfAddr type", + t1: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.0.0.0:80"), + }, + t2: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("[::1]:80"), + }, + ascOp: sockaddr.AscIfType, + descOp: sockaddr.DescIfType, + ascResult: -1, + descResult: -1, + }, + } + + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d must have a name", i) + } + + // Test ascending operation + ascExpected := test.ascResult + ascResult := test.ascOp(&test.t1, &test.t2) + if ascResult != ascExpected { + t.Errorf("%s: Unexpected result %d, expected %d when comparing %v and %v using %v", test.name, ascResult, ascExpected, test.t1, test.t2, test.ascOp) + } + + // Test descending operation + descExpected := test.descResult + descResult := test.descOp(&test.t2, &test.t1) + if descResult != descExpected { + t.Errorf("%s: Unexpected result %d, expected %d when comparing %v and %v using %v", test.name, descResult, descExpected, test.t1, test.t2, test.descOp) + } + + if ascResult != descResult { + t.Fatalf("bad") + } + + // Reverse the args + ascExpected = -1 * test.ascResult + ascResult = test.ascOp(&test.t2, &test.t1) + if ascResult != ascExpected { + t.Errorf("%s: Unexpected result %d, expected %d when comparing %v and %v using %v", test.name, ascResult, ascExpected, test.t1, test.t2, test.ascOp) + } + + descExpected = -1 * test.descResult + descResult = test.descOp(&test.t1, &test.t2) + if descResult != descExpected { + t.Errorf("%s: Unexpected result %d, expected %d when comparing %v and %v using %v", test.name, descResult, descExpected, test.t1, test.t2, test.descOp) + } + + if ascResult != descResult { + t.Fatalf("bad") + } + + // Test equality + ascExpected = 0 + ascResult = test.ascOp(&test.t1, &test.t1) + if ascResult != ascExpected { + t.Errorf("%s: Unexpected result %d, expected %d when comparing %v and %v using %v", test.name, ascResult, ascExpected, test.t1, test.t2, test.ascOp) + } + + descExpected = 0 + descResult = test.descOp(&test.t1, &test.t1) + if descResult != descExpected { + t.Errorf("%s: Unexpected result %d, expected %d when comparing %v and %v using %v", test.name, descResult, descExpected, test.t1, test.t2, test.descOp) + } + } +} + +func TestFilterIfByFlags(t *testing.T) { + tests := []struct { + name string + selector string + ifAddrs sockaddr.IfAddrs + flags net.Flags + fail bool + }{ + { + name: "broadcast", + selector: "broadcast", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagBroadcast, + }, + SockAddr: sockaddr.MustIPv4Addr("1.2.3.1"), + }, + }, + }, + { + name: "down", + selector: "down", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv4Addr("1.2.3.2"), + }, + }, + }, + { + name: "forwardable IPv4", + selector: "forwardable", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv4Addr("1.2.3.3"), + }, + }, + }, + { + name: "forwardable IPv6", + selector: "forwardable", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv6Addr("cc::1/128"), + }, + }, + }, + { + name: "global unicast", + selector: "global unicast", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv6Addr("cc::2"), + }, + }, + }, + { + name: "interface-local multicast", + selector: "interface-local multicast", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv6Addr("ff01::2"), + }, + }, + }, + { + name: "link-local multicast", + selector: "link-local multicast", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv6Addr("ff02::3"), + }, + }, + }, + { + name: "link-local unicast IPv4", + selector: "link-local unicast", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv4Addr("169.254.1.101"), + }, + }, + }, + { + name: "link-local unicast IPv6", + selector: "link-local unicast", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv6Addr("fe80::3"), + }, + }, + }, + { + name: "loopback ipv4", + selector: "loopback", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagLoopback, + }, + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1"), + }, + }, + }, + { + name: "loopback ipv6", + selector: "loopback", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagLoopback, + }, + SockAddr: sockaddr.MustIPv6Addr("::1"), + }, + }, + }, + { + name: "multicast IPv4", + selector: "multicast", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagMulticast, + }, + SockAddr: sockaddr.MustIPv4Addr("224.0.0.1"), + }, + }, + }, + { + name: "multicast IPv6", + selector: "multicast", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagMulticast, + }, + SockAddr: sockaddr.MustIPv6Addr("ff05::3"), + }, + }, + }, + { + name: "point-to-point", + selector: "point-to-point", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagPointToPoint, + }, + SockAddr: sockaddr.MustIPv6Addr("cc::3"), + }, + }, + }, + { + name: "unspecified", + selector: "unspecified", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv6Addr("::"), + }, + }, + }, + { + name: "up", + selector: "up", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagUp, + }, + SockAddr: sockaddr.MustIPv6Addr("cc::3"), + }, + }, + }, + { + name: "invalid", + selector: "foo", + fail: true, + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{}, + SockAddr: sockaddr.MustIPv6Addr("cc::3"), + }, + }, + }, + } + + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d needs a name", i) + } + + t.Run(test.name, func(t *testing.T) { + in, out, err := sockaddr.IfByFlag(test.selector, test.ifAddrs) + if test.fail == true && err == nil { + t.Fatalf("%s: expected failure", test.name) + } else if test.fail == true && err != nil { + return + } + + if err != nil && test.fail != true { + t.Fatalf("%s: failed: %v", test.name, err) + } + if ilen := len(in); ilen != 1 { + t.Fatalf("%s: wrong in length %d, expected 1", test.name, ilen) + } + if olen := len(out); olen != 0 { + t.Fatalf("%s: wrong in length %d, expected 0", test.name, olen) + } + }) + } +} + +func TestIfByNetwork(t *testing.T) { + tests := []struct { + name string + input sockaddr.IfAddrs + selector string + matched sockaddr.IfAddrs + excluded sockaddr.IfAddrs + fail bool + }{ + { + name: "exact match", + input: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + }, + selector: "1.2.3.4", + matched: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + }, + }, + { + name: "exact match plural", + input: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.0/24"), + }, + }, + selector: "1.2.3.0/24", + matched: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.0/24"), + }, + }, + }, + { + name: "split plural", + input: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("12.2.3.0/24"), + }, + }, + selector: "1.2.3.0/24", + excluded: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("12.2.3.0/24"), + }, + }, + matched: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + }, + }, + { + name: "excluded plural", + input: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("12.2.3.0/24"), + }, + }, + selector: "10.0.0.0/8", + excluded: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("12.2.3.0/24"), + }, + }, + }, + { + name: "invalid selector", + input: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("12.2.3.0/24"), + }, + }, + selector: "[:]", + fail: true, + }, + } + + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d needs a name", i) + } + + t.Run(test.name, func(t *testing.T) { + matched, excluded, err := sockaddr.IfByNetwork(test.selector, test.input) + if err != nil && !test.fail { + t.Fatal("bad") + } else if err == nil && test.fail { + t.Fatal("bad") + } + + if len(test.matched) != len(matched) { + t.Fatal("bad") + } else if len(test.excluded) != len(excluded) { + t.Fatal("bad") + } + + for i := 0; i < len(test.excluded); i++ { + if !reflect.DeepEqual(test.excluded[i], excluded[i]) { + t.Errorf("wrong excluded: %d %v %v", i, test.excluded[i], excluded[i]) + } + } + + for i := 0; i < len(test.matched); i++ { + if !reflect.DeepEqual(test.matched[i], matched[i]) { + t.Errorf("wrong matched: %d %v %v", i, test.matched[i], matched[i]) + } + } + }) + } +} + +func TestFilterIfByType(t *testing.T) { + tests := []struct { + name string + ifAddrs sockaddr.IfAddrs + ifAddrType sockaddr.SockAddrType + matchedLen int + remainingLen int + }{ + { + name: "include all", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("2.3.4.5"), + }, + }, + ifAddrType: sockaddr.TypeIPv4, + matchedLen: 2, + remainingLen: 0, + }, + { + name: "include some", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1"), + }, + }, + ifAddrType: sockaddr.TypeIPv4, + matchedLen: 1, + remainingLen: 1, + }, + { + name: "exclude all", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.5"), + }, + }, + ifAddrType: sockaddr.TypeIPv6, + matchedLen: 0, + remainingLen: 2, + }, + } + + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d needs a name", i) + } + + in, out := sockaddr.FilterIfByType(test.ifAddrs, test.ifAddrType) + if len(in) != test.matchedLen { + t.Fatalf("%s: wrong length %d, expected %d", test.name, len(in), test.matchedLen) + } + + if len(out) != test.remainingLen { + t.Fatalf("%s: wrong length %d, expected %d", test.name, len(out), test.remainingLen) + } + } +} + +// TestGetIfAddrs runs through the motions of calling sockaddr.GetIfAddrs(), but +// doesn't do much in the way of testing beyond verifying that `lo0` has a +// loopback address present. +func TestGetIfAddrs(t *testing.T) { + ifAddrs, err := sockaddr.GetAllInterfaces() + if err != nil { + t.Fatalf("Unable to proceed: %v", err) + } + if len(ifAddrs) == 0 { + t.Skip() + } + + var loInt *sockaddr.IfAddr + for _, ifAddr := range ifAddrs { + val := sockaddr.IfAddrAttr(ifAddr, "name") + if val == "" { + t.Fatalf("name failed") + } else if val == "lo0" || val == "lo" || val == "Loopback Pseudo-Interface 1" { + loInt = &ifAddr + break + } + } + if loInt == nil { + t.Fatalf("No loopback interfaces found, loInt nil") + } + + if val := sockaddr.IfAddrAttr(*loInt, "flags"); !(val == "up|loopback|multicast" || val == "up|loopback") { + t.Fatalf("expected different flags from loopback: %q", val) + } + + if loInt == nil { + t.Fatalf("Expected to find an lo0 interface, didn't find any") + } + + haveIPv4, foundIPv4lo := false, false + haveIPv6, foundIPv6lo := false, false + switch loInt.SockAddr.(type) { + case sockaddr.IPv4Addr: + haveIPv4 = true + + // Make the semi-brittle assumption that if we have + // IPv4, we also have an address at 127.0.0.1 available + // to us. + if loInt.SockAddr.String() == "127.0.0.1/8" { + foundIPv4lo = true + } + case sockaddr.IPv6Addr: + haveIPv6 = true + if loInt.SockAddr.String() == "::1" { + foundIPv6lo = true + } + default: + t.Fatalf("Unsupported type %v for address %v", loInt.Type(), loInt) + } + + // While not wise, it's entirely possible a host doesn't have IPv4 + // enabled. + if haveIPv4 && !foundIPv4lo { + t.Fatalf("Had an IPv4 w/o an expected IPv4 loopback addresses") + } + + // While prudent to run without, a sane environment may still contain an + // IPv6 loopback address. + if haveIPv6 && !foundIPv6lo { + t.Fatalf("Had an IPv6 w/o an expected IPv6 loopback addresses") + } +} + +// TestGetDefaultIfName tests to make sure a default interface name is always +// returned from getDefaultIfName(). +func TestGetDefaultInterface(t *testing.T) { + reportOnDefault := func(args ...interface{}) { + if havePublicIP() || havePrivateIP() { + t.Fatalf(args[0].(string), args[1:]...) + } else { + t.Skipf(args[0].(string), args[1:]...) + } + } + + ifAddrs, err := sockaddr.GetDefaultInterfaces() + if err != nil { + switch { + case len(ifAddrs) == 0: + reportOnDefault("bad: %v", err) + case ifAddrs[0].Flags&net.FlagUp == 0: + reportOnDefault("bad: %v", err) + default: + reportOnDefault("bad: %v", err) + } + } +} + +func TestGetPrivateIP(t *testing.T) { + reportOnPrivate := func(args ...interface{}) { + if havePrivateIP() { + t.Fatalf(args[0].(string), args[1:]...) + } else { + t.Skipf(args[0].(string), args[1:]...) + } + } + + ip, err := sockaddr.GetPrivateIP() + if err != nil { + reportOnPrivate("private IP failed: %v", err) + } + + if len(ip) == 0 { + reportOnPrivate("no private IP found", nil) + } +} + +func TestIfAddrAttrs(t *testing.T) { + const expectedNumAttrs = 2 + attrs := sockaddr.IfAddrAttrs() + if len(attrs) != expectedNumAttrs { + t.Fatalf("wrong number of attrs") + } +} + +func TestGetAllInterfaces(t *testing.T) { + ifAddrs, err := sockaddr.GetAllInterfaces() + if err != nil { + t.Fatalf("unable to gather interfaces: %v", err) + } + + initialLen := len(ifAddrs) + if initialLen == 0 { + t.Fatalf("no interfaces available") + } + + ifAddrs, err = sockaddr.SortIfBy("name,type,port,size,address", ifAddrs) + if err != nil { + t.Fatalf("unable to initially sort address") + } + + ascSorted, err := sockaddr.SortIfBy("name,type,port,size,address", ifAddrs) + if err != nil { + t.Fatalf("unable to asc sort address") + } + + descSorted, err := sockaddr.SortIfBy("name,type,port,size,-address", ascSorted) + if err != nil { + t.Fatalf("unable to desc sort address") + } + + if initialLen != len(ascSorted) && len(ascSorted) != len(descSorted) { + t.Fatalf("wrong len") + } + + for i := initialLen - 1; i >= 0; i-- { + if !reflect.DeepEqual(descSorted[i], ifAddrs[i]) { + t.Errorf("wrong sort order: %d %v %v", i, descSorted[i], ifAddrs[i]) + } + } +} + +func TestGetDefaultInterfaces(t *testing.T) { + reportOnDefault := func(args ...interface{}) { + if havePublicIP() || havePrivateIP() { + t.Fatalf(args[0].(string), args[1:]...) + } else { + t.Skipf(args[0].(string), args[1:]...) + } + } + + ifAddrs, err := sockaddr.GetDefaultInterfaces() + if err != nil { + reportOnDefault("unable to gather default interfaces: %v", err) + } + + if len(ifAddrs) == 0 { + reportOnDefault("no default interfaces available", nil) + } +} + +func TestGetPrivateInterfaces(t *testing.T) { + reportOnPrivate := func(args ...interface{}) { + if havePrivateIP() { + t.Fatalf(args[0].(string), args[1:]...) + } else { + t.Skipf(args[0].(string), args[1:]...) + } + } + + ifAddrs, err := sockaddr.GetPrivateInterfaces() + if err != nil { + reportOnPrivate("failed: %v", err) + } + + if len(ifAddrs) == 0 { + reportOnPrivate("no public IPs found", nil) + } + + if len(ifAddrs[0].String()) == 0 { + reportOnPrivate("no string representation of private IP found") + } +} + +func TestGetPublicInterfaces(t *testing.T) { + reportOnPublic := func(args ...interface{}) { + if havePublicIP() { + t.Fatalf(args[0].(string), args[1:]...) + } else { + t.Skipf(args[0].(string), args[1:]...) + } + } + + ifAddrs, err := sockaddr.GetPublicInterfaces() + if err != nil { + reportOnPublic("failed: %v", err) + } + + if len(ifAddrs) == 0 { + reportOnPublic("no public IPs found") + } +} + +func TestIncludeExcludeIfs(t *testing.T) { + tests := []struct { + name string + ifAddrs sockaddr.IfAddrs + fail bool + excludeNum int + excludeName string + excludeParam string + includeName string + includeParam string + includeNum int + }{ + { + name: "address", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("2.3.4.5"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("3.4.5.6"), + }, + }, + excludeName: "address", + excludeNum: 2, + excludeParam: `^1\..*\.4$`, + includeName: "address", + includeNum: 1, + includeParam: `^1\.2\.3\.`, + }, + { + name: "address invalid", + fail: true, + excludeName: "address", + excludeNum: 0, + excludeParam: `*`, + includeName: "address", + includeNum: 0, + includeParam: `[`, + }, + { + name: "flag", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagUp | net.FlagLoopback, + }, + }, + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagLoopback, + }, + }, + sockaddr.IfAddr{ + Interface: net.Interface{ + Flags: net.FlagMulticast, + }, + }, + }, + excludeName: "flags", + excludeNum: 2, + excludeParam: `up|loopback`, + includeName: "flags", + includeNum: 2, + includeParam: `loopback`, + }, + { + name: "flag invalid", + fail: true, + excludeName: "foo", + excludeNum: 0, + excludeParam: `*`, + includeName: "bar", + includeNum: 0, + includeParam: `[`, + }, + { + name: "name", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + Interface: net.Interface{ + Name: "abc0", + }, + }, + sockaddr.IfAddr{ + Interface: net.Interface{ + Name: "xyz0", + }, + }, + sockaddr.IfAddr{ + Interface: net.Interface{ + Name: "docker666", + }, + }, + }, + excludeName: "name", + excludeNum: 2, + excludeParam: `^docker[\d]+$`, + includeName: "name", + includeNum: 2, + includeParam: `^([a-z]+)0$`, + }, + { + name: "name invalid", + fail: true, + excludeName: "name", + excludeNum: 0, + excludeParam: `*`, + includeName: "name", + includeNum: 0, + includeParam: `[`, + }, + { + name: "network", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.2.3.4/24"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.255.255.4/24"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("::1"), + }, + }, + excludeName: "network", + excludeNum: 1, + excludeParam: `10.0.0.0/8`, + includeName: "network", + includeNum: 1, + includeParam: `::/127`, + }, + { + name: "port", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:8600"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("2.3.4.5:4646"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("3.4.5.6:4647"), + }, + }, + excludeName: "port", + excludeNum: 2, + excludeParam: `0$`, + includeName: "port", + includeNum: 2, + includeParam: `^46[\d]{2}$`, + }, + { + name: "port invalid", + fail: true, + excludeName: "port", + excludeNum: 0, + excludeParam: `*`, + includeName: "port", + includeNum: 0, + includeParam: `[`, + }, + { + name: "rfc", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.2.3.4/24"), + }, + sockaddr.IfAddr{ + // Excluded (/127 vs /128) + SockAddr: sockaddr.MustIPv6Addr("::1/127"), + }, + sockaddr.IfAddr{ + // Excluded (/127 vs /128) + SockAddr: sockaddr.MustIPv6Addr("::/127"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("203.0.113.0/24"), + }, + }, + excludeName: "rfc", + excludeNum: 2, + excludeParam: `6890`, + includeName: "rfc", + includeNum: 1, + includeParam: `3330`, + }, + { + name: "rfc invalid", + fail: true, + excludeName: "rfc", + excludeNum: 0, + excludeParam: `rfcOneTwoThree`, + includeName: "rfc", + includeNum: 0, + includeParam: `99999999999999`, + }, + { + name: "rfc IPv4 exclude", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("192.169.1.1"), + }, + }, + excludeName: "rfc", + excludeNum: 1, + excludeParam: `1918`, + includeName: "rfc", + includeNum: 0, + includeParam: `1918`, + }, + { + name: "rfc IPv4 include", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("192.168.1.1"), + }, + }, + excludeName: "rfc", + excludeNum: 0, + excludeParam: `1918`, + includeName: "rfc", + includeNum: 1, + includeParam: `1918`, + }, + { + name: "rfc IPv4 excluded RFCs", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("192.168.1.1"), + }, + }, + excludeName: "rfc", + excludeNum: 1, + excludeParam: `4291`, + includeName: "rfc", + includeNum: 0, + includeParam: `4291`, + }, + { + name: "rfc IPv6 exclude", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("cc::1/127"), + }, + }, + excludeName: "rfc", + excludeNum: 1, + excludeParam: `4291`, + includeName: "rfc", + includeNum: 0, + includeParam: `4291`, + }, + { + name: "rfc IPv6 include", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/127"), + }, + }, + excludeName: "rfc", + excludeNum: 0, + excludeParam: `4291`, + includeName: "rfc", + includeNum: 1, + includeParam: `4291`, + }, + { + name: "rfc zero match", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + }, + }, + excludeName: "rfc", + excludeNum: 1, + excludeParam: `1918`, + includeName: "rfc", + includeNum: 0, + includeParam: `1918`, + }, + { + name: "rfc empty list", + ifAddrs: sockaddr.IfAddrs{}, + excludeName: "rfc", + excludeNum: 0, + excludeParam: `4291`, + includeName: "rfc", + includeNum: 0, + includeParam: `1918`, + }, + { + name: "size", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.2.3.4/24"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("203.0.113.0/24"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/24"), + }, + }, + excludeName: "size", + excludeParam: `24`, + excludeNum: 0, + includeName: "size", + includeParam: `24`, + includeNum: 3, + }, + { + name: "size invalid", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.2.3.4/24"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/128"), + }, + }, + fail: true, + excludeName: "size", + excludeParam: `33`, + excludeNum: 0, + includeName: "size", + includeParam: `-1`, + includeNum: 0, + }, + { + name: "type", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.2.3.4/24"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("203.0.113.0/24"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/127"), + }, + }, + excludeName: "type", + excludeParam: `ipv6`, + excludeNum: 2, + includeName: "type", + includeParam: `ipv4`, + includeNum: 2, + }, + { + name: "type", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("10.2.3.4/24"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("::1"), + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustUnixSock("/tmp/foo"), + }, + }, + excludeName: "type", + excludeParam: `ip`, + excludeNum: 1, + includeName: "type", + includeParam: `unix`, + includeNum: 1, + }, + { + name: "type invalid arg", + fail: true, + excludeName: "type", + excludeParam: `*`, + excludeNum: 0, + includeName: "type", + includeParam: `[`, + includeNum: 0, + }, + { + name: "type invalid", + fail: true, + excludeName: "foo", + excludeParam: `bar`, + excludeNum: 0, + includeName: "baz", + includeParam: `bur`, + includeNum: 0, + }, + } + + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d must have a name", i) + } + t.Run(fmt.Sprintf("%s-%s", test.name, "include"), func(t *testing.T) { + t.Logf("test.ifAddrs: %v", test.ifAddrs) + inIfAddrs, err := sockaddr.IncludeIfs(test.includeName, test.includeParam, test.ifAddrs) + t.Logf("inIfAddrs: %v", inIfAddrs) + + switch { + case !test.fail && err != nil: + t.Errorf("%s: failed unexpectedly: %v", test.name, err) + case test.fail && err == nil: + t.Errorf("%s: failed to throw an error", test.name) + case test.fail && err != nil: + // expected test failure + return + } + + if len(inIfAddrs) != test.includeNum { + t.Errorf("%s: failed include length check. Expected %d, got %d. Input: %q", test.name, test.includeNum, len(inIfAddrs), test.includeParam) + } + }) + + t.Run(fmt.Sprintf("%s-%s", test.name, "exclude"), func(t *testing.T) { + t.Logf("test.ifAddrs: %v", test.ifAddrs) + outIfAddrs, err := sockaddr.ExcludeIfs(test.excludeName, test.excludeParam, test.ifAddrs) + t.Logf("outIfAddrs: %v", outIfAddrs) + + switch { + case !test.fail && err != nil: + t.Errorf("%s: failed unexpectedly: %v", test.name, err) + case test.fail && err == nil: + t.Errorf("%s: failed to throw an error", test.name) + case test.fail && err != nil: + // expected test failure + return + } + + if len(outIfAddrs) != test.excludeNum { + t.Errorf("%s: failed exclude length check. Expected %d, got %d. Input: %q", test.name, test.excludeNum, len(outIfAddrs), test.excludeParam) + } + }) + } +} + +func TestNewIPAddr(t *testing.T) { + tests := []struct { + name string + input string + output string + pass bool + }{ + { + name: "ipv4", + input: "1.2.3.4", + output: "1.2.3.4", + pass: true, + }, + { + name: "ipv6", + input: "::1", + output: "::1", + pass: true, + }, + { + name: "invalid", + input: "255.255.255.256", + output: "", + pass: false, + }, + } + + for _, test := range tests { + ip, err := sockaddr.NewIPAddr(test.input) + switch { + case err == nil && test.pass, + err != nil && !test.pass: + + default: + t.Errorf("expected %s's success to be %t", test.input, test.pass) + } + + if !test.pass { + continue + } + + ipStr := ip.String() + if ipStr != test.output { + t.Errorf("Expected %q to match %q", test.input, test.output, ipStr) + } + + } +} + +func TestIPAttrs(t *testing.T) { + const expectedIPAttrs = 11 + ipAttrs := sockaddr.IPAttrs() + if len(ipAttrs) != expectedIPAttrs { + t.Fatalf("wrong number of args") + } +} + +func TestUniqueIfAddrsBy(t *testing.T) { + tests := []struct { + name string + ifAddrs sockaddr.IfAddrs + fail bool + selector string + expected []string + }{ + { + name: "address", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("203.0.113.0/24"), + Interface: net.Interface{ + Name: "abc0", + }, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("203.0.113.0/24"), + Interface: net.Interface{ + Name: "abc0", + }, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("10.2.3.4"), + Interface: net.Interface{ + Name: "foo1", + }, + }, + }, + selector: "address", + expected: []string{"203.0.113.0/24 {0 0 abc0 0}", "10.2.3.4 {0 0 foo1 0}"}, + }, + { + name: "name", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("::1"), + Interface: net.Interface{ + Name: "lo0", + }, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("fe80::1"), + Interface: net.Interface{ + Name: "lo0", + }, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("127.0.0.1"), + Interface: net.Interface{ + Name: "foo1", + }, + }, + }, + selector: "name", + expected: []string{"::1 {0 0 lo0 0}", "127.0.0.1 {0 0 foo1 0}"}, + }, + { + name: "invalid", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{}, + }, + fail: true, + selector: "goozfraba", + expected: []string{}, + }, + } + + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d must have a name", i) + } + t.Run(test.name, func(t *testing.T) { + + uniqueAddrs, err := sockaddr.UniqueIfAddrsBy(test.selector, test.ifAddrs) + switch { + case !test.fail && err != nil: + t.Fatalf("%s: failed unexpectedly: %v", test.name, err) + case test.fail && err == nil: + t.Fatalf("%s: failed to throw an error", test.name) + case test.fail && err != nil: + // expected test failure + return + } + + if len(uniqueAddrs) != len(test.expected) { + t.Fatalf("%s: failed uniquify by attribute %s", test.name, test.selector) + } + + for i := 0; i < len(uniqueAddrs); i++ { + got := uniqueAddrs[i].String() + if got != test.expected[i] { + t.Fatalf("%s: expected %q got %q", test.name, test.expected[i], got) + } + } + + }) + } +} + +func TestJoinIfAddrsBy(t *testing.T) { + tests := []struct { + name string + ifAddrs sockaddr.IfAddrs + fail bool + selector string + joinStr string + expected string + }{ + { + name: "address", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("203.0.113.0/24"), + Interface: net.Interface{ + Name: "abc0", + }, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("203.0.113.1"), + Interface: net.Interface{ + Name: "abc0", + }, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("10.2.3.4"), + Interface: net.Interface{ + Name: "foo1", + }, + }, + }, + selector: "address", + joinStr: " ", + expected: "203.0.113.0 203.0.113.1 10.2.3.4", + }, + { + name: "name", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("::1"), + Interface: net.Interface{ + Name: "lo0", + }, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("fe80::1"), + Interface: net.Interface{ + Name: "foo0", + }, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("127.0.0.1"), + Interface: net.Interface{ + Name: "bar2", + }, + }, + }, + selector: "name", + joinStr: "-/-", + expected: "lo0-/-foo0-/-bar2", + }, + { + name: "invalid", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPAddr("127.0.0.1"), + Interface: net.Interface{ + Name: "bar2", + }, + }, + }, + fail: true, + selector: "goozfraba", + expected: "", + }, + } + + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d must have a name", i) + } + t.Run(test.name, func(t *testing.T) { + + result, err := sockaddr.JoinIfAddrs(test.selector, test.joinStr, test.ifAddrs) + switch { + case !test.fail && err != nil: + t.Fatalf("%s: failed unexpectedly: %v", test.name, err) + case test.fail && err == nil: + t.Fatalf("%s: failed to throw an error", test.name) + case test.fail && err != nil: + // expected test failure + return + } + + if result != test.expected { + t.Fatalf("%s: expected %q got %q", test.name, test.expected, result) + } + + }) + } +} + +func TestLimitOffset(t *testing.T) { + tests := []struct { + name string + ifAddrs sockaddr.IfAddrs + limit uint + offset int + fail bool + expected sockaddr.IfAddrs + }{ + { + name: "basic limit offset", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.0/24")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.2")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.3")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.4")}, + }, + limit: 2, + offset: 1, + expected: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.2")}, + }, + }, + { + name: "negative offset with limit", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.0/24")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.2")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.3")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.4")}, + }, + limit: 2, + offset: -3, + expected: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.2")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.3")}, + }, + }, + { + name: "large limit", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.0/24")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.2")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.3")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.4")}, + }, + limit: 100, + offset: 3, + expected: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.3")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.4")}, + }, + }, + { + name: "bigger offset than size", + ifAddrs: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.0/24")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPAddr("203.0.113.1")}, + }, + fail: true, + limit: 1, + offset: 3, + }, + } + + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d must have a name", i) + } + t.Run(test.name, func(t *testing.T) { + + offsetResults, err := sockaddr.OffsetIfAddrs(test.offset, test.ifAddrs) + switch { + case !test.fail && err != nil: + t.Fatalf("%s: failed unexpectedly: %v", test.name, err) + case test.fail && err == nil: + t.Fatalf("%s: failed to throw an error", test.name) + case test.fail && err != nil: + // expected test failure + return + } + + limitResults, err := sockaddr.LimitIfAddrs(test.limit, offsetResults) + switch { + case !test.fail && err != nil: + t.Fatalf("%s: failed unexpectedly: %v", test.name, err) + case test.fail && err == nil: + t.Fatalf("%s: failed to throw an error", test.name) + case test.fail && err != nil: + // expected test failure + return + } + + if len(test.expected) != len(limitResults) { + t.Fatalf("bad") + } + + for i := 0; i < len(test.expected); i++ { + if !reflect.DeepEqual(limitResults[i], test.expected[i]) { + t.Errorf("objects in ordered limit") + } + } + }) + } +} + +func TestSortIfBy(t *testing.T) { + tests := []struct { + name string + sortStr string + in sockaddr.IfAddrs + out sockaddr.IfAddrs + fail bool + }{ + { + name: "sort address", + sortStr: "address", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.3")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.3")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4")}, + }, + }, + { + name: "sort +address", + sortStr: "+address", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.3")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.3")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4")}, + }, + }, + { + name: "sort -address", + sortStr: "-address", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.3")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.3")}, + }, + }, + { + name: "sort name", + sortStr: "name", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{Interface: net.Interface{Name: "foo"}}, + sockaddr.IfAddr{Interface: net.Interface{Name: "bar"}}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{Interface: net.Interface{Name: "bar"}}, + sockaddr.IfAddr{Interface: net.Interface{Name: "foo"}}, + }, + }, + { + name: "sort +name", + sortStr: "+name", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{Interface: net.Interface{Name: "foo"}}, + sockaddr.IfAddr{Interface: net.Interface{Name: "bar"}}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{Interface: net.Interface{Name: "bar"}}, + sockaddr.IfAddr{Interface: net.Interface{Name: "foo"}}, + }, + }, + { + name: "sort -name", + sortStr: "-name", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{Interface: net.Interface{Name: "bar"}}, + sockaddr.IfAddr{Interface: net.Interface{Name: "foo"}}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{Interface: net.Interface{Name: "foo"}}, + sockaddr.IfAddr{Interface: net.Interface{Name: "bar"}}, + }, + }, + { + name: "sort port", + sortStr: "port", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("[::1]:53")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("[::1]:53")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + }, + { + name: "sort +port", + sortStr: "+port", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("[::1]:53")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("[::1]:53")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + }, + { + name: "sort -port", + sortStr: "-port", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("[::1]:53")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("[::1]:53")}, + }, + }, + { + name: "sort private", + sortStr: "private", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + }, + { + name: "sort +private", + sortStr: "+private", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + }, + { + name: "sort -private", + sortStr: "-private", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1")}, + }, + }, + { + name: "sort size", + sortStr: "size", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + }, + { + name: "sort +size", + sortStr: "+size", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + }, + { + name: "sort -size", + sortStr: "-size", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + }, + }, + { + name: "sort type", + sortStr: "type", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("::1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("::1")}, + }, + }, + { + name: "sort +type", + sortStr: "+type", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("::1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("192.168.1.1/27")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("::1")}, + }, + }, + { + name: "sort -type", + sortStr: "-type", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("::1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv6Addr("::1")}, + sockaddr.IfAddr{SockAddr: sockaddr.MustIPv4Addr("1.2.3.4:80")}, + }, + }, + { + name: "sort invalid", + sortStr: "ENOENT", + fail: true, + }, + } + + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %i needs a name", i) + } + + t.Run(test.name, func(t *testing.T) { + sorted, err := sockaddr.SortIfBy(test.sortStr, test.in) + if err != nil && !test.fail { + t.Fatalf("%s: sort failed: %v", test.name, err) + } + + if len(test.in) != len(sorted) { + t.Fatalf("wrong len") + } + + for i := 0; i < len(sorted); i++ { + if !reflect.DeepEqual(sorted[i], test.out[i]) { + t.Errorf("wrong sort order: %d %v %v", i, sorted[i], test.out[i]) + } + } + }) + } + +} |