Skip to content

Commit

Permalink
Add unit tests for pkg/agent/agent.go (antrea-io#4703)
Browse files Browse the repository at this point in the history
Signed-off-by: Kumar Atish <atish.iaf@gmail.com>
  • Loading branch information
Atish-iaf committed Jul 17, 2023
1 parent 7ac3d06 commit c372130
Show file tree
Hide file tree
Showing 5 changed files with 408 additions and 9 deletions.
20 changes: 14 additions & 6 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"time"

"github.com/containernetworking/plugins/pkg/ip"
"github.com/spf13/afero"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
apitypes "k8s.io/apimachinery/pkg/types"
Expand All @@ -35,6 +36,7 @@ import (
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/util/retry"
"k8s.io/klog/v2"
clockutils "k8s.io/utils/clock"

"antrea.io/antrea/pkg/agent/cniserver"
"antrea.io/antrea/pkg/agent/config"
Expand Down Expand Up @@ -90,6 +92,12 @@ var (
// need to be deleted when changing to "psk".
var otherConfigKeysForIPsecCertificates = []string{"certificate", "private_key", "ca_cert", "remote_cert", "remote_name"}

var (
// Declared as variables for testing.
defaultFs = afero.NewOsFs()
clock clockutils.WithTicker = &clockutils.RealClock{}
)

// Initializer knows how to setup host networking, OpenVSwitch, and Openflow.
type Initializer struct {
client clientset.Interface
Expand Down Expand Up @@ -211,7 +219,7 @@ func (i *Initializer) setupOVSBridge() error {
}

func (i *Initializer) validateSupportedDPFeatures() error {
gotFeatures, err := ovsctl.NewClient(i.ovsBridge).GetDPFeatures()
gotFeatures, err := i.ovsCtlClient.GetDPFeatures()
if err != nil {
return err
}
Expand Down Expand Up @@ -1064,19 +1072,19 @@ func (i *Initializer) waitForIPsecMonitorDaemon() error {
// PID files before starting the OVS daemons, it is safe to assume that
// if this file exists, the IPsec monitor is indeed running.
const ovsMonitorIPSecPID = "/var/run/openvswitch/ovs-monitor-ipsec.pid"
timer := time.NewTimer(10 * time.Second)
timer := clock.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(1 * time.Second)
ticker := clock.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
if _, err := os.Stat(ovsMonitorIPSecPID); err == nil {
if _, err := defaultFs.Stat(ovsMonitorIPSecPID); err == nil {
klog.V(2).Infof("OVS IPsec monitor seems to be present")
break
}
select {
case <-ticker.C:
case <-ticker.C():
continue
case <-timer.C:
case <-timer.C():
return fmt.Errorf("IPsec was requested, but the OVS IPsec monitor does not seem to be running")
}
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/agent/agent_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ import (
utilip "antrea.io/antrea/pkg/util/ip"
)

var (
// getInterfaceByName is meant to be overridden for testing.
getInterfaceByName = net.InterfaceByName
)

// prepareHostNetwork returns immediately on Linux.
func (i *Initializer) prepareHostNetwork() error {
return nil
Expand Down Expand Up @@ -89,7 +94,7 @@ func (i *Initializer) prepareOVSBridgeForK8sNode() error {
} else {
uplinkNetConfig.OFPort = uint32(uplinkOFPort)
}
if adapter, err := net.InterfaceByName(bridgedUplinkName); err != nil {
if adapter, err := getInterfaceByName(bridgedUplinkName); err != nil {
return fmt.Errorf("cannot find uplink interface %s: err=%w", bridgedUplinkName, err)
} else {
uplinkNetConfig.Index = adapter.Index
Expand Down
111 changes: 111 additions & 0 deletions pkg/agent/agent_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,117 @@

package agent

import (
"fmt"
"net"
"strings"
"testing"

mock "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"antrea.io/antrea/pkg/agent/config"
"antrea.io/antrea/pkg/agent/interfacestore"
"antrea.io/antrea/pkg/ovs/ovsconfig"
ovsconfigtest "antrea.io/antrea/pkg/ovs/ovsconfig/testing"
)

func mockSetInterfaceMTU(returnErr error) func() {
return func() {}
}

func mockGetInterfaceByName(ipDevice *net.Interface) func() {
prevGetInterfaceByName := getInterfaceByName
getInterfaceByName = func(name string) (*net.Interface, error) {
return ipDevice, nil
}
return func() { getInterfaceByName = prevGetInterfaceByName }
}

func TestPrepareOVSBridgeForK8sNode(t *testing.T) {
macAddr, _ := net.ParseMAC("00:00:5e:00:53:01")
_, nodeIPNet, _ := net.ParseCIDR("192.168.10.10/24")
ipDevice := &net.Interface{
Index: 10,
MTU: 1500,
Name: "ens160",
HardwareAddr: macAddr,
}
datapathID := "0000" + strings.Replace(macAddr.String(), ":", "", -1)
nodeConfig := &config.NodeConfig{
UplinkNetConfig: new(config.AdapterNetConfig),
NodeIPv4Addr: nodeIPNet,
}

tests := []struct {
name string
connectUplinkToBridge bool
expectedCalls func(m *ovsconfigtest.MockOVSBridgeClient)
expectedHostInterfaceOFPort uint32
expectedUplinkOFPort uint32
expectedErr string
}{
{
name: "connectUplinkToBridge is false, do nothing",
},
{
name: "failed to set datapath_id",
connectUplinkToBridge: true,
expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) {
m.EXPECT().SetDatapathID(datapathID).Return(ovsconfig.InvalidArgumentsError("unable to set datapath_id"))
},
expectedErr: fmt.Sprintf("failed to set datapath_id %s: err=unable to set datapath_id", datapathID),
},
{
name: "local port does not exist, allocate it",
connectUplinkToBridge: true,
expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) {
m.EXPECT().SetDatapathID(datapathID).Return(nil)
m.EXPECT().GetOFPort(ipDevice.Name, false).Return(int32(0), ovsconfig.InvalidArgumentsError("interface not found"))
m.EXPECT().AllocateOFPort(config.UplinkOFPort).Return(int32(2), nil)
m.EXPECT().AllocateOFPort(config.UplinkOFPort).Return(int32(3), nil)
},
expectedUplinkOFPort: 2,
expectedHostInterfaceOFPort: 3,
},
{
name: "uplink interface found",
connectUplinkToBridge: true,
expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) {
m.EXPECT().SetDatapathID(datapathID).Return(nil)
m.EXPECT().GetOFPort(ipDevice.Name, false).Return(int32(2), nil)
m.EXPECT().GetOFPort(ipDevice.Name+"~", false).Return(int32(3), nil)
},
expectedHostInterfaceOFPort: 2,
expectedUplinkOFPort: 3,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
controller := mock.NewController(t)
mockOVSBridgeClient := ovsconfigtest.NewMockOVSBridgeClient(controller)
store := interfacestore.NewInterfaceStore()
initializer := newAgentInitializer(mockOVSBridgeClient, store)
initializer.nodeType = config.K8sNode
initializer.connectUplinkToBridge = tt.connectUplinkToBridge
initializer.nodeConfig = nodeConfig
defer mockGetIPNetDeviceFromIP(nodeIPNet, ipDevice)()
defer mockGetInterfaceByName(ipDevice)()
if tt.expectedCalls != nil {
tt.expectedCalls(mockOVSBridgeClient)
}
err := initializer.prepareOVSBridgeForK8sNode()
if tt.expectedErr != "" {
assert.ErrorContains(t, err, tt.expectedErr)
} else {
require.NoError(t, err)
if tt.connectUplinkToBridge {
assert.Equal(t, tt.expectedUplinkOFPort, initializer.nodeConfig.UplinkNetConfig.OFPort)
assert.Equal(t, tt.expectedHostInterfaceOFPort, initializer.nodeConfig.HostInterfaceOFPort)
}
}
})
}
}
Loading

0 comments on commit c372130

Please sign in to comment.