You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.0 KiB
Go
207 lines
5.0 KiB
Go
package manager
|
|
|
|
import (
|
|
"math/rand"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// creating, starting and stopping tests
|
|
|
|
// newManager is a helper for creating new managers for tests
|
|
func newManager(conn int, want error, t *testing.T) *Manager {
|
|
var manager *Manager
|
|
var err error
|
|
assert := assert.New(t)
|
|
|
|
manager, err = New(conn)
|
|
|
|
if err != want {
|
|
t.Fatalf(
|
|
`New(%d) = %v, %v, %d max connections failed`,
|
|
conn,
|
|
manager,
|
|
err,
|
|
conn,
|
|
)
|
|
}
|
|
|
|
assert.Equal(manager.IsActive(), 0, "manager should start inactive")
|
|
|
|
return manager
|
|
}
|
|
|
|
// TestEmptyManager creates a new manager with 0 max connections
|
|
func TestEmptyManager(t *testing.T) {
|
|
conn := 0
|
|
newManager(conn, nil, t)
|
|
}
|
|
|
|
// TestPostiveManager creates a new manager with valid max connections
|
|
func TestPositiveManager(t *testing.T) {
|
|
conn := rand.Intn(MaxConnAttempts)
|
|
newManager(conn, nil, t)
|
|
}
|
|
|
|
// TestNegativeManager creates a new manager with negative max connections
|
|
func TestNegativeManager(t *testing.T) {
|
|
conn := -1 * rand.Intn(MaxConnAttempts)
|
|
newManager(conn, ErrInvalidMaxConn, t)
|
|
}
|
|
|
|
// TestInvalidManager creates a new manager with large max connections
|
|
func TestInvalidManager(t *testing.T) {
|
|
conn := MaxConnAttempts + 0xf
|
|
newManager(conn, ErrInvalidMaxConn, t)
|
|
}
|
|
|
|
// TestManagerLifeCycle tests that a manager can start and exit several times
|
|
func TestManagerLifeCycle(t *testing.T) {
|
|
|
|
var manager *Manager
|
|
assert := assert.New(t)
|
|
|
|
conn := rand.Intn(MaxConnAttempts)
|
|
manager = newManager(conn, nil, t)
|
|
|
|
cycles := 10
|
|
|
|
// starting and stopping sequentially
|
|
for i := 0; i < cycles; i++ {
|
|
|
|
assert.NoError(manager.Start(), "starting manager failed")
|
|
assert.Equal(manager.IsActive(), 1, "manager is inactive after start")
|
|
|
|
assert.NoError(manager.Stop(), "stopping manager failed")
|
|
assert.Equal(manager.IsActive(), 0, "manager is active after stop")
|
|
}
|
|
}
|
|
|
|
// TestManagerStopFail tests that stopping an inactive manager will error
|
|
func TestManagerStopFail(t *testing.T) {
|
|
|
|
var manager *Manager
|
|
assert := assert.New(t)
|
|
|
|
conn := rand.Intn(MaxConnAttempts)
|
|
manager = newManager(conn, nil, t)
|
|
|
|
assert.NoError(manager.Start(), "starting manager failed")
|
|
|
|
// stopping sequentially
|
|
assert.NoError(manager.Stop(), "stopping manager failed")
|
|
assert.Error(manager.Stop(), "stopping inactive manager should fail")
|
|
}
|
|
|
|
// TestManagerStartFail tests that starting an active manager will error
|
|
func TestManagerStartFail(t *testing.T) {
|
|
|
|
var manager *Manager
|
|
assert := assert.New(t)
|
|
|
|
conn := rand.Intn(MaxConnAttempts)
|
|
manager = newManager(conn, nil, t)
|
|
|
|
// starting sequentially
|
|
assert.NoError(manager.Start(), "starting manager failed")
|
|
assert.Error(manager.Start(), "starting active manager should fail")
|
|
}
|
|
|
|
// auxiliary tests
|
|
|
|
// TestManagerTimeout checks that timeouts exponentially backoff
|
|
func TestManagerTimeout(t *testing.T) {
|
|
var manager *Manager
|
|
assert := assert.New(t)
|
|
|
|
conn := 10
|
|
manager = newManager(conn, nil, t)
|
|
|
|
assert.NoError(manager.Start(), "starting manager failed")
|
|
assert.Equal(manager.IsActive(), 1, "manager is inactive")
|
|
|
|
prevTimeout, err := manager.Timeout()
|
|
|
|
for i := 1; i <= conn; i++ {
|
|
assert.NoError(err, "generating timeout failed")
|
|
assert.True(prevTimeout > 0, "invalid timeout")
|
|
|
|
timeout, err := manager.Timeout()
|
|
|
|
if i == conn {
|
|
assert.Error(err, "allowed exceeding max attempts")
|
|
} else {
|
|
assert.NoError(err, "generating timeout failed")
|
|
assert.True(
|
|
timeout == 2*prevTimeout,
|
|
"incorrect timeout %d, expected %d",
|
|
timeout, 2*prevTimeout,
|
|
)
|
|
}
|
|
|
|
prevTimeout = timeout
|
|
}
|
|
}
|
|
|
|
// TestManagerHB tests the heartbeat channel opens and closes
|
|
func TestManagerHB(t *testing.T) {
|
|
|
|
var manager *Manager
|
|
assert := assert.New(t)
|
|
|
|
conn := rand.Intn(MaxConnAttempts)
|
|
manager = newManager(conn, nil, t)
|
|
|
|
assert.NoError(manager.Start(), "starting manager failed")
|
|
assert.Equal(manager.IsActive(), 1, "manager is inactive")
|
|
|
|
ch := make(chan struct{})
|
|
|
|
go manager.HeartBeat(ch, 10, 0, time.Millisecond)
|
|
|
|
for range ch {
|
|
// close on first ping
|
|
assert.NoError(manager.Stop(), "stopping manager failed")
|
|
}
|
|
|
|
assert.Equal(manager.IsActive(), 0, "manager is active")
|
|
}
|
|
|
|
// TestManagerHBTiming tests the heartbeat channel timing is correct
|
|
func TestManagerHBTiming(t *testing.T) {
|
|
|
|
var manager *Manager
|
|
assert := assert.New(t)
|
|
|
|
conn := rand.Intn(MaxConnAttempts)
|
|
manager = newManager(conn, nil, t)
|
|
|
|
assert.NoError(manager.Start(), "starting manager failed")
|
|
assert.Equal(manager.IsActive(), 1, "manager is inactive")
|
|
|
|
ch := make(chan struct{})
|
|
hb := 100
|
|
pings := 10
|
|
|
|
// expected time with tolerance for other logic and worst case rand timeout
|
|
expected := time.Duration(pings*hb+15) * time.Millisecond
|
|
|
|
go manager.HeartBeat(ch, hb, 1, time.Millisecond)
|
|
|
|
iter := 0
|
|
start := time.Now()
|
|
for range ch {
|
|
// close after 10 pings
|
|
iter += 1
|
|
if iter >= pings {
|
|
assert.NoError(manager.Stop(), "stopping manager failed")
|
|
}
|
|
}
|
|
end := time.Now()
|
|
|
|
assert.Equal(manager.IsActive(), 0, "manager is active")
|
|
assert.WithinDuration(start, end, expected, "inaccurate heartbeat")
|
|
}
|