]> Cypherpunks repositories - gostls13.git/commitdiff
net: enable TestInterfaceHardwareAddrWithGetmac on all windows versions
authorJeff Johnson <jrjohnson@google.com>
Fri, 8 Dec 2017 17:21:57 +0000 (09:21 -0800)
committerBrad Fitzpatrick <bradfitz@golang.org>
Fri, 8 Dec 2017 19:02:40 +0000 (19:02 +0000)
Re-work the test to use wmic instead of PowerShell's getmac that's
only avaliable on Server 2008. Maintains duplicate detection added
for golang/go#21027.

Tested on windows-amd64-{2008, 2012, 2016} buildlets.
Enabling for Windows XP because it should work[1].

Fixes golang/go#20073

[1] https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/wmic_overview.mspx?mfr=true

Change-Id: Ic11d569f7964f61d08ae0dcc1b926efc5336ac5b
Reviewed-on: https://go-review.googlesource.com/82975
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/net/net_windows_test.go

index db211e9d6ed60dd7807f3c87c16449cbe6e5b38d..ab09cdb28a89ee27555dd6131c627e38d9c945df 100644 (file)
@@ -503,139 +503,72 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
        }
 }
 
-// check that getmac exists as a powershell command, and that it
-// speaks English.
-func checkGetmac(t *testing.T) {
-       out, err := runCmd("getmac", "/?")
-       if err != nil {
-               if strings.Contains(err.Error(), "term 'getmac' is not recognized as the name of a cmdlet") {
-                       t.Skipf("getmac not available")
+func contains(needle string, haystack []string) bool {
+       for _, v := range haystack {
+               if v == needle {
+                       return true
                }
-               t.Fatal(err)
-       }
-       if !bytes.Contains(out, []byte("network adapters on a system")) {
-               t.Skipf("skipping test on non-English system")
        }
+       return false
 }
 
-func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
-       if isWindowsXP(t) {
-               t.Skip("Windows XP does not have powershell command")
-       }
-       checkGetmac(t)
-
+func TestInterfaceHardwareAddrWithWmic(t *testing.T) {
        ift, err := Interfaces()
        if err != nil {
                t.Fatal(err)
        }
-       have := make(map[string]string)
+       goMacToName := make(map[string]string)
        for _, ifi := range ift {
                if ifi.Flags&FlagLoopback != 0 {
                        // no MAC address for loopback interfaces
                        continue
                }
-               have[ifi.Name] = ifi.HardwareAddr.String()
+               goMacToName[ifi.HardwareAddr.String()] = ifi.Name
        }
 
-       out, err := runCmd("getmac", "/fo", "list", "/v")
+       //wmic nic get MACAddress,NetConnectionID /format:csv
+       //
+       //Node,MACAddress,NetConnectionID
+       //SERVER-2008R2-V,,
+       //SERVER-2008R2-V,42:01:0A:F0:00:18,Local Area Connection
+       //SERVER-2008R2-V,42:01:0A:F0:00:18,Duplicate Adapter
+       //SERVER-2008R2-V,20:41:53:59:4E:FF,
+       out, err := exec.Command("wmic", "nic", "get", "MACAddress,NetConnectionID", "/format:csv").CombinedOutput()
        if err != nil {
                t.Fatal(err)
        }
-       // getmac output looks like:
-       //
-       //Connection Name:  Local Area Connection
-       //Network Adapter:  Intel Gigabit Network Connection
-       //Physical Address: XX-XX-XX-XX-XX-XX
-       //Transport Name:   \Device\Tcpip_{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
-       //
-       //Connection Name:  Wireless Network Connection
-       //Network Adapter:  Wireles WLAN Card
-       //Physical Address: XX-XX-XX-XX-XX-XX
-       //Transport Name:   Media disconnected
-       //
-       //Connection Name:  Bluetooth Network Connection
-       //Network Adapter:  Bluetooth Device (Personal Area Network)
-       //Physical Address: N/A
-       //Transport Name:   Hardware not present
-       //
-       //Connection Name:  VMware Network Adapter VMnet8
-       //Network Adapter:  VMware Virtual Ethernet Adapter for VMnet8
-       //Physical Address: Disabled
-       //Transport Name:   Disconnected
-       //
-       want := make(map[string]string)
-       group := make(map[string]string) // name / values for single adapter
-       getValue := func(name string) string {
-               value, found := group[name]
-               if !found {
-                       t.Fatalf("%q has no %q line in it", group, name)
-               }
-               if value == "" {
-                       t.Fatalf("%q has empty %q value", group, name)
-               }
-               return value
-       }
-       processGroup := func() {
-               if len(group) == 0 {
-                       return
-               }
-               tname := strings.ToLower(getValue("Transport Name"))
-               if tname == "n/a" {
-                       // skip these
-                       return
-               }
-               addr := strings.ToLower(getValue("Physical Address"))
-               if addr == "disabled" || addr == "n/a" {
-                       // skip these
-                       return
-               }
-               addr = strings.Replace(addr, "-", ":", -1)
-               cname := getValue("Connection Name")
-               want[cname] = addr
-               group = make(map[string]string)
-       }
+       winMacToNames := make(map[string][]string)
        lines := bytes.Split(out, []byte{'\r', '\n'})
+
        for _, line := range lines {
-               if len(line) == 0 {
-                       processGroup()
+               entry := strings.Split(string(line), ",")
+               if len(entry) != 3 || entry[1] == "MACAddress" {
+                       // skip empty lines, header
                        continue
                }
-               i := bytes.IndexByte(line, ':')
-               if i == -1 {
-                       t.Fatalf("line %q has no : in it", line)
+
+               mac, name := strings.ToLower(entry[1]), strings.TrimSpace(entry[2])
+               if mac == "" || name == "" {
+                       // skip non-physical devices
+                       continue
                }
-               group[string(line[:i])] = string(bytes.TrimSpace(line[i+1:]))
+
+               winMacToNames[mac] = append(winMacToNames[mac], name)
        }
-       processGroup()
 
-       dups := make(map[string][]string)
-       for name, addr := range want {
-               if _, ok := dups[addr]; !ok {
-                       dups[addr] = make([]string, 0)
-               }
-               dups[addr] = append(dups[addr], name)
+       if len(goMacToName) != len(winMacToNames) {
+               t.Errorf("go interface count (%d, %v) differs from wmic count (%d, %v)", len(goMacToName), goMacToName, len(winMacToNames), winMacToNames)
        }
 
-nextWant:
-       for name, wantAddr := range want {
-               if haveAddr, ok := have[name]; ok {
-                       if haveAddr != wantAddr {
-                               t.Errorf("unexpected MAC address for %q - %v, want %v", name, haveAddr, wantAddr)
-                       }
-                       continue
-               }
-               // We could not find the interface in getmac output by name.
-               // But sometimes getmac lists many interface names
-               // for the same MAC address. If that is the case here,
-               // and we can match at least one of those names,
-               // let's ignore the other names.
-               if dupNames, ok := dups[wantAddr]; ok && len(dupNames) > 1 {
-                       for _, dupName := range dupNames {
-                               if haveAddr, ok := have[dupName]; ok && haveAddr == wantAddr {
-                                       continue nextWant
-                               }
+       for mac, name := range goMacToName {
+               // Windows appears to associate multiple names to a single MAC
+               // Consider it a success if one of those names was found
+               if cmdNames, ok := winMacToNames[mac]; ok {
+                       if contains(name, cmdNames) {
+                               continue
                        }
                }
-               t.Errorf("getmac lists %q, but it could not be found among Go interfaces %v", name, have)
+
+               t.Errorf("go found interface (name: %s, mac: %s) not found by wmic (%v)", name, mac, winMacToNames)
        }
 }