github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/nomad/eval_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "reflect" 5 "testing" 6 "time" 7 8 "github.com/hashicorp/net-rpc-msgpackrpc" 9 "github.com/hashicorp/nomad/nomad/mock" 10 "github.com/hashicorp/nomad/nomad/structs" 11 "github.com/hashicorp/nomad/testutil" 12 ) 13 14 func TestEvalEndpoint_GetEval(t *testing.T) { 15 s1 := testServer(t, nil) 16 defer s1.Shutdown() 17 codec := rpcClient(t, s1) 18 testutil.WaitForLeader(t, s1.RPC) 19 20 // Create the register request 21 eval1 := mock.Eval() 22 s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}) 23 24 // Lookup the eval 25 get := &structs.EvalSpecificRequest{ 26 EvalID: eval1.ID, 27 QueryOptions: structs.QueryOptions{Region: "global"}, 28 } 29 var resp structs.SingleEvalResponse 30 if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil { 31 t.Fatalf("err: %v", err) 32 } 33 if resp.Index != 1000 { 34 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 35 } 36 37 if !reflect.DeepEqual(eval1, resp.Eval) { 38 t.Fatalf("bad: %#v %#v", eval1, resp.Eval) 39 } 40 41 // Lookup non-existing node 42 get.EvalID = structs.GenerateUUID() 43 if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil { 44 t.Fatalf("err: %v", err) 45 } 46 if resp.Index != 1000 { 47 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 48 } 49 if resp.Eval != nil { 50 t.Fatalf("unexpected eval") 51 } 52 } 53 54 func TestEvalEndpoint_Dequeue(t *testing.T) { 55 s1 := testServer(t, func(c *Config) { 56 c.NumSchedulers = 0 // Prevent automatic dequeue 57 }) 58 defer s1.Shutdown() 59 codec := rpcClient(t, s1) 60 testutil.WaitForLeader(t, s1.RPC) 61 62 // Create the register request 63 eval1 := mock.Eval() 64 testutil.WaitForResult(func() (bool, error) { 65 err := s1.evalBroker.Enqueue(eval1) 66 return err == nil, err 67 }, func(err error) { 68 t.Fatalf("err: %v", err) 69 }) 70 71 // Dequeue the eval 72 get := &structs.EvalDequeueRequest{ 73 Schedulers: defaultSched, 74 WriteRequest: structs.WriteRequest{Region: "global"}, 75 } 76 var resp structs.EvalDequeueResponse 77 if err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp); err != nil { 78 t.Fatalf("err: %v", err) 79 } 80 81 if !reflect.DeepEqual(eval1, resp.Eval) { 82 t.Fatalf("bad: %v %v", eval1, resp.Eval) 83 } 84 85 // Ensure outstanding 86 token, ok := s1.evalBroker.Outstanding(eval1.ID) 87 if !ok { 88 t.Fatalf("should be outstanding") 89 } 90 if token != resp.Token { 91 t.Fatalf("bad token: %#v %#v", token, resp.Token) 92 } 93 } 94 95 func TestEvalEndpoint_Ack(t *testing.T) { 96 s1 := testServer(t, nil) 97 defer s1.Shutdown() 98 codec := rpcClient(t, s1) 99 100 testutil.WaitForResult(func() (bool, error) { 101 return s1.evalBroker.Enabled(), nil 102 }, func(err error) { 103 t.Fatalf("should enable eval broker") 104 }) 105 106 // Create the register request 107 eval1 := mock.Eval() 108 s1.evalBroker.Enqueue(eval1) 109 out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second) 110 if err != nil { 111 t.Fatalf("err: %v", err) 112 } 113 if out == nil { 114 t.Fatalf("missing eval") 115 } 116 117 // Ack the eval 118 get := &structs.EvalAckRequest{ 119 EvalID: out.ID, 120 Token: token, 121 WriteRequest: structs.WriteRequest{Region: "global"}, 122 } 123 var resp structs.GenericResponse 124 if err := msgpackrpc.CallWithCodec(codec, "Eval.Ack", get, &resp); err != nil { 125 t.Fatalf("err: %v", err) 126 } 127 128 // Ensure outstanding 129 if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok { 130 t.Fatalf("should not be outstanding") 131 } 132 } 133 134 func TestEvalEndpoint_Nack(t *testing.T) { 135 s1 := testServer(t, func(c *Config) { 136 // Disable all of the schedulers so we can manually dequeue 137 // evals and check the queue status 138 c.NumSchedulers = 0 139 }) 140 defer s1.Shutdown() 141 codec := rpcClient(t, s1) 142 143 testutil.WaitForResult(func() (bool, error) { 144 return s1.evalBroker.Enabled(), nil 145 }, func(err error) { 146 t.Fatalf("should enable eval broker") 147 }) 148 149 // Create the register request 150 eval1 := mock.Eval() 151 s1.evalBroker.Enqueue(eval1) 152 out, token, _ := s1.evalBroker.Dequeue(defaultSched, time.Second) 153 if out == nil { 154 t.Fatalf("missing eval") 155 } 156 157 // Nack the eval 158 get := &structs.EvalAckRequest{ 159 EvalID: out.ID, 160 Token: token, 161 WriteRequest: structs.WriteRequest{Region: "global"}, 162 } 163 var resp structs.GenericResponse 164 if err := msgpackrpc.CallWithCodec(codec, "Eval.Nack", get, &resp); err != nil { 165 t.Fatalf("err: %v", err) 166 } 167 168 // Ensure outstanding 169 if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok { 170 t.Fatalf("should not be outstanding") 171 } 172 173 // Should get it back 174 out2, _, _ := s1.evalBroker.Dequeue(defaultSched, time.Second) 175 if out2 != out { 176 t.Fatalf("nack failed") 177 } 178 } 179 180 func TestEvalEndpoint_Update(t *testing.T) { 181 s1 := testServer(t, nil) 182 defer s1.Shutdown() 183 codec := rpcClient(t, s1) 184 185 testutil.WaitForResult(func() (bool, error) { 186 return s1.evalBroker.Enabled(), nil 187 }, func(err error) { 188 t.Fatalf("should enable eval broker") 189 }) 190 191 // Create the register request 192 eval1 := mock.Eval() 193 s1.evalBroker.Enqueue(eval1) 194 out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second) 195 if err != nil { 196 t.Fatalf("err: %v", err) 197 } 198 if out == nil { 199 t.Fatalf("missing eval") 200 } 201 202 // Update the eval 203 eval2 := eval1.Copy() 204 eval2.Status = structs.EvalStatusComplete 205 206 get := &structs.EvalUpdateRequest{ 207 Evals: []*structs.Evaluation{eval2}, 208 EvalToken: token, 209 WriteRequest: structs.WriteRequest{Region: "global"}, 210 } 211 var resp structs.GenericResponse 212 if err := msgpackrpc.CallWithCodec(codec, "Eval.Update", get, &resp); err != nil { 213 t.Fatalf("err: %v", err) 214 } 215 216 // Ensure updated 217 outE, err := s1.fsm.State().EvalByID(eval2.ID) 218 if err != nil { 219 t.Fatalf("err: %v", err) 220 } 221 if outE.Status != structs.EvalStatusComplete { 222 t.Fatalf("Bad: %#v", out) 223 } 224 } 225 226 func TestEvalEndpoint_Create(t *testing.T) { 227 s1 := testServer(t, func(c *Config) { 228 c.NumSchedulers = 0 // Prevent automatic dequeue 229 }) 230 defer s1.Shutdown() 231 codec := rpcClient(t, s1) 232 233 testutil.WaitForResult(func() (bool, error) { 234 return s1.evalBroker.Enabled(), nil 235 }, func(err error) { 236 t.Fatalf("should enable eval broker") 237 }) 238 239 // Create the register request 240 prev := mock.Eval() 241 s1.evalBroker.Enqueue(prev) 242 out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second) 243 if err != nil { 244 t.Fatalf("err: %v", err) 245 } 246 if out == nil { 247 t.Fatalf("missing eval") 248 } 249 250 // Create the register request 251 eval1 := mock.Eval() 252 eval1.PreviousEval = prev.ID 253 get := &structs.EvalUpdateRequest{ 254 Evals: []*structs.Evaluation{eval1}, 255 EvalToken: token, 256 WriteRequest: structs.WriteRequest{Region: "global"}, 257 } 258 var resp structs.GenericResponse 259 if err := msgpackrpc.CallWithCodec(codec, "Eval.Create", get, &resp); err != nil { 260 t.Fatalf("err: %v", err) 261 } 262 263 // Ensure created 264 outE, err := s1.fsm.State().EvalByID(eval1.ID) 265 if err != nil { 266 t.Fatalf("err: %v", err) 267 } 268 269 eval1.CreateIndex = resp.Index 270 eval1.ModifyIndex = resp.Index 271 if !reflect.DeepEqual(eval1, outE) { 272 t.Fatalf("Bad: %#v %#v", outE, eval1) 273 } 274 } 275 276 func TestEvalEndpoint_Reap(t *testing.T) { 277 s1 := testServer(t, nil) 278 defer s1.Shutdown() 279 codec := rpcClient(t, s1) 280 testutil.WaitForLeader(t, s1.RPC) 281 282 // Create the register request 283 eval1 := mock.Eval() 284 s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}) 285 286 // Reap the eval 287 get := &structs.EvalDeleteRequest{ 288 Evals: []string{eval1.ID}, 289 WriteRequest: structs.WriteRequest{Region: "global"}, 290 } 291 var resp structs.GenericResponse 292 if err := msgpackrpc.CallWithCodec(codec, "Eval.Reap", get, &resp); err != nil { 293 t.Fatalf("err: %v", err) 294 } 295 if resp.Index == 0 { 296 t.Fatalf("Bad index: %d", resp.Index) 297 } 298 299 // Ensure deleted 300 outE, err := s1.fsm.State().EvalByID(eval1.ID) 301 if err != nil { 302 t.Fatalf("err: %v", err) 303 } 304 if outE != nil { 305 t.Fatalf("Bad: %#v", outE) 306 } 307 } 308 309 func TestEvalEndpoint_List(t *testing.T) { 310 s1 := testServer(t, nil) 311 defer s1.Shutdown() 312 codec := rpcClient(t, s1) 313 testutil.WaitForLeader(t, s1.RPC) 314 315 // Create the register request 316 eval1 := mock.Eval() 317 eval2 := mock.Eval() 318 s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1, eval2}) 319 320 // Lookup the eval 321 get := &structs.EvalListRequest{ 322 QueryOptions: structs.QueryOptions{Region: "global"}, 323 } 324 var resp structs.EvalListResponse 325 if err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp); err != nil { 326 t.Fatalf("err: %v", err) 327 } 328 if resp.Index != 1000 { 329 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 330 } 331 332 if len(resp.Evaluations) != 2 { 333 t.Fatalf("bad: %#v", resp.Evaluations) 334 } 335 } 336 337 func TestEvalEndpoint_Allocations(t *testing.T) { 338 s1 := testServer(t, nil) 339 defer s1.Shutdown() 340 codec := rpcClient(t, s1) 341 testutil.WaitForLeader(t, s1.RPC) 342 343 // Create the register request 344 alloc1 := mock.Alloc() 345 alloc2 := mock.Alloc() 346 alloc2.EvalID = alloc1.EvalID 347 state := s1.fsm.State() 348 err := state.UpsertAllocs(1000, 349 []*structs.Allocation{alloc1, alloc2}) 350 if err != nil { 351 t.Fatalf("err: %v", err) 352 } 353 354 // Lookup the eval 355 get := &structs.EvalSpecificRequest{ 356 EvalID: alloc1.EvalID, 357 QueryOptions: structs.QueryOptions{Region: "global"}, 358 } 359 var resp structs.EvalAllocationsResponse 360 if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil { 361 t.Fatalf("err: %v", err) 362 } 363 if resp.Index != 1000 { 364 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 365 } 366 367 if len(resp.Allocations) != 2 { 368 t.Fatalf("bad: %#v", resp.Allocations) 369 } 370 }