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 }