github.com/taylorchu/nomad@v0.5.3-rc1.0.20170407200202-db11e7dd7b55/nomad/eval_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "reflect" 5 "strings" 6 "testing" 7 "time" 8 9 memdb "github.com/hashicorp/go-memdb" 10 "github.com/hashicorp/net-rpc-msgpackrpc" 11 "github.com/hashicorp/nomad/nomad/mock" 12 "github.com/hashicorp/nomad/nomad/structs" 13 "github.com/hashicorp/nomad/scheduler" 14 "github.com/hashicorp/nomad/testutil" 15 ) 16 17 func TestEvalEndpoint_GetEval(t *testing.T) { 18 s1 := testServer(t, nil) 19 defer s1.Shutdown() 20 codec := rpcClient(t, s1) 21 testutil.WaitForLeader(t, s1.RPC) 22 23 // Create the register request 24 eval1 := mock.Eval() 25 s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}) 26 27 // Lookup the eval 28 get := &structs.EvalSpecificRequest{ 29 EvalID: eval1.ID, 30 QueryOptions: structs.QueryOptions{Region: "global"}, 31 } 32 var resp structs.SingleEvalResponse 33 if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil { 34 t.Fatalf("err: %v", err) 35 } 36 if resp.Index != 1000 { 37 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 38 } 39 40 if !reflect.DeepEqual(eval1, resp.Eval) { 41 t.Fatalf("bad: %#v %#v", eval1, resp.Eval) 42 } 43 44 // Lookup non-existing node 45 get.EvalID = structs.GenerateUUID() 46 if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil { 47 t.Fatalf("err: %v", err) 48 } 49 if resp.Index != 1000 { 50 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 51 } 52 if resp.Eval != nil { 53 t.Fatalf("unexpected eval") 54 } 55 } 56 57 func TestEvalEndpoint_GetEval_Blocking(t *testing.T) { 58 s1 := testServer(t, nil) 59 defer s1.Shutdown() 60 state := s1.fsm.State() 61 codec := rpcClient(t, s1) 62 testutil.WaitForLeader(t, s1.RPC) 63 64 // Create the evals 65 eval1 := mock.Eval() 66 eval2 := mock.Eval() 67 68 // First create an unrelated eval 69 time.AfterFunc(100*time.Millisecond, func() { 70 err := state.UpsertEvals(100, []*structs.Evaluation{eval1}) 71 if err != nil { 72 t.Fatalf("err: %v", err) 73 } 74 }) 75 76 // Upsert the eval we are watching later 77 time.AfterFunc(200*time.Millisecond, func() { 78 err := state.UpsertEvals(200, []*structs.Evaluation{eval2}) 79 if err != nil { 80 t.Fatalf("err: %v", err) 81 } 82 }) 83 84 // Lookup the eval 85 req := &structs.EvalSpecificRequest{ 86 EvalID: eval2.ID, 87 QueryOptions: structs.QueryOptions{ 88 Region: "global", 89 MinQueryIndex: 150, 90 }, 91 } 92 var resp structs.SingleEvalResponse 93 start := time.Now() 94 if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", req, &resp); err != nil { 95 t.Fatalf("err: %v", err) 96 } 97 98 if elapsed := time.Since(start); elapsed < 200*time.Millisecond { 99 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 100 } 101 if resp.Index != 200 { 102 t.Fatalf("Bad index: %d %d", resp.Index, 200) 103 } 104 if resp.Eval == nil || resp.Eval.ID != eval2.ID { 105 t.Fatalf("bad: %#v", resp.Eval) 106 } 107 108 // Eval delete triggers watches 109 time.AfterFunc(100*time.Millisecond, func() { 110 err := state.DeleteEval(300, []string{eval2.ID}, []string{}) 111 if err != nil { 112 t.Fatalf("err: %v", err) 113 } 114 }) 115 116 req.QueryOptions.MinQueryIndex = 250 117 var resp2 structs.SingleEvalResponse 118 start = time.Now() 119 if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", req, &resp2); err != nil { 120 t.Fatalf("err: %v", err) 121 } 122 123 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 124 t.Fatalf("should block (returned in %s) %#v", elapsed, resp2) 125 } 126 if resp2.Index != 300 { 127 t.Fatalf("Bad index: %d %d", resp2.Index, 300) 128 } 129 if resp2.Eval != nil { 130 t.Fatalf("bad: %#v", resp2.Eval) 131 } 132 } 133 134 func TestEvalEndpoint_Dequeue(t *testing.T) { 135 s1 := testServer(t, func(c *Config) { 136 c.NumSchedulers = 0 // Prevent automatic dequeue 137 }) 138 defer s1.Shutdown() 139 codec := rpcClient(t, s1) 140 testutil.WaitForLeader(t, s1.RPC) 141 142 // Create the register request 143 eval1 := mock.Eval() 144 s1.evalBroker.Enqueue(eval1) 145 146 // Dequeue the eval 147 get := &structs.EvalDequeueRequest{ 148 Schedulers: defaultSched, 149 SchedulerVersion: scheduler.SchedulerVersion, 150 WriteRequest: structs.WriteRequest{Region: "global"}, 151 } 152 var resp structs.EvalDequeueResponse 153 if err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp); err != nil { 154 t.Fatalf("err: %v", err) 155 } 156 157 if !reflect.DeepEqual(eval1, resp.Eval) { 158 t.Fatalf("bad: %v %v", eval1, resp.Eval) 159 } 160 161 // Ensure outstanding 162 token, ok := s1.evalBroker.Outstanding(eval1.ID) 163 if !ok { 164 t.Fatalf("should be outstanding") 165 } 166 if token != resp.Token { 167 t.Fatalf("bad token: %#v %#v", token, resp.Token) 168 } 169 } 170 171 func TestEvalEndpoint_Dequeue_Version_Mismatch(t *testing.T) { 172 s1 := testServer(t, func(c *Config) { 173 c.NumSchedulers = 0 // Prevent automatic dequeue 174 }) 175 defer s1.Shutdown() 176 codec := rpcClient(t, s1) 177 testutil.WaitForLeader(t, s1.RPC) 178 179 // Create the register request 180 eval1 := mock.Eval() 181 s1.evalBroker.Enqueue(eval1) 182 183 // Dequeue the eval 184 get := &structs.EvalDequeueRequest{ 185 Schedulers: defaultSched, 186 SchedulerVersion: 0, 187 WriteRequest: structs.WriteRequest{Region: "global"}, 188 } 189 var resp structs.EvalDequeueResponse 190 err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp) 191 if err == nil || !strings.Contains(err.Error(), "scheduler version is 0") { 192 t.Fatalf("err: %v", err) 193 } 194 } 195 196 func TestEvalEndpoint_Ack(t *testing.T) { 197 s1 := testServer(t, nil) 198 defer s1.Shutdown() 199 codec := rpcClient(t, s1) 200 201 testutil.WaitForResult(func() (bool, error) { 202 return s1.evalBroker.Enabled(), nil 203 }, func(err error) { 204 t.Fatalf("should enable eval broker") 205 }) 206 207 // Create the register request 208 eval1 := mock.Eval() 209 s1.evalBroker.Enqueue(eval1) 210 out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second) 211 if err != nil { 212 t.Fatalf("err: %v", err) 213 } 214 if out == nil { 215 t.Fatalf("missing eval") 216 } 217 218 // Ack the eval 219 get := &structs.EvalAckRequest{ 220 EvalID: out.ID, 221 Token: token, 222 WriteRequest: structs.WriteRequest{Region: "global"}, 223 } 224 var resp structs.GenericResponse 225 if err := msgpackrpc.CallWithCodec(codec, "Eval.Ack", get, &resp); err != nil { 226 t.Fatalf("err: %v", err) 227 } 228 229 // Ensure outstanding 230 if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok { 231 t.Fatalf("should not be outstanding") 232 } 233 } 234 235 func TestEvalEndpoint_Nack(t *testing.T) { 236 s1 := testServer(t, func(c *Config) { 237 // Disable all of the schedulers so we can manually dequeue 238 // evals and check the queue status 239 c.NumSchedulers = 0 240 }) 241 defer s1.Shutdown() 242 codec := rpcClient(t, s1) 243 244 testutil.WaitForResult(func() (bool, error) { 245 return s1.evalBroker.Enabled(), nil 246 }, func(err error) { 247 t.Fatalf("should enable eval broker") 248 }) 249 250 // Create the register request 251 eval1 := mock.Eval() 252 s1.evalBroker.Enqueue(eval1) 253 out, token, _ := s1.evalBroker.Dequeue(defaultSched, time.Second) 254 if out == nil { 255 t.Fatalf("missing eval") 256 } 257 258 // Nack the eval 259 get := &structs.EvalAckRequest{ 260 EvalID: out.ID, 261 Token: token, 262 WriteRequest: structs.WriteRequest{Region: "global"}, 263 } 264 var resp structs.GenericResponse 265 if err := msgpackrpc.CallWithCodec(codec, "Eval.Nack", get, &resp); err != nil { 266 t.Fatalf("err: %v", err) 267 } 268 269 // Ensure outstanding 270 if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok { 271 t.Fatalf("should not be outstanding") 272 } 273 274 // Should get it back 275 out2, _, _ := s1.evalBroker.Dequeue(defaultSched, time.Second) 276 if out2 != out { 277 t.Fatalf("nack failed") 278 } 279 } 280 281 func TestEvalEndpoint_Update(t *testing.T) { 282 s1 := testServer(t, nil) 283 defer s1.Shutdown() 284 codec := rpcClient(t, s1) 285 286 testutil.WaitForResult(func() (bool, error) { 287 return s1.evalBroker.Enabled(), nil 288 }, func(err error) { 289 t.Fatalf("should enable eval broker") 290 }) 291 292 // Create the register request 293 eval1 := mock.Eval() 294 s1.evalBroker.Enqueue(eval1) 295 out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second) 296 if err != nil { 297 t.Fatalf("err: %v", err) 298 } 299 if out == nil { 300 t.Fatalf("missing eval") 301 } 302 303 // Update the eval 304 eval2 := eval1.Copy() 305 eval2.Status = structs.EvalStatusComplete 306 307 get := &structs.EvalUpdateRequest{ 308 Evals: []*structs.Evaluation{eval2}, 309 EvalToken: token, 310 WriteRequest: structs.WriteRequest{Region: "global"}, 311 } 312 var resp structs.GenericResponse 313 if err := msgpackrpc.CallWithCodec(codec, "Eval.Update", get, &resp); err != nil { 314 t.Fatalf("err: %v", err) 315 } 316 317 // Ensure updated 318 ws := memdb.NewWatchSet() 319 outE, err := s1.fsm.State().EvalByID(ws, eval2.ID) 320 if err != nil { 321 t.Fatalf("err: %v", err) 322 } 323 if outE.Status != structs.EvalStatusComplete { 324 t.Fatalf("Bad: %#v", out) 325 } 326 } 327 328 func TestEvalEndpoint_Create(t *testing.T) { 329 s1 := testServer(t, func(c *Config) { 330 c.NumSchedulers = 0 // Prevent automatic dequeue 331 }) 332 defer s1.Shutdown() 333 codec := rpcClient(t, s1) 334 335 testutil.WaitForResult(func() (bool, error) { 336 return s1.evalBroker.Enabled(), nil 337 }, func(err error) { 338 t.Fatalf("should enable eval broker") 339 }) 340 341 // Create the register request 342 prev := mock.Eval() 343 s1.evalBroker.Enqueue(prev) 344 out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second) 345 if err != nil { 346 t.Fatalf("err: %v", err) 347 } 348 if out == nil { 349 t.Fatalf("missing eval") 350 } 351 352 // Create the register request 353 eval1 := mock.Eval() 354 eval1.PreviousEval = prev.ID 355 get := &structs.EvalUpdateRequest{ 356 Evals: []*structs.Evaluation{eval1}, 357 EvalToken: token, 358 WriteRequest: structs.WriteRequest{Region: "global"}, 359 } 360 var resp structs.GenericResponse 361 if err := msgpackrpc.CallWithCodec(codec, "Eval.Create", get, &resp); err != nil { 362 t.Fatalf("err: %v", err) 363 } 364 365 // Ensure created 366 ws := memdb.NewWatchSet() 367 outE, err := s1.fsm.State().EvalByID(ws, eval1.ID) 368 if err != nil { 369 t.Fatalf("err: %v", err) 370 } 371 372 eval1.CreateIndex = resp.Index 373 eval1.ModifyIndex = resp.Index 374 if !reflect.DeepEqual(eval1, outE) { 375 t.Fatalf("Bad: %#v %#v", outE, eval1) 376 } 377 } 378 379 func TestEvalEndpoint_Reap(t *testing.T) { 380 s1 := testServer(t, nil) 381 defer s1.Shutdown() 382 codec := rpcClient(t, s1) 383 testutil.WaitForLeader(t, s1.RPC) 384 385 // Create the register request 386 eval1 := mock.Eval() 387 s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}) 388 389 // Reap the eval 390 get := &structs.EvalDeleteRequest{ 391 Evals: []string{eval1.ID}, 392 WriteRequest: structs.WriteRequest{Region: "global"}, 393 } 394 var resp structs.GenericResponse 395 if err := msgpackrpc.CallWithCodec(codec, "Eval.Reap", get, &resp); err != nil { 396 t.Fatalf("err: %v", err) 397 } 398 if resp.Index == 0 { 399 t.Fatalf("Bad index: %d", resp.Index) 400 } 401 402 // Ensure deleted 403 ws := memdb.NewWatchSet() 404 outE, err := s1.fsm.State().EvalByID(ws, eval1.ID) 405 if err != nil { 406 t.Fatalf("err: %v", err) 407 } 408 if outE != nil { 409 t.Fatalf("Bad: %#v", outE) 410 } 411 } 412 413 func TestEvalEndpoint_List(t *testing.T) { 414 s1 := testServer(t, nil) 415 defer s1.Shutdown() 416 codec := rpcClient(t, s1) 417 testutil.WaitForLeader(t, s1.RPC) 418 419 // Create the register request 420 eval1 := mock.Eval() 421 eval1.ID = "aaaaaaaa-3350-4b4b-d185-0e1992ed43e9" 422 eval2 := mock.Eval() 423 eval2.ID = "aaaabbbb-3350-4b4b-d185-0e1992ed43e9" 424 s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1, eval2}) 425 426 // Lookup the eval 427 get := &structs.EvalListRequest{ 428 QueryOptions: structs.QueryOptions{Region: "global"}, 429 } 430 var resp structs.EvalListResponse 431 if err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp); err != nil { 432 t.Fatalf("err: %v", err) 433 } 434 if resp.Index != 1000 { 435 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 436 } 437 438 if len(resp.Evaluations) != 2 { 439 t.Fatalf("bad: %#v", resp.Evaluations) 440 } 441 442 // Lookup the eval by prefix 443 get = &structs.EvalListRequest{ 444 QueryOptions: structs.QueryOptions{Region: "global", Prefix: "aaaabb"}, 445 } 446 var resp2 structs.EvalListResponse 447 if err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp2); err != nil { 448 t.Fatalf("err: %v", err) 449 } 450 if resp2.Index != 1000 { 451 t.Fatalf("Bad index: %d %d", resp2.Index, 1000) 452 } 453 454 if len(resp2.Evaluations) != 1 { 455 t.Fatalf("bad: %#v", resp2.Evaluations) 456 } 457 458 } 459 460 func TestEvalEndpoint_List_Blocking(t *testing.T) { 461 s1 := testServer(t, nil) 462 defer s1.Shutdown() 463 state := s1.fsm.State() 464 codec := rpcClient(t, s1) 465 testutil.WaitForLeader(t, s1.RPC) 466 467 // Create the ieval 468 eval := mock.Eval() 469 470 // Upsert eval triggers watches 471 time.AfterFunc(100*time.Millisecond, func() { 472 if err := state.UpsertEvals(2, []*structs.Evaluation{eval}); err != nil { 473 t.Fatalf("err: %v", err) 474 } 475 }) 476 477 req := &structs.EvalListRequest{ 478 QueryOptions: structs.QueryOptions{ 479 Region: "global", 480 MinQueryIndex: 1, 481 }, 482 } 483 start := time.Now() 484 var resp structs.EvalListResponse 485 if err := msgpackrpc.CallWithCodec(codec, "Eval.List", req, &resp); err != nil { 486 t.Fatalf("err: %v", err) 487 } 488 489 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 490 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 491 } 492 if resp.Index != 2 { 493 t.Fatalf("Bad index: %d %d", resp.Index, 2) 494 } 495 if len(resp.Evaluations) != 1 || resp.Evaluations[0].ID != eval.ID { 496 t.Fatalf("bad: %#v", resp.Evaluations) 497 } 498 499 // Eval deletion triggers watches 500 time.AfterFunc(100*time.Millisecond, func() { 501 if err := state.DeleteEval(3, []string{eval.ID}, nil); err != nil { 502 t.Fatalf("err: %v", err) 503 } 504 }) 505 506 req.MinQueryIndex = 2 507 start = time.Now() 508 var resp2 structs.EvalListResponse 509 if err := msgpackrpc.CallWithCodec(codec, "Eval.List", req, &resp2); err != nil { 510 t.Fatalf("err: %v", err) 511 } 512 513 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 514 t.Fatalf("should block (returned in %s) %#v", elapsed, resp2) 515 } 516 if resp2.Index != 3 { 517 t.Fatalf("Bad index: %d %d", resp2.Index, 3) 518 } 519 if len(resp2.Evaluations) != 0 { 520 t.Fatalf("bad: %#v", resp2.Evaluations) 521 } 522 } 523 524 func TestEvalEndpoint_Allocations(t *testing.T) { 525 s1 := testServer(t, nil) 526 defer s1.Shutdown() 527 codec := rpcClient(t, s1) 528 testutil.WaitForLeader(t, s1.RPC) 529 530 // Create the register request 531 alloc1 := mock.Alloc() 532 alloc2 := mock.Alloc() 533 alloc2.EvalID = alloc1.EvalID 534 state := s1.fsm.State() 535 state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID)) 536 state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)) 537 err := state.UpsertAllocs(1000, 538 []*structs.Allocation{alloc1, alloc2}) 539 if err != nil { 540 t.Fatalf("err: %v", err) 541 } 542 543 // Lookup the eval 544 get := &structs.EvalSpecificRequest{ 545 EvalID: alloc1.EvalID, 546 QueryOptions: structs.QueryOptions{Region: "global"}, 547 } 548 var resp structs.EvalAllocationsResponse 549 if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil { 550 t.Fatalf("err: %v", err) 551 } 552 if resp.Index != 1000 { 553 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 554 } 555 556 if len(resp.Allocations) != 2 { 557 t.Fatalf("bad: %#v", resp.Allocations) 558 } 559 } 560 561 func TestEvalEndpoint_Allocations_Blocking(t *testing.T) { 562 s1 := testServer(t, nil) 563 defer s1.Shutdown() 564 state := s1.fsm.State() 565 codec := rpcClient(t, s1) 566 testutil.WaitForLeader(t, s1.RPC) 567 568 // Create the allocs 569 alloc1 := mock.Alloc() 570 alloc2 := mock.Alloc() 571 572 // Upsert an unrelated alloc first 573 time.AfterFunc(100*time.Millisecond, func() { 574 state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID)) 575 err := state.UpsertAllocs(100, []*structs.Allocation{alloc1}) 576 if err != nil { 577 t.Fatalf("err: %v", err) 578 } 579 }) 580 581 // Upsert an alloc which will trigger the watch later 582 time.AfterFunc(200*time.Millisecond, func() { 583 state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID)) 584 err := state.UpsertAllocs(200, []*structs.Allocation{alloc2}) 585 if err != nil { 586 t.Fatalf("err: %v", err) 587 } 588 }) 589 590 // Lookup the eval 591 get := &structs.EvalSpecificRequest{ 592 EvalID: alloc2.EvalID, 593 QueryOptions: structs.QueryOptions{ 594 Region: "global", 595 MinQueryIndex: 150, 596 }, 597 } 598 var resp structs.EvalAllocationsResponse 599 start := time.Now() 600 if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil { 601 t.Fatalf("err: %v", err) 602 } 603 604 if elapsed := time.Since(start); elapsed < 200*time.Millisecond { 605 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 606 } 607 if resp.Index != 200 { 608 t.Fatalf("Bad index: %d %d", resp.Index, 200) 609 } 610 if len(resp.Allocations) != 1 || resp.Allocations[0].ID != alloc2.ID { 611 t.Fatalf("bad: %#v", resp.Allocations) 612 } 613 } 614 615 func TestEvalEndpoint_Reblock_NonExistent(t *testing.T) { 616 s1 := testServer(t, func(c *Config) { 617 c.NumSchedulers = 0 // Prevent automatic dequeue 618 }) 619 defer s1.Shutdown() 620 codec := rpcClient(t, s1) 621 622 testutil.WaitForResult(func() (bool, error) { 623 return s1.evalBroker.Enabled(), nil 624 }, func(err error) { 625 t.Fatalf("should enable eval broker") 626 }) 627 628 // Create the register request 629 eval1 := mock.Eval() 630 s1.evalBroker.Enqueue(eval1) 631 out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second) 632 if err != nil { 633 t.Fatalf("err: %v", err) 634 } 635 if out == nil { 636 t.Fatalf("missing eval") 637 } 638 639 get := &structs.EvalUpdateRequest{ 640 Evals: []*structs.Evaluation{eval1}, 641 EvalToken: token, 642 WriteRequest: structs.WriteRequest{Region: "global"}, 643 } 644 var resp structs.GenericResponse 645 if err := msgpackrpc.CallWithCodec(codec, "Eval.Reblock", get, &resp); err == nil { 646 t.Fatalf("expect error since eval does not exist") 647 } 648 } 649 650 func TestEvalEndpoint_Reblock_NonBlocked(t *testing.T) { 651 s1 := testServer(t, func(c *Config) { 652 c.NumSchedulers = 0 // Prevent automatic dequeue 653 }) 654 defer s1.Shutdown() 655 codec := rpcClient(t, s1) 656 657 testutil.WaitForResult(func() (bool, error) { 658 return s1.evalBroker.Enabled(), nil 659 }, func(err error) { 660 t.Fatalf("should enable eval broker") 661 }) 662 663 // Create the eval 664 eval1 := mock.Eval() 665 s1.evalBroker.Enqueue(eval1) 666 667 // Insert it into the state store 668 if err := s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}); err != nil { 669 t.Fatal(err) 670 } 671 672 out, token, err := s1.evalBroker.Dequeue(defaultSched, 2*time.Second) 673 if err != nil { 674 t.Fatalf("err: %v", err) 675 } 676 if out == nil { 677 t.Fatalf("missing eval") 678 } 679 680 get := &structs.EvalUpdateRequest{ 681 Evals: []*structs.Evaluation{eval1}, 682 EvalToken: token, 683 WriteRequest: structs.WriteRequest{Region: "global"}, 684 } 685 var resp structs.GenericResponse 686 if err := msgpackrpc.CallWithCodec(codec, "Eval.Reblock", get, &resp); err == nil { 687 t.Fatalf("should error since eval was not in blocked state: %v", err) 688 } 689 } 690 691 func TestEvalEndpoint_Reblock(t *testing.T) { 692 s1 := testServer(t, func(c *Config) { 693 c.NumSchedulers = 0 // Prevent automatic dequeue 694 }) 695 defer s1.Shutdown() 696 codec := rpcClient(t, s1) 697 698 testutil.WaitForResult(func() (bool, error) { 699 return s1.evalBroker.Enabled(), nil 700 }, func(err error) { 701 t.Fatalf("should enable eval broker") 702 }) 703 704 // Create the eval 705 eval1 := mock.Eval() 706 eval1.Status = structs.EvalStatusBlocked 707 s1.evalBroker.Enqueue(eval1) 708 709 // Insert it into the state store 710 if err := s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}); err != nil { 711 t.Fatal(err) 712 } 713 714 out, token, err := s1.evalBroker.Dequeue(defaultSched, 7*time.Second) 715 if err != nil { 716 t.Fatalf("err: %v", err) 717 } 718 if out == nil { 719 t.Fatalf("bad: %v", out) 720 } 721 722 get := &structs.EvalUpdateRequest{ 723 Evals: []*structs.Evaluation{eval1}, 724 EvalToken: token, 725 WriteRequest: structs.WriteRequest{Region: "global"}, 726 } 727 var resp structs.GenericResponse 728 if err := msgpackrpc.CallWithCodec(codec, "Eval.Reblock", get, &resp); err != nil { 729 t.Fatalf("err: %v", err) 730 } 731 732 // Check that it is blocked 733 bStats := s1.blockedEvals.Stats() 734 if bStats.TotalBlocked+bStats.TotalEscaped == 0 { 735 t.Fatalf("ReblockEval didn't insert eval into the blocked eval tracker") 736 } 737 }