diff options
Diffstat (limited to 'src/net/interface_unix_test.go')
-rw-r--r-- | src/net/interface_unix_test.go | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/src/net/interface_unix_test.go b/src/net/interface_unix_test.go new file mode 100644 index 0000000..bf41a0f --- /dev/null +++ b/src/net/interface_unix_test.go @@ -0,0 +1,212 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd + +package net + +import ( + "fmt" + "os" + "os/exec" + "runtime" + "strings" + "testing" + "time" +) + +type testInterface struct { + name string + local string + remote string + setupCmds []*exec.Cmd + teardownCmds []*exec.Cmd +} + +func (ti *testInterface) setup() error { + for _, cmd := range ti.setupCmds { + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("args=%v out=%q err=%v", cmd.Args, string(out), err) + } + } + return nil +} + +func (ti *testInterface) teardown() error { + for _, cmd := range ti.teardownCmds { + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("args=%v out=%q err=%v ", cmd.Args, string(out), err) + } + } + return nil +} + +func TestPointToPointInterface(t *testing.T) { + if testing.Short() { + t.Skip("avoid external network") + } + if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { + t.Skipf("not supported on %s", runtime.GOOS) + } + if os.Getuid() != 0 { + t.Skip("must be root") + } + + // We suppose that using IPv4 link-local addresses doesn't + // harm anyone. + local, remote := "169.254.0.1", "169.254.0.254" + ip := ParseIP(remote) + for i := 0; i < 3; i++ { + ti := &testInterface{local: local, remote: remote} + if err := ti.setPointToPoint(5963 + i); err != nil { + t.Skipf("test requires external command: %v", err) + } + if err := ti.setup(); err != nil { + if e := err.Error(); strings.Contains(e, "No such device") && strings.Contains(e, "gre0") { + t.Skip("skipping test; no gre0 device. likely running in container?") + } + t.Fatal(err) + } else { + time.Sleep(3 * time.Millisecond) + } + ift, err := Interfaces() + if err != nil { + ti.teardown() + t.Fatal(err) + } + for _, ifi := range ift { + if ti.name != ifi.Name { + continue + } + ifat, err := ifi.Addrs() + if err != nil { + ti.teardown() + t.Fatal(err) + } + for _, ifa := range ifat { + if ip.Equal(ifa.(*IPNet).IP) { + ti.teardown() + t.Fatalf("got %v", ifa) + } + } + } + if err := ti.teardown(); err != nil { + t.Fatal(err) + } else { + time.Sleep(3 * time.Millisecond) + } + } +} + +func TestInterfaceArrivalAndDeparture(t *testing.T) { + if testing.Short() { + t.Skip("avoid external network") + } + if os.Getuid() != 0 { + t.Skip("must be root") + } + + // We suppose that using IPv4 link-local addresses and the + // dot1Q ID for Token Ring and FDDI doesn't harm anyone. + local, remote := "169.254.0.1", "169.254.0.254" + ip := ParseIP(remote) + for _, vid := range []int{1002, 1003, 1004, 1005} { + ift1, err := Interfaces() + if err != nil { + t.Fatal(err) + } + ti := &testInterface{local: local, remote: remote} + if err := ti.setBroadcast(vid); err != nil { + t.Skipf("test requires external command: %v", err) + } + if err := ti.setup(); err != nil { + t.Fatal(err) + } else { + time.Sleep(3 * time.Millisecond) + } + ift2, err := Interfaces() + if err != nil { + ti.teardown() + t.Fatal(err) + } + if len(ift2) <= len(ift1) { + for _, ifi := range ift1 { + t.Logf("before: %v", ifi) + } + for _, ifi := range ift2 { + t.Logf("after: %v", ifi) + } + ti.teardown() + t.Fatalf("got %v; want gt %v", len(ift2), len(ift1)) + } + for _, ifi := range ift2 { + if ti.name != ifi.Name { + continue + } + ifat, err := ifi.Addrs() + if err != nil { + ti.teardown() + t.Fatal(err) + } + for _, ifa := range ifat { + if ip.Equal(ifa.(*IPNet).IP) { + ti.teardown() + t.Fatalf("got %v", ifa) + } + } + } + if err := ti.teardown(); err != nil { + t.Fatal(err) + } else { + time.Sleep(3 * time.Millisecond) + } + ift3, err := Interfaces() + if err != nil { + t.Fatal(err) + } + if len(ift3) >= len(ift2) { + for _, ifi := range ift2 { + t.Logf("before: %v", ifi) + } + for _, ifi := range ift3 { + t.Logf("after: %v", ifi) + } + t.Fatalf("got %v; want lt %v", len(ift3), len(ift2)) + } + } +} + +func TestInterfaceArrivalAndDepartureZoneCache(t *testing.T) { + if testing.Short() { + t.Skip("avoid external network") + } + if os.Getuid() != 0 { + t.Skip("must be root") + } + + // Ensure zoneCache is filled: + _, _ = Listen("tcp", "[fe80::1%nonexistent]:0") + + ti := &testInterface{local: "fe80::1"} + if err := ti.setLinkLocal(0); err != nil { + t.Skipf("test requires external command: %v", err) + } + if err := ti.setup(); err != nil { + t.Fatal(err) + } + defer ti.teardown() + + time.Sleep(3 * time.Millisecond) + + // If Listen fails (on Linux with “bind: invalid argument”), zoneCache was + // not updated when encountering a nonexistent interface: + ln, err := Listen("tcp", "[fe80::1%"+ti.name+"]:0") + if err != nil { + t.Fatal(err) + } + ln.Close() + if err := ti.teardown(); err != nil { + t.Fatal(err) + } +} |