Skip to content

Commit 82f58c1

Browse files
johnsonjbradfitz
authored andcommitted
net: enable TestInterfaceHardwareAddrWithGetmac on all windows versions
Re-work the test to use wmic instead of PowerShell's getmac that's only avaliable on Server 2008. Maintains duplicate detection added for #21027. Tested on windows-amd64-{2008, 2012, 2016} buildlets. Enabling for Windows XP because it should work[1]. Fixes #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 <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 66ba18b commit 82f58c1

File tree

1 file changed

+38
-105
lines changed

1 file changed

+38
-105
lines changed

src/net/net_windows_test.go

Lines changed: 38 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -503,139 +503,72 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
503503
}
504504
}
505505

506-
// check that getmac exists as a powershell command, and that it
507-
// speaks English.
508-
func checkGetmac(t *testing.T) {
509-
out, err := runCmd("getmac", "/?")
510-
if err != nil {
511-
if strings.Contains(err.Error(), "term 'getmac' is not recognized as the name of a cmdlet") {
512-
t.Skipf("getmac not available")
506+
func contains(needle string, haystack []string) bool {
507+
for _, v := range haystack {
508+
if v == needle {
509+
return true
513510
}
514-
t.Fatal(err)
515-
}
516-
if !bytes.Contains(out, []byte("network adapters on a system")) {
517-
t.Skipf("skipping test on non-English system")
518511
}
512+
return false
519513
}
520514

521-
func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
522-
if isWindowsXP(t) {
523-
t.Skip("Windows XP does not have powershell command")
524-
}
525-
checkGetmac(t)
526-
515+
func TestInterfaceHardwareAddrWithWmic(t *testing.T) {
527516
ift, err := Interfaces()
528517
if err != nil {
529518
t.Fatal(err)
530519
}
531-
have := make(map[string]string)
520+
goMacToName := make(map[string]string)
532521
for _, ifi := range ift {
533522
if ifi.Flags&FlagLoopback != 0 {
534523
// no MAC address for loopback interfaces
535524
continue
536525
}
537-
have[ifi.Name] = ifi.HardwareAddr.String()
526+
goMacToName[ifi.HardwareAddr.String()] = ifi.Name
538527
}
539528

540-
out, err := runCmd("getmac", "/fo", "list", "/v")
529+
//wmic nic get MACAddress,NetConnectionID /format:csv
530+
//
531+
//Node,MACAddress,NetConnectionID
532+
//SERVER-2008R2-V,,
533+
//SERVER-2008R2-V,42:01:0A:F0:00:18,Local Area Connection
534+
//SERVER-2008R2-V,42:01:0A:F0:00:18,Duplicate Adapter
535+
//SERVER-2008R2-V,20:41:53:59:4E:FF,
536+
out, err := exec.Command("wmic", "nic", "get", "MACAddress,NetConnectionID", "/format:csv").CombinedOutput()
541537
if err != nil {
542538
t.Fatal(err)
543539
}
544-
// getmac output looks like:
545-
//
546-
//Connection Name: Local Area Connection
547-
//Network Adapter: Intel Gigabit Network Connection
548-
//Physical Address: XX-XX-XX-XX-XX-XX
549-
//Transport Name: \Device\Tcpip_{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
550-
//
551-
//Connection Name: Wireless Network Connection
552-
//Network Adapter: Wireles WLAN Card
553-
//Physical Address: XX-XX-XX-XX-XX-XX
554-
//Transport Name: Media disconnected
555-
//
556-
//Connection Name: Bluetooth Network Connection
557-
//Network Adapter: Bluetooth Device (Personal Area Network)
558-
//Physical Address: N/A
559-
//Transport Name: Hardware not present
560-
//
561-
//Connection Name: VMware Network Adapter VMnet8
562-
//Network Adapter: VMware Virtual Ethernet Adapter for VMnet8
563-
//Physical Address: Disabled
564-
//Transport Name: Disconnected
565-
//
566-
want := make(map[string]string)
567-
group := make(map[string]string) // name / values for single adapter
568-
getValue := func(name string) string {
569-
value, found := group[name]
570-
if !found {
571-
t.Fatalf("%q has no %q line in it", group, name)
572-
}
573-
if value == "" {
574-
t.Fatalf("%q has empty %q value", group, name)
575-
}
576-
return value
577-
}
578-
processGroup := func() {
579-
if len(group) == 0 {
580-
return
581-
}
582-
tname := strings.ToLower(getValue("Transport Name"))
583-
if tname == "n/a" {
584-
// skip these
585-
return
586-
}
587-
addr := strings.ToLower(getValue("Physical Address"))
588-
if addr == "disabled" || addr == "n/a" {
589-
// skip these
590-
return
591-
}
592-
addr = strings.Replace(addr, "-", ":", -1)
593-
cname := getValue("Connection Name")
594-
want[cname] = addr
595-
group = make(map[string]string)
596-
}
540+
winMacToNames := make(map[string][]string)
597541
lines := bytes.Split(out, []byte{'\r', '\n'})
542+
598543
for _, line := range lines {
599-
if len(line) == 0 {
600-
processGroup()
544+
entry := strings.Split(string(line), ",")
545+
if len(entry) != 3 || entry[1] == "MACAddress" {
546+
// skip empty lines, header
601547
continue
602548
}
603-
i := bytes.IndexByte(line, ':')
604-
if i == -1 {
605-
t.Fatalf("line %q has no : in it", line)
549+
550+
mac, name := strings.ToLower(entry[1]), strings.TrimSpace(entry[2])
551+
if mac == "" || name == "" {
552+
// skip non-physical devices
553+
continue
606554
}
607-
group[string(line[:i])] = string(bytes.TrimSpace(line[i+1:]))
555+
556+
winMacToNames[mac] = append(winMacToNames[mac], name)
608557
}
609-
processGroup()
610558

611-
dups := make(map[string][]string)
612-
for name, addr := range want {
613-
if _, ok := dups[addr]; !ok {
614-
dups[addr] = make([]string, 0)
615-
}
616-
dups[addr] = append(dups[addr], name)
559+
if len(goMacToName) != len(winMacToNames) {
560+
t.Errorf("go interface count (%d, %v) differs from wmic count (%d, %v)", len(goMacToName), goMacToName, len(winMacToNames), winMacToNames)
617561
}
618562

619-
nextWant:
620-
for name, wantAddr := range want {
621-
if haveAddr, ok := have[name]; ok {
622-
if haveAddr != wantAddr {
623-
t.Errorf("unexpected MAC address for %q - %v, want %v", name, haveAddr, wantAddr)
624-
}
625-
continue
626-
}
627-
// We could not find the interface in getmac output by name.
628-
// But sometimes getmac lists many interface names
629-
// for the same MAC address. If that is the case here,
630-
// and we can match at least one of those names,
631-
// let's ignore the other names.
632-
if dupNames, ok := dups[wantAddr]; ok && len(dupNames) > 1 {
633-
for _, dupName := range dupNames {
634-
if haveAddr, ok := have[dupName]; ok && haveAddr == wantAddr {
635-
continue nextWant
636-
}
563+
for mac, name := range goMacToName {
564+
// Windows appears to associate multiple names to a single MAC
565+
// Consider it a success if one of those names was found
566+
if cmdNames, ok := winMacToNames[mac]; ok {
567+
if contains(name, cmdNames) {
568+
continue
637569
}
638570
}
639-
t.Errorf("getmac lists %q, but it could not be found among Go interfaces %v", name, have)
571+
572+
t.Errorf("go found interface (name: %s, mac: %s) not found by wmic (%v)", name, mac, winMacToNames)
640573
}
641574
}

0 commit comments

Comments
 (0)