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