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