net: fix TestInterfaces, TestInterfaceAddrs on platforms without loopback interface

Fixes #10214.

Change-Id: If29d26c590eb53d4976e0a6ace0ed33aaf0c3e80
Reviewed-on: https://go-review.googlesource.com/7924
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index 15c0cd7..16217e7 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -47,12 +47,20 @@
 	return ""
 }
 
+type routeStats struct {
+	loop  int // # of active loopback interfaces
+	other int // # of active other interfaces
+
+	uni4, uni6     int // # of active connected unicast, anycast routes
+	multi4, multi6 int // # of active connected multicast route clones
+}
+
 func TestInterfaces(t *testing.T) {
 	ift, err := Interfaces()
 	if err != nil {
 		t.Fatal(err)
 	}
-	var nifs, naf4, naf6, nmaf4, nmaf6 int
+	var stats routeStats
 	for _, ifi := range ift {
 		ifxi, err := InterfaceByIndex(ifi.Index)
 		if err != nil {
@@ -70,36 +78,53 @@
 		}
 		t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
 		t.Logf("hardware address %q", ifi.HardwareAddr.String())
-		if ifi.Flags&FlagUp != 0 && ifi.Flags&FlagLoopback == 0 {
-			nifs++ // active interfaces except loopback interfaces
+		if ifi.Flags&FlagUp != 0 {
+			if ifi.Flags&FlagLoopback != 0 {
+				stats.loop++
+			} else {
+				stats.other++
+			}
 		}
 		n4, n6 := testInterfaceAddrs(t, &ifi)
-		naf4 += n4
-		naf6 += n6
+		stats.uni4 += n4
+		stats.uni6 += n6
 		n4, n6 = testInterfaceMulticastAddrs(t, &ifi)
-		nmaf4 += n4
-		nmaf6 += n6
+		stats.multi4 += n4
+		stats.multi6 += n6
 	}
 	switch runtime.GOOS {
 	case "nacl", "plan9", "solaris":
 	default:
-		if supportsIPv4 && nifs > 0 && naf4 == 0 {
-			t.Errorf("got %v; want more than or equal to one", naf4)
+		// Test the existence of connected unicast routes for
+		// IPv4.
+		if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
+			t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
 		}
-		if supportsIPv6 && nifs > 0 && naf6 == 0 {
-			t.Errorf("got %v; want more than or equal to one", naf6)
+		// Test the existence of connected unicast routes for
+		// IPv6. We can assume the existence of ::1/128 when
+		// at least one looopback interface is installed.
+		if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
+			t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
 		}
 	}
 	switch runtime.GOOS {
 	case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris":
 	default:
-		// Unlike IPv6, IPv4 multicast capability is not a
-		// mandatory feature.
-		//if supportsIPv4 && nactvifs > 0 && nmaf4 == 0 {
-		//	t.Errorf("got %v; want more than or equal to one", nmaf4)
+		// Test the existence of connected multicast route
+		// clones for IPv4. Unlike IPv6, IPv4 multicast
+		// capability is not a mandatory feature, and so this
+		// test is disabled.
+		//if supportsIPv4 && stats.loop > 0 && stats.uni4 > 1 && stats.multi4 == 0 {
+		//	t.Errorf("num IPv4 multicast route clones = 0; want >0; summary: %+v", stats)
 		//}
-		if supportsIPv6 && nifs > 0 && nmaf6 == 0 {
-			t.Errorf("got %v; want more than or equal to one", nmaf6)
+		// Test the existence of connected multicast route
+		// clones for IPv6. Some platform never uses loopback
+		// interface as the nexthop for multicast routing.
+		// We can assume the existence of connected multicast
+		// route clones when at least two connected unicast
+		// routes, ::1/128 and other, are installed.
+		if supportsIPv6 && stats.loop > 0 && stats.uni6 > 1 && stats.multi6 == 0 {
+			t.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v", stats)
 		}
 	}
 }
@@ -109,22 +134,30 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	var nifs int
+	var stats routeStats
 	for _, ifi := range ift {
-		if ifi.Flags&FlagUp != 0 && ifi.Flags&FlagLoopback == 0 {
-			nifs++ // active interfaces except loopback interfaces
+		if ifi.Flags&FlagUp != 0 {
+			if ifi.Flags&FlagLoopback != 0 {
+				stats.loop++
+			} else {
+				stats.other++
+			}
 		}
 	}
 	ifat, err := InterfaceAddrs()
 	if err != nil {
 		t.Fatal(err)
 	}
-	naf4, naf6 := testAddrs(t, ifat)
-	if supportsIPv4 && nifs > 0 && naf4 == 0 {
-		t.Errorf("got %v; want more than or equal to one", naf4)
+	stats.uni4, stats.uni6 = testAddrs(t, ifat)
+	// Test the existence of connected unicast routes for IPv4.
+	if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
+		t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
 	}
-	if supportsIPv6 && nifs > 0 && naf6 == 0 {
-		t.Errorf("got %v; want more than or equal to one", naf6)
+	// Test the existence of connected unicast routes for IPv6.
+	// We can assume the existence of ::1/128 when at least one
+	// looopback interface is installed.
+	if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
+		t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
 	}
 }