github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/nomad/heartbeat_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	memdb "github.com/hashicorp/go-memdb"
     9  	"github.com/hashicorp/net-rpc-msgpackrpc"
    10  	"github.com/hashicorp/nomad/nomad/mock"
    11  	"github.com/hashicorp/nomad/nomad/structs"
    12  	"github.com/hashicorp/nomad/testutil"
    13  )
    14  
    15  func TestInitializeHeartbeatTimers(t *testing.T) {
    16  	s1 := testServer(t, nil)
    17  	defer s1.Shutdown()
    18  	testutil.WaitForLeader(t, s1.RPC)
    19  
    20  	node := mock.Node()
    21  	state := s1.fsm.State()
    22  	err := state.UpsertNode(1, node)
    23  	if err != nil {
    24  		t.Fatalf("err: %v", err)
    25  	}
    26  
    27  	// Reset the heartbeat timers
    28  	err = s1.initializeHeartbeatTimers()
    29  	if err != nil {
    30  		t.Fatalf("err: %v", err)
    31  	}
    32  
    33  	// Check that we have a timer
    34  	_, ok := s1.heartbeatTimers[node.ID]
    35  	if !ok {
    36  		t.Fatalf("missing heartbeat timer")
    37  	}
    38  }
    39  
    40  func TestResetHeartbeatTimer(t *testing.T) {
    41  	s1 := testServer(t, nil)
    42  	defer s1.Shutdown()
    43  	testutil.WaitForLeader(t, s1.RPC)
    44  
    45  	// Create a new timer
    46  	ttl, err := s1.resetHeartbeatTimer("test")
    47  	if err != nil {
    48  		t.Fatalf("err: %v", err)
    49  	}
    50  	if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL {
    51  		t.Fatalf("bad: %#v", ttl)
    52  	}
    53  
    54  	// Check that we have a timer
    55  	_, ok := s1.heartbeatTimers["test"]
    56  	if !ok {
    57  		t.Fatalf("missing heartbeat timer")
    58  	}
    59  }
    60  
    61  func TestResetHeartbeatTimerLocked(t *testing.T) {
    62  	s1 := testServer(t, nil)
    63  	defer s1.Shutdown()
    64  	testutil.WaitForLeader(t, s1.RPC)
    65  
    66  	s1.heartbeatTimersLock.Lock()
    67  	s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
    68  	s1.heartbeatTimersLock.Unlock()
    69  
    70  	if _, ok := s1.heartbeatTimers["foo"]; !ok {
    71  		t.Fatalf("missing timer")
    72  	}
    73  
    74  	time.Sleep(time.Duration(testutil.TestMultiplier()*10) * time.Millisecond)
    75  
    76  	if _, ok := s1.heartbeatTimers["foo"]; ok {
    77  		t.Fatalf("timer should be gone")
    78  	}
    79  }
    80  
    81  func TestResetHeartbeatTimerLocked_Renew(t *testing.T) {
    82  	s1 := testServer(t, nil)
    83  	defer s1.Shutdown()
    84  	testutil.WaitForLeader(t, s1.RPC)
    85  
    86  	s1.heartbeatTimersLock.Lock()
    87  	s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
    88  	s1.heartbeatTimersLock.Unlock()
    89  
    90  	if _, ok := s1.heartbeatTimers["foo"]; !ok {
    91  		t.Fatalf("missing timer")
    92  	}
    93  
    94  	time.Sleep(2 * time.Millisecond)
    95  
    96  	// Renew the heartbeat
    97  	s1.heartbeatTimersLock.Lock()
    98  	s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
    99  	s1.heartbeatTimersLock.Unlock()
   100  	renew := time.Now()
   101  
   102  	// Watch for invalidation
   103  	for time.Now().Sub(renew) < time.Duration(testutil.TestMultiplier()*20)*time.Millisecond {
   104  		s1.heartbeatTimersLock.Lock()
   105  		_, ok := s1.heartbeatTimers["foo"]
   106  		s1.heartbeatTimersLock.Unlock()
   107  		if !ok {
   108  			end := time.Now()
   109  			if diff := end.Sub(renew); diff < 5*time.Millisecond {
   110  				t.Fatalf("early invalidate %v", diff)
   111  			}
   112  			return
   113  		}
   114  		time.Sleep(time.Millisecond)
   115  	}
   116  	t.Fatalf("should have expired")
   117  }
   118  
   119  func TestInvalidateHeartbeat(t *testing.T) {
   120  	s1 := testServer(t, nil)
   121  	defer s1.Shutdown()
   122  	testutil.WaitForLeader(t, s1.RPC)
   123  
   124  	// Create a node
   125  	node := mock.Node()
   126  	state := s1.fsm.State()
   127  	err := state.UpsertNode(1, node)
   128  	if err != nil {
   129  		t.Fatalf("err: %v", err)
   130  	}
   131  
   132  	// This should cause a status update
   133  	s1.invalidateHeartbeat(node.ID)
   134  
   135  	// Check it is updated
   136  	ws := memdb.NewWatchSet()
   137  	out, err := state.NodeByID(ws, node.ID)
   138  	if err != nil {
   139  		t.Fatalf("err: %v", err)
   140  	}
   141  	if !out.TerminalStatus() {
   142  		t.Fatalf("should update node: %#v", out)
   143  	}
   144  }
   145  
   146  func TestClearHeartbeatTimer(t *testing.T) {
   147  	s1 := testServer(t, nil)
   148  	defer s1.Shutdown()
   149  	testutil.WaitForLeader(t, s1.RPC)
   150  
   151  	s1.heartbeatTimersLock.Lock()
   152  	s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
   153  	s1.heartbeatTimersLock.Unlock()
   154  
   155  	err := s1.clearHeartbeatTimer("foo")
   156  	if err != nil {
   157  		t.Fatalf("err: %v", err)
   158  	}
   159  
   160  	if _, ok := s1.heartbeatTimers["foo"]; ok {
   161  		t.Fatalf("timer should be gone")
   162  	}
   163  }
   164  
   165  func TestClearAllHeartbeatTimers(t *testing.T) {
   166  	s1 := testServer(t, nil)
   167  	defer s1.Shutdown()
   168  	testutil.WaitForLeader(t, s1.RPC)
   169  
   170  	s1.heartbeatTimersLock.Lock()
   171  	s1.resetHeartbeatTimerLocked("foo", 10*time.Millisecond)
   172  	s1.resetHeartbeatTimerLocked("bar", 10*time.Millisecond)
   173  	s1.resetHeartbeatTimerLocked("baz", 10*time.Millisecond)
   174  	s1.heartbeatTimersLock.Unlock()
   175  
   176  	err := s1.clearAllHeartbeatTimers()
   177  	if err != nil {
   178  		t.Fatalf("err: %v", err)
   179  	}
   180  
   181  	if len(s1.heartbeatTimers) != 0 {
   182  		t.Fatalf("timers should be gone")
   183  	}
   184  }
   185  
   186  func TestServer_HeartbeatTTL_Failover(t *testing.T) {
   187  	s1 := testServer(t, nil)
   188  	defer s1.Shutdown()
   189  
   190  	s2 := testServer(t, func(c *Config) {
   191  		c.DevDisableBootstrap = true
   192  	})
   193  	defer s2.Shutdown()
   194  
   195  	s3 := testServer(t, func(c *Config) {
   196  		c.DevDisableBootstrap = true
   197  	})
   198  	defer s3.Shutdown()
   199  	servers := []*Server{s1, s2, s3}
   200  	testJoin(t, s1, s2, s3)
   201  
   202  	testutil.WaitForResult(func() (bool, error) {
   203  		peers, _ := s1.numPeers()
   204  		return peers == 3, nil
   205  	}, func(err error) {
   206  		t.Fatalf("should have 3 peers")
   207  	})
   208  
   209  	// Find the leader
   210  	var leader *Server
   211  	for _, s := range servers {
   212  		// Check that s.heartbeatTimers is empty
   213  		if len(s.heartbeatTimers) != 0 {
   214  			t.Fatalf("should have no heartbeatTimers")
   215  		}
   216  		// Find the leader too
   217  		if s.IsLeader() {
   218  			leader = s
   219  		}
   220  	}
   221  	if leader == nil {
   222  		t.Fatalf("Should have a leader")
   223  	}
   224  	codec := rpcClient(t, leader)
   225  
   226  	// Create the register request
   227  	node := mock.Node()
   228  	req := &structs.NodeRegisterRequest{
   229  		Node:         node,
   230  		WriteRequest: structs.WriteRequest{Region: "global"},
   231  	}
   232  
   233  	// Fetch the response
   234  	var resp structs.GenericResponse
   235  	if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil {
   236  		t.Fatalf("err: %v", err)
   237  	}
   238  
   239  	// Check that heartbeatTimers has the heartbeat ID
   240  	if _, ok := leader.heartbeatTimers[node.ID]; !ok {
   241  		t.Fatalf("missing heartbeat timer")
   242  	}
   243  
   244  	// Shutdown the leader!
   245  	leader.Shutdown()
   246  
   247  	// heartbeatTimers should be cleared on leader shutdown
   248  	if len(leader.heartbeatTimers) != 0 {
   249  		t.Fatalf("heartbeat timers should be empty on the shutdown leader")
   250  	}
   251  
   252  	// Find the new leader
   253  	testutil.WaitForResult(func() (bool, error) {
   254  		leader = nil
   255  		for _, s := range servers {
   256  			if s.IsLeader() {
   257  				leader = s
   258  			}
   259  		}
   260  		if leader == nil {
   261  			return false, fmt.Errorf("Should have a new leader")
   262  		}
   263  
   264  		// Ensure heartbeat timer is restored
   265  		if _, ok := leader.heartbeatTimers[node.ID]; !ok {
   266  			return false, fmt.Errorf("missing heartbeat timer")
   267  		}
   268  
   269  		return true, nil
   270  	}, func(err error) {
   271  		t.Fatalf("err: %s", err)
   272  	})
   273  }