package ipcmd import ( "fmt" "strings" "testing" "k8s.io/kubernetes/pkg/util/exec" ) func normalSetup() *exec.FakeExec { return &exec.FakeExec{ LookPathFunc: func(prog string) (string, error) { if prog == "ip" { return "/sbin/ip", nil } else { return "", fmt.Errorf("%s not found", prog) } }, } } func missingSetup() *exec.FakeExec { return &exec.FakeExec{ LookPathFunc: func(prog string) (string, error) { return "", fmt.Errorf("%s not found", prog) }, } } func addTestResult(t *testing.T, fexec *exec.FakeExec, command string, output string, err error) { fcmd := exec.FakeCmd{ CombinedOutputScript: []exec.FakeCombinedOutputAction{ func() ([]byte, error) { return []byte(output), err }, }, } fexec.CommandScript = append(fexec.CommandScript, func(cmd string, args ...string) exec.Cmd { execCommand := strings.Join(append([]string{cmd}, args...), " ") if execCommand != command { t.Fatalf("Unexpected command: wanted %q got %q", command, execCommand) } return exec.InitFakeCmd(&fcmd, cmd, args...) }) } func ensureTestResults(t *testing.T, fexec *exec.FakeExec) { if fexec.CommandCalls != len(fexec.CommandScript) { t.Fatalf("Only used %d of %d expected commands", fexec.CommandCalls, len(fexec.CommandScript)) } } func TestGetAddresses(t *testing.T) { fexec := normalSetup() addTestResult(t, fexec, "/sbin/ip addr show dev lo", `1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever `, nil) itx := NewTransaction(fexec, "lo") addrs, err := itx.GetAddresses() if err != nil { t.Fatalf("Failed to get addresses for 'lo': %v", err) } if len(addrs) != 1 { t.Fatalf("'lo' has unexpected len(addrs) %d", len(addrs)) } if addrs[0] != "127.0.0.1/8" { t.Fatalf("'lo' has unexpected address %s", addrs[0]) } err = itx.EndTransaction() if err != nil { t.Fatalf("Transaction unexpectedly returned error: %v", err) } ensureTestResults(t, fexec) addTestResult(t, fexec, "/sbin/ip addr show dev eth0", `2: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff inet 192.168.1.10/24 brd 192.168.1.255 scope global dynamic eth0 valid_lft 81296sec preferred_lft 81296sec inet 192.168.1.152/24 brd 192.168.1.255 scope global dynamic eth0 valid_lft 81296sec preferred_lft 81296sec `, nil) itx = NewTransaction(fexec, "eth0") addrs, err = itx.GetAddresses() if err != nil { t.Fatalf("Failed to get addresses for 'eth0': %v", err) } if len(addrs) != 2 { t.Fatalf("'eth0' has unexpected len(addrs) %d", len(addrs)) } if addrs[0] != "192.168.1.10/24" || addrs[1] != "192.168.1.152/24" { t.Fatalf("'eth0' has unexpected addresses %v", addrs) } err = itx.EndTransaction() if err != nil { t.Fatalf("Transaction unexpectedly returned error: %v", err) } ensureTestResults(t, fexec) addTestResult(t, fexec, "/sbin/ip addr show dev wlan0", "", fmt.Errorf("Device \"%s\" does not exist", "wlan0")) itx = NewTransaction(fexec, "wlan0") addrs, err = itx.GetAddresses() if err == nil { t.Fatalf("Allegedly got addresses for non-existent link: %v", addrs) } err = itx.EndTransaction() if err == nil { t.Fatalf("Transaction unexpectedly returned no error") } ensureTestResults(t, fexec) } func TestGetRoutes(t *testing.T) { const ( l1 = "default via 192.168.1.1 proto static metric 1024 " l2 = "1.2.3.4 via 192.168.1.1 proto static metric 10 " l3 = "192.168.1.0/24 proto kernel scope link src 192.168.1.15 " ) fexec := normalSetup() addTestResult(t, fexec, "/sbin/ip route show dev wlp3s0", l1+"\n"+l2+"\n"+l3+"\n", nil) itx := NewTransaction(fexec, "wlp3s0") routes, err := itx.GetRoutes() if err != nil { t.Fatalf("Failed to get routes for 'wlp3s0': %v", err) } if len(routes) != 3 { t.Fatalf("'wlp3s0' has unexpected len(routes) %d", len(routes)) } if routes[0] != l1 { t.Fatalf("Unexpected first route %s", routes[0]) } if routes[1] != l2 { t.Fatalf("Unexpected second route %s", routes[1]) } if routes[2] != l3 { t.Fatalf("Unexpected third route %s", routes[2]) } err = itx.EndTransaction() if err != nil { t.Fatalf("Transaction unexpectedly returned error: %v", err) } ensureTestResults(t, fexec) addTestResult(t, fexec, "/sbin/ip route show dev wlan0", "", fmt.Errorf("Device \"%s\" does not exist", "wlan0")) itx = NewTransaction(fexec, "wlan0") routes, err = itx.GetRoutes() if err == nil { t.Fatalf("Allegedly got routes for non-existent link: %v", routes) } err = itx.EndTransaction() if err == nil { t.Fatalf("Transaction unexpectedly returned no error") } ensureTestResults(t, fexec) } func TestErrorHandling(t *testing.T) { fexec := normalSetup() addTestResult(t, fexec, "/sbin/ip link del dummy0", "", fmt.Errorf("Device \"%s\" does not exist", "dummy0")) itx := NewTransaction(fexec, "dummy0") itx.DeleteLink() err := itx.EndTransaction() if err == nil { t.Fatalf("Failed to get expected error") } ensureTestResults(t, fexec) addTestResult(t, fexec, "/sbin/ip link del dummy0", "", fmt.Errorf("Device \"%s\" does not exist", "dummy0")) addTestResult(t, fexec, "/sbin/ip link add dummy0 type dummy", "", nil) itx = NewTransaction(fexec, "dummy0") itx.DeleteLink() itx.IgnoreError() itx.AddLink("type", "dummy") err = itx.EndTransaction() if err != nil { t.Fatalf("Unexpectedly got error after IgnoreError(): %v", err) } ensureTestResults(t, fexec) addTestResult(t, fexec, "/sbin/ip link add dummy0 type dummy", "", fmt.Errorf("RTNETLINK answers: Operation not permitted")) // other commands do not get run due to previous error itx = NewTransaction(fexec, "dummy0") itx.AddLink("type", "dummy") itx.SetLink("up") itx.DeleteLink() err = itx.EndTransaction() if err == nil { t.Fatalf("Failed to get expected error") } ensureTestResults(t, fexec) } func TestIPMissing(t *testing.T) { fexec := missingSetup() itx := NewTransaction(fexec, "dummy0") itx.AddLink("type", "dummy") err := itx.EndTransaction() if err == nil { t.Fatalf("Unexpectedly did not get error") } if err.Error() != "ip is not installed" { t.Fatalf("Got wrong error: %v", err) } }