diff --git a/go.mod b/go.mod index cf462dc33b..ad15ca4f35 100644 --- a/go.mod +++ b/go.mod @@ -276,6 +276,7 @@ require ( ) require ( + bou.ke/monkey v1.0.2 github.com/Azure/azure-container-networking/zapai v0.0.3 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 diff --git a/go.sum b/go.sum index 1cef0554b5..b6a91681c3 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI= +bou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA= cel.dev/expr v0.15.0 h1:O1jzfJCQBfL5BFoYktaxwIhuttaQPsVWerH9/EEKx0w= cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= diff --git a/pkg/watchers/endpoint/types.go b/pkg/watchers/endpoint/types.go index 652f1eb192..de06db38b2 100644 --- a/pkg/watchers/endpoint/types.go +++ b/pkg/watchers/endpoint/types.go @@ -29,16 +29,6 @@ func NewWatcher() *Watcher { return w } -type key struct { - name string - hardwareAddr string - // Network namespace for linux. - // Compartment ID for windows. - netNsID int -} - -type cache map[key]interface{} - type EndpointEvent struct { // Type is the type of the event. Type EventType @@ -70,11 +60,3 @@ func (e EventType) String() string { return "unknown" } } - -func (c cache) deepcopy() cache { - copy := make(cache) - for k, v := range c { - copy[k] = v - } - return copy -} diff --git a/pkg/watchers/endpoint/watcher_test.go b/pkg/watchers/endpoint/watcher_test.go new file mode 100644 index 0000000000..afb052c01a --- /dev/null +++ b/pkg/watchers/endpoint/watcher_test.go @@ -0,0 +1,86 @@ +package endpoint + +import ( + "context" + "testing" + "time" + + "bou.ke/monkey" + "github.com/microsoft/retina/pkg/log" + "github.com/stretchr/testify/require" + "github.com/vishvananda/netlink" + "golang.org/x/sys/unix" +) + +func TestName(t *testing.T) { + _, err := log.SetupZapLogger(log.GetDefaultLogOpts()) + require.NoError(t, err) + w := NewWatcher() + require.Equal(t, watcherName, w.Name()) +} + +func TestStart(t *testing.T) { + // Monkey patch netlink.LinkSubscribeWithOptions with our fakeLinkSubscribe function to simulate netlink events. + // TIL: https://bou.ke/blog/monkey-patching-in-go/ + // Should be fine for testing purposes (?) + patch := monkey.Patch(netlink.LinkSubscribeWithOptions, fakeLinkSubscribe) + defer patch.Unpatch() + + _, err := log.SetupZapLogger(log.GetDefaultLogOpts()) + require.NoError(t, err) + + w := NewWatcher() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + doneCh := make(chan error, 1) + go func() { + doneCh <- w.Start(ctx) + }() + + // Wait briefly to allow the fake event to be sent. + time.Sleep(50 * time.Millisecond) + + // Cancel the context to stop the watcher. + cancel() + + // Wait for Start to finish. + err = <-doneCh + require.NoError(t, err, "Start should exit without error") +} + +// fakeLinkSubscribe simulates netlink events by sending a fake event after a short delay. +func fakeLinkSubscribe(netlinkEvCh chan<- netlink.LinkUpdate, done <-chan struct{}, _ netlink.LinkSubscribeOptions) error { + go func() { + time.Sleep(10 * time.Millisecond) + fakeVethCreatedEvent := netlink.LinkUpdate{ + Header: unix.NlMsghdr{ + Type: unix.RTM_NEWLINK, + }, + Link: &netlink.Veth{ + LinkAttrs: netlink.LinkAttrs{ + Name: "veth0", + Index: 1, + OperState: netlink.OperUp, + }, + }, + } + netlinkEvCh <- fakeVethCreatedEvent + fakeVethDeletedEvent := netlink.LinkUpdate{ + Header: unix.NlMsghdr{ + Type: unix.RTM_DELLINK, + }, + Link: &netlink.Veth{ + LinkAttrs: netlink.LinkAttrs{ + Name: "veth0", + Index: 1, + OperState: netlink.OperDown, + }, + }, + } + netlinkEvCh <- fakeVethDeletedEvent + <-done + }() + return nil +}