Clean up conntrack unit tests

Fix the test names to match the functions they are testing.

Abstract out the repetitive FakeExec handling.

Explicitly specify the "expectCommand" in each one, to make it clearer
that that's really the part that we're testing.

For everything except TestExec(), test each case with both a "success"
result and a "nothing to delete" result from the conntrack binary.
This commit is contained in:
Dan Winship 2024-01-14 09:32:29 -05:00
parent 12fc215656
commit 51063cb5c4

View File

@ -27,47 +27,60 @@ import (
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/utils/exec" "k8s.io/utils/exec"
fakeexec "k8s.io/utils/exec/testing" fakeexec "k8s.io/utils/exec/testing"
utilnet "k8s.io/utils/net"
) )
func familyParamStr(isIPv6 bool) string { var success = func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil }
if isIPv6 { var nothingToDelete = func() ([]byte, []byte, error) {
return " -f ipv6" return []byte(""), nil, fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
}
return ""
} }
func TestExecConntrackTool(t *testing.T) { func makeCT(result fakeexec.FakeAction) (*fakeexec.FakeExec, *fakeexec.FakeCmd) {
fcmd := fakeexec.FakeCmd{ fcmd := &fakeexec.FakeCmd{
CombinedOutputScript: []fakeexec.FakeAction{ CombinedOutputScript: []fakeexec.FakeAction{result},
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
func() ([]byte, []byte, error) {
return []byte(""), nil, fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
},
},
} }
fexec := &fakeexec.FakeExec{ fexec := &fakeexec.FakeExec{
CommandScript: []fakeexec.FakeCommandAction{ CommandScript: []fakeexec.FakeCommandAction{
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
}, },
LookPathFunc: func(cmd string) (string, error) { return cmd, nil }, LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
} }
testCases := [][]string{ return fexec, fcmd
{"-L", "-p", "udp"}, }
{"-D", "-p", "udp", "-d", "10.0.240.1"},
{"-D", "-p", "udp", "--orig-dst", "10.240.0.2", "--dst-nat", "10.0.10.2"}, // Gets the command that fexec executed. (If it didn't execute any commands, this will
// return "".)
func getExecutedCommand(fexec *fakeexec.FakeExec, fcmd *fakeexec.FakeCmd) string {
// FakeExec panics if you try to run more commands than you set it up for. So the
// only possibilities here are that we ran 1 command or we ran 0.
if fexec.CommandCalls != 1 {
return ""
}
return strings.Join(fcmd.CombinedOutputLog[0], " ")
}
func TestExec(t *testing.T) {
testCases := []struct {
args []string
result fakeexec.FakeAction
expectErr bool
}{
{
args: []string{"-D", "-p", "udp", "-d", "10.0.240.1"},
result: success,
expectErr: false,
},
{
args: []string{"-D", "-p", "udp", "--orig-dst", "10.240.0.2", "--dst-nat", "10.0.10.2"},
result: nothingToDelete,
expectErr: true,
},
} }
expectErr := []bool{false, false, true} for _, tc := range testCases {
fexec, fcmd := makeCT(tc.result)
for i := range testCases { err := Exec(fexec, tc.args...)
err := Exec(fexec, testCases[i]...) if tc.expectErr {
if expectErr[i] {
if err == nil { if err == nil {
t.Errorf("expected err, got %v", err) t.Errorf("expected err, got %v", err)
} }
@ -77,204 +90,177 @@ func TestExecConntrackTool(t *testing.T) {
} }
} }
execCmd := strings.Join(fcmd.CombinedOutputLog[i], " ") execCmd := getExecutedCommand(fexec, fcmd)
expectCmd := fmt.Sprintf("%s %s", "conntrack", strings.Join(testCases[i], " ")) expectCmd := "conntrack " + strings.Join(tc.args, " ")
if execCmd != expectCmd { if execCmd != expectCmd {
t.Errorf("expect execute command: %s, but got: %s", expectCmd, execCmd) t.Errorf("expect execute command: %s, but got: %s", expectCmd, execCmd)
} }
} }
} }
func TestClearUDPConntrackForIP(t *testing.T) { func TestClearEntriesForIP(t *testing.T) {
fcmd := fakeexec.FakeCmd{
CombinedOutputScript: []fakeexec.FakeAction{
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
func() ([]byte, []byte, error) {
return []byte(""), nil, fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
},
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
},
}
fexec := &fakeexec.FakeExec{
CommandScript: []fakeexec.FakeCommandAction{
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
},
LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
}
testCases := []struct { testCases := []struct {
name string name string
ip string ip string
expectCommand string
}{ }{
{"IPv4 success", "10.240.0.3"}, {
{"IPv4 success", "10.240.0.5"}, name: "IPv4",
{"IPv4 simulated error", "10.240.0.4"}, ip: "10.240.0.3",
{"IPv6 success", "2001:db8::10"},
expectCommand: "conntrack -D --orig-dst 10.240.0.3 -p udp",
},
{
name: "IPv6",
ip: "2001:db8::10",
expectCommand: "conntrack -D --orig-dst 2001:db8::10 -p udp -f ipv6",
},
} }
svcCount := 0
for _, tc := range testCases { for _, tc := range testCases {
fexec, fcmd := makeCT(success)
if err := ClearEntriesForIP(fexec, tc.ip, v1.ProtocolUDP); err != nil { if err := ClearEntriesForIP(fexec, tc.ip, v1.ProtocolUDP); err != nil {
t.Errorf("%s test case:, Unexpected error: %v", tc.name, err) t.Errorf("%s/success: Unexpected error: %v", tc.name, err)
} }
expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s -p udp", tc.ip) + familyParamStr(utilnet.IsIPv6String(tc.ip)) execCommand := getExecutedCommand(fexec, fcmd)
execCommand := strings.Join(fcmd.CombinedOutputLog[svcCount], " ") if tc.expectCommand != execCommand {
if expectCommand != execCommand { t.Errorf("%s/success: Expect command: %s, but executed %s", tc.name, tc.expectCommand, execCommand)
t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand) }
fexec, _ = makeCT(nothingToDelete)
if err := ClearEntriesForIP(fexec, tc.ip, v1.ProtocolUDP); err != nil {
t.Errorf("%s/nothing to delete: Unexpected error: %v", tc.name, err)
} }
svcCount++
}
if svcCount != fexec.CommandCalls {
t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
} }
} }
func TestClearUDPConntrackForPort(t *testing.T) { func TestClearEntriesForPort(t *testing.T) {
fcmd := fakeexec.FakeCmd{
CombinedOutputScript: []fakeexec.FakeAction{
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
func() ([]byte, []byte, error) {
return []byte(""), nil, fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
},
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
},
}
fexec := &fakeexec.FakeExec{
CommandScript: []fakeexec.FakeCommandAction{
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
},
LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
}
testCases := []struct { testCases := []struct {
name string name string
port int port int
isIPv6 bool isIPv6 bool
expectCommand string
}{ }{
{"IPv4, no error", 8080, false}, {
{"IPv4, simulated error", 9090, false}, name: "IPv4",
{"IPv6, no error", 6666, true}, port: 8080,
isIPv6: false,
expectCommand: "conntrack -D -p udp --dport 8080",
},
{
name: "IPv6",
port: 6666,
isIPv6: true,
expectCommand: "conntrack -D -p udp --dport 6666 -f ipv6",
},
} }
svcCount := 0
for _, tc := range testCases { for _, tc := range testCases {
fexec, fcmd := makeCT(success)
err := ClearEntriesForPort(fexec, tc.port, tc.isIPv6, v1.ProtocolUDP) err := ClearEntriesForPort(fexec, tc.port, tc.isIPv6, v1.ProtocolUDP)
if err != nil { if err != nil {
t.Errorf("%s test case: Unexpected error: %v", tc.name, err) t.Errorf("%s/success: Unexpected error: %v", tc.name, err)
} }
expectCommand := fmt.Sprintf("conntrack -D -p udp --dport %d", tc.port) + familyParamStr(tc.isIPv6) execCommand := getExecutedCommand(fexec, fcmd)
execCommand := strings.Join(fcmd.CombinedOutputLog[svcCount], " ") if tc.expectCommand != execCommand {
if expectCommand != execCommand { t.Errorf("%s/success: Expect command: %s, but executed %s", tc.name, tc.expectCommand, execCommand)
t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand) }
fexec, _ = makeCT(nothingToDelete)
err = ClearEntriesForPort(fexec, tc.port, tc.isIPv6, v1.ProtocolUDP)
if err != nil {
t.Errorf("%s/nothing to delete: Unexpected error: %v", tc.name, err)
} }
svcCount++
}
if svcCount != fexec.CommandCalls {
t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
} }
} }
func TestDeleteUDPConnections(t *testing.T) { func TestClearEntriesForNAT(t *testing.T) {
fcmd := fakeexec.FakeCmd{
CombinedOutputScript: []fakeexec.FakeAction{
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
func() ([]byte, []byte, error) {
return []byte(""), nil, fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
},
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
},
}
fexec := &fakeexec.FakeExec{
CommandScript: []fakeexec.FakeCommandAction{
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
},
LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
}
testCases := []struct { testCases := []struct {
name string name string
origin string origin string
dest string dest string
expectCommand string
}{ }{
{ {
name: "IPv4 success", name: "IPv4",
origin: "1.2.3.4", origin: "1.2.3.4",
dest: "10.20.30.40", dest: "10.20.30.40",
expectCommand: "conntrack -D --orig-dst 1.2.3.4 --dst-nat 10.20.30.40 -p udp",
}, },
{ {
name: "IPv4 simulated failure", name: "IPv6",
origin: "2.3.4.5",
dest: "20.30.40.50",
},
{
name: "IPv6 success",
origin: "fd00::600d:f00d", origin: "fd00::600d:f00d",
dest: "2001:db8::5", dest: "2001:db8::5",
expectCommand: "conntrack -D --orig-dst fd00::600d:f00d --dst-nat 2001:db8::5 -p udp -f ipv6",
}, },
} }
svcCount := 0
for i, tc := range testCases { for _, tc := range testCases {
fexec, fcmd := makeCT(success)
err := ClearEntriesForNAT(fexec, tc.origin, tc.dest, v1.ProtocolUDP) err := ClearEntriesForNAT(fexec, tc.origin, tc.dest, v1.ProtocolUDP)
if err != nil { if err != nil {
t.Errorf("%s test case: unexpected error: %v", tc.name, err) t.Errorf("%s/success: unexpected error: %v", tc.name, err)
} }
expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s --dst-nat %s -p udp", tc.origin, tc.dest) + familyParamStr(utilnet.IsIPv6String(tc.origin)) execCommand := getExecutedCommand(fexec, fcmd)
execCommand := strings.Join(fcmd.CombinedOutputLog[i], " ") if tc.expectCommand != execCommand {
if expectCommand != execCommand { t.Errorf("%s/success: Expect command: %s, but executed %s", tc.name, tc.expectCommand, execCommand)
t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand) }
fexec, _ = makeCT(nothingToDelete)
err = ClearEntriesForNAT(fexec, tc.origin, tc.dest, v1.ProtocolUDP)
if err != nil {
t.Errorf("%s/nothing to delete: unexpected error: %v", tc.name, err)
} }
svcCount++
}
if svcCount != fexec.CommandCalls {
t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
} }
} }
func TestClearUDPConntrackForPortNAT(t *testing.T) { func TestClearEntriesForPortNAT(t *testing.T) {
fcmd := fakeexec.FakeCmd{
CombinedOutputScript: []fakeexec.FakeAction{
func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
},
}
fexec := &fakeexec.FakeExec{
CommandScript: []fakeexec.FakeCommandAction{
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
},
LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
}
testCases := []struct { testCases := []struct {
name string name string
port int port int
dest string dest string
expectCommand string
}{ }{
{ {
name: "IPv4 success", name: "IPv4",
port: 30211, port: 30211,
dest: "1.2.3.4", dest: "1.2.3.4",
expectCommand: "conntrack -D -p udp --dport 30211 --dst-nat 1.2.3.4",
},
{
name: "IPv6",
port: 30212,
dest: "2600:5200::7800",
expectCommand: "conntrack -D -p udp --dport 30212 --dst-nat 2600:5200::7800 -f ipv6",
}, },
} }
svcCount := 0
for i, tc := range testCases { for _, tc := range testCases {
fexec, fcmd := makeCT(success)
err := ClearEntriesForPortNAT(fexec, tc.dest, tc.port, v1.ProtocolUDP) err := ClearEntriesForPortNAT(fexec, tc.dest, tc.port, v1.ProtocolUDP)
if err != nil { if err != nil {
t.Errorf("%s test case: unexpected error: %v", tc.name, err) t.Errorf("%s/success: unexpected error: %v", tc.name, err)
} }
expectCommand := fmt.Sprintf("conntrack -D -p udp --dport %d --dst-nat %s", tc.port, tc.dest) + familyParamStr(utilnet.IsIPv6String(tc.dest)) execCommand := getExecutedCommand(fexec, fcmd)
execCommand := strings.Join(fcmd.CombinedOutputLog[i], " ") if tc.expectCommand != execCommand {
if expectCommand != execCommand { t.Errorf("%s/success: Expect command: %s, but executed %s", tc.name, tc.expectCommand, execCommand)
t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand) }
fexec, _ = makeCT(nothingToDelete)
err = ClearEntriesForPortNAT(fexec, tc.dest, tc.port, v1.ProtocolUDP)
if err != nil {
t.Errorf("%s/nothing to delete: unexpected error: %v", tc.name, err)
} }
svcCount++
}
if svcCount != fexec.CommandCalls {
t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
} }
} }