open-nomad/nomad/heartbeat_test.go

286 lines
6.6 KiB
Go
Raw Normal View History

2015-08-23 00:37:50 +00:00
package nomad
import (
"fmt"
"testing"
"time"
2017-02-08 05:22:48 +00:00
memdb "github.com/hashicorp/go-memdb"
2019-01-15 19:46:12 +00:00
msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc"
2015-08-23 00:37:50 +00:00
"github.com/hashicorp/nomad/nomad/mock"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/hashicorp/nomad/testutil"
2018-02-20 18:22:15 +00:00
"github.com/stretchr/testify/require"
2015-08-23 00:37:50 +00:00
)
2018-02-20 18:22:15 +00:00
func TestHeartbeat_InitializeHeartbeatTimers(t *testing.T) {
2017-07-23 22:04:38 +00:00
t.Parallel()
s1, cleanupS1 := TestServer(t, nil)
defer cleanupS1()
2015-08-23 00:37:50 +00:00
testutil.WaitForLeader(t, s1.RPC)
node := mock.Node()
state := s1.fsm.State()
2015-09-07 03:47:42 +00:00
err := state.UpsertNode(1, node)
2015-08-23 00:37:50 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Reset the heartbeat timers
err = s1.initializeHeartbeatTimers()
if err != nil {
t.Fatalf("err: %v", err)
}
// Check that we have a timer
_, ok := s1.heartbeatTimers[node.ID]
if !ok {
t.Fatalf("missing heartbeat timer")
}
}
2018-02-20 18:22:15 +00:00
func TestHeartbeat_ResetHeartbeatTimer(t *testing.T) {
2017-07-23 22:04:38 +00:00
t.Parallel()
s1, cleanupS1 := TestServer(t, nil)
defer cleanupS1()
2015-08-23 00:37:50 +00:00
testutil.WaitForLeader(t, s1.RPC)
// Create a new timer
ttl, err := s1.resetHeartbeatTimer("test")
if err != nil {
t.Fatalf("err: %v", err)
}
2015-08-31 01:10:12 +00:00
if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL {
2015-08-23 00:37:50 +00:00
t.Fatalf("bad: %#v", ttl)
}
// Check that we have a timer
_, ok := s1.heartbeatTimers["test"]
if !ok {
t.Fatalf("missing heartbeat timer")
}
}
2018-02-20 18:22:15 +00:00
func TestHeartbeat_ResetHeartbeatTimer_Nonleader(t *testing.T) {
t.Parallel()
require := require.New(t)
s1, cleanupS1 := TestServer(t, func(c *Config) {
2018-02-20 18:22:15 +00:00
c.BootstrapExpect = 3 // Won't become leader
c.DevDisableBootstrap = true
})
defer cleanupS1()
2018-02-20 18:22:15 +00:00
require.False(s1.IsLeader())
// Create a new timer
_, err := s1.resetHeartbeatTimer("test")
require.NotNil(err)
require.EqualError(err, heartbeatNotLeader)
}
func TestHeartbeat_ResetHeartbeatTimerLocked(t *testing.T) {
2017-07-23 22:04:38 +00:00
t.Parallel()
s1, cleanupS1 := TestServer(t, nil)
defer cleanupS1()
2015-08-23 00:37:50 +00:00
testutil.WaitForLeader(t, s1.RPC)
s1.heartbeatTimersLock.Lock()
s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
s1.heartbeatTimersLock.Unlock()
if _, ok := s1.heartbeatTimers["foo"]; !ok {
t.Fatalf("missing timer")
}
2017-01-26 23:06:14 +00:00
time.Sleep(time.Duration(testutil.TestMultiplier()*10) * time.Millisecond)
2015-08-23 00:37:50 +00:00
if _, ok := s1.heartbeatTimers["foo"]; ok {
t.Fatalf("timer should be gone")
}
}
2018-02-20 18:22:15 +00:00
func TestHeartbeat_ResetHeartbeatTimerLocked_Renew(t *testing.T) {
2017-07-23 22:04:38 +00:00
t.Parallel()
s1, cleanupS1 := TestServer(t, nil)
defer cleanupS1()
2015-08-23 00:37:50 +00:00
testutil.WaitForLeader(t, s1.RPC)
s1.heartbeatTimersLock.Lock()
2017-10-20 00:13:27 +00:00
s1.resetHeartbeatTimerLocked("foo", 30*time.Millisecond)
2015-08-23 00:37:50 +00:00
s1.heartbeatTimersLock.Unlock()
if _, ok := s1.heartbeatTimers["foo"]; !ok {
t.Fatalf("missing timer")
}
time.Sleep(2 * time.Millisecond)
// Renew the heartbeat
s1.heartbeatTimersLock.Lock()
2017-10-20 00:13:27 +00:00
s1.resetHeartbeatTimerLocked("foo", 30*time.Millisecond)
2015-08-23 00:37:50 +00:00
s1.heartbeatTimersLock.Unlock()
renew := time.Now()
// Watch for invalidation
2017-10-20 00:13:27 +00:00
for time.Now().Sub(renew) < time.Duration(testutil.TestMultiplier()*100)*time.Millisecond {
2015-08-23 00:37:50 +00:00
s1.heartbeatTimersLock.Lock()
_, ok := s1.heartbeatTimers["foo"]
s1.heartbeatTimersLock.Unlock()
if !ok {
end := time.Now()
2017-10-20 00:13:27 +00:00
if diff := end.Sub(renew); diff < 30*time.Millisecond {
2015-08-23 00:37:50 +00:00
t.Fatalf("early invalidate %v", diff)
}
return
}
2017-10-20 00:13:27 +00:00
time.Sleep(2 * time.Millisecond)
2015-08-23 00:37:50 +00:00
}
t.Fatalf("should have expired")
}
2018-02-20 18:22:15 +00:00
func TestHeartbeat_InvalidateHeartbeat(t *testing.T) {
2017-07-23 22:04:38 +00:00
t.Parallel()
2018-05-11 21:53:41 +00:00
require := require.New(t)
s1, cleanupS1 := TestServer(t, nil)
defer cleanupS1()
2015-08-23 00:37:50 +00:00
testutil.WaitForLeader(t, s1.RPC)
// Create a node
node := mock.Node()
state := s1.fsm.State()
2018-05-11 21:53:41 +00:00
require.NoError(state.UpsertNode(1, node))
2015-08-23 00:37:50 +00:00
// This should cause a status update
s1.invalidateHeartbeat(node.ID)
// Check it is updated
2017-02-08 05:22:48 +00:00
ws := memdb.NewWatchSet()
out, err := state.NodeByID(ws, node.ID)
2018-05-11 21:53:41 +00:00
require.NoError(err)
require.True(out.TerminalStatus())
require.Len(out.Events, 2)
require.Equal(NodeHeartbeatEventMissed, out.Events[1].Message)
2015-08-23 00:37:50 +00:00
}
2018-02-20 18:22:15 +00:00
func TestHeartbeat_ClearHeartbeatTimer(t *testing.T) {
2017-07-23 22:04:38 +00:00
t.Parallel()
s1, cleanupS1 := TestServer(t, nil)
defer cleanupS1()
2015-08-23 00:37:50 +00:00
testutil.WaitForLeader(t, s1.RPC)
s1.heartbeatTimersLock.Lock()
s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
s1.heartbeatTimersLock.Unlock()
err := s1.clearHeartbeatTimer("foo")
if err != nil {
t.Fatalf("err: %v", err)
}
if _, ok := s1.heartbeatTimers["foo"]; ok {
t.Fatalf("timer should be gone")
}
}
2018-02-20 18:22:15 +00:00
func TestHeartbeat_ClearAllHeartbeatTimers(t *testing.T) {
2017-07-23 22:04:38 +00:00
t.Parallel()
s1, cleanupS1 := TestServer(t, nil)
defer cleanupS1()
2015-08-23 00:37:50 +00:00
testutil.WaitForLeader(t, s1.RPC)
s1.heartbeatTimersLock.Lock()
s1.resetHeartbeatTimerLocked("foo", 10*time.Millisecond)
s1.resetHeartbeatTimerLocked("bar", 10*time.Millisecond)
s1.resetHeartbeatTimerLocked("baz", 10*time.Millisecond)
s1.heartbeatTimersLock.Unlock()
err := s1.clearAllHeartbeatTimers()
if err != nil {
t.Fatalf("err: %v", err)
}
if len(s1.heartbeatTimers) != 0 {
t.Fatalf("timers should be gone")
}
}
2018-02-20 18:22:15 +00:00
func TestHeartbeat_Server_HeartbeatTTL_Failover(t *testing.T) {
2017-07-23 22:04:38 +00:00
t.Parallel()
2015-08-23 00:37:50 +00:00
s1, cleanupS1 := TestServer(t, nil)
defer cleanupS1()
s2, cleanupS2 := TestServer(t, func(c *Config) {
2015-08-23 00:37:50 +00:00
c.DevDisableBootstrap = true
})
defer cleanupS2()
2015-08-23 00:37:50 +00:00
s3, cleanupS3 := TestServer(t, func(c *Config) {
2015-08-23 00:37:50 +00:00
c.DevDisableBootstrap = true
})
defer cleanupS3()
2015-08-23 00:37:50 +00:00
servers := []*Server{s1, s2, s3}
2018-01-12 01:00:30 +00:00
TestJoin(t, s1, s2, s3)
2015-08-23 00:37:50 +00:00
leader := waitForStableLeadership(t, servers)
2015-08-23 00:37:50 +00:00
codec := rpcClient(t, leader)
// Create the register request
node := mock.Node()
req := &structs.NodeRegisterRequest{
Node: node,
WriteRequest: structs.WriteRequest{Region: "global"},
2015-08-23 00:37:50 +00:00
}
// Fetch the response
var resp structs.GenericResponse
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil {
2015-08-23 00:37:50 +00:00
t.Fatalf("err: %v", err)
}
// Check that heartbeatTimers has the heartbeat ID
if _, ok := leader.heartbeatTimers[node.ID]; !ok {
t.Fatalf("missing heartbeat timer")
}
// Shutdown the leader!
leader.Shutdown()
// heartbeatTimers should be cleared on leader shutdown
2018-02-21 00:05:43 +00:00
testutil.WaitForResult(func() (bool, error) {
return len(leader.heartbeatTimers) == 0, nil
}, func(err error) {
2015-08-23 00:37:50 +00:00
t.Fatalf("heartbeat timers should be empty on the shutdown leader")
2018-02-21 00:05:43 +00:00
})
2015-08-23 00:37:50 +00:00
// Find the new leader
testutil.WaitForResult(func() (bool, error) {
leader = nil
for _, s := range servers {
if s.IsLeader() {
leader = s
}
}
if leader == nil {
return false, fmt.Errorf("Should have a new leader")
}
// Ensure heartbeat timer is restored
if _, ok := leader.heartbeatTimers[node.ID]; !ok {
return false, fmt.Errorf("missing heartbeat timer")
}
return true, nil
}, func(err error) {
t.Fatalf("err: %s", err)
})
}