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