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