Skip to content

Commit

Permalink
Fix unit test TestReconcile
Browse files Browse the repository at this point in the history
cniServer.reconcile() now installs flows asynchorously.

Signed-off-by: Quan Tian <qtian@vmware.com>
  • Loading branch information
tnqn committed Dec 14, 2023
1 parent cfd7b86 commit 4c9a802
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 92 deletions.
96 changes: 53 additions & 43 deletions pkg/agent/cniserver/server_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"net"
"testing"
"time"

cnitypes "github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100"
Expand All @@ -45,6 +46,7 @@ import (
"antrea.io/antrea/pkg/ovs/ovsconfig"
ovsconfigtest "antrea.io/antrea/pkg/ovs/ovsconfig/testing"
"antrea.io/antrea/pkg/util/channel"
utilip "antrea.io/antrea/pkg/util/ip"
)

func TestValidatePrevResult(t *testing.T) {
Expand Down Expand Up @@ -652,59 +654,67 @@ func TestReconcile(t *testing.T) {
},
},
}
containerIfaces := map[string]*interfacestore.InterfaceConfig{
"iface1": {
InterfaceName: "iface1",
Type: interfacestore.ContainerInterface,
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(3),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p1",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
normalInterface := &interfacestore.InterfaceConfig{
InterfaceName: "iface1",
Type: interfacestore.ContainerInterface,
IPs: []net.IP{net.ParseIP("1.1.1.1")},
MAC: utilip.MustParseMAC("00:11:22:33:44:01"),
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(3),
},
"iface3": {
InterfaceName: "iface3",
Type: interfacestore.ContainerInterface,
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(4),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p3",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p1",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
"iface4": {
InterfaceName: "iface4",
Type: interfacestore.ContainerInterface,
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(-1),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p4",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
}
staleInterface := &interfacestore.InterfaceConfig{
InterfaceName: "iface3",
Type: interfacestore.ContainerInterface,
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(4),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p3",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
}
unconnectedInterface := &interfacestore.InterfaceConfig{
InterfaceName: "iface4",
Type: interfacestore.ContainerInterface,
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(-1),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p4",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
}
kubeClient := fakeclientset.NewSimpleClientset(pods...)
cniServer.kubeClient = kubeClient
for _, containerIface := range containerIfaces {
for _, containerIface := range []*interfacestore.InterfaceConfig{normalInterface, staleInterface, unconnectedInterface} {
ifaceStore.AddInterface(containerIface)
}
mockOFClient.EXPECT().InstallPodFlows("iface1", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1)
iface := containerIfaces["iface3"]
mockOFClient.EXPECT().UninstallPodFlows("iface3").Return(nil).Times(1)
mockOVSBridgeClient.EXPECT().DeletePort(iface.PortUUID).Return(nil).Times(1)
podFlowsInstalled := make(chan struct{})
mockOFClient.EXPECT().InstallPodFlows(normalInterface.InterfaceName, normalInterface.IPs, normalInterface.MAC, uint32(normalInterface.OFPort), uint16(0), nil).
Do(func(_ string, _ []net.IP, _ net.HardwareAddr, _ uint32, _ uint16, _ *uint32) {
close(podFlowsInstalled)
}).Times(1)
mockOFClient.EXPECT().UninstallPodFlows(staleInterface.InterfaceName).Return(nil).Times(1)
mockOVSBridgeClient.EXPECT().DeletePort(staleInterface.PortUUID).Return(nil).Times(1)
mockRoute.EXPECT().DeleteLocalAntreaFlexibleIPAMPodRule(gomock.Any()).Return(nil).Times(1)
err := cniServer.reconcile()
assert.NoError(t, err)
_, exists := ifaceStore.GetInterfaceByName("iface3")
_, exists := ifaceStore.GetInterfaceByName(staleInterface.InterfaceName)
assert.False(t, exists)
select {
case <-podFlowsInstalled:
case <-time.After(500 * time.Millisecond):
t.Errorf("InstallPodFlows for %s should be called but was not", normalInterface.InterfaceName)
}
}
113 changes: 64 additions & 49 deletions pkg/agent/cniserver/server_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
cnipb "antrea.io/antrea/pkg/apis/cni/v1beta1"
ovsconfigtest "antrea.io/antrea/pkg/ovs/ovsconfig/testing"
"antrea.io/antrea/pkg/util/channel"
utilip "antrea.io/antrea/pkg/util/ip"
)

var (
Expand Down Expand Up @@ -897,72 +898,86 @@ func TestReconcile(t *testing.T) {
}
kubeClient := fakeclientset.NewSimpleClientset(pods...)
cniServer.kubeClient = kubeClient
containerIfaces := map[string]*interfacestore.InterfaceConfig{
"iface1": {
InterfaceName: "iface1",
Type: interfacestore.ContainerInterface,
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(3),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p1",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
normalInterface := &interfacestore.InterfaceConfig{
InterfaceName: "iface1",
Type: interfacestore.ContainerInterface,
IPs: []net.IP{net.ParseIP("1.1.1.1")},
MAC: utilip.MustParseMAC("00:11:22:33:44:01"),
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(3),
},
"iface3": {
InterfaceName: "iface3",
Type: interfacestore.ContainerInterface,
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(4),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p3",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p1",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
"iface4": {
InterfaceName: "iface4",
Type: interfacestore.ContainerInterface,
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(-1),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p4",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
}
staleInterface := &interfacestore.InterfaceConfig{
InterfaceName: "iface3",
Type: interfacestore.ContainerInterface,
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(4),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p3",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
}
unconnectedInterface := &interfacestore.InterfaceConfig{
InterfaceName: "iface4",
Type: interfacestore.ContainerInterface,
IPs: []net.IP{net.ParseIP("1.1.1.2")},
MAC: utilip.MustParseMAC("00:11:22:33:44:02"),
OVSPortConfig: &interfacestore.OVSPortConfig{
PortUUID: generateUUID(t),
OFPort: int32(-1),
},
ContainerInterfaceConfig: &interfacestore.ContainerInterfaceConfig{
PodName: "p4",
PodNamespace: testPodNamespace,
ContainerID: generateUUID(t),
},
}
for _, containerIface := range containerIfaces {
for _, containerIface := range []*interfacestore.InterfaceConfig{normalInterface, staleInterface, unconnectedInterface} {
ifaceStore.AddInterface(containerIface)
}
pod4IfaceName := "iface4"
pod4Iface := containerIfaces["iface4"]
waiter := newAsyncWaiter(pod4Iface.PodName, pod4Iface.ContainerID)
waiter := newAsyncWaiter(unconnectedInterface.PodName, unconnectedInterface.ContainerID)
cniServer.podConfigurator, _ = newPodConfigurator(mockOVSBridgeClient, mockOFClient, mockRoute, ifaceStore, gwMAC, "system", false, false, waiter.notifier)
cniServer.nodeConfig = &config.NodeConfig{Name: nodeName}

// Re-install Pod1 flows
mockOFClient.EXPECT().InstallPodFlows("iface1", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1)
podFlowsInstalled := make(chan string, 2)
mockOFClient.EXPECT().InstallPodFlows(normalInterface.InterfaceName, normalInterface.IPs, normalInterface.MAC, uint32(normalInterface.OFPort), uint16(0), nil).
Do(func(interfaceName string, _ []net.IP, _ net.HardwareAddr, _ uint32, _ uint16, _ *uint32) {
podFlowsInstalled <- interfaceName
}).Times(1)
// Uninstall Pod3 flows which is deleted.
iface := containerIfaces["iface3"]
mockOFClient.EXPECT().UninstallPodFlows("iface3").Return(nil).Times(1)
mockOVSBridgeClient.EXPECT().DeletePort(iface.PortUUID).Return(nil).Times(1)
mockOFClient.EXPECT().UninstallPodFlows(staleInterface.InterfaceName).Return(nil).Times(1)
mockOVSBridgeClient.EXPECT().DeletePort(staleInterface.PortUUID).Return(nil).Times(1)
mockRoute.EXPECT().DeleteLocalAntreaFlexibleIPAMPodRule(gomock.Any()).Return(nil).Times(1)
// Re-connect to Pod4
hostIfaces.Store(fmt.Sprintf("vEthernet (%s)", pod4IfaceName), true)
mockOVSBridgeClient.EXPECT().SetInterfaceType(pod4IfaceName, "internal").Return(nil).Times(1)
mockOVSBridgeClient.EXPECT().GetOFPort(pod4IfaceName, true).Return(int32(5), nil).Times(1)
mockOFClient.EXPECT().InstallPodFlows(pod4IfaceName, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1)
hostIfaces.Store(fmt.Sprintf("vEthernet (%s)", unconnectedInterface.InterfaceName), true)
mockOVSBridgeClient.EXPECT().SetInterfaceType(unconnectedInterface.InterfaceName, "internal").Return(nil).Times(1)
mockOVSBridgeClient.EXPECT().GetOFPort(unconnectedInterface.InterfaceName, true).Return(int32(5), nil).Times(1)
mockOFClient.EXPECT().InstallPodFlows(unconnectedInterface.InterfaceName, unconnectedInterface.IPs, unconnectedInterface.MAC, uint32(5), uint16(0), nil).
Do(func(interfaceName string, _ []net.IP, _ net.HardwareAddr, _ uint32, _ uint16, _ *uint32) {
podFlowsInstalled <- interfaceName
}).Times(1)
err := cniServer.reconcile()
assert.NoError(t, err)
_, exists := ifaceStore.GetInterfaceByName("iface3")
assert.False(t, exists)
for i := 0; i < 2; i++ {
select {
case <-podFlowsInstalled:
case <-time.After(500 * time.Millisecond):
t.Errorf("InstallPodFlows should be called 2 times but was only called %d times", i)
break
}
}
waiter.wait()
waiter.close()
}
Expand Down
8 changes: 8 additions & 0 deletions pkg/util/ip/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ func MustParseCIDR(cidr string) *net.IPNet {
return ipNet
}

func MustParseMAC(mac string) net.HardwareAddr {
addr, err := net.ParseMAC(mac)
if err != nil {
panic(fmt.Errorf("cannot parse '%v': %v", mac, err))
}
return addr
}

// IPNetEqual returns if the provided IPNets are the same subnet.
func IPNetEqual(ipNet1, ipNet2 *net.IPNet) bool {
if ipNet1 == nil && ipNet2 == nil {
Expand Down

0 comments on commit 4c9a802

Please sign in to comment.