summaryrefslogtreecommitdiff
path: root/internal/failover
diff options
context:
space:
mode:
Diffstat (limited to 'internal/failover')
-rw-r--r--internal/failover/monitor.go14
-rw-r--r--internal/failover/monitor_test.go106
2 files changed, 118 insertions, 2 deletions
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)
+ }
+}