From d9e474cd515e87a9c21897800d0258d3d4b69395 Mon Sep 17 00:00:00 2001 From: jwijenbergh Date: Tue, 27 Aug 2024 14:27:16 +0200 Subject: Failover: add tests --- internal/failover/monitor.go | 14 ++++- internal/failover/monitor_test.go | 106 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 internal/failover/monitor_test.go (limited to 'internal') diff --git a/internal/failover/monitor.go b/internal/failover/monitor.go index 5b44ee6..6f3e551 100644 --- a/internal/failover/monitor.go +++ b/internal/failover/monitor.go @@ -8,6 +8,11 @@ import ( "github.com/eduvpn/eduvpn-common/internal/log" ) +type sender interface { + Read(deadline time.Time) error + Send(seq int) error +} + // The DroppedConMon is a connection monitor that checks for an increase in rx bytes in certain intervals type DroppedConMon struct { // pInterval means how the interval in which to send pings @@ -17,6 +22,9 @@ type DroppedConMon struct { // The function that reads Rx bytes // If this function returns an error, the monitor exits readRxBytes func() (int64, error) + // newPinger creates a new pinger + // This gets used in the tests to mock the Ping sender interface + newPinger func(gateway string, mtu int) (sender, error) } // NewDroppedMonitor creates a new failover monitor @@ -24,7 +32,9 @@ type DroppedConMon struct { // `pDropped` is how many pings we need to send before we deem it is dropped // `readRxBytes` is a function that gets the rx bytes from the client func NewDroppedMonitor(pingInterval time.Duration, pDropped int, readRxBytes func() (int64, error)) *DroppedConMon { - return &DroppedConMon{pInterval: pingInterval, pDropped: pDropped, readRxBytes: readRxBytes} + return &DroppedConMon{pInterval: pingInterval, pDropped: pDropped, readRxBytes: readRxBytes, newPinger: func(gateway string, mtu int) (sender, error) { + return NewPinger(gateway, mtu) + }} } // Dropped checks whether or not the connection is 'dropped' @@ -47,7 +57,7 @@ func (m *DroppedConMon) Start(ctx context.Context, gateway string, mtuSize int) } // Create a ping struct with our mtu size - p, err := NewPinger(gateway, mtuSize) + p, err := m.newPinger(gateway, mtuSize) if err != nil { return false, err } diff --git a/internal/failover/monitor_test.go b/internal/failover/monitor_test.go new file mode 100644 index 0000000..87fb3cd --- /dev/null +++ b/internal/failover/monitor_test.go @@ -0,0 +1,106 @@ +package failover + +import ( + "context" + "errors" + "io" + "testing" + "time" + + "github.com/eduvpn/eduvpn-common/internal/test" +) + +// mockedPinger is a ping sender that always returns nil for sending +// but returns EOF for reading +type mockedPinger struct{} + +func (mp *mockedPinger) Read(_ time.Time) error { + return io.EOF +} + +func (mp *mockedPinger) Send(_ int) error { + return nil +} + +func TestMonitor(t *testing.T) { + cases := []struct { + interval time.Duration + pDropped int + readRxBytes func() (int64, error) + gateway string + mtuSize int + disableDefaults bool + mockedPinger func(gateway string, mtu int) (sender, error) + wantDropped bool + wantErr string + }{ + { + mtuSize: 1, + wantDropped: false, + wantErr: "invalid MTU size given, MTU has to be at least: 28 bytes", + }, + { + readRxBytes: func() (int64, error) { + return 0, errors.New("error test") + }, + wantDropped: false, + wantErr: "error test", + }, + // default case, not dropped + {}, + // readRxBytes always returns 0 + // still we do not want a drop because we get a pong from 127.0.0.1 + { + readRxBytes: func() (int64, error) { + return 0, nil + }, + wantDropped: false, + }, + // readRxBytes always returns 0 + // we want dropped as the mock pinger does nothing + { + readRxBytes: func() (int64, error) { + return 0, nil + }, + gateway: "127.0.0.1", + mockedPinger: func(_ string, _ int) (sender, error) { + return &mockedPinger{}, nil + }, + wantDropped: true, + }, + } + + for _, c := range cases { + var counter int64 + // some defaults + if c.interval == 0 { + c.interval = 2 * time.Second + } + if c.pDropped == 0 { + c.pDropped = 5 + } + if c.gateway == "" { + c.gateway = "127.0.0.1" + } + if c.mtuSize == 0 { + c.mtuSize = 28 + } + if c.readRxBytes == nil { + c.readRxBytes = func() (int64, error) { + defer func() { + counter++ + }() + return counter, nil + } + } + dcm := NewDroppedMonitor(c.interval, c.pDropped, c.readRxBytes) + if c.mockedPinger != nil { + dcm.newPinger = c.mockedPinger + } + dropped, err := dcm.Start(context.Background(), c.gateway, c.mtuSize) + if dropped != c.wantDropped { + t.Fatalf("dropped is not equal to want dropped, got: %v, want: %v", dropped, c.wantDropped) + } + test.AssertError(t, err, c.wantErr) + } +} -- cgit v1.2.3