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 }