github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/nomad/state/state_store_test.go (about) 1 package state 2 3 import ( 4 "fmt" 5 "os" 6 "reflect" 7 "sort" 8 "strings" 9 "testing" 10 "time" 11 12 memdb "github.com/hashicorp/go-memdb" 13 "github.com/hashicorp/nomad/helper" 14 "github.com/hashicorp/nomad/nomad/mock" 15 "github.com/hashicorp/nomad/nomad/structs" 16 ) 17 18 func testStateStore(t *testing.T) *StateStore { 19 state, err := NewStateStore(os.Stderr) 20 if err != nil { 21 t.Fatalf("err: %v", err) 22 } 23 if state == nil { 24 t.Fatalf("missing state") 25 } 26 return state 27 } 28 29 // This test checks that: 30 // 1) The job is denormalized 31 // 2) Allocations are created 32 func TestStateStore_UpsertPlanResults_AllocationsCreated_Denormalized(t *testing.T) { 33 state := testStateStore(t) 34 alloc := mock.Alloc() 35 job := alloc.Job 36 alloc.Job = nil 37 38 if err := state.UpsertJob(999, job); err != nil { 39 t.Fatalf("err: %v", err) 40 } 41 42 // Create a plan result 43 res := structs.ApplyPlanResultsRequest{ 44 AllocUpdateRequest: structs.AllocUpdateRequest{ 45 Alloc: []*structs.Allocation{alloc}, 46 Job: job, 47 }, 48 } 49 50 err := state.UpsertPlanResults(1000, &res) 51 if err != nil { 52 t.Fatalf("err: %v", err) 53 } 54 55 ws := memdb.NewWatchSet() 56 out, err := state.AllocByID(ws, alloc.ID) 57 if err != nil { 58 t.Fatalf("err: %v", err) 59 } 60 61 if !reflect.DeepEqual(alloc, out) { 62 t.Fatalf("bad: %#v %#v", alloc, out) 63 } 64 65 index, err := state.Index("allocs") 66 if err != nil { 67 t.Fatalf("err: %v", err) 68 } 69 if index != 1000 { 70 t.Fatalf("bad: %d", index) 71 } 72 73 if watchFired(ws) { 74 t.Fatalf("bad") 75 } 76 } 77 78 // This test checks that the deployment is created and allocations count towards 79 // the deployment 80 func TestStateStore_UpsertPlanResults_Deployment(t *testing.T) { 81 state := testStateStore(t) 82 alloc := mock.Alloc() 83 alloc2 := mock.Alloc() 84 job := alloc.Job 85 alloc.Job = nil 86 alloc2.Job = nil 87 88 d := mock.Deployment() 89 alloc.DeploymentID = d.ID 90 alloc2.DeploymentID = d.ID 91 92 if err := state.UpsertJob(999, job); err != nil { 93 t.Fatalf("err: %v", err) 94 } 95 96 // Create a plan result 97 res := structs.ApplyPlanResultsRequest{ 98 AllocUpdateRequest: structs.AllocUpdateRequest{ 99 Alloc: []*structs.Allocation{alloc, alloc2}, 100 Job: job, 101 }, 102 Deployment: d, 103 } 104 105 err := state.UpsertPlanResults(1000, &res) 106 if err != nil { 107 t.Fatalf("err: %v", err) 108 } 109 110 ws := memdb.NewWatchSet() 111 out, err := state.AllocByID(ws, alloc.ID) 112 if err != nil { 113 t.Fatalf("err: %v", err) 114 } 115 116 if !reflect.DeepEqual(alloc, out) { 117 t.Fatalf("bad: %#v %#v", alloc, out) 118 } 119 120 dout, err := state.DeploymentByID(ws, d.ID) 121 if err != nil { 122 t.Fatalf("err: %v", err) 123 } 124 125 if dout == nil { 126 t.Fatalf("bad: nil deployment") 127 } 128 129 tg, ok := dout.TaskGroups[alloc.TaskGroup] 130 if !ok { 131 t.Fatalf("bad: nil deployment state") 132 } 133 if tg == nil || tg.PlacedAllocs != 2 { 134 t.Fatalf("bad: %v", dout) 135 } 136 137 if watchFired(ws) { 138 t.Fatalf("bad") 139 } 140 141 // Update the allocs to be part of a new deployment 142 d2 := d.Copy() 143 d2.ID = structs.GenerateUUID() 144 145 allocNew := alloc.Copy() 146 allocNew.DeploymentID = d2.ID 147 allocNew2 := alloc2.Copy() 148 allocNew2.DeploymentID = d2.ID 149 150 // Create another plan 151 res = structs.ApplyPlanResultsRequest{ 152 AllocUpdateRequest: structs.AllocUpdateRequest{ 153 Alloc: []*structs.Allocation{allocNew, allocNew2}, 154 Job: job, 155 }, 156 Deployment: d2, 157 } 158 159 err = state.UpsertPlanResults(1001, &res) 160 if err != nil { 161 t.Fatalf("err: %v", err) 162 } 163 164 dout, err = state.DeploymentByID(ws, d2.ID) 165 if err != nil { 166 t.Fatalf("err: %v", err) 167 } 168 169 if dout == nil { 170 t.Fatalf("bad: nil deployment") 171 } 172 173 tg, ok = dout.TaskGroups[alloc.TaskGroup] 174 if !ok { 175 t.Fatalf("bad: nil deployment state") 176 } 177 if tg == nil || tg.PlacedAllocs != 2 { 178 t.Fatalf("bad: %v", dout) 179 } 180 } 181 182 // This test checks that deployment updates are applied correctly 183 func TestStateStore_UpsertPlanResults_DeploymentUpdates(t *testing.T) { 184 state := testStateStore(t) 185 186 // Create a job that applies to all 187 job := mock.Job() 188 if err := state.UpsertJob(998, job); err != nil { 189 t.Fatalf("err: %v", err) 190 } 191 192 // Create a deployment that we will update its status 193 doutstanding := mock.Deployment() 194 doutstanding.JobID = job.ID 195 196 if err := state.UpsertDeployment(1000, doutstanding); err != nil { 197 t.Fatalf("err: %v", err) 198 } 199 200 alloc := mock.Alloc() 201 alloc.Job = nil 202 203 dnew := mock.Deployment() 204 dnew.JobID = job.ID 205 alloc.DeploymentID = dnew.ID 206 207 // Update the old deployment 208 update := &structs.DeploymentStatusUpdate{ 209 DeploymentID: doutstanding.ID, 210 Status: "foo", 211 StatusDescription: "bar", 212 } 213 214 // Create a plan result 215 res := structs.ApplyPlanResultsRequest{ 216 AllocUpdateRequest: structs.AllocUpdateRequest{ 217 Alloc: []*structs.Allocation{alloc}, 218 Job: job, 219 }, 220 Deployment: dnew, 221 DeploymentUpdates: []*structs.DeploymentStatusUpdate{update}, 222 } 223 224 err := state.UpsertPlanResults(1000, &res) 225 if err != nil { 226 t.Fatalf("err: %v", err) 227 } 228 229 ws := memdb.NewWatchSet() 230 231 // Check the deployments are correctly updated. 232 dout, err := state.DeploymentByID(ws, dnew.ID) 233 if err != nil { 234 t.Fatalf("err: %v", err) 235 } 236 237 if dout == nil { 238 t.Fatalf("bad: nil deployment") 239 } 240 241 tg, ok := dout.TaskGroups[alloc.TaskGroup] 242 if !ok { 243 t.Fatalf("bad: nil deployment state") 244 } 245 if tg == nil || tg.PlacedAllocs != 1 { 246 t.Fatalf("bad: %v", dout) 247 } 248 249 doutstandingout, err := state.DeploymentByID(ws, doutstanding.ID) 250 if err != nil || doutstandingout == nil { 251 t.Fatalf("bad: %v %v", err, doutstandingout) 252 } 253 if doutstandingout.Status != update.Status || doutstandingout.StatusDescription != update.StatusDescription || doutstandingout.ModifyIndex != 1000 { 254 t.Fatalf("bad: %v", doutstandingout) 255 } 256 257 if watchFired(ws) { 258 t.Fatalf("bad") 259 } 260 } 261 262 func TestStateStore_UpsertDeployment(t *testing.T) { 263 state := testStateStore(t) 264 deployment := mock.Deployment() 265 266 // Create a watchset so we can test that upsert fires the watch 267 ws := memdb.NewWatchSet() 268 _, err := state.DeploymentsByJobID(ws, deployment.ID) 269 if err != nil { 270 t.Fatalf("bad: %v", err) 271 } 272 273 err = state.UpsertDeployment(1000, deployment) 274 if err != nil { 275 t.Fatalf("err: %v", err) 276 } 277 if !watchFired(ws) { 278 t.Fatalf("bad") 279 } 280 281 ws = memdb.NewWatchSet() 282 out, err := state.DeploymentByID(ws, deployment.ID) 283 if err != nil { 284 t.Fatalf("err: %v", err) 285 } 286 287 if !reflect.DeepEqual(deployment, out) { 288 t.Fatalf("bad: %#v %#v", deployment, out) 289 } 290 291 index, err := state.Index("deployment") 292 if err != nil { 293 t.Fatalf("err: %v", err) 294 } 295 if index != 1000 { 296 t.Fatalf("bad: %d", index) 297 } 298 299 if watchFired(ws) { 300 t.Fatalf("bad") 301 } 302 } 303 304 func TestStateStore_DeleteDeployment(t *testing.T) { 305 state := testStateStore(t) 306 d1 := mock.Deployment() 307 d2 := mock.Deployment() 308 309 err := state.UpsertDeployment(1000, d1) 310 if err != nil { 311 t.Fatalf("err: %v", err) 312 } 313 if err := state.UpsertDeployment(1001, d2); err != nil { 314 t.Fatalf("err: %v", err) 315 } 316 317 // Create a watchset so we can test that delete fires the watch 318 ws := memdb.NewWatchSet() 319 if _, err := state.DeploymentByID(ws, d1.ID); err != nil { 320 t.Fatalf("bad: %v", err) 321 } 322 323 err = state.DeleteDeployment(1002, []string{d1.ID, d2.ID}) 324 if err != nil { 325 t.Fatalf("err: %v", err) 326 } 327 328 if !watchFired(ws) { 329 t.Fatalf("bad") 330 } 331 332 ws = memdb.NewWatchSet() 333 out, err := state.DeploymentByID(ws, d1.ID) 334 if err != nil { 335 t.Fatalf("err: %v", err) 336 } 337 338 if out != nil { 339 t.Fatalf("bad: %#v %#v", d1, out) 340 } 341 342 index, err := state.Index("deployment") 343 if err != nil { 344 t.Fatalf("err: %v", err) 345 } 346 if index != 1002 { 347 t.Fatalf("bad: %d", index) 348 } 349 350 if watchFired(ws) { 351 t.Fatalf("bad") 352 } 353 } 354 355 func TestStateStore_Deployments(t *testing.T) { 356 state := testStateStore(t) 357 var deployments []*structs.Deployment 358 359 for i := 0; i < 10; i++ { 360 deployment := mock.Deployment() 361 deployments = append(deployments, deployment) 362 363 err := state.UpsertDeployment(1000+uint64(i), deployment) 364 if err != nil { 365 t.Fatalf("err: %v", err) 366 } 367 } 368 369 ws := memdb.NewWatchSet() 370 iter, err := state.Deployments(ws) 371 if err != nil { 372 t.Fatalf("err: %v", err) 373 } 374 375 var out []*structs.Deployment 376 for { 377 raw := iter.Next() 378 if raw == nil { 379 break 380 } 381 out = append(out, raw.(*structs.Deployment)) 382 } 383 384 lessThan := func(i, j int) bool { 385 return deployments[i].ID < deployments[j].ID 386 } 387 sort.Slice(deployments, lessThan) 388 sort.Slice(out, lessThan) 389 390 if !reflect.DeepEqual(deployments, out) { 391 t.Fatalf("bad: %#v %#v", deployments, out) 392 } 393 394 if watchFired(ws) { 395 t.Fatalf("bad") 396 } 397 } 398 399 func TestStateStore_DeploymentsByIDPrefix(t *testing.T) { 400 state := testStateStore(t) 401 deploy := mock.Deployment() 402 403 deploy.ID = "11111111-662e-d0ab-d1c9-3e434af7bdb4" 404 err := state.UpsertDeployment(1000, deploy) 405 if err != nil { 406 t.Fatalf("err: %v", err) 407 } 408 409 // Create a watchset so we can test that getters don't cause it to fire 410 ws := memdb.NewWatchSet() 411 iter, err := state.DeploymentsByIDPrefix(ws, deploy.ID) 412 if err != nil { 413 t.Fatalf("err: %v", err) 414 } 415 416 gatherDeploys := func(iter memdb.ResultIterator) []*structs.Deployment { 417 var deploys []*structs.Deployment 418 for { 419 raw := iter.Next() 420 if raw == nil { 421 break 422 } 423 deploy := raw.(*structs.Deployment) 424 deploys = append(deploys, deploy) 425 } 426 return deploys 427 } 428 429 deploys := gatherDeploys(iter) 430 if len(deploys) != 1 { 431 t.Fatalf("err: %v", err) 432 } 433 434 if watchFired(ws) { 435 t.Fatalf("bad") 436 } 437 438 iter, err = state.DeploymentsByIDPrefix(ws, "11") 439 if err != nil { 440 t.Fatalf("err: %v", err) 441 } 442 443 deploys = gatherDeploys(iter) 444 if len(deploys) != 1 { 445 t.Fatalf("err: %v", err) 446 } 447 448 deploy = mock.Deployment() 449 deploy.ID = "11222222-662e-d0ab-d1c9-3e434af7bdb4" 450 err = state.UpsertDeployment(1001, deploy) 451 if err != nil { 452 t.Fatalf("err: %v", err) 453 } 454 455 if !watchFired(ws) { 456 t.Fatalf("bad") 457 } 458 459 ws = memdb.NewWatchSet() 460 iter, err = state.DeploymentsByIDPrefix(ws, "11") 461 if err != nil { 462 t.Fatalf("err: %v", err) 463 } 464 465 deploys = gatherDeploys(iter) 466 if len(deploys) != 2 { 467 t.Fatalf("err: %v", err) 468 } 469 470 iter, err = state.DeploymentsByIDPrefix(ws, "1111") 471 if err != nil { 472 t.Fatalf("err: %v", err) 473 } 474 475 deploys = gatherDeploys(iter) 476 if len(deploys) != 1 { 477 t.Fatalf("err: %v", err) 478 } 479 480 if watchFired(ws) { 481 t.Fatalf("bad") 482 } 483 } 484 485 func TestStateStore_UpsertNode_Node(t *testing.T) { 486 state := testStateStore(t) 487 node := mock.Node() 488 489 // Create a watchset so we can test that upsert fires the watch 490 ws := memdb.NewWatchSet() 491 _, err := state.NodeByID(ws, node.ID) 492 if err != nil { 493 t.Fatalf("bad: %v", err) 494 } 495 496 err = state.UpsertNode(1000, node) 497 if err != nil { 498 t.Fatalf("err: %v", err) 499 } 500 if !watchFired(ws) { 501 t.Fatalf("bad") 502 } 503 504 ws = memdb.NewWatchSet() 505 out, err := state.NodeByID(ws, node.ID) 506 if err != nil { 507 t.Fatalf("err: %v", err) 508 } 509 510 if !reflect.DeepEqual(node, out) { 511 t.Fatalf("bad: %#v %#v", node, out) 512 } 513 514 index, err := state.Index("nodes") 515 if err != nil { 516 t.Fatalf("err: %v", err) 517 } 518 if index != 1000 { 519 t.Fatalf("bad: %d", index) 520 } 521 522 if watchFired(ws) { 523 t.Fatalf("bad") 524 } 525 } 526 527 func TestStateStore_DeleteNode_Node(t *testing.T) { 528 state := testStateStore(t) 529 node := mock.Node() 530 531 err := state.UpsertNode(1000, node) 532 if err != nil { 533 t.Fatalf("err: %v", err) 534 } 535 536 // Create a watchset so we can test that delete fires the watch 537 ws := memdb.NewWatchSet() 538 if _, err := state.NodeByID(ws, node.ID); err != nil { 539 t.Fatalf("bad: %v", err) 540 } 541 542 err = state.DeleteNode(1001, node.ID) 543 if err != nil { 544 t.Fatalf("err: %v", err) 545 } 546 547 if !watchFired(ws) { 548 t.Fatalf("bad") 549 } 550 551 ws = memdb.NewWatchSet() 552 out, err := state.NodeByID(ws, node.ID) 553 if err != nil { 554 t.Fatalf("err: %v", err) 555 } 556 557 if out != nil { 558 t.Fatalf("bad: %#v %#v", node, out) 559 } 560 561 index, err := state.Index("nodes") 562 if err != nil { 563 t.Fatalf("err: %v", err) 564 } 565 if index != 1001 { 566 t.Fatalf("bad: %d", index) 567 } 568 569 if watchFired(ws) { 570 t.Fatalf("bad") 571 } 572 } 573 574 func TestStateStore_UpdateNodeStatus_Node(t *testing.T) { 575 state := testStateStore(t) 576 node := mock.Node() 577 578 err := state.UpsertNode(800, node) 579 if err != nil { 580 t.Fatalf("err: %v", err) 581 } 582 583 // Create a watchset so we can test that update node status fires the watch 584 ws := memdb.NewWatchSet() 585 if _, err := state.NodeByID(ws, node.ID); err != nil { 586 t.Fatalf("bad: %v", err) 587 } 588 589 err = state.UpdateNodeStatus(801, node.ID, structs.NodeStatusReady) 590 if err != nil { 591 t.Fatalf("err: %v", err) 592 } 593 594 if !watchFired(ws) { 595 t.Fatalf("bad") 596 } 597 598 ws = memdb.NewWatchSet() 599 out, err := state.NodeByID(ws, node.ID) 600 if err != nil { 601 t.Fatalf("err: %v", err) 602 } 603 604 if out.Status != structs.NodeStatusReady { 605 t.Fatalf("bad: %#v", out) 606 } 607 if out.ModifyIndex != 801 { 608 t.Fatalf("bad: %#v", out) 609 } 610 611 index, err := state.Index("nodes") 612 if err != nil { 613 t.Fatalf("err: %v", err) 614 } 615 if index != 801 { 616 t.Fatalf("bad: %d", index) 617 } 618 619 if watchFired(ws) { 620 t.Fatalf("bad") 621 } 622 } 623 624 func TestStateStore_UpdateNodeDrain_Node(t *testing.T) { 625 state := testStateStore(t) 626 node := mock.Node() 627 628 err := state.UpsertNode(1000, node) 629 if err != nil { 630 t.Fatalf("err: %v", err) 631 } 632 633 // Create a watchset so we can test that update node drain fires the watch 634 ws := memdb.NewWatchSet() 635 if _, err := state.NodeByID(ws, node.ID); err != nil { 636 t.Fatalf("bad: %v", err) 637 } 638 639 err = state.UpdateNodeDrain(1001, node.ID, true) 640 if err != nil { 641 t.Fatalf("err: %v", err) 642 } 643 644 if !watchFired(ws) { 645 t.Fatalf("bad") 646 } 647 648 ws = memdb.NewWatchSet() 649 out, err := state.NodeByID(ws, node.ID) 650 if err != nil { 651 t.Fatalf("err: %v", err) 652 } 653 654 if !out.Drain { 655 t.Fatalf("bad: %#v", out) 656 } 657 if out.ModifyIndex != 1001 { 658 t.Fatalf("bad: %#v", out) 659 } 660 661 index, err := state.Index("nodes") 662 if err != nil { 663 t.Fatalf("err: %v", err) 664 } 665 if index != 1001 { 666 t.Fatalf("bad: %d", index) 667 } 668 669 if watchFired(ws) { 670 t.Fatalf("bad") 671 } 672 } 673 674 func TestStateStore_Nodes(t *testing.T) { 675 state := testStateStore(t) 676 var nodes []*structs.Node 677 678 for i := 0; i < 10; i++ { 679 node := mock.Node() 680 nodes = append(nodes, node) 681 682 err := state.UpsertNode(1000+uint64(i), node) 683 if err != nil { 684 t.Fatalf("err: %v", err) 685 } 686 } 687 688 // Create a watchset so we can test that getters don't cause it to fire 689 ws := memdb.NewWatchSet() 690 iter, err := state.Nodes(ws) 691 if err != nil { 692 t.Fatalf("bad: %v", err) 693 } 694 695 var out []*structs.Node 696 for { 697 raw := iter.Next() 698 if raw == nil { 699 break 700 } 701 out = append(out, raw.(*structs.Node)) 702 } 703 704 sort.Sort(NodeIDSort(nodes)) 705 sort.Sort(NodeIDSort(out)) 706 707 if !reflect.DeepEqual(nodes, out) { 708 t.Fatalf("bad: %#v %#v", nodes, out) 709 } 710 711 if watchFired(ws) { 712 t.Fatalf("bad") 713 } 714 } 715 716 func TestStateStore_NodesByIDPrefix(t *testing.T) { 717 state := testStateStore(t) 718 node := mock.Node() 719 720 node.ID = "11111111-662e-d0ab-d1c9-3e434af7bdb4" 721 err := state.UpsertNode(1000, node) 722 if err != nil { 723 t.Fatalf("err: %v", err) 724 } 725 726 // Create a watchset so we can test that getters don't cause it to fire 727 ws := memdb.NewWatchSet() 728 iter, err := state.NodesByIDPrefix(ws, node.ID) 729 if err != nil { 730 t.Fatalf("err: %v", err) 731 } 732 733 gatherNodes := func(iter memdb.ResultIterator) []*structs.Node { 734 var nodes []*structs.Node 735 for { 736 raw := iter.Next() 737 if raw == nil { 738 break 739 } 740 node := raw.(*structs.Node) 741 nodes = append(nodes, node) 742 } 743 return nodes 744 } 745 746 nodes := gatherNodes(iter) 747 if len(nodes) != 1 { 748 t.Fatalf("err: %v", err) 749 } 750 751 if watchFired(ws) { 752 t.Fatalf("bad") 753 } 754 755 iter, err = state.NodesByIDPrefix(ws, "11") 756 if err != nil { 757 t.Fatalf("err: %v", err) 758 } 759 760 nodes = gatherNodes(iter) 761 if len(nodes) != 1 { 762 t.Fatalf("err: %v", err) 763 } 764 765 node = mock.Node() 766 node.ID = "11222222-662e-d0ab-d1c9-3e434af7bdb4" 767 err = state.UpsertNode(1001, node) 768 if err != nil { 769 t.Fatalf("err: %v", err) 770 } 771 772 if !watchFired(ws) { 773 t.Fatalf("bad") 774 } 775 776 ws = memdb.NewWatchSet() 777 iter, err = state.NodesByIDPrefix(ws, "11") 778 if err != nil { 779 t.Fatalf("err: %v", err) 780 } 781 782 nodes = gatherNodes(iter) 783 if len(nodes) != 2 { 784 t.Fatalf("err: %v", err) 785 } 786 787 iter, err = state.NodesByIDPrefix(ws, "1111") 788 if err != nil { 789 t.Fatalf("err: %v", err) 790 } 791 792 nodes = gatherNodes(iter) 793 if len(nodes) != 1 { 794 t.Fatalf("err: %v", err) 795 } 796 797 if watchFired(ws) { 798 t.Fatalf("bad") 799 } 800 } 801 802 func TestStateStore_RestoreNode(t *testing.T) { 803 state := testStateStore(t) 804 node := mock.Node() 805 806 restore, err := state.Restore() 807 if err != nil { 808 t.Fatalf("err: %v", err) 809 } 810 811 err = restore.NodeRestore(node) 812 if err != nil { 813 t.Fatalf("err: %v", err) 814 } 815 restore.Commit() 816 817 ws := memdb.NewWatchSet() 818 out, err := state.NodeByID(ws, node.ID) 819 if err != nil { 820 t.Fatalf("err: %v", err) 821 } 822 823 if !reflect.DeepEqual(out, node) { 824 t.Fatalf("Bad: %#v %#v", out, node) 825 } 826 } 827 828 func TestStateStore_UpsertJob_Job(t *testing.T) { 829 state := testStateStore(t) 830 job := mock.Job() 831 832 // Create a watchset so we can test that upsert fires the watch 833 ws := memdb.NewWatchSet() 834 _, err := state.JobByID(ws, job.ID) 835 if err != nil { 836 t.Fatalf("bad: %v", err) 837 } 838 839 if err := state.UpsertJob(1000, job); err != nil { 840 t.Fatalf("err: %v", err) 841 } 842 if !watchFired(ws) { 843 t.Fatalf("bad") 844 } 845 846 ws = memdb.NewWatchSet() 847 out, err := state.JobByID(ws, job.ID) 848 if err != nil { 849 t.Fatalf("err: %v", err) 850 } 851 852 if !reflect.DeepEqual(job, out) { 853 t.Fatalf("bad: %#v %#v", job, out) 854 } 855 856 index, err := state.Index("jobs") 857 if err != nil { 858 t.Fatalf("err: %v", err) 859 } 860 if index != 1000 { 861 t.Fatalf("bad: %d", index) 862 } 863 864 summary, err := state.JobSummaryByID(ws, job.ID) 865 if err != nil { 866 t.Fatalf("err: %v", err) 867 } 868 if summary == nil { 869 t.Fatalf("nil summary") 870 } 871 if summary.JobID != job.ID { 872 t.Fatalf("bad summary id: %v", summary.JobID) 873 } 874 _, ok := summary.Summary["web"] 875 if !ok { 876 t.Fatalf("nil summary for task group") 877 } 878 if watchFired(ws) { 879 t.Fatalf("bad") 880 } 881 882 // Check the job versions 883 allVersions, err := state.JobVersionsByID(ws, job.ID) 884 if err != nil { 885 t.Fatalf("err: %v", err) 886 } 887 if len(allVersions) != 1 { 888 t.Fatalf("got %d; want 1", len(allVersions)) 889 } 890 891 if a := allVersions[0]; a.ID != job.ID || a.Version != 0 { 892 t.Fatalf("bad: %v", a) 893 } 894 895 // Test the looking up the job by version returns the same results 896 vout, err := state.JobByIDAndVersion(ws, job.ID, 0) 897 if err != nil { 898 t.Fatalf("err: %v", err) 899 } 900 901 if !reflect.DeepEqual(out, vout) { 902 t.Fatalf("bad: %#v %#v", out, vout) 903 } 904 } 905 906 func TestStateStore_UpdateUpsertJob_Job(t *testing.T) { 907 state := testStateStore(t) 908 job := mock.Job() 909 910 // Create a watchset so we can test that upsert fires the watch 911 ws := memdb.NewWatchSet() 912 _, err := state.JobByID(ws, job.ID) 913 if err != nil { 914 t.Fatalf("bad: %v", err) 915 } 916 917 if err := state.UpsertJob(1000, job); err != nil { 918 t.Fatalf("err: %v", err) 919 } 920 921 job2 := mock.Job() 922 job2.ID = job.ID 923 job2.AllAtOnce = true 924 err = state.UpsertJob(1001, job2) 925 if err != nil { 926 t.Fatalf("err: %v", err) 927 } 928 929 if !watchFired(ws) { 930 t.Fatalf("bad") 931 } 932 933 ws = memdb.NewWatchSet() 934 out, err := state.JobByID(ws, job.ID) 935 if err != nil { 936 t.Fatalf("err: %v", err) 937 } 938 939 if !reflect.DeepEqual(job2, out) { 940 t.Fatalf("bad: %#v %#v", job2, out) 941 } 942 943 if out.CreateIndex != 1000 { 944 t.Fatalf("bad: %#v", out) 945 } 946 if out.ModifyIndex != 1001 { 947 t.Fatalf("bad: %#v", out) 948 } 949 if out.Version != 1 { 950 t.Fatalf("bad: %#v", out) 951 } 952 953 index, err := state.Index("jobs") 954 if err != nil { 955 t.Fatalf("err: %v", err) 956 } 957 if index != 1001 { 958 t.Fatalf("bad: %d", index) 959 } 960 961 // Test the looking up the job by version returns the same results 962 vout, err := state.JobByIDAndVersion(ws, job.ID, 1) 963 if err != nil { 964 t.Fatalf("err: %v", err) 965 } 966 967 if !reflect.DeepEqual(out, vout) { 968 t.Fatalf("bad: %#v %#v", out, vout) 969 } 970 971 // Test that the job summary remains the same if the job is updated but 972 // count remains same 973 summary, err := state.JobSummaryByID(ws, job.ID) 974 if err != nil { 975 t.Fatalf("err: %v", err) 976 } 977 if summary == nil { 978 t.Fatalf("nil summary") 979 } 980 if summary.JobID != job.ID { 981 t.Fatalf("bad summary id: %v", summary.JobID) 982 } 983 _, ok := summary.Summary["web"] 984 if !ok { 985 t.Fatalf("nil summary for task group") 986 } 987 988 // Check the job versions 989 allVersions, err := state.JobVersionsByID(ws, job.ID) 990 if err != nil { 991 t.Fatalf("err: %v", err) 992 } 993 if len(allVersions) != 2 { 994 t.Fatalf("got %d; want 1", len(allVersions)) 995 } 996 997 if a := allVersions[0]; a.ID != job.ID || a.Version != 1 || !a.AllAtOnce { 998 t.Fatalf("bad: %+v", a) 999 } 1000 if a := allVersions[1]; a.ID != job.ID || a.Version != 0 || a.AllAtOnce { 1001 t.Fatalf("bad: %+v", a) 1002 } 1003 1004 if watchFired(ws) { 1005 t.Fatalf("bad") 1006 } 1007 } 1008 1009 func TestStateStore_UpdateUpsertJob_PeriodicJob(t *testing.T) { 1010 state := testStateStore(t) 1011 job := mock.PeriodicJob() 1012 1013 // Create a watchset so we can test that upsert fires the watch 1014 ws := memdb.NewWatchSet() 1015 _, err := state.JobByID(ws, job.ID) 1016 if err != nil { 1017 t.Fatalf("bad: %v", err) 1018 } 1019 1020 if err := state.UpsertJob(1000, job); err != nil { 1021 t.Fatalf("err: %v", err) 1022 } 1023 1024 // Create a child and an evaluation 1025 job2 := job.Copy() 1026 job2.Periodic = nil 1027 job2.ID = fmt.Sprintf("%v/%s-1490635020", job.ID, structs.PeriodicLaunchSuffix) 1028 err = state.UpsertJob(1001, job2) 1029 if err != nil { 1030 t.Fatalf("err: %v", err) 1031 } 1032 1033 eval := mock.Eval() 1034 eval.JobID = job2.ID 1035 err = state.UpsertEvals(1002, []*structs.Evaluation{eval}) 1036 if err != nil { 1037 t.Fatalf("err: %v", err) 1038 } 1039 1040 job3 := job.Copy() 1041 job3.TaskGroups[0].Tasks[0].Name = "new name" 1042 err = state.UpsertJob(1003, job3) 1043 if err != nil { 1044 t.Fatalf("err: %v", err) 1045 } 1046 1047 if !watchFired(ws) { 1048 t.Fatalf("bad") 1049 } 1050 1051 ws = memdb.NewWatchSet() 1052 out, err := state.JobByID(ws, job.ID) 1053 if err != nil { 1054 t.Fatalf("err: %v", err) 1055 } 1056 1057 if s, e := out.Status, structs.JobStatusRunning; s != e { 1058 t.Fatalf("got status %v; want %v", s, e) 1059 } 1060 1061 } 1062 1063 // This test ensures that UpsertJob creates the EphemeralDisk is a job doesn't have 1064 // one and clear out the task's disk resource asks 1065 // COMPAT 0.4.1 -> 0.5 1066 func TestStateStore_UpsertJob_NoEphemeralDisk(t *testing.T) { 1067 state := testStateStore(t) 1068 job := mock.Job() 1069 1070 // Set the EphemeralDisk to nil and set the tasks's DiskMB to 150 1071 job.TaskGroups[0].EphemeralDisk = nil 1072 job.TaskGroups[0].Tasks[0].Resources.DiskMB = 150 1073 1074 err := state.UpsertJob(1000, job) 1075 if err != nil { 1076 t.Fatalf("err: %v", err) 1077 } 1078 1079 ws := memdb.NewWatchSet() 1080 out, err := state.JobByID(ws, job.ID) 1081 if err != nil { 1082 t.Fatalf("err: %v", err) 1083 } 1084 1085 // Expect the state store to create the EphemeralDisk and clear out Tasks's 1086 // DiskMB 1087 expected := job.Copy() 1088 expected.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{ 1089 SizeMB: 150, 1090 } 1091 expected.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 1092 1093 if !reflect.DeepEqual(expected, out) { 1094 t.Fatalf("bad: %#v %#v", expected, out) 1095 } 1096 } 1097 1098 // Upsert a job that is the child of a parent job and ensures its summary gets 1099 // updated. 1100 func TestStateStore_UpsertJob_ChildJob(t *testing.T) { 1101 state := testStateStore(t) 1102 1103 // Create a watchset so we can test that upsert fires the watch 1104 parent := mock.Job() 1105 ws := memdb.NewWatchSet() 1106 _, err := state.JobByID(ws, parent.ID) 1107 if err != nil { 1108 t.Fatalf("bad: %v", err) 1109 } 1110 1111 if err := state.UpsertJob(1000, parent); err != nil { 1112 t.Fatalf("err: %v", err) 1113 } 1114 1115 child := mock.Job() 1116 child.ParentID = parent.ID 1117 if err := state.UpsertJob(1001, child); err != nil { 1118 t.Fatalf("err: %v", err) 1119 } 1120 1121 summary, err := state.JobSummaryByID(ws, parent.ID) 1122 if err != nil { 1123 t.Fatalf("err: %v", err) 1124 } 1125 if summary == nil { 1126 t.Fatalf("nil summary") 1127 } 1128 if summary.JobID != parent.ID { 1129 t.Fatalf("bad summary id: %v", parent.ID) 1130 } 1131 if summary.Children == nil { 1132 t.Fatalf("nil children summary") 1133 } 1134 if summary.Children.Pending != 1 || summary.Children.Running != 0 || summary.Children.Dead != 0 { 1135 t.Fatalf("bad children summary: %v", summary.Children) 1136 } 1137 if !watchFired(ws) { 1138 t.Fatalf("bad") 1139 } 1140 } 1141 1142 func TestStateStore_UpdateUpsertJob_JobVersion(t *testing.T) { 1143 state := testStateStore(t) 1144 1145 // Create a job and mark it as stable 1146 job := mock.Job() 1147 job.Stable = true 1148 job.Priority = 0 1149 1150 // Create a watchset so we can test that upsert fires the watch 1151 ws := memdb.NewWatchSet() 1152 _, err := state.JobVersionsByID(ws, job.ID) 1153 if err != nil { 1154 t.Fatalf("bad: %v", err) 1155 } 1156 1157 if err := state.UpsertJob(1000, job); err != nil { 1158 t.Fatalf("err: %v", err) 1159 } 1160 1161 if !watchFired(ws) { 1162 t.Fatalf("bad") 1163 } 1164 1165 var finalJob *structs.Job 1166 for i := 1; i < 20; i++ { 1167 finalJob = mock.Job() 1168 finalJob.ID = job.ID 1169 finalJob.Priority = i 1170 err = state.UpsertJob(uint64(1000+i), finalJob) 1171 if err != nil { 1172 t.Fatalf("err: %v", err) 1173 } 1174 } 1175 1176 ws = memdb.NewWatchSet() 1177 out, err := state.JobByID(ws, job.ID) 1178 if err != nil { 1179 t.Fatalf("err: %v", err) 1180 } 1181 1182 if !reflect.DeepEqual(finalJob, out) { 1183 t.Fatalf("bad: %#v %#v", finalJob, out) 1184 } 1185 1186 if out.CreateIndex != 1000 { 1187 t.Fatalf("bad: %#v", out) 1188 } 1189 if out.ModifyIndex != 1019 { 1190 t.Fatalf("bad: %#v", out) 1191 } 1192 if out.Version != 19 { 1193 t.Fatalf("bad: %#v", out) 1194 } 1195 1196 index, err := state.Index("job_version") 1197 if err != nil { 1198 t.Fatalf("err: %v", err) 1199 } 1200 if index != 1019 { 1201 t.Fatalf("bad: %d", index) 1202 } 1203 1204 // Check the job versions 1205 allVersions, err := state.JobVersionsByID(ws, job.ID) 1206 if err != nil { 1207 t.Fatalf("err: %v", err) 1208 } 1209 if len(allVersions) != structs.JobTrackedVersions { 1210 t.Fatalf("got %d; want 1", len(allVersions)) 1211 } 1212 1213 if a := allVersions[0]; a.ID != job.ID || a.Version != 19 || a.Priority != 19 { 1214 t.Fatalf("bad: %+v", a) 1215 } 1216 if a := allVersions[1]; a.ID != job.ID || a.Version != 18 || a.Priority != 18 { 1217 t.Fatalf("bad: %+v", a) 1218 } 1219 1220 // Ensure we didn't delete the stable job 1221 if a := allVersions[structs.JobTrackedVersions-1]; a.ID != job.ID || 1222 a.Version != 0 || a.Priority != 0 || !a.Stable { 1223 t.Fatalf("bad: %+v", a) 1224 } 1225 1226 if watchFired(ws) { 1227 t.Fatalf("bad") 1228 } 1229 } 1230 1231 func TestStateStore_DeleteJob_Job(t *testing.T) { 1232 state := testStateStore(t) 1233 job := mock.Job() 1234 1235 err := state.UpsertJob(1000, job) 1236 if err != nil { 1237 t.Fatalf("err: %v", err) 1238 } 1239 1240 // Create a watchset so we can test that delete fires the watch 1241 ws := memdb.NewWatchSet() 1242 if _, err := state.JobByID(ws, job.ID); err != nil { 1243 t.Fatalf("bad: %v", err) 1244 } 1245 1246 err = state.DeleteJob(1001, job.ID) 1247 if err != nil { 1248 t.Fatalf("err: %v", err) 1249 } 1250 1251 if !watchFired(ws) { 1252 t.Fatalf("bad") 1253 } 1254 1255 ws = memdb.NewWatchSet() 1256 out, err := state.JobByID(ws, job.ID) 1257 if err != nil { 1258 t.Fatalf("err: %v", err) 1259 } 1260 1261 if out != nil { 1262 t.Fatalf("bad: %#v %#v", job, out) 1263 } 1264 1265 index, err := state.Index("jobs") 1266 if err != nil { 1267 t.Fatalf("err: %v", err) 1268 } 1269 if index != 1001 { 1270 t.Fatalf("bad: %d", index) 1271 } 1272 1273 summary, err := state.JobSummaryByID(ws, job.ID) 1274 if err != nil { 1275 t.Fatalf("err: %v", err) 1276 } 1277 if summary != nil { 1278 t.Fatalf("expected summary to be nil, but got: %v", summary) 1279 } 1280 1281 index, err = state.Index("job_summary") 1282 if err != nil { 1283 t.Fatalf("err: %v", err) 1284 } 1285 if index != 1001 { 1286 t.Fatalf("bad: %d", index) 1287 } 1288 1289 versions, err := state.JobVersionsByID(ws, job.ID) 1290 if err != nil { 1291 t.Fatalf("err: %v", err) 1292 } 1293 if len(versions) != 0 { 1294 t.Fatalf("expected no job versions") 1295 } 1296 1297 index, err = state.Index("job_summary") 1298 if err != nil { 1299 t.Fatalf("err: %v", err) 1300 } 1301 if index != 1001 { 1302 t.Fatalf("bad: %d", index) 1303 } 1304 1305 if watchFired(ws) { 1306 t.Fatalf("bad") 1307 } 1308 } 1309 1310 func TestStateStore_DeleteJob_ChildJob(t *testing.T) { 1311 state := testStateStore(t) 1312 1313 parent := mock.Job() 1314 if err := state.UpsertJob(998, parent); err != nil { 1315 t.Fatalf("err: %v", err) 1316 } 1317 1318 child := mock.Job() 1319 child.ParentID = parent.ID 1320 1321 if err := state.UpsertJob(999, child); err != nil { 1322 t.Fatalf("err: %v", err) 1323 } 1324 1325 // Create a watchset so we can test that delete fires the watch 1326 ws := memdb.NewWatchSet() 1327 if _, err := state.JobSummaryByID(ws, parent.ID); err != nil { 1328 t.Fatalf("bad: %v", err) 1329 } 1330 1331 err := state.DeleteJob(1001, child.ID) 1332 if err != nil { 1333 t.Fatalf("err: %v", err) 1334 } 1335 if !watchFired(ws) { 1336 t.Fatalf("bad") 1337 } 1338 1339 ws = memdb.NewWatchSet() 1340 summary, err := state.JobSummaryByID(ws, parent.ID) 1341 if err != nil { 1342 t.Fatalf("err: %v", err) 1343 } 1344 if summary == nil { 1345 t.Fatalf("nil summary") 1346 } 1347 if summary.JobID != parent.ID { 1348 t.Fatalf("bad summary id: %v", parent.ID) 1349 } 1350 if summary.Children == nil { 1351 t.Fatalf("nil children summary") 1352 } 1353 if summary.Children.Pending != 0 || summary.Children.Running != 0 || summary.Children.Dead != 1 { 1354 t.Fatalf("bad children summary: %v", summary.Children) 1355 } 1356 if watchFired(ws) { 1357 t.Fatalf("bad") 1358 } 1359 } 1360 1361 func TestStateStore_Jobs(t *testing.T) { 1362 state := testStateStore(t) 1363 var jobs []*structs.Job 1364 1365 for i := 0; i < 10; i++ { 1366 job := mock.Job() 1367 jobs = append(jobs, job) 1368 1369 err := state.UpsertJob(1000+uint64(i), job) 1370 if err != nil { 1371 t.Fatalf("err: %v", err) 1372 } 1373 } 1374 1375 ws := memdb.NewWatchSet() 1376 iter, err := state.Jobs(ws) 1377 if err != nil { 1378 t.Fatalf("err: %v", err) 1379 } 1380 1381 var out []*structs.Job 1382 for { 1383 raw := iter.Next() 1384 if raw == nil { 1385 break 1386 } 1387 out = append(out, raw.(*structs.Job)) 1388 } 1389 1390 sort.Sort(JobIDSort(jobs)) 1391 sort.Sort(JobIDSort(out)) 1392 1393 if !reflect.DeepEqual(jobs, out) { 1394 t.Fatalf("bad: %#v %#v", jobs, out) 1395 } 1396 if watchFired(ws) { 1397 t.Fatalf("bad") 1398 } 1399 } 1400 1401 func TestStateStore_JobVersions(t *testing.T) { 1402 state := testStateStore(t) 1403 var jobs []*structs.Job 1404 1405 for i := 0; i < 10; i++ { 1406 job := mock.Job() 1407 jobs = append(jobs, job) 1408 1409 err := state.UpsertJob(1000+uint64(i), job) 1410 if err != nil { 1411 t.Fatalf("err: %v", err) 1412 } 1413 } 1414 1415 ws := memdb.NewWatchSet() 1416 iter, err := state.JobVersions(ws) 1417 if err != nil { 1418 t.Fatalf("err: %v", err) 1419 } 1420 1421 var out []*structs.Job 1422 for { 1423 raw := iter.Next() 1424 if raw == nil { 1425 break 1426 } 1427 out = append(out, raw.(*structs.Job)) 1428 } 1429 1430 sort.Sort(JobIDSort(jobs)) 1431 sort.Sort(JobIDSort(out)) 1432 1433 if !reflect.DeepEqual(jobs, out) { 1434 t.Fatalf("bad: %#v %#v", jobs, out) 1435 } 1436 if watchFired(ws) { 1437 t.Fatalf("bad") 1438 } 1439 } 1440 1441 func TestStateStore_JobsByIDPrefix(t *testing.T) { 1442 state := testStateStore(t) 1443 job := mock.Job() 1444 1445 job.ID = "redis" 1446 err := state.UpsertJob(1000, job) 1447 if err != nil { 1448 t.Fatalf("err: %v", err) 1449 } 1450 1451 ws := memdb.NewWatchSet() 1452 iter, err := state.JobsByIDPrefix(ws, job.ID) 1453 if err != nil { 1454 t.Fatalf("err: %v", err) 1455 } 1456 1457 gatherJobs := func(iter memdb.ResultIterator) []*structs.Job { 1458 var jobs []*structs.Job 1459 for { 1460 raw := iter.Next() 1461 if raw == nil { 1462 break 1463 } 1464 jobs = append(jobs, raw.(*structs.Job)) 1465 } 1466 return jobs 1467 } 1468 1469 jobs := gatherJobs(iter) 1470 if len(jobs) != 1 { 1471 t.Fatalf("err: %v", err) 1472 } 1473 1474 iter, err = state.JobsByIDPrefix(ws, "re") 1475 if err != nil { 1476 t.Fatalf("err: %v", err) 1477 } 1478 1479 jobs = gatherJobs(iter) 1480 if len(jobs) != 1 { 1481 t.Fatalf("err: %v", err) 1482 } 1483 if watchFired(ws) { 1484 t.Fatalf("bad") 1485 } 1486 1487 job = mock.Job() 1488 job.ID = "riak" 1489 err = state.UpsertJob(1001, job) 1490 if err != nil { 1491 t.Fatalf("err: %v", err) 1492 } 1493 1494 if !watchFired(ws) { 1495 t.Fatalf("bad") 1496 } 1497 1498 ws = memdb.NewWatchSet() 1499 iter, err = state.JobsByIDPrefix(ws, "r") 1500 if err != nil { 1501 t.Fatalf("err: %v", err) 1502 } 1503 1504 jobs = gatherJobs(iter) 1505 if len(jobs) != 2 { 1506 t.Fatalf("err: %v", err) 1507 } 1508 1509 iter, err = state.JobsByIDPrefix(ws, "ri") 1510 if err != nil { 1511 t.Fatalf("err: %v", err) 1512 } 1513 1514 jobs = gatherJobs(iter) 1515 if len(jobs) != 1 { 1516 t.Fatalf("err: %v", err) 1517 } 1518 if watchFired(ws) { 1519 t.Fatalf("bad") 1520 } 1521 } 1522 1523 func TestStateStore_JobsByPeriodic(t *testing.T) { 1524 state := testStateStore(t) 1525 var periodic, nonPeriodic []*structs.Job 1526 1527 for i := 0; i < 10; i++ { 1528 job := mock.Job() 1529 nonPeriodic = append(nonPeriodic, job) 1530 1531 err := state.UpsertJob(1000+uint64(i), job) 1532 if err != nil { 1533 t.Fatalf("err: %v", err) 1534 } 1535 } 1536 1537 for i := 0; i < 10; i++ { 1538 job := mock.PeriodicJob() 1539 periodic = append(periodic, job) 1540 1541 err := state.UpsertJob(2000+uint64(i), job) 1542 if err != nil { 1543 t.Fatalf("err: %v", err) 1544 } 1545 } 1546 1547 ws := memdb.NewWatchSet() 1548 iter, err := state.JobsByPeriodic(ws, true) 1549 if err != nil { 1550 t.Fatalf("err: %v", err) 1551 } 1552 1553 var outPeriodic []*structs.Job 1554 for { 1555 raw := iter.Next() 1556 if raw == nil { 1557 break 1558 } 1559 outPeriodic = append(outPeriodic, raw.(*structs.Job)) 1560 } 1561 1562 iter, err = state.JobsByPeriodic(ws, false) 1563 if err != nil { 1564 t.Fatalf("err: %v", err) 1565 } 1566 1567 var outNonPeriodic []*structs.Job 1568 for { 1569 raw := iter.Next() 1570 if raw == nil { 1571 break 1572 } 1573 outNonPeriodic = append(outNonPeriodic, raw.(*structs.Job)) 1574 } 1575 1576 sort.Sort(JobIDSort(periodic)) 1577 sort.Sort(JobIDSort(nonPeriodic)) 1578 sort.Sort(JobIDSort(outPeriodic)) 1579 sort.Sort(JobIDSort(outNonPeriodic)) 1580 1581 if !reflect.DeepEqual(periodic, outPeriodic) { 1582 t.Fatalf("bad: %#v %#v", periodic, outPeriodic) 1583 } 1584 1585 if !reflect.DeepEqual(nonPeriodic, outNonPeriodic) { 1586 t.Fatalf("bad: %#v %#v", nonPeriodic, outNonPeriodic) 1587 } 1588 if watchFired(ws) { 1589 t.Fatalf("bad") 1590 } 1591 } 1592 1593 func TestStateStore_JobsByScheduler(t *testing.T) { 1594 state := testStateStore(t) 1595 var serviceJobs []*structs.Job 1596 var sysJobs []*structs.Job 1597 1598 for i := 0; i < 10; i++ { 1599 job := mock.Job() 1600 serviceJobs = append(serviceJobs, job) 1601 1602 err := state.UpsertJob(1000+uint64(i), job) 1603 if err != nil { 1604 t.Fatalf("err: %v", err) 1605 } 1606 } 1607 1608 for i := 0; i < 10; i++ { 1609 job := mock.SystemJob() 1610 job.Status = structs.JobStatusRunning 1611 sysJobs = append(sysJobs, job) 1612 1613 err := state.UpsertJob(2000+uint64(i), job) 1614 if err != nil { 1615 t.Fatalf("err: %v", err) 1616 } 1617 } 1618 1619 ws := memdb.NewWatchSet() 1620 iter, err := state.JobsByScheduler(ws, "service") 1621 if err != nil { 1622 t.Fatalf("err: %v", err) 1623 } 1624 1625 var outService []*structs.Job 1626 for { 1627 raw := iter.Next() 1628 if raw == nil { 1629 break 1630 } 1631 outService = append(outService, raw.(*structs.Job)) 1632 } 1633 1634 iter, err = state.JobsByScheduler(ws, "system") 1635 if err != nil { 1636 t.Fatalf("err: %v", err) 1637 } 1638 1639 var outSystem []*structs.Job 1640 for { 1641 raw := iter.Next() 1642 if raw == nil { 1643 break 1644 } 1645 outSystem = append(outSystem, raw.(*structs.Job)) 1646 } 1647 1648 sort.Sort(JobIDSort(serviceJobs)) 1649 sort.Sort(JobIDSort(sysJobs)) 1650 sort.Sort(JobIDSort(outService)) 1651 sort.Sort(JobIDSort(outSystem)) 1652 1653 if !reflect.DeepEqual(serviceJobs, outService) { 1654 t.Fatalf("bad: %#v %#v", serviceJobs, outService) 1655 } 1656 1657 if !reflect.DeepEqual(sysJobs, outSystem) { 1658 t.Fatalf("bad: %#v %#v", sysJobs, outSystem) 1659 } 1660 if watchFired(ws) { 1661 t.Fatalf("bad") 1662 } 1663 } 1664 1665 func TestStateStore_JobsByGC(t *testing.T) { 1666 state := testStateStore(t) 1667 gc, nonGc := make(map[string]struct{}), make(map[string]struct{}) 1668 1669 for i := 0; i < 20; i++ { 1670 var job *structs.Job 1671 if i%2 == 0 { 1672 job = mock.Job() 1673 } else { 1674 job = mock.PeriodicJob() 1675 } 1676 nonGc[job.ID] = struct{}{} 1677 1678 if err := state.UpsertJob(1000+uint64(i), job); err != nil { 1679 t.Fatalf("err: %v", err) 1680 } 1681 } 1682 1683 for i := 0; i < 20; i += 2 { 1684 job := mock.Job() 1685 job.Type = structs.JobTypeBatch 1686 gc[job.ID] = struct{}{} 1687 1688 if err := state.UpsertJob(2000+uint64(i), job); err != nil { 1689 t.Fatalf("err: %v", err) 1690 } 1691 1692 // Create an eval for it 1693 eval := mock.Eval() 1694 eval.JobID = job.ID 1695 eval.Status = structs.EvalStatusComplete 1696 if err := state.UpsertEvals(2000+uint64(i+1), []*structs.Evaluation{eval}); err != nil { 1697 t.Fatalf("err: %v", err) 1698 } 1699 1700 } 1701 1702 ws := memdb.NewWatchSet() 1703 iter, err := state.JobsByGC(ws, true) 1704 if err != nil { 1705 t.Fatalf("err: %v", err) 1706 } 1707 1708 outGc := make(map[string]struct{}) 1709 for i := iter.Next(); i != nil; i = iter.Next() { 1710 j := i.(*structs.Job) 1711 outGc[j.ID] = struct{}{} 1712 } 1713 1714 iter, err = state.JobsByGC(ws, false) 1715 if err != nil { 1716 t.Fatalf("err: %v", err) 1717 } 1718 1719 outNonGc := make(map[string]struct{}) 1720 for i := iter.Next(); i != nil; i = iter.Next() { 1721 j := i.(*structs.Job) 1722 outNonGc[j.ID] = struct{}{} 1723 } 1724 1725 if !reflect.DeepEqual(gc, outGc) { 1726 t.Fatalf("bad: %#v %#v", gc, outGc) 1727 } 1728 1729 if !reflect.DeepEqual(nonGc, outNonGc) { 1730 t.Fatalf("bad: %#v %#v", nonGc, outNonGc) 1731 } 1732 if watchFired(ws) { 1733 t.Fatalf("bad") 1734 } 1735 } 1736 1737 func TestStateStore_RestoreJob(t *testing.T) { 1738 state := testStateStore(t) 1739 job := mock.Job() 1740 1741 restore, err := state.Restore() 1742 if err != nil { 1743 t.Fatalf("err: %v", err) 1744 } 1745 1746 err = restore.JobRestore(job) 1747 if err != nil { 1748 t.Fatalf("err: %v", err) 1749 } 1750 restore.Commit() 1751 1752 ws := memdb.NewWatchSet() 1753 out, err := state.JobByID(ws, job.ID) 1754 if err != nil { 1755 t.Fatalf("err: %v", err) 1756 } 1757 1758 if !reflect.DeepEqual(out, job) { 1759 t.Fatalf("Bad: %#v %#v", out, job) 1760 } 1761 } 1762 1763 // This test ensures that the state restore creates the EphemeralDisk for a job if 1764 // it doesn't have one 1765 // COMPAT 0.4.1 -> 0.5 1766 func TestStateStore_Jobs_NoEphemeralDisk(t *testing.T) { 1767 state := testStateStore(t) 1768 job := mock.Job() 1769 1770 // Set EphemeralDisk to nil and set the DiskMB to 150 1771 job.TaskGroups[0].EphemeralDisk = nil 1772 job.TaskGroups[0].Tasks[0].Resources.DiskMB = 150 1773 1774 restore, err := state.Restore() 1775 if err != nil { 1776 t.Fatalf("err: %v", err) 1777 } 1778 1779 err = restore.JobRestore(job) 1780 if err != nil { 1781 t.Fatalf("err: %v", err) 1782 } 1783 restore.Commit() 1784 1785 ws := memdb.NewWatchSet() 1786 out, err := state.JobByID(ws, job.ID) 1787 if err != nil { 1788 t.Fatalf("err: %v", err) 1789 } 1790 1791 // Expect job to have local disk and clear out the task's disk resource ask 1792 expected := job.Copy() 1793 expected.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{ 1794 SizeMB: 150, 1795 } 1796 expected.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 1797 if !reflect.DeepEqual(out, expected) { 1798 t.Fatalf("Bad: %#v %#v", out, job) 1799 } 1800 } 1801 1802 func TestStateStore_UpsertPeriodicLaunch(t *testing.T) { 1803 state := testStateStore(t) 1804 job := mock.Job() 1805 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 1806 1807 // Create a watchset so we can test that upsert fires the watch 1808 ws := memdb.NewWatchSet() 1809 if _, err := state.PeriodicLaunchByID(ws, launch.ID); err != nil { 1810 t.Fatalf("bad: %v", err) 1811 } 1812 1813 err := state.UpsertPeriodicLaunch(1000, launch) 1814 if err != nil { 1815 t.Fatalf("err: %v", err) 1816 } 1817 1818 if !watchFired(ws) { 1819 t.Fatalf("bad") 1820 } 1821 1822 ws = memdb.NewWatchSet() 1823 out, err := state.PeriodicLaunchByID(ws, job.ID) 1824 if err != nil { 1825 t.Fatalf("err: %v", err) 1826 } 1827 if out.CreateIndex != 1000 { 1828 t.Fatalf("bad: %#v", out) 1829 } 1830 if out.ModifyIndex != 1000 { 1831 t.Fatalf("bad: %#v", out) 1832 } 1833 1834 if !reflect.DeepEqual(launch, out) { 1835 t.Fatalf("bad: %#v %#v", job, out) 1836 } 1837 1838 index, err := state.Index("periodic_launch") 1839 if err != nil { 1840 t.Fatalf("err: %v", err) 1841 } 1842 if index != 1000 { 1843 t.Fatalf("bad: %d", index) 1844 } 1845 1846 if watchFired(ws) { 1847 t.Fatalf("bad") 1848 } 1849 } 1850 1851 func TestStateStore_UpdateUpsertPeriodicLaunch(t *testing.T) { 1852 state := testStateStore(t) 1853 job := mock.Job() 1854 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 1855 1856 err := state.UpsertPeriodicLaunch(1000, launch) 1857 if err != nil { 1858 t.Fatalf("err: %v", err) 1859 } 1860 1861 // Create a watchset so we can test that upsert fires the watch 1862 ws := memdb.NewWatchSet() 1863 if _, err := state.PeriodicLaunchByID(ws, launch.ID); err != nil { 1864 t.Fatalf("bad: %v", err) 1865 } 1866 1867 launch2 := &structs.PeriodicLaunch{ 1868 ID: job.ID, 1869 Launch: launch.Launch.Add(1 * time.Second), 1870 } 1871 err = state.UpsertPeriodicLaunch(1001, launch2) 1872 if err != nil { 1873 t.Fatalf("err: %v", err) 1874 } 1875 1876 if !watchFired(ws) { 1877 t.Fatalf("bad") 1878 } 1879 1880 ws = memdb.NewWatchSet() 1881 out, err := state.PeriodicLaunchByID(ws, job.ID) 1882 if err != nil { 1883 t.Fatalf("err: %v", err) 1884 } 1885 if out.CreateIndex != 1000 { 1886 t.Fatalf("bad: %#v", out) 1887 } 1888 if out.ModifyIndex != 1001 { 1889 t.Fatalf("bad: %#v", out) 1890 } 1891 1892 if !reflect.DeepEqual(launch2, out) { 1893 t.Fatalf("bad: %#v %#v", launch2, out) 1894 } 1895 1896 index, err := state.Index("periodic_launch") 1897 if err != nil { 1898 t.Fatalf("err: %v", err) 1899 } 1900 if index != 1001 { 1901 t.Fatalf("bad: %d", index) 1902 } 1903 1904 if watchFired(ws) { 1905 t.Fatalf("bad") 1906 } 1907 } 1908 1909 func TestStateStore_DeletePeriodicLaunch(t *testing.T) { 1910 state := testStateStore(t) 1911 job := mock.Job() 1912 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 1913 1914 err := state.UpsertPeriodicLaunch(1000, launch) 1915 if err != nil { 1916 t.Fatalf("err: %v", err) 1917 } 1918 1919 // Create a watchset so we can test that delete fires the watch 1920 ws := memdb.NewWatchSet() 1921 if _, err := state.PeriodicLaunchByID(ws, launch.ID); err != nil { 1922 t.Fatalf("bad: %v", err) 1923 } 1924 1925 err = state.DeletePeriodicLaunch(1001, launch.ID) 1926 if err != nil { 1927 t.Fatalf("err: %v", err) 1928 } 1929 1930 if !watchFired(ws) { 1931 t.Fatalf("bad") 1932 } 1933 1934 ws = memdb.NewWatchSet() 1935 out, err := state.PeriodicLaunchByID(ws, job.ID) 1936 if err != nil { 1937 t.Fatalf("err: %v", err) 1938 } 1939 1940 if out != nil { 1941 t.Fatalf("bad: %#v %#v", job, out) 1942 } 1943 1944 index, err := state.Index("periodic_launch") 1945 if err != nil { 1946 t.Fatalf("err: %v", err) 1947 } 1948 if index != 1001 { 1949 t.Fatalf("bad: %d", index) 1950 } 1951 1952 if watchFired(ws) { 1953 t.Fatalf("bad") 1954 } 1955 } 1956 1957 func TestStateStore_PeriodicLaunches(t *testing.T) { 1958 state := testStateStore(t) 1959 var launches []*structs.PeriodicLaunch 1960 1961 for i := 0; i < 10; i++ { 1962 job := mock.Job() 1963 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 1964 launches = append(launches, launch) 1965 1966 err := state.UpsertPeriodicLaunch(1000+uint64(i), launch) 1967 if err != nil { 1968 t.Fatalf("err: %v", err) 1969 } 1970 } 1971 1972 ws := memdb.NewWatchSet() 1973 iter, err := state.PeriodicLaunches(ws) 1974 if err != nil { 1975 t.Fatalf("err: %v", err) 1976 } 1977 1978 out := make(map[string]*structs.PeriodicLaunch, 10) 1979 for { 1980 raw := iter.Next() 1981 if raw == nil { 1982 break 1983 } 1984 launch := raw.(*structs.PeriodicLaunch) 1985 if _, ok := out[launch.ID]; ok { 1986 t.Fatalf("duplicate: %v", launch.ID) 1987 } 1988 1989 out[launch.ID] = launch 1990 } 1991 1992 for _, launch := range launches { 1993 l, ok := out[launch.ID] 1994 if !ok { 1995 t.Fatalf("bad %v", launch.ID) 1996 } 1997 1998 if !reflect.DeepEqual(launch, l) { 1999 t.Fatalf("bad: %#v %#v", launch, l) 2000 } 2001 2002 delete(out, launch.ID) 2003 } 2004 2005 if len(out) != 0 { 2006 t.Fatalf("leftover: %#v", out) 2007 } 2008 2009 if watchFired(ws) { 2010 t.Fatalf("bad") 2011 } 2012 } 2013 2014 func TestStateStore_RestorePeriodicLaunch(t *testing.T) { 2015 state := testStateStore(t) 2016 job := mock.Job() 2017 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 2018 2019 restore, err := state.Restore() 2020 if err != nil { 2021 t.Fatalf("err: %v", err) 2022 } 2023 2024 err = restore.PeriodicLaunchRestore(launch) 2025 if err != nil { 2026 t.Fatalf("err: %v", err) 2027 } 2028 restore.Commit() 2029 2030 ws := memdb.NewWatchSet() 2031 out, err := state.PeriodicLaunchByID(ws, job.ID) 2032 if err != nil { 2033 t.Fatalf("err: %v", err) 2034 } 2035 2036 if !reflect.DeepEqual(out, launch) { 2037 t.Fatalf("Bad: %#v %#v", out, job) 2038 } 2039 2040 if watchFired(ws) { 2041 t.Fatalf("bad") 2042 } 2043 } 2044 2045 func TestStateStore_RestoreJobVersion(t *testing.T) { 2046 state := testStateStore(t) 2047 job := mock.Job() 2048 2049 restore, err := state.Restore() 2050 if err != nil { 2051 t.Fatalf("err: %v", err) 2052 } 2053 2054 err = restore.JobVersionRestore(job) 2055 if err != nil { 2056 t.Fatalf("err: %v", err) 2057 } 2058 restore.Commit() 2059 2060 ws := memdb.NewWatchSet() 2061 out, err := state.JobByIDAndVersion(ws, job.ID, job.Version) 2062 if err != nil { 2063 t.Fatalf("err: %v", err) 2064 } 2065 2066 if !reflect.DeepEqual(out, job) { 2067 t.Fatalf("Bad: %#v %#v", out, job) 2068 } 2069 2070 if watchFired(ws) { 2071 t.Fatalf("bad") 2072 } 2073 } 2074 2075 func TestStateStore_RestoreDeployment(t *testing.T) { 2076 state := testStateStore(t) 2077 d := mock.Deployment() 2078 2079 restore, err := state.Restore() 2080 if err != nil { 2081 t.Fatalf("err: %v", err) 2082 } 2083 2084 err = restore.DeploymentRestore(d) 2085 if err != nil { 2086 t.Fatalf("err: %v", err) 2087 } 2088 restore.Commit() 2089 2090 ws := memdb.NewWatchSet() 2091 out, err := state.DeploymentByID(ws, d.ID) 2092 if err != nil { 2093 t.Fatalf("err: %v", err) 2094 } 2095 2096 if !reflect.DeepEqual(out, d) { 2097 t.Fatalf("Bad: %#v %#v", out, d) 2098 } 2099 2100 if watchFired(ws) { 2101 t.Fatalf("bad") 2102 } 2103 } 2104 2105 func TestStateStore_RestoreJobSummary(t *testing.T) { 2106 state := testStateStore(t) 2107 job := mock.Job() 2108 jobSummary := &structs.JobSummary{ 2109 JobID: job.ID, 2110 Summary: map[string]structs.TaskGroupSummary{ 2111 "web": structs.TaskGroupSummary{ 2112 Starting: 10, 2113 }, 2114 }, 2115 } 2116 restore, err := state.Restore() 2117 if err != nil { 2118 t.Fatalf("err: %v", err) 2119 } 2120 2121 err = restore.JobSummaryRestore(jobSummary) 2122 if err != nil { 2123 t.Fatalf("err: %v", err) 2124 } 2125 restore.Commit() 2126 2127 ws := memdb.NewWatchSet() 2128 out, err := state.JobSummaryByID(ws, job.ID) 2129 if err != nil { 2130 t.Fatalf("err: %v", err) 2131 } 2132 2133 if !reflect.DeepEqual(out, jobSummary) { 2134 t.Fatalf("Bad: %#v %#v", out, jobSummary) 2135 } 2136 } 2137 2138 func TestStateStore_Indexes(t *testing.T) { 2139 state := testStateStore(t) 2140 node := mock.Node() 2141 2142 err := state.UpsertNode(1000, node) 2143 if err != nil { 2144 t.Fatalf("err: %v", err) 2145 } 2146 2147 iter, err := state.Indexes() 2148 if err != nil { 2149 t.Fatalf("err: %v", err) 2150 } 2151 2152 var out []*IndexEntry 2153 for { 2154 raw := iter.Next() 2155 if raw == nil { 2156 break 2157 } 2158 out = append(out, raw.(*IndexEntry)) 2159 } 2160 2161 expect := []*IndexEntry{ 2162 &IndexEntry{"nodes", 1000}, 2163 } 2164 2165 if !reflect.DeepEqual(expect, out) { 2166 t.Fatalf("bad: %#v %#v", expect, out) 2167 } 2168 } 2169 2170 func TestStateStore_LatestIndex(t *testing.T) { 2171 state := testStateStore(t) 2172 2173 if err := state.UpsertNode(1000, mock.Node()); err != nil { 2174 t.Fatalf("err: %v", err) 2175 } 2176 2177 exp := uint64(2000) 2178 if err := state.UpsertJob(exp, mock.Job()); err != nil { 2179 t.Fatalf("err: %v", err) 2180 } 2181 2182 latest, err := state.LatestIndex() 2183 if err != nil { 2184 t.Fatalf("err: %v", err) 2185 } 2186 2187 if latest != exp { 2188 t.Fatalf("LatestIndex() returned %d; want %d", latest, exp) 2189 } 2190 } 2191 2192 func TestStateStore_RestoreIndex(t *testing.T) { 2193 state := testStateStore(t) 2194 2195 restore, err := state.Restore() 2196 if err != nil { 2197 t.Fatalf("err: %v", err) 2198 } 2199 2200 index := &IndexEntry{"jobs", 1000} 2201 err = restore.IndexRestore(index) 2202 if err != nil { 2203 t.Fatalf("err: %v", err) 2204 } 2205 2206 restore.Commit() 2207 2208 out, err := state.Index("jobs") 2209 if err != nil { 2210 t.Fatalf("err: %v", err) 2211 } 2212 2213 if out != 1000 { 2214 t.Fatalf("Bad: %#v %#v", out, 1000) 2215 } 2216 } 2217 2218 func TestStateStore_UpsertEvals_Eval(t *testing.T) { 2219 state := testStateStore(t) 2220 eval := mock.Eval() 2221 2222 // Create a watchset so we can test that upsert fires the watch 2223 ws := memdb.NewWatchSet() 2224 if _, err := state.EvalByID(ws, eval.ID); err != nil { 2225 t.Fatalf("bad: %v", err) 2226 } 2227 2228 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 2229 if err != nil { 2230 t.Fatalf("err: %v", err) 2231 } 2232 2233 if !watchFired(ws) { 2234 t.Fatalf("bad") 2235 } 2236 2237 ws = memdb.NewWatchSet() 2238 out, err := state.EvalByID(ws, eval.ID) 2239 if err != nil { 2240 t.Fatalf("err: %v", err) 2241 } 2242 2243 if !reflect.DeepEqual(eval, out) { 2244 t.Fatalf("bad: %#v %#v", eval, out) 2245 } 2246 2247 index, err := state.Index("evals") 2248 if err != nil { 2249 t.Fatalf("err: %v", err) 2250 } 2251 if index != 1000 { 2252 t.Fatalf("bad: %d", index) 2253 } 2254 2255 if watchFired(ws) { 2256 t.Fatalf("bad") 2257 } 2258 } 2259 2260 func TestStateStore_UpsertEvals_CancelBlocked(t *testing.T) { 2261 state := testStateStore(t) 2262 2263 // Create two blocked evals for the same job 2264 j := "test-job" 2265 b1, b2 := mock.Eval(), mock.Eval() 2266 b1.JobID = j 2267 b1.Status = structs.EvalStatusBlocked 2268 b2.JobID = j 2269 b2.Status = structs.EvalStatusBlocked 2270 2271 err := state.UpsertEvals(999, []*structs.Evaluation{b1, b2}) 2272 if err != nil { 2273 t.Fatalf("err: %v", err) 2274 } 2275 2276 // Create one complete and successful eval for the job 2277 eval := mock.Eval() 2278 eval.JobID = j 2279 eval.Status = structs.EvalStatusComplete 2280 2281 // Create a watchset so we can test that the upsert of the complete eval 2282 // fires the watch 2283 ws := memdb.NewWatchSet() 2284 if _, err := state.EvalByID(ws, b1.ID); err != nil { 2285 t.Fatalf("bad: %v", err) 2286 } 2287 if _, err := state.EvalByID(ws, b2.ID); err != nil { 2288 t.Fatalf("bad: %v", err) 2289 } 2290 2291 if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil { 2292 t.Fatalf("err: %v", err) 2293 } 2294 2295 if !watchFired(ws) { 2296 t.Fatalf("bad") 2297 } 2298 2299 ws = memdb.NewWatchSet() 2300 out, err := state.EvalByID(ws, eval.ID) 2301 if err != nil { 2302 t.Fatalf("err: %v", err) 2303 } 2304 2305 if !reflect.DeepEqual(eval, out) { 2306 t.Fatalf("bad: %#v %#v", eval, out) 2307 } 2308 2309 index, err := state.Index("evals") 2310 if err != nil { 2311 t.Fatalf("err: %v", err) 2312 } 2313 if index != 1000 { 2314 t.Fatalf("bad: %d", index) 2315 } 2316 2317 // Get b1/b2 and check they are cancelled 2318 out1, err := state.EvalByID(ws, b1.ID) 2319 if err != nil { 2320 t.Fatalf("err: %v", err) 2321 } 2322 2323 out2, err := state.EvalByID(ws, b2.ID) 2324 if err != nil { 2325 t.Fatalf("err: %v", err) 2326 } 2327 2328 if out1.Status != structs.EvalStatusCancelled || out2.Status != structs.EvalStatusCancelled { 2329 t.Fatalf("bad: %#v %#v", out1, out2) 2330 } 2331 2332 if watchFired(ws) { 2333 t.Fatalf("bad") 2334 } 2335 } 2336 2337 func TestStateStore_Update_UpsertEvals_Eval(t *testing.T) { 2338 state := testStateStore(t) 2339 eval := mock.Eval() 2340 2341 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 2342 if err != nil { 2343 t.Fatalf("err: %v", err) 2344 } 2345 2346 // Create a watchset so we can test that delete fires the watch 2347 ws := memdb.NewWatchSet() 2348 ws2 := memdb.NewWatchSet() 2349 if _, err := state.EvalByID(ws, eval.ID); err != nil { 2350 t.Fatalf("bad: %v", err) 2351 } 2352 2353 if _, err := state.EvalsByJob(ws2, eval.JobID); err != nil { 2354 t.Fatalf("bad: %v", err) 2355 } 2356 2357 eval2 := mock.Eval() 2358 eval2.ID = eval.ID 2359 eval2.JobID = eval.JobID 2360 err = state.UpsertEvals(1001, []*structs.Evaluation{eval2}) 2361 if err != nil { 2362 t.Fatalf("err: %v", err) 2363 } 2364 2365 if !watchFired(ws) { 2366 t.Fatalf("bad") 2367 } 2368 if !watchFired(ws2) { 2369 t.Fatalf("bad") 2370 } 2371 2372 ws = memdb.NewWatchSet() 2373 out, err := state.EvalByID(ws, eval.ID) 2374 if err != nil { 2375 t.Fatalf("err: %v", err) 2376 } 2377 2378 if !reflect.DeepEqual(eval2, out) { 2379 t.Fatalf("bad: %#v %#v", eval2, out) 2380 } 2381 2382 if out.CreateIndex != 1000 { 2383 t.Fatalf("bad: %#v", out) 2384 } 2385 if out.ModifyIndex != 1001 { 2386 t.Fatalf("bad: %#v", out) 2387 } 2388 2389 index, err := state.Index("evals") 2390 if err != nil { 2391 t.Fatalf("err: %v", err) 2392 } 2393 if index != 1001 { 2394 t.Fatalf("bad: %d", index) 2395 } 2396 2397 if watchFired(ws) { 2398 t.Fatalf("bad") 2399 } 2400 } 2401 2402 func TestStateStore_UpsertEvals_Eval_ChildJob(t *testing.T) { 2403 state := testStateStore(t) 2404 2405 parent := mock.Job() 2406 if err := state.UpsertJob(998, parent); err != nil { 2407 t.Fatalf("err: %v", err) 2408 } 2409 2410 child := mock.Job() 2411 child.ParentID = parent.ID 2412 2413 if err := state.UpsertJob(999, child); err != nil { 2414 t.Fatalf("err: %v", err) 2415 } 2416 2417 eval := mock.Eval() 2418 eval.Status = structs.EvalStatusComplete 2419 eval.JobID = child.ID 2420 2421 // Create watchsets so we can test that upsert fires the watch 2422 ws := memdb.NewWatchSet() 2423 ws2 := memdb.NewWatchSet() 2424 ws3 := memdb.NewWatchSet() 2425 if _, err := state.JobSummaryByID(ws, parent.ID); err != nil { 2426 t.Fatalf("bad: %v", err) 2427 } 2428 if _, err := state.EvalByID(ws2, eval.ID); err != nil { 2429 t.Fatalf("bad: %v", err) 2430 } 2431 if _, err := state.EvalsByJob(ws3, eval.JobID); err != nil { 2432 t.Fatalf("bad: %v", err) 2433 } 2434 2435 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 2436 if err != nil { 2437 t.Fatalf("err: %v", err) 2438 } 2439 2440 if !watchFired(ws) { 2441 t.Fatalf("bad") 2442 } 2443 if !watchFired(ws2) { 2444 t.Fatalf("bad") 2445 } 2446 if !watchFired(ws3) { 2447 t.Fatalf("bad") 2448 } 2449 2450 ws = memdb.NewWatchSet() 2451 out, err := state.EvalByID(ws, eval.ID) 2452 if err != nil { 2453 t.Fatalf("err: %v", err) 2454 } 2455 2456 if !reflect.DeepEqual(eval, out) { 2457 t.Fatalf("bad: %#v %#v", eval, out) 2458 } 2459 2460 index, err := state.Index("evals") 2461 if err != nil { 2462 t.Fatalf("err: %v", err) 2463 } 2464 if index != 1000 { 2465 t.Fatalf("bad: %d", index) 2466 } 2467 2468 summary, err := state.JobSummaryByID(ws, parent.ID) 2469 if err != nil { 2470 t.Fatalf("err: %v", err) 2471 } 2472 if summary == nil { 2473 t.Fatalf("nil summary") 2474 } 2475 if summary.JobID != parent.ID { 2476 t.Fatalf("bad summary id: %v", parent.ID) 2477 } 2478 if summary.Children == nil { 2479 t.Fatalf("nil children summary") 2480 } 2481 if summary.Children.Pending != 0 || summary.Children.Running != 0 || summary.Children.Dead != 1 { 2482 t.Fatalf("bad children summary: %v", summary.Children) 2483 } 2484 2485 if watchFired(ws) { 2486 t.Fatalf("bad") 2487 } 2488 } 2489 2490 func TestStateStore_DeleteEval_Eval(t *testing.T) { 2491 state := testStateStore(t) 2492 eval1 := mock.Eval() 2493 eval2 := mock.Eval() 2494 alloc1 := mock.Alloc() 2495 alloc2 := mock.Alloc() 2496 2497 // Create watchsets so we can test that upsert fires the watch 2498 watches := make([]memdb.WatchSet, 12) 2499 for i := 0; i < 12; i++ { 2500 watches[i] = memdb.NewWatchSet() 2501 } 2502 if _, err := state.EvalByID(watches[0], eval1.ID); err != nil { 2503 t.Fatalf("bad: %v", err) 2504 } 2505 if _, err := state.EvalByID(watches[1], eval2.ID); err != nil { 2506 t.Fatalf("bad: %v", err) 2507 } 2508 if _, err := state.EvalsByJob(watches[2], eval1.JobID); err != nil { 2509 t.Fatalf("bad: %v", err) 2510 } 2511 if _, err := state.EvalsByJob(watches[3], eval2.JobID); err != nil { 2512 t.Fatalf("bad: %v", err) 2513 } 2514 if _, err := state.AllocByID(watches[4], alloc1.ID); err != nil { 2515 t.Fatalf("bad: %v", err) 2516 } 2517 if _, err := state.AllocByID(watches[5], alloc2.ID); err != nil { 2518 t.Fatalf("bad: %v", err) 2519 } 2520 if _, err := state.AllocsByEval(watches[6], alloc1.EvalID); err != nil { 2521 t.Fatalf("bad: %v", err) 2522 } 2523 if _, err := state.AllocsByEval(watches[7], alloc2.EvalID); err != nil { 2524 t.Fatalf("bad: %v", err) 2525 } 2526 if _, err := state.AllocsByJob(watches[8], alloc1.JobID, false); err != nil { 2527 t.Fatalf("bad: %v", err) 2528 } 2529 if _, err := state.AllocsByJob(watches[9], alloc2.JobID, false); err != nil { 2530 t.Fatalf("bad: %v", err) 2531 } 2532 if _, err := state.AllocsByNode(watches[10], alloc1.NodeID); err != nil { 2533 t.Fatalf("bad: %v", err) 2534 } 2535 if _, err := state.AllocsByNode(watches[11], alloc2.NodeID); err != nil { 2536 t.Fatalf("bad: %v", err) 2537 } 2538 2539 state.UpsertJobSummary(900, mock.JobSummary(eval1.JobID)) 2540 state.UpsertJobSummary(901, mock.JobSummary(eval2.JobID)) 2541 state.UpsertJobSummary(902, mock.JobSummary(alloc1.JobID)) 2542 state.UpsertJobSummary(903, mock.JobSummary(alloc2.JobID)) 2543 err := state.UpsertEvals(1000, []*structs.Evaluation{eval1, eval2}) 2544 if err != nil { 2545 t.Fatalf("err: %v", err) 2546 } 2547 2548 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc1, alloc2}) 2549 if err != nil { 2550 t.Fatalf("err: %v", err) 2551 } 2552 2553 err = state.DeleteEval(1002, []string{eval1.ID, eval2.ID}, []string{alloc1.ID, alloc2.ID}) 2554 if err != nil { 2555 t.Fatalf("err: %v", err) 2556 } 2557 2558 for i, ws := range watches { 2559 if !watchFired(ws) { 2560 t.Fatalf("bad %d", i) 2561 } 2562 } 2563 2564 ws := memdb.NewWatchSet() 2565 out, err := state.EvalByID(ws, eval1.ID) 2566 if err != nil { 2567 t.Fatalf("err: %v", err) 2568 } 2569 2570 if out != nil { 2571 t.Fatalf("bad: %#v %#v", eval1, out) 2572 } 2573 2574 out, err = state.EvalByID(ws, eval2.ID) 2575 if err != nil { 2576 t.Fatalf("err: %v", err) 2577 } 2578 2579 if out != nil { 2580 t.Fatalf("bad: %#v %#v", eval1, out) 2581 } 2582 2583 outA, err := state.AllocByID(ws, alloc1.ID) 2584 if err != nil { 2585 t.Fatalf("err: %v", err) 2586 } 2587 2588 if out != nil { 2589 t.Fatalf("bad: %#v %#v", alloc1, outA) 2590 } 2591 2592 outA, err = state.AllocByID(ws, alloc2.ID) 2593 if err != nil { 2594 t.Fatalf("err: %v", err) 2595 } 2596 2597 if out != nil { 2598 t.Fatalf("bad: %#v %#v", alloc1, outA) 2599 } 2600 2601 index, err := state.Index("evals") 2602 if err != nil { 2603 t.Fatalf("err: %v", err) 2604 } 2605 if index != 1002 { 2606 t.Fatalf("bad: %d", index) 2607 } 2608 2609 index, err = state.Index("allocs") 2610 if err != nil { 2611 t.Fatalf("err: %v", err) 2612 } 2613 if index != 1002 { 2614 t.Fatalf("bad: %d", index) 2615 } 2616 2617 if watchFired(ws) { 2618 t.Fatalf("bad") 2619 } 2620 } 2621 2622 func TestStateStore_DeleteEval_ChildJob(t *testing.T) { 2623 state := testStateStore(t) 2624 2625 parent := mock.Job() 2626 if err := state.UpsertJob(998, parent); err != nil { 2627 t.Fatalf("err: %v", err) 2628 } 2629 2630 child := mock.Job() 2631 child.ParentID = parent.ID 2632 2633 if err := state.UpsertJob(999, child); err != nil { 2634 t.Fatalf("err: %v", err) 2635 } 2636 2637 eval1 := mock.Eval() 2638 eval1.JobID = child.ID 2639 alloc1 := mock.Alloc() 2640 alloc1.JobID = child.ID 2641 2642 err := state.UpsertEvals(1000, []*structs.Evaluation{eval1}) 2643 if err != nil { 2644 t.Fatalf("err: %v", err) 2645 } 2646 2647 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc1}) 2648 if err != nil { 2649 t.Fatalf("err: %v", err) 2650 } 2651 2652 // Create watchsets so we can test that delete fires the watch 2653 ws := memdb.NewWatchSet() 2654 if _, err := state.JobSummaryByID(ws, parent.ID); err != nil { 2655 t.Fatalf("bad: %v", err) 2656 } 2657 2658 err = state.DeleteEval(1002, []string{eval1.ID}, []string{alloc1.ID}) 2659 if err != nil { 2660 t.Fatalf("err: %v", err) 2661 } 2662 2663 if !watchFired(ws) { 2664 t.Fatalf("bad") 2665 } 2666 2667 ws = memdb.NewWatchSet() 2668 summary, err := state.JobSummaryByID(ws, parent.ID) 2669 if err != nil { 2670 t.Fatalf("err: %v", err) 2671 } 2672 if summary == nil { 2673 t.Fatalf("nil summary") 2674 } 2675 if summary.JobID != parent.ID { 2676 t.Fatalf("bad summary id: %v", parent.ID) 2677 } 2678 if summary.Children == nil { 2679 t.Fatalf("nil children summary") 2680 } 2681 if summary.Children.Pending != 0 || summary.Children.Running != 0 || summary.Children.Dead != 1 { 2682 t.Fatalf("bad children summary: %v", summary.Children) 2683 } 2684 2685 if watchFired(ws) { 2686 t.Fatalf("bad") 2687 } 2688 } 2689 2690 func TestStateStore_EvalsByJob(t *testing.T) { 2691 state := testStateStore(t) 2692 2693 eval1 := mock.Eval() 2694 eval2 := mock.Eval() 2695 eval2.JobID = eval1.JobID 2696 eval3 := mock.Eval() 2697 evals := []*structs.Evaluation{eval1, eval2} 2698 2699 err := state.UpsertEvals(1000, evals) 2700 if err != nil { 2701 t.Fatalf("err: %v", err) 2702 } 2703 err = state.UpsertEvals(1001, []*structs.Evaluation{eval3}) 2704 if err != nil { 2705 t.Fatalf("err: %v", err) 2706 } 2707 2708 ws := memdb.NewWatchSet() 2709 out, err := state.EvalsByJob(ws, eval1.JobID) 2710 if err != nil { 2711 t.Fatalf("err: %v", err) 2712 } 2713 2714 sort.Sort(EvalIDSort(evals)) 2715 sort.Sort(EvalIDSort(out)) 2716 2717 if !reflect.DeepEqual(evals, out) { 2718 t.Fatalf("bad: %#v %#v", evals, out) 2719 } 2720 2721 if watchFired(ws) { 2722 t.Fatalf("bad") 2723 } 2724 } 2725 2726 func TestStateStore_Evals(t *testing.T) { 2727 state := testStateStore(t) 2728 var evals []*structs.Evaluation 2729 2730 for i := 0; i < 10; i++ { 2731 eval := mock.Eval() 2732 evals = append(evals, eval) 2733 2734 err := state.UpsertEvals(1000+uint64(i), []*structs.Evaluation{eval}) 2735 if err != nil { 2736 t.Fatalf("err: %v", err) 2737 } 2738 } 2739 2740 ws := memdb.NewWatchSet() 2741 iter, err := state.Evals(ws) 2742 if err != nil { 2743 t.Fatalf("err: %v", err) 2744 } 2745 2746 var out []*structs.Evaluation 2747 for { 2748 raw := iter.Next() 2749 if raw == nil { 2750 break 2751 } 2752 out = append(out, raw.(*structs.Evaluation)) 2753 } 2754 2755 sort.Sort(EvalIDSort(evals)) 2756 sort.Sort(EvalIDSort(out)) 2757 2758 if !reflect.DeepEqual(evals, out) { 2759 t.Fatalf("bad: %#v %#v", evals, out) 2760 } 2761 2762 if watchFired(ws) { 2763 t.Fatalf("bad") 2764 } 2765 } 2766 2767 func TestStateStore_EvalsByIDPrefix(t *testing.T) { 2768 state := testStateStore(t) 2769 var evals []*structs.Evaluation 2770 2771 ids := []string{ 2772 "aaaaaaaa-7bfb-395d-eb95-0685af2176b2", 2773 "aaaaaaab-7bfb-395d-eb95-0685af2176b2", 2774 "aaaaaabb-7bfb-395d-eb95-0685af2176b2", 2775 "aaaaabbb-7bfb-395d-eb95-0685af2176b2", 2776 "aaaabbbb-7bfb-395d-eb95-0685af2176b2", 2777 "aaabbbbb-7bfb-395d-eb95-0685af2176b2", 2778 "aabbbbbb-7bfb-395d-eb95-0685af2176b2", 2779 "abbbbbbb-7bfb-395d-eb95-0685af2176b2", 2780 "bbbbbbbb-7bfb-395d-eb95-0685af2176b2", 2781 } 2782 for i := 0; i < 9; i++ { 2783 eval := mock.Eval() 2784 eval.ID = ids[i] 2785 evals = append(evals, eval) 2786 } 2787 2788 err := state.UpsertEvals(1000, evals) 2789 if err != nil { 2790 t.Fatalf("err: %v", err) 2791 } 2792 2793 ws := memdb.NewWatchSet() 2794 iter, err := state.EvalsByIDPrefix(ws, "aaaa") 2795 if err != nil { 2796 t.Fatalf("err: %v", err) 2797 } 2798 2799 gatherEvals := func(iter memdb.ResultIterator) []*structs.Evaluation { 2800 var evals []*structs.Evaluation 2801 for { 2802 raw := iter.Next() 2803 if raw == nil { 2804 break 2805 } 2806 evals = append(evals, raw.(*structs.Evaluation)) 2807 } 2808 return evals 2809 } 2810 2811 out := gatherEvals(iter) 2812 if len(out) != 5 { 2813 t.Fatalf("bad: expected five evaluations, got: %#v", out) 2814 } 2815 2816 sort.Sort(EvalIDSort(evals)) 2817 2818 for index, eval := range out { 2819 if ids[index] != eval.ID { 2820 t.Fatalf("bad: got unexpected id: %s", eval.ID) 2821 } 2822 } 2823 2824 iter, err = state.EvalsByIDPrefix(ws, "b-a7bfb") 2825 if err != nil { 2826 t.Fatalf("err: %v", err) 2827 } 2828 2829 out = gatherEvals(iter) 2830 if len(out) != 0 { 2831 t.Fatalf("bad: unexpected zero evaluations, got: %#v", out) 2832 } 2833 2834 if watchFired(ws) { 2835 t.Fatalf("bad") 2836 } 2837 } 2838 2839 func TestStateStore_RestoreEval(t *testing.T) { 2840 state := testStateStore(t) 2841 eval := mock.Eval() 2842 2843 restore, err := state.Restore() 2844 if err != nil { 2845 t.Fatalf("err: %v", err) 2846 } 2847 2848 err = restore.EvalRestore(eval) 2849 if err != nil { 2850 t.Fatalf("err: %v", err) 2851 } 2852 restore.Commit() 2853 2854 ws := memdb.NewWatchSet() 2855 out, err := state.EvalByID(ws, eval.ID) 2856 if err != nil { 2857 t.Fatalf("err: %v", err) 2858 } 2859 2860 if !reflect.DeepEqual(out, eval) { 2861 t.Fatalf("Bad: %#v %#v", out, eval) 2862 } 2863 } 2864 2865 func TestStateStore_UpdateAllocsFromClient(t *testing.T) { 2866 state := testStateStore(t) 2867 parent := mock.Job() 2868 if err := state.UpsertJob(998, parent); err != nil { 2869 t.Fatalf("err: %v", err) 2870 } 2871 2872 child := mock.Job() 2873 child.ParentID = parent.ID 2874 if err := state.UpsertJob(999, child); err != nil { 2875 t.Fatalf("err: %v", err) 2876 } 2877 2878 alloc := mock.Alloc() 2879 alloc.JobID = child.ID 2880 alloc.Job = child 2881 2882 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 2883 if err != nil { 2884 t.Fatalf("err: %v", err) 2885 } 2886 2887 ws := memdb.NewWatchSet() 2888 summary, err := state.JobSummaryByID(ws, parent.ID) 2889 if err != nil { 2890 t.Fatalf("err: %v", err) 2891 } 2892 if summary == nil { 2893 t.Fatalf("nil summary") 2894 } 2895 if summary.JobID != parent.ID { 2896 t.Fatalf("bad summary id: %v", parent.ID) 2897 } 2898 if summary.Children == nil { 2899 t.Fatalf("nil children summary") 2900 } 2901 if summary.Children.Pending != 0 || summary.Children.Running != 1 || summary.Children.Dead != 0 { 2902 t.Fatalf("bad children summary: %v", summary.Children) 2903 } 2904 2905 // Create watchsets so we can test that update fires the watch 2906 ws = memdb.NewWatchSet() 2907 if _, err := state.JobSummaryByID(ws, parent.ID); err != nil { 2908 t.Fatalf("bad: %v", err) 2909 } 2910 2911 // Create the delta updates 2912 ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStateRunning}} 2913 update := &structs.Allocation{ 2914 ID: alloc.ID, 2915 ClientStatus: structs.AllocClientStatusComplete, 2916 TaskStates: ts, 2917 JobID: alloc.JobID, 2918 TaskGroup: alloc.TaskGroup, 2919 } 2920 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update}) 2921 if err != nil { 2922 t.Fatalf("err: %v", err) 2923 } 2924 2925 if !watchFired(ws) { 2926 t.Fatalf("bad") 2927 } 2928 2929 ws = memdb.NewWatchSet() 2930 summary, err = state.JobSummaryByID(ws, parent.ID) 2931 if err != nil { 2932 t.Fatalf("err: %v", err) 2933 } 2934 if summary == nil { 2935 t.Fatalf("nil summary") 2936 } 2937 if summary.JobID != parent.ID { 2938 t.Fatalf("bad summary id: %v", parent.ID) 2939 } 2940 if summary.Children == nil { 2941 t.Fatalf("nil children summary") 2942 } 2943 if summary.Children.Pending != 0 || summary.Children.Running != 0 || summary.Children.Dead != 1 { 2944 t.Fatalf("bad children summary: %v", summary.Children) 2945 } 2946 2947 if watchFired(ws) { 2948 t.Fatalf("bad") 2949 } 2950 } 2951 2952 func TestStateStore_UpdateAllocsFromClient_ChildJob(t *testing.T) { 2953 state := testStateStore(t) 2954 alloc1 := mock.Alloc() 2955 alloc2 := mock.Alloc() 2956 2957 if err := state.UpsertJob(999, alloc1.Job); err != nil { 2958 t.Fatalf("err: %v", err) 2959 } 2960 if err := state.UpsertJob(999, alloc2.Job); err != nil { 2961 t.Fatalf("err: %v", err) 2962 } 2963 2964 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc1, alloc2}) 2965 if err != nil { 2966 t.Fatalf("err: %v", err) 2967 } 2968 2969 // Create watchsets so we can test that update fires the watch 2970 watches := make([]memdb.WatchSet, 8) 2971 for i := 0; i < 8; i++ { 2972 watches[i] = memdb.NewWatchSet() 2973 } 2974 if _, err := state.AllocByID(watches[0], alloc1.ID); err != nil { 2975 t.Fatalf("bad: %v", err) 2976 } 2977 if _, err := state.AllocByID(watches[1], alloc2.ID); err != nil { 2978 t.Fatalf("bad: %v", err) 2979 } 2980 if _, err := state.AllocsByEval(watches[2], alloc1.EvalID); err != nil { 2981 t.Fatalf("bad: %v", err) 2982 } 2983 if _, err := state.AllocsByEval(watches[3], alloc2.EvalID); err != nil { 2984 t.Fatalf("bad: %v", err) 2985 } 2986 if _, err := state.AllocsByJob(watches[4], alloc1.JobID, false); err != nil { 2987 t.Fatalf("bad: %v", err) 2988 } 2989 if _, err := state.AllocsByJob(watches[5], alloc2.JobID, false); err != nil { 2990 t.Fatalf("bad: %v", err) 2991 } 2992 if _, err := state.AllocsByNode(watches[6], alloc1.NodeID); err != nil { 2993 t.Fatalf("bad: %v", err) 2994 } 2995 if _, err := state.AllocsByNode(watches[7], alloc2.NodeID); err != nil { 2996 t.Fatalf("bad: %v", err) 2997 } 2998 2999 // Create the delta updates 3000 ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}} 3001 update := &structs.Allocation{ 3002 ID: alloc1.ID, 3003 ClientStatus: structs.AllocClientStatusFailed, 3004 TaskStates: ts, 3005 JobID: alloc1.JobID, 3006 TaskGroup: alloc1.TaskGroup, 3007 } 3008 update2 := &structs.Allocation{ 3009 ID: alloc2.ID, 3010 ClientStatus: structs.AllocClientStatusRunning, 3011 TaskStates: ts, 3012 JobID: alloc2.JobID, 3013 TaskGroup: alloc2.TaskGroup, 3014 } 3015 3016 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2}) 3017 if err != nil { 3018 t.Fatalf("err: %v", err) 3019 } 3020 3021 for i, ws := range watches { 3022 if !watchFired(ws) { 3023 t.Fatalf("bad %d", i) 3024 } 3025 } 3026 3027 ws := memdb.NewWatchSet() 3028 out, err := state.AllocByID(ws, alloc1.ID) 3029 if err != nil { 3030 t.Fatalf("err: %v", err) 3031 } 3032 3033 alloc1.CreateIndex = 1000 3034 alloc1.ModifyIndex = 1001 3035 alloc1.TaskStates = ts 3036 alloc1.ClientStatus = structs.AllocClientStatusFailed 3037 if !reflect.DeepEqual(alloc1, out) { 3038 t.Fatalf("bad: %#v %#v", alloc1, out) 3039 } 3040 3041 out, err = state.AllocByID(ws, alloc2.ID) 3042 if err != nil { 3043 t.Fatalf("err: %v", err) 3044 } 3045 3046 alloc2.ModifyIndex = 1000 3047 alloc2.ModifyIndex = 1001 3048 alloc2.ClientStatus = structs.AllocClientStatusRunning 3049 alloc2.TaskStates = ts 3050 if !reflect.DeepEqual(alloc2, out) { 3051 t.Fatalf("bad: %#v %#v", alloc2, out) 3052 } 3053 3054 index, err := state.Index("allocs") 3055 if err != nil { 3056 t.Fatalf("err: %v", err) 3057 } 3058 if index != 1001 { 3059 t.Fatalf("bad: %d", index) 3060 } 3061 3062 // Ensure summaries have been updated 3063 summary, err := state.JobSummaryByID(ws, alloc1.JobID) 3064 if err != nil { 3065 t.Fatalf("err: %v", err) 3066 } 3067 tgSummary := summary.Summary["web"] 3068 if tgSummary.Failed != 1 { 3069 t.Fatalf("expected failed: %v, actual: %v, summary: %#v", 1, tgSummary.Failed, tgSummary) 3070 } 3071 3072 summary2, err := state.JobSummaryByID(ws, alloc2.JobID) 3073 if err != nil { 3074 t.Fatalf("err: %v", err) 3075 } 3076 tgSummary2 := summary2.Summary["web"] 3077 if tgSummary2.Running != 1 { 3078 t.Fatalf("expected running: %v, actual: %v", 1, tgSummary2.Running) 3079 } 3080 3081 if watchFired(ws) { 3082 t.Fatalf("bad") 3083 } 3084 } 3085 3086 func TestStateStore_UpdateMultipleAllocsFromClient(t *testing.T) { 3087 state := testStateStore(t) 3088 alloc := mock.Alloc() 3089 3090 if err := state.UpsertJob(999, alloc.Job); err != nil { 3091 t.Fatalf("err: %v", err) 3092 } 3093 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3094 if err != nil { 3095 t.Fatalf("err: %v", err) 3096 } 3097 3098 // Create the delta updates 3099 ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}} 3100 update := &structs.Allocation{ 3101 ID: alloc.ID, 3102 ClientStatus: structs.AllocClientStatusRunning, 3103 TaskStates: ts, 3104 JobID: alloc.JobID, 3105 TaskGroup: alloc.TaskGroup, 3106 } 3107 update2 := &structs.Allocation{ 3108 ID: alloc.ID, 3109 ClientStatus: structs.AllocClientStatusPending, 3110 TaskStates: ts, 3111 JobID: alloc.JobID, 3112 TaskGroup: alloc.TaskGroup, 3113 } 3114 3115 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2}) 3116 if err != nil { 3117 t.Fatalf("err: %v", err) 3118 } 3119 3120 ws := memdb.NewWatchSet() 3121 out, err := state.AllocByID(ws, alloc.ID) 3122 if err != nil { 3123 t.Fatalf("err: %v", err) 3124 } 3125 3126 alloc.CreateIndex = 1000 3127 alloc.ModifyIndex = 1001 3128 alloc.TaskStates = ts 3129 alloc.ClientStatus = structs.AllocClientStatusPending 3130 if !reflect.DeepEqual(alloc, out) { 3131 t.Fatalf("bad: %#v , actual:%#v", alloc, out) 3132 } 3133 3134 summary, err := state.JobSummaryByID(ws, alloc.JobID) 3135 expectedSummary := &structs.JobSummary{ 3136 JobID: alloc.JobID, 3137 Summary: map[string]structs.TaskGroupSummary{ 3138 "web": structs.TaskGroupSummary{ 3139 Starting: 1, 3140 }, 3141 }, 3142 Children: new(structs.JobChildrenSummary), 3143 CreateIndex: 999, 3144 ModifyIndex: 1001, 3145 } 3146 if err != nil { 3147 t.Fatalf("err: %v", err) 3148 } 3149 if !reflect.DeepEqual(summary, expectedSummary) { 3150 t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary) 3151 } 3152 } 3153 3154 func TestStateStore_UpsertAlloc_Alloc(t *testing.T) { 3155 state := testStateStore(t) 3156 alloc := mock.Alloc() 3157 3158 if err := state.UpsertJob(999, alloc.Job); err != nil { 3159 t.Fatalf("err: %v", err) 3160 } 3161 3162 // Create watchsets so we can test that update fires the watch 3163 watches := make([]memdb.WatchSet, 4) 3164 for i := 0; i < 4; i++ { 3165 watches[i] = memdb.NewWatchSet() 3166 } 3167 if _, err := state.AllocByID(watches[0], alloc.ID); err != nil { 3168 t.Fatalf("bad: %v", err) 3169 } 3170 if _, err := state.AllocsByEval(watches[1], alloc.EvalID); err != nil { 3171 t.Fatalf("bad: %v", err) 3172 } 3173 if _, err := state.AllocsByJob(watches[2], alloc.JobID, false); err != nil { 3174 t.Fatalf("bad: %v", err) 3175 } 3176 if _, err := state.AllocsByNode(watches[3], alloc.NodeID); err != nil { 3177 t.Fatalf("bad: %v", err) 3178 } 3179 3180 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3181 if err != nil { 3182 t.Fatalf("err: %v", err) 3183 } 3184 3185 for i, ws := range watches { 3186 if !watchFired(ws) { 3187 t.Fatalf("bad %d", i) 3188 } 3189 } 3190 3191 ws := memdb.NewWatchSet() 3192 out, err := state.AllocByID(ws, alloc.ID) 3193 if err != nil { 3194 t.Fatalf("err: %v", err) 3195 } 3196 3197 if !reflect.DeepEqual(alloc, out) { 3198 t.Fatalf("bad: %#v %#v", alloc, out) 3199 } 3200 3201 index, err := state.Index("allocs") 3202 if err != nil { 3203 t.Fatalf("err: %v", err) 3204 } 3205 if index != 1000 { 3206 t.Fatalf("bad: %d", index) 3207 } 3208 3209 summary, err := state.JobSummaryByID(ws, alloc.JobID) 3210 if err != nil { 3211 t.Fatalf("err: %v", err) 3212 } 3213 3214 tgSummary, ok := summary.Summary["web"] 3215 if !ok { 3216 t.Fatalf("no summary for task group web") 3217 } 3218 if tgSummary.Starting != 1 { 3219 t.Fatalf("expected queued: %v, actual: %v", 1, tgSummary.Starting) 3220 } 3221 3222 if watchFired(ws) { 3223 t.Fatalf("bad") 3224 } 3225 } 3226 3227 func TestStateStore_UpsertAlloc_Deployment(t *testing.T) { 3228 state := testStateStore(t) 3229 deployment := mock.Deployment() 3230 alloc := mock.Alloc() 3231 alloc.DeploymentID = deployment.ID 3232 3233 if err := state.UpsertJob(999, alloc.Job); err != nil { 3234 t.Fatalf("err: %v", err) 3235 } 3236 if err := state.UpsertDeployment(1000, deployment); err != nil { 3237 t.Fatalf("err: %v", err) 3238 } 3239 3240 // Create a watch set so we can test that update fires the watch 3241 ws := memdb.NewWatchSet() 3242 if _, err := state.AllocsByDeployment(ws, alloc.DeploymentID); err != nil { 3243 t.Fatalf("bad: %v", err) 3244 } 3245 3246 err := state.UpsertAllocs(1001, []*structs.Allocation{alloc}) 3247 if err != nil { 3248 t.Fatalf("err: %v", err) 3249 } 3250 3251 if !watchFired(ws) { 3252 t.Fatalf("watch not fired") 3253 } 3254 3255 ws = memdb.NewWatchSet() 3256 allocs, err := state.AllocsByDeployment(ws, alloc.DeploymentID) 3257 if err != nil { 3258 t.Fatalf("err: %v", err) 3259 } 3260 3261 if len(allocs) != 1 { 3262 t.Fatalf("bad: %#v", allocs) 3263 } 3264 3265 if !reflect.DeepEqual(alloc, allocs[0]) { 3266 t.Fatalf("bad: %#v %#v", alloc, allocs[0]) 3267 } 3268 3269 index, err := state.Index("allocs") 3270 if err != nil { 3271 t.Fatalf("err: %v", err) 3272 } 3273 if index != 1001 { 3274 t.Fatalf("bad: %d", index) 3275 } 3276 3277 if watchFired(ws) { 3278 t.Fatalf("bad") 3279 } 3280 } 3281 3282 // Testing to ensure we keep issue 3283 // https://github.com/hashicorp/nomad/issues/2583 fixed 3284 func TestStateStore_UpsertAlloc_No_Job(t *testing.T) { 3285 state := testStateStore(t) 3286 alloc := mock.Alloc() 3287 alloc.Job = nil 3288 3289 err := state.UpsertAllocs(999, []*structs.Allocation{alloc}) 3290 if err == nil || !strings.Contains(err.Error(), "without a job") { 3291 t.Fatalf("expect err: %v", err) 3292 } 3293 } 3294 3295 func TestStateStore_UpsertAlloc_NoEphemeralDisk(t *testing.T) { 3296 state := testStateStore(t) 3297 alloc := mock.Alloc() 3298 alloc.Job.TaskGroups[0].EphemeralDisk = nil 3299 alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120 3300 3301 if err := state.UpsertJob(999, alloc.Job); err != nil { 3302 t.Fatalf("err: %v", err) 3303 } 3304 3305 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3306 if err != nil { 3307 t.Fatalf("err: %v", err) 3308 } 3309 3310 ws := memdb.NewWatchSet() 3311 out, err := state.AllocByID(ws, alloc.ID) 3312 if err != nil { 3313 t.Fatalf("err: %v", err) 3314 } 3315 3316 expected := alloc.Copy() 3317 expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120} 3318 if !reflect.DeepEqual(expected, out) { 3319 t.Fatalf("bad: %#v %#v", expected, out) 3320 } 3321 } 3322 3323 func TestStateStore_UpsertAlloc_ChildJob(t *testing.T) { 3324 state := testStateStore(t) 3325 3326 parent := mock.Job() 3327 if err := state.UpsertJob(998, parent); err != nil { 3328 t.Fatalf("err: %v", err) 3329 } 3330 3331 child := mock.Job() 3332 child.ParentID = parent.ID 3333 3334 if err := state.UpsertJob(999, child); err != nil { 3335 t.Fatalf("err: %v", err) 3336 } 3337 3338 alloc := mock.Alloc() 3339 alloc.JobID = child.ID 3340 alloc.Job = child 3341 3342 // Create watchsets so we can test that delete fires the watch 3343 ws := memdb.NewWatchSet() 3344 if _, err := state.JobSummaryByID(ws, parent.ID); err != nil { 3345 t.Fatalf("bad: %v", err) 3346 } 3347 3348 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3349 if err != nil { 3350 t.Fatalf("err: %v", err) 3351 } 3352 3353 if !watchFired(ws) { 3354 t.Fatalf("bad") 3355 } 3356 3357 ws = memdb.NewWatchSet() 3358 summary, err := state.JobSummaryByID(ws, parent.ID) 3359 if err != nil { 3360 t.Fatalf("err: %v", err) 3361 } 3362 if summary == nil { 3363 t.Fatalf("nil summary") 3364 } 3365 if summary.JobID != parent.ID { 3366 t.Fatalf("bad summary id: %v", parent.ID) 3367 } 3368 if summary.Children == nil { 3369 t.Fatalf("nil children summary") 3370 } 3371 if summary.Children.Pending != 0 || summary.Children.Running != 1 || summary.Children.Dead != 0 { 3372 t.Fatalf("bad children summary: %v", summary.Children) 3373 } 3374 3375 if watchFired(ws) { 3376 t.Fatalf("bad") 3377 } 3378 } 3379 3380 func TestStateStore_UpdateAlloc_Alloc(t *testing.T) { 3381 state := testStateStore(t) 3382 alloc := mock.Alloc() 3383 3384 if err := state.UpsertJob(999, alloc.Job); err != nil { 3385 t.Fatalf("err: %v", err) 3386 } 3387 3388 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3389 if err != nil { 3390 t.Fatalf("err: %v", err) 3391 } 3392 3393 ws := memdb.NewWatchSet() 3394 summary, err := state.JobSummaryByID(ws, alloc.JobID) 3395 if err != nil { 3396 t.Fatalf("err: %v", err) 3397 } 3398 tgSummary := summary.Summary["web"] 3399 if tgSummary.Starting != 1 { 3400 t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting) 3401 } 3402 3403 alloc2 := mock.Alloc() 3404 alloc2.ID = alloc.ID 3405 alloc2.NodeID = alloc.NodeID + ".new" 3406 state.UpsertJobSummary(1001, mock.JobSummary(alloc2.JobID)) 3407 3408 // Create watchsets so we can test that update fires the watch 3409 watches := make([]memdb.WatchSet, 4) 3410 for i := 0; i < 4; i++ { 3411 watches[i] = memdb.NewWatchSet() 3412 } 3413 if _, err := state.AllocByID(watches[0], alloc2.ID); err != nil { 3414 t.Fatalf("bad: %v", err) 3415 } 3416 if _, err := state.AllocsByEval(watches[1], alloc2.EvalID); err != nil { 3417 t.Fatalf("bad: %v", err) 3418 } 3419 if _, err := state.AllocsByJob(watches[2], alloc2.JobID, false); err != nil { 3420 t.Fatalf("bad: %v", err) 3421 } 3422 if _, err := state.AllocsByNode(watches[3], alloc2.NodeID); err != nil { 3423 t.Fatalf("bad: %v", err) 3424 } 3425 3426 err = state.UpsertAllocs(1002, []*structs.Allocation{alloc2}) 3427 if err != nil { 3428 t.Fatalf("err: %v", err) 3429 } 3430 3431 for i, ws := range watches { 3432 if !watchFired(ws) { 3433 t.Fatalf("bad %d", i) 3434 } 3435 } 3436 3437 ws = memdb.NewWatchSet() 3438 out, err := state.AllocByID(ws, alloc.ID) 3439 if err != nil { 3440 t.Fatalf("err: %v", err) 3441 } 3442 3443 if !reflect.DeepEqual(alloc2, out) { 3444 t.Fatalf("bad: %#v %#v", alloc2, out) 3445 } 3446 3447 if out.CreateIndex != 1000 { 3448 t.Fatalf("bad: %#v", out) 3449 } 3450 if out.ModifyIndex != 1002 { 3451 t.Fatalf("bad: %#v", out) 3452 } 3453 3454 index, err := state.Index("allocs") 3455 if err != nil { 3456 t.Fatalf("err: %v", err) 3457 } 3458 if index != 1002 { 3459 t.Fatalf("bad: %d", index) 3460 } 3461 3462 // Ensure that summary hasb't changed 3463 summary, err = state.JobSummaryByID(ws, alloc.JobID) 3464 if err != nil { 3465 t.Fatalf("err: %v", err) 3466 } 3467 tgSummary = summary.Summary["web"] 3468 if tgSummary.Starting != 1 { 3469 t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting) 3470 } 3471 3472 if watchFired(ws) { 3473 t.Fatalf("bad") 3474 } 3475 } 3476 3477 // This test ensures that the state store will mark the clients status as lost 3478 // when set rather than preferring the existing status. 3479 func TestStateStore_UpdateAlloc_Lost(t *testing.T) { 3480 state := testStateStore(t) 3481 alloc := mock.Alloc() 3482 alloc.ClientStatus = "foo" 3483 3484 if err := state.UpsertJob(999, alloc.Job); err != nil { 3485 t.Fatalf("err: %v", err) 3486 } 3487 3488 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3489 if err != nil { 3490 t.Fatalf("err: %v", err) 3491 } 3492 3493 alloc2 := new(structs.Allocation) 3494 *alloc2 = *alloc 3495 alloc2.ClientStatus = structs.AllocClientStatusLost 3496 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc2}); err != nil { 3497 t.Fatalf("err: %v", err) 3498 } 3499 3500 ws := memdb.NewWatchSet() 3501 out, err := state.AllocByID(ws, alloc2.ID) 3502 if err != nil { 3503 t.Fatalf("err: %v", err) 3504 } 3505 3506 if out.ClientStatus != structs.AllocClientStatusLost { 3507 t.Fatalf("bad: %#v", out) 3508 } 3509 } 3510 3511 // This test ensures an allocation can be updated when there is no job 3512 // associated with it. This will happen when a job is stopped by an user which 3513 // has non-terminal allocations on clients 3514 func TestStateStore_UpdateAlloc_NoJob(t *testing.T) { 3515 state := testStateStore(t) 3516 alloc := mock.Alloc() 3517 3518 // Upsert a job 3519 state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)) 3520 if err := state.UpsertJob(999, alloc.Job); err != nil { 3521 t.Fatalf("err: %v", err) 3522 } 3523 3524 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3525 if err != nil { 3526 t.Fatalf("err: %v", err) 3527 } 3528 3529 if err := state.DeleteJob(1001, alloc.JobID); err != nil { 3530 t.Fatalf("err: %v", err) 3531 } 3532 3533 // Update the desired state of the allocation to stop 3534 allocCopy := alloc.Copy() 3535 allocCopy.DesiredStatus = structs.AllocDesiredStatusStop 3536 if err := state.UpsertAllocs(1002, []*structs.Allocation{allocCopy}); err != nil { 3537 t.Fatalf("err: %v", err) 3538 } 3539 3540 // Update the client state of the allocation to complete 3541 allocCopy1 := allocCopy.Copy() 3542 allocCopy1.ClientStatus = structs.AllocClientStatusComplete 3543 if err := state.UpdateAllocsFromClient(1003, []*structs.Allocation{allocCopy1}); err != nil { 3544 t.Fatalf("err: %v", err) 3545 } 3546 3547 ws := memdb.NewWatchSet() 3548 out, _ := state.AllocByID(ws, alloc.ID) 3549 // Update the modify index of the alloc before comparing 3550 allocCopy1.ModifyIndex = 1003 3551 if !reflect.DeepEqual(out, allocCopy1) { 3552 t.Fatalf("expected: %#v \n actual: %#v", allocCopy1, out) 3553 } 3554 } 3555 3556 func TestStateStore_JobSummary(t *testing.T) { 3557 state := testStateStore(t) 3558 3559 // Add a job 3560 job := mock.Job() 3561 state.UpsertJob(900, job) 3562 3563 // Get the job back 3564 ws := memdb.NewWatchSet() 3565 outJob, _ := state.JobByID(ws, job.ID) 3566 if outJob.CreateIndex != 900 { 3567 t.Fatalf("bad create index: %v", outJob.CreateIndex) 3568 } 3569 summary, _ := state.JobSummaryByID(ws, job.ID) 3570 if summary.CreateIndex != 900 { 3571 t.Fatalf("bad create index: %v", summary.CreateIndex) 3572 } 3573 3574 // Upsert an allocation 3575 alloc := mock.Alloc() 3576 alloc.JobID = job.ID 3577 alloc.Job = job 3578 state.UpsertAllocs(910, []*structs.Allocation{alloc}) 3579 3580 // Update the alloc from client 3581 alloc1 := alloc.Copy() 3582 alloc1.ClientStatus = structs.AllocClientStatusPending 3583 alloc1.DesiredStatus = "" 3584 state.UpdateAllocsFromClient(920, []*structs.Allocation{alloc}) 3585 3586 alloc3 := alloc.Copy() 3587 alloc3.ClientStatus = structs.AllocClientStatusRunning 3588 alloc3.DesiredStatus = "" 3589 state.UpdateAllocsFromClient(930, []*structs.Allocation{alloc3}) 3590 3591 // Upsert the alloc 3592 alloc4 := alloc.Copy() 3593 alloc4.ClientStatus = structs.AllocClientStatusPending 3594 alloc4.DesiredStatus = structs.AllocDesiredStatusRun 3595 state.UpsertAllocs(950, []*structs.Allocation{alloc4}) 3596 3597 // Again upsert the alloc 3598 alloc5 := alloc.Copy() 3599 alloc5.ClientStatus = structs.AllocClientStatusPending 3600 alloc5.DesiredStatus = structs.AllocDesiredStatusRun 3601 state.UpsertAllocs(970, []*structs.Allocation{alloc5}) 3602 3603 if !watchFired(ws) { 3604 t.Fatalf("bad") 3605 } 3606 3607 expectedSummary := structs.JobSummary{ 3608 JobID: job.ID, 3609 Summary: map[string]structs.TaskGroupSummary{ 3610 "web": structs.TaskGroupSummary{ 3611 Running: 1, 3612 }, 3613 }, 3614 Children: new(structs.JobChildrenSummary), 3615 CreateIndex: 900, 3616 ModifyIndex: 930, 3617 } 3618 3619 summary, _ = state.JobSummaryByID(ws, job.ID) 3620 if !reflect.DeepEqual(&expectedSummary, summary) { 3621 t.Fatalf("expected: %#v, actual: %v", expectedSummary, summary) 3622 } 3623 3624 // De-register the job. 3625 state.DeleteJob(980, job.ID) 3626 3627 // Shouldn't have any effect on the summary 3628 alloc6 := alloc.Copy() 3629 alloc6.ClientStatus = structs.AllocClientStatusRunning 3630 alloc6.DesiredStatus = "" 3631 state.UpdateAllocsFromClient(990, []*structs.Allocation{alloc6}) 3632 3633 // We shouldn't have any summary at this point 3634 summary, _ = state.JobSummaryByID(ws, job.ID) 3635 if summary != nil { 3636 t.Fatalf("expected nil, actual: %#v", summary) 3637 } 3638 3639 // Re-register the same job 3640 job1 := mock.Job() 3641 job1.ID = job.ID 3642 state.UpsertJob(1000, job1) 3643 outJob2, _ := state.JobByID(ws, job1.ID) 3644 if outJob2.CreateIndex != 1000 { 3645 t.Fatalf("bad create index: %v", outJob2.CreateIndex) 3646 } 3647 summary, _ = state.JobSummaryByID(ws, job1.ID) 3648 if summary.CreateIndex != 1000 { 3649 t.Fatalf("bad create index: %v", summary.CreateIndex) 3650 } 3651 3652 // Upsert an allocation 3653 alloc7 := alloc.Copy() 3654 alloc7.JobID = outJob.ID 3655 alloc7.Job = outJob 3656 alloc7.ClientStatus = structs.AllocClientStatusComplete 3657 alloc7.DesiredStatus = structs.AllocDesiredStatusRun 3658 state.UpdateAllocsFromClient(1020, []*structs.Allocation{alloc7}) 3659 3660 expectedSummary = structs.JobSummary{ 3661 JobID: job.ID, 3662 Summary: map[string]structs.TaskGroupSummary{ 3663 "web": structs.TaskGroupSummary{}, 3664 }, 3665 Children: new(structs.JobChildrenSummary), 3666 CreateIndex: 1000, 3667 ModifyIndex: 1000, 3668 } 3669 3670 summary, _ = state.JobSummaryByID(ws, job1.ID) 3671 if !reflect.DeepEqual(&expectedSummary, summary) { 3672 t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary) 3673 } 3674 } 3675 3676 func TestStateStore_ReconcileJobSummary(t *testing.T) { 3677 state := testStateStore(t) 3678 3679 // Create an alloc 3680 alloc := mock.Alloc() 3681 3682 // Add another task group to the job 3683 tg2 := alloc.Job.TaskGroups[0].Copy() 3684 tg2.Name = "db" 3685 alloc.Job.TaskGroups = append(alloc.Job.TaskGroups, tg2) 3686 state.UpsertJob(100, alloc.Job) 3687 3688 // Create one more alloc for the db task group 3689 alloc2 := mock.Alloc() 3690 alloc2.TaskGroup = "db" 3691 alloc2.JobID = alloc.JobID 3692 alloc2.Job = alloc.Job 3693 3694 // Upserts the alloc 3695 state.UpsertAllocs(110, []*structs.Allocation{alloc, alloc2}) 3696 3697 // Change the state of the first alloc to running 3698 alloc3 := alloc.Copy() 3699 alloc3.ClientStatus = structs.AllocClientStatusRunning 3700 state.UpdateAllocsFromClient(120, []*structs.Allocation{alloc3}) 3701 3702 //Add some more allocs to the second tg 3703 alloc4 := mock.Alloc() 3704 alloc4.JobID = alloc.JobID 3705 alloc4.Job = alloc.Job 3706 alloc4.TaskGroup = "db" 3707 alloc5 := alloc4.Copy() 3708 alloc5.ClientStatus = structs.AllocClientStatusRunning 3709 3710 alloc6 := mock.Alloc() 3711 alloc6.JobID = alloc.JobID 3712 alloc6.Job = alloc.Job 3713 alloc6.TaskGroup = "db" 3714 alloc7 := alloc6.Copy() 3715 alloc7.ClientStatus = structs.AllocClientStatusComplete 3716 3717 alloc8 := mock.Alloc() 3718 alloc8.JobID = alloc.JobID 3719 alloc8.Job = alloc.Job 3720 alloc8.TaskGroup = "db" 3721 alloc9 := alloc8.Copy() 3722 alloc9.ClientStatus = structs.AllocClientStatusFailed 3723 3724 alloc10 := mock.Alloc() 3725 alloc10.JobID = alloc.JobID 3726 alloc10.Job = alloc.Job 3727 alloc10.TaskGroup = "db" 3728 alloc11 := alloc10.Copy() 3729 alloc11.ClientStatus = structs.AllocClientStatusLost 3730 3731 state.UpsertAllocs(130, []*structs.Allocation{alloc4, alloc6, alloc8, alloc10}) 3732 3733 state.UpdateAllocsFromClient(150, []*structs.Allocation{alloc5, alloc7, alloc9, alloc11}) 3734 3735 // DeleteJobSummary is a helper method and doesn't modify the indexes table 3736 state.DeleteJobSummary(130, alloc.Job.ID) 3737 3738 state.ReconcileJobSummaries(120) 3739 3740 ws := memdb.NewWatchSet() 3741 summary, _ := state.JobSummaryByID(ws, alloc.Job.ID) 3742 expectedSummary := structs.JobSummary{ 3743 JobID: alloc.Job.ID, 3744 Summary: map[string]structs.TaskGroupSummary{ 3745 "web": structs.TaskGroupSummary{ 3746 Running: 1, 3747 }, 3748 "db": structs.TaskGroupSummary{ 3749 Starting: 1, 3750 Running: 1, 3751 Failed: 1, 3752 Complete: 1, 3753 Lost: 1, 3754 }, 3755 }, 3756 CreateIndex: 100, 3757 ModifyIndex: 120, 3758 } 3759 if !reflect.DeepEqual(&expectedSummary, summary) { 3760 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 3761 } 3762 } 3763 3764 func TestStateStore_UpdateAlloc_JobNotPresent(t *testing.T) { 3765 state := testStateStore(t) 3766 3767 alloc := mock.Alloc() 3768 state.UpsertJob(100, alloc.Job) 3769 state.UpsertAllocs(200, []*structs.Allocation{alloc}) 3770 3771 // Delete the job 3772 state.DeleteJob(300, alloc.Job.ID) 3773 3774 // Update the alloc 3775 alloc1 := alloc.Copy() 3776 alloc1.ClientStatus = structs.AllocClientStatusRunning 3777 3778 // Updating allocation should not throw any error 3779 if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil { 3780 t.Fatalf("expect err: %v", err) 3781 } 3782 3783 // Re-Register the job 3784 state.UpsertJob(500, alloc.Job) 3785 3786 // Update the alloc again 3787 alloc2 := alloc.Copy() 3788 alloc2.ClientStatus = structs.AllocClientStatusComplete 3789 if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil { 3790 t.Fatalf("expect err: %v", err) 3791 } 3792 3793 // Job Summary of the newly registered job shouldn't account for the 3794 // allocation update for the older job 3795 expectedSummary := structs.JobSummary{ 3796 JobID: alloc1.JobID, 3797 Summary: map[string]structs.TaskGroupSummary{ 3798 "web": structs.TaskGroupSummary{}, 3799 }, 3800 Children: new(structs.JobChildrenSummary), 3801 CreateIndex: 500, 3802 ModifyIndex: 500, 3803 } 3804 3805 ws := memdb.NewWatchSet() 3806 summary, _ := state.JobSummaryByID(ws, alloc.Job.ID) 3807 if !reflect.DeepEqual(&expectedSummary, summary) { 3808 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 3809 } 3810 } 3811 3812 func TestStateStore_EvictAlloc_Alloc(t *testing.T) { 3813 state := testStateStore(t) 3814 alloc := mock.Alloc() 3815 3816 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 3817 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3818 if err != nil { 3819 t.Fatalf("err: %v", err) 3820 } 3821 3822 alloc2 := new(structs.Allocation) 3823 *alloc2 = *alloc 3824 alloc2.DesiredStatus = structs.AllocDesiredStatusEvict 3825 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc2}) 3826 if err != nil { 3827 t.Fatalf("err: %v", err) 3828 } 3829 3830 ws := memdb.NewWatchSet() 3831 out, err := state.AllocByID(ws, alloc.ID) 3832 if err != nil { 3833 t.Fatalf("err: %v", err) 3834 } 3835 3836 if out.DesiredStatus != structs.AllocDesiredStatusEvict { 3837 t.Fatalf("bad: %#v %#v", alloc, out) 3838 } 3839 3840 index, err := state.Index("allocs") 3841 if err != nil { 3842 t.Fatalf("err: %v", err) 3843 } 3844 if index != 1001 { 3845 t.Fatalf("bad: %d", index) 3846 } 3847 } 3848 3849 func TestStateStore_AllocsByNode(t *testing.T) { 3850 state := testStateStore(t) 3851 var allocs []*structs.Allocation 3852 3853 for i := 0; i < 10; i++ { 3854 alloc := mock.Alloc() 3855 alloc.NodeID = "foo" 3856 allocs = append(allocs, alloc) 3857 } 3858 3859 for idx, alloc := range allocs { 3860 state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID)) 3861 } 3862 3863 err := state.UpsertAllocs(1000, allocs) 3864 if err != nil { 3865 t.Fatalf("err: %v", err) 3866 } 3867 3868 ws := memdb.NewWatchSet() 3869 out, err := state.AllocsByNode(ws, "foo") 3870 if err != nil { 3871 t.Fatalf("err: %v", err) 3872 } 3873 3874 sort.Sort(AllocIDSort(allocs)) 3875 sort.Sort(AllocIDSort(out)) 3876 3877 if !reflect.DeepEqual(allocs, out) { 3878 t.Fatalf("bad: %#v %#v", allocs, out) 3879 } 3880 3881 if watchFired(ws) { 3882 t.Fatalf("bad") 3883 } 3884 } 3885 3886 func TestStateStore_AllocsByNodeTerminal(t *testing.T) { 3887 state := testStateStore(t) 3888 var allocs, term, nonterm []*structs.Allocation 3889 3890 for i := 0; i < 10; i++ { 3891 alloc := mock.Alloc() 3892 alloc.NodeID = "foo" 3893 if i%2 == 0 { 3894 alloc.DesiredStatus = structs.AllocDesiredStatusStop 3895 term = append(term, alloc) 3896 } else { 3897 nonterm = append(nonterm, alloc) 3898 } 3899 allocs = append(allocs, alloc) 3900 } 3901 3902 for idx, alloc := range allocs { 3903 state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID)) 3904 } 3905 3906 err := state.UpsertAllocs(1000, allocs) 3907 if err != nil { 3908 t.Fatalf("err: %v", err) 3909 } 3910 3911 // Verify the terminal allocs 3912 ws := memdb.NewWatchSet() 3913 out, err := state.AllocsByNodeTerminal(ws, "foo", true) 3914 if err != nil { 3915 t.Fatalf("err: %v", err) 3916 } 3917 3918 sort.Sort(AllocIDSort(term)) 3919 sort.Sort(AllocIDSort(out)) 3920 3921 if !reflect.DeepEqual(term, out) { 3922 t.Fatalf("bad: %#v %#v", term, out) 3923 } 3924 3925 // Verify the non-terminal allocs 3926 out, err = state.AllocsByNodeTerminal(ws, "foo", false) 3927 if err != nil { 3928 t.Fatalf("err: %v", err) 3929 } 3930 3931 sort.Sort(AllocIDSort(nonterm)) 3932 sort.Sort(AllocIDSort(out)) 3933 3934 if !reflect.DeepEqual(nonterm, out) { 3935 t.Fatalf("bad: %#v %#v", nonterm, out) 3936 } 3937 3938 if watchFired(ws) { 3939 t.Fatalf("bad") 3940 } 3941 } 3942 3943 func TestStateStore_AllocsByJob(t *testing.T) { 3944 state := testStateStore(t) 3945 var allocs []*structs.Allocation 3946 3947 for i := 0; i < 10; i++ { 3948 alloc := mock.Alloc() 3949 alloc.JobID = "foo" 3950 allocs = append(allocs, alloc) 3951 } 3952 3953 for i, alloc := range allocs { 3954 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 3955 } 3956 3957 err := state.UpsertAllocs(1000, allocs) 3958 if err != nil { 3959 t.Fatalf("err: %v", err) 3960 } 3961 3962 ws := memdb.NewWatchSet() 3963 out, err := state.AllocsByJob(ws, "foo", false) 3964 if err != nil { 3965 t.Fatalf("err: %v", err) 3966 } 3967 3968 sort.Sort(AllocIDSort(allocs)) 3969 sort.Sort(AllocIDSort(out)) 3970 3971 if !reflect.DeepEqual(allocs, out) { 3972 t.Fatalf("bad: %#v %#v", allocs, out) 3973 } 3974 3975 if watchFired(ws) { 3976 t.Fatalf("bad") 3977 } 3978 } 3979 3980 func TestStateStore_AllocsForRegisteredJob(t *testing.T) { 3981 state := testStateStore(t) 3982 var allocs []*structs.Allocation 3983 var allocs1 []*structs.Allocation 3984 3985 job := mock.Job() 3986 job.ID = "foo" 3987 state.UpsertJob(100, job) 3988 for i := 0; i < 3; i++ { 3989 alloc := mock.Alloc() 3990 alloc.Job = job 3991 alloc.JobID = job.ID 3992 allocs = append(allocs, alloc) 3993 } 3994 if err := state.UpsertAllocs(200, allocs); err != nil { 3995 t.Fatalf("err: %v", err) 3996 } 3997 3998 if err := state.DeleteJob(250, job.ID); err != nil { 3999 t.Fatalf("err: %v", err) 4000 } 4001 4002 job1 := mock.Job() 4003 job1.ID = "foo" 4004 job1.CreateIndex = 50 4005 state.UpsertJob(300, job1) 4006 for i := 0; i < 4; i++ { 4007 alloc := mock.Alloc() 4008 alloc.Job = job1 4009 alloc.JobID = job1.ID 4010 allocs1 = append(allocs1, alloc) 4011 } 4012 4013 if err := state.UpsertAllocs(1000, allocs1); err != nil { 4014 t.Fatalf("err: %v", err) 4015 } 4016 4017 ws := memdb.NewWatchSet() 4018 out, err := state.AllocsByJob(ws, job1.ID, true) 4019 if err != nil { 4020 t.Fatalf("err: %v", err) 4021 } 4022 4023 expected := len(allocs) + len(allocs1) 4024 if len(out) != expected { 4025 t.Fatalf("expected: %v, actual: %v", expected, len(out)) 4026 } 4027 4028 out1, err := state.AllocsByJob(ws, job1.ID, false) 4029 expected = len(allocs1) 4030 if len(out1) != expected { 4031 t.Fatalf("expected: %v, actual: %v", expected, len(out1)) 4032 } 4033 4034 if watchFired(ws) { 4035 t.Fatalf("bad") 4036 } 4037 } 4038 4039 func TestStateStore_AllocsByIDPrefix(t *testing.T) { 4040 state := testStateStore(t) 4041 var allocs []*structs.Allocation 4042 4043 ids := []string{ 4044 "aaaaaaaa-7bfb-395d-eb95-0685af2176b2", 4045 "aaaaaaab-7bfb-395d-eb95-0685af2176b2", 4046 "aaaaaabb-7bfb-395d-eb95-0685af2176b2", 4047 "aaaaabbb-7bfb-395d-eb95-0685af2176b2", 4048 "aaaabbbb-7bfb-395d-eb95-0685af2176b2", 4049 "aaabbbbb-7bfb-395d-eb95-0685af2176b2", 4050 "aabbbbbb-7bfb-395d-eb95-0685af2176b2", 4051 "abbbbbbb-7bfb-395d-eb95-0685af2176b2", 4052 "bbbbbbbb-7bfb-395d-eb95-0685af2176b2", 4053 } 4054 for i := 0; i < 9; i++ { 4055 alloc := mock.Alloc() 4056 alloc.ID = ids[i] 4057 allocs = append(allocs, alloc) 4058 } 4059 4060 for i, alloc := range allocs { 4061 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 4062 } 4063 4064 err := state.UpsertAllocs(1000, allocs) 4065 if err != nil { 4066 t.Fatalf("err: %v", err) 4067 } 4068 4069 ws := memdb.NewWatchSet() 4070 iter, err := state.AllocsByIDPrefix(ws, "aaaa") 4071 if err != nil { 4072 t.Fatalf("err: %v", err) 4073 } 4074 4075 gatherAllocs := func(iter memdb.ResultIterator) []*structs.Allocation { 4076 var allocs []*structs.Allocation 4077 for { 4078 raw := iter.Next() 4079 if raw == nil { 4080 break 4081 } 4082 allocs = append(allocs, raw.(*structs.Allocation)) 4083 } 4084 return allocs 4085 } 4086 4087 out := gatherAllocs(iter) 4088 if len(out) != 5 { 4089 t.Fatalf("bad: expected five allocations, got: %#v", out) 4090 } 4091 4092 sort.Sort(AllocIDSort(allocs)) 4093 4094 for index, alloc := range out { 4095 if ids[index] != alloc.ID { 4096 t.Fatalf("bad: got unexpected id: %s", alloc.ID) 4097 } 4098 } 4099 4100 iter, err = state.AllocsByIDPrefix(ws, "b-a7bfb") 4101 if err != nil { 4102 t.Fatalf("err: %v", err) 4103 } 4104 4105 out = gatherAllocs(iter) 4106 if len(out) != 0 { 4107 t.Fatalf("bad: unexpected zero allocations, got: %#v", out) 4108 } 4109 4110 if watchFired(ws) { 4111 t.Fatalf("bad") 4112 } 4113 } 4114 4115 func TestStateStore_Allocs(t *testing.T) { 4116 state := testStateStore(t) 4117 var allocs []*structs.Allocation 4118 4119 for i := 0; i < 10; i++ { 4120 alloc := mock.Alloc() 4121 allocs = append(allocs, alloc) 4122 } 4123 for i, alloc := range allocs { 4124 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 4125 } 4126 4127 err := state.UpsertAllocs(1000, allocs) 4128 if err != nil { 4129 t.Fatalf("err: %v", err) 4130 } 4131 4132 ws := memdb.NewWatchSet() 4133 iter, err := state.Allocs(ws) 4134 if err != nil { 4135 t.Fatalf("err: %v", err) 4136 } 4137 4138 var out []*structs.Allocation 4139 for { 4140 raw := iter.Next() 4141 if raw == nil { 4142 break 4143 } 4144 out = append(out, raw.(*structs.Allocation)) 4145 } 4146 4147 sort.Sort(AllocIDSort(allocs)) 4148 sort.Sort(AllocIDSort(out)) 4149 4150 if !reflect.DeepEqual(allocs, out) { 4151 t.Fatalf("bad: %#v %#v", allocs, out) 4152 } 4153 4154 if watchFired(ws) { 4155 t.Fatalf("bad") 4156 } 4157 } 4158 4159 func TestStateStore_RestoreAlloc(t *testing.T) { 4160 state := testStateStore(t) 4161 alloc := mock.Alloc() 4162 4163 restore, err := state.Restore() 4164 if err != nil { 4165 t.Fatalf("err: %v", err) 4166 } 4167 4168 err = restore.AllocRestore(alloc) 4169 if err != nil { 4170 t.Fatalf("err: %v", err) 4171 } 4172 4173 restore.Commit() 4174 4175 ws := memdb.NewWatchSet() 4176 out, err := state.AllocByID(ws, alloc.ID) 4177 if err != nil { 4178 t.Fatalf("err: %v", err) 4179 } 4180 4181 if !reflect.DeepEqual(out, alloc) { 4182 t.Fatalf("Bad: %#v %#v", out, alloc) 4183 } 4184 4185 if watchFired(ws) { 4186 t.Fatalf("bad") 4187 } 4188 } 4189 4190 func TestStateStore_RestoreAlloc_NoEphemeralDisk(t *testing.T) { 4191 state := testStateStore(t) 4192 alloc := mock.Alloc() 4193 alloc.Job.TaskGroups[0].EphemeralDisk = nil 4194 alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120 4195 4196 restore, err := state.Restore() 4197 if err != nil { 4198 t.Fatalf("err: %v", err) 4199 } 4200 4201 err = restore.AllocRestore(alloc) 4202 if err != nil { 4203 t.Fatalf("err: %v", err) 4204 } 4205 4206 restore.Commit() 4207 4208 ws := memdb.NewWatchSet() 4209 out, err := state.AllocByID(ws, alloc.ID) 4210 if err != nil { 4211 t.Fatalf("err: %v", err) 4212 } 4213 4214 expected := alloc.Copy() 4215 expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120} 4216 expected.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 4217 4218 if !reflect.DeepEqual(out, expected) { 4219 t.Fatalf("Bad: %#v %#v", out, expected) 4220 } 4221 4222 if watchFired(ws) { 4223 t.Fatalf("bad") 4224 } 4225 } 4226 4227 func TestStateStore_SetJobStatus_ForceStatus(t *testing.T) { 4228 state := testStateStore(t) 4229 txn := state.db.Txn(true) 4230 4231 // Create and insert a mock job. 4232 job := mock.Job() 4233 job.Status = "" 4234 job.ModifyIndex = 0 4235 if err := txn.Insert("jobs", job); err != nil { 4236 t.Fatalf("job insert failed: %v", err) 4237 } 4238 4239 exp := "foobar" 4240 index := uint64(1000) 4241 if err := state.setJobStatus(index, txn, job, false, exp); err != nil { 4242 t.Fatalf("setJobStatus() failed: %v", err) 4243 } 4244 4245 i, err := txn.First("jobs", "id", job.ID) 4246 if err != nil { 4247 t.Fatalf("job lookup failed: %v", err) 4248 } 4249 updated := i.(*structs.Job) 4250 4251 if updated.Status != exp { 4252 t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, exp) 4253 } 4254 4255 if updated.ModifyIndex != index { 4256 t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index) 4257 } 4258 } 4259 4260 func TestStateStore_SetJobStatus_NoOp(t *testing.T) { 4261 state := testStateStore(t) 4262 txn := state.db.Txn(true) 4263 4264 // Create and insert a mock job that should be pending. 4265 job := mock.Job() 4266 job.Status = structs.JobStatusPending 4267 job.ModifyIndex = 10 4268 if err := txn.Insert("jobs", job); err != nil { 4269 t.Fatalf("job insert failed: %v", err) 4270 } 4271 4272 index := uint64(1000) 4273 if err := state.setJobStatus(index, txn, job, false, ""); err != nil { 4274 t.Fatalf("setJobStatus() failed: %v", err) 4275 } 4276 4277 i, err := txn.First("jobs", "id", job.ID) 4278 if err != nil { 4279 t.Fatalf("job lookup failed: %v", err) 4280 } 4281 updated := i.(*structs.Job) 4282 4283 if updated.ModifyIndex == index { 4284 t.Fatalf("setJobStatus() should have been a no-op") 4285 } 4286 } 4287 4288 func TestStateStore_SetJobStatus(t *testing.T) { 4289 state := testStateStore(t) 4290 txn := state.db.Txn(true) 4291 4292 // Create and insert a mock job that should be pending but has an incorrect 4293 // status. 4294 job := mock.Job() 4295 job.Status = "foobar" 4296 job.ModifyIndex = 10 4297 if err := txn.Insert("jobs", job); err != nil { 4298 t.Fatalf("job insert failed: %v", err) 4299 } 4300 4301 index := uint64(1000) 4302 if err := state.setJobStatus(index, txn, job, false, ""); err != nil { 4303 t.Fatalf("setJobStatus() failed: %v", err) 4304 } 4305 4306 i, err := txn.First("jobs", "id", job.ID) 4307 if err != nil { 4308 t.Fatalf("job lookup failed: %v", err) 4309 } 4310 updated := i.(*structs.Job) 4311 4312 if updated.Status != structs.JobStatusPending { 4313 t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, structs.JobStatusPending) 4314 } 4315 4316 if updated.ModifyIndex != index { 4317 t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index) 4318 } 4319 } 4320 4321 func TestStateStore_GetJobStatus_NoEvalsOrAllocs(t *testing.T) { 4322 job := mock.Job() 4323 state := testStateStore(t) 4324 txn := state.db.Txn(false) 4325 status, err := state.getJobStatus(txn, job, false) 4326 if err != nil { 4327 t.Fatalf("getJobStatus() failed: %v", err) 4328 } 4329 4330 if status != structs.JobStatusPending { 4331 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending) 4332 } 4333 } 4334 4335 func TestStateStore_GetJobStatus_NoEvalsOrAllocs_Periodic(t *testing.T) { 4336 job := mock.PeriodicJob() 4337 state := testStateStore(t) 4338 txn := state.db.Txn(false) 4339 status, err := state.getJobStatus(txn, job, false) 4340 if err != nil { 4341 t.Fatalf("getJobStatus() failed: %v", err) 4342 } 4343 4344 if status != structs.JobStatusRunning { 4345 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 4346 } 4347 } 4348 4349 func TestStateStore_GetJobStatus_NoEvalsOrAllocs_EvalDelete(t *testing.T) { 4350 job := mock.Job() 4351 state := testStateStore(t) 4352 txn := state.db.Txn(false) 4353 status, err := state.getJobStatus(txn, job, true) 4354 if err != nil { 4355 t.Fatalf("getJobStatus() failed: %v", err) 4356 } 4357 4358 if status != structs.JobStatusDead { 4359 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 4360 } 4361 } 4362 4363 func TestStateStore_GetJobStatus_DeadEvalsAndAllocs(t *testing.T) { 4364 state := testStateStore(t) 4365 job := mock.Job() 4366 4367 // Create a mock alloc that is dead. 4368 alloc := mock.Alloc() 4369 alloc.JobID = job.ID 4370 alloc.DesiredStatus = structs.AllocDesiredStatusStop 4371 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 4372 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { 4373 t.Fatalf("err: %v", err) 4374 } 4375 4376 // Create a mock eval that is complete 4377 eval := mock.Eval() 4378 eval.JobID = job.ID 4379 eval.Status = structs.EvalStatusComplete 4380 if err := state.UpsertEvals(1001, []*structs.Evaluation{eval}); err != nil { 4381 t.Fatalf("err: %v", err) 4382 } 4383 4384 txn := state.db.Txn(false) 4385 status, err := state.getJobStatus(txn, job, false) 4386 if err != nil { 4387 t.Fatalf("getJobStatus() failed: %v", err) 4388 } 4389 4390 if status != structs.JobStatusDead { 4391 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 4392 } 4393 } 4394 4395 func TestStateStore_GetJobStatus_RunningAlloc(t *testing.T) { 4396 state := testStateStore(t) 4397 job := mock.Job() 4398 4399 // Create a mock alloc that is running. 4400 alloc := mock.Alloc() 4401 alloc.JobID = job.ID 4402 alloc.DesiredStatus = structs.AllocDesiredStatusRun 4403 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 4404 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { 4405 t.Fatalf("err: %v", err) 4406 } 4407 4408 txn := state.db.Txn(false) 4409 status, err := state.getJobStatus(txn, job, true) 4410 if err != nil { 4411 t.Fatalf("getJobStatus() failed: %v", err) 4412 } 4413 4414 if status != structs.JobStatusRunning { 4415 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 4416 } 4417 } 4418 4419 func TestStateStore_GetJobStatus_PeriodicJob(t *testing.T) { 4420 state := testStateStore(t) 4421 job := mock.PeriodicJob() 4422 4423 txn := state.db.Txn(false) 4424 status, err := state.getJobStatus(txn, job, false) 4425 if err != nil { 4426 t.Fatalf("getJobStatus() failed: %v", err) 4427 } 4428 4429 if status != structs.JobStatusRunning { 4430 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 4431 } 4432 4433 // Mark it as stopped 4434 job.Stop = true 4435 status, err = state.getJobStatus(txn, job, false) 4436 if err != nil { 4437 t.Fatalf("getJobStatus() failed: %v", err) 4438 } 4439 4440 if status != structs.JobStatusDead { 4441 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 4442 } 4443 } 4444 4445 func TestStateStore_GetJobStatus_ParameterizedJob(t *testing.T) { 4446 state := testStateStore(t) 4447 job := mock.Job() 4448 job.ParameterizedJob = &structs.ParameterizedJobConfig{} 4449 4450 txn := state.db.Txn(false) 4451 status, err := state.getJobStatus(txn, job, false) 4452 if err != nil { 4453 t.Fatalf("getJobStatus() failed: %v", err) 4454 } 4455 4456 if status != structs.JobStatusRunning { 4457 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 4458 } 4459 4460 // Mark it as stopped 4461 job.Stop = true 4462 status, err = state.getJobStatus(txn, job, false) 4463 if err != nil { 4464 t.Fatalf("getJobStatus() failed: %v", err) 4465 } 4466 4467 if status != structs.JobStatusDead { 4468 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 4469 } 4470 } 4471 4472 func TestStateStore_SetJobStatus_PendingEval(t *testing.T) { 4473 state := testStateStore(t) 4474 job := mock.Job() 4475 4476 // Create a mock eval that is pending. 4477 eval := mock.Eval() 4478 eval.JobID = job.ID 4479 eval.Status = structs.EvalStatusPending 4480 if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil { 4481 t.Fatalf("err: %v", err) 4482 } 4483 4484 txn := state.db.Txn(false) 4485 status, err := state.getJobStatus(txn, job, true) 4486 if err != nil { 4487 t.Fatalf("getJobStatus() failed: %v", err) 4488 } 4489 4490 if status != structs.JobStatusPending { 4491 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending) 4492 } 4493 } 4494 4495 // TestStateStore_SetJobStatus_SystemJob asserts that system jobs are still 4496 // considered running until explicitly stopped. 4497 func TestStateStore_SetJobStatus_SystemJob(t *testing.T) { 4498 state := testStateStore(t) 4499 job := mock.SystemJob() 4500 4501 // Create a mock eval that is pending. 4502 eval := mock.Eval() 4503 eval.JobID = job.ID 4504 eval.Type = job.Type 4505 eval.Status = structs.EvalStatusComplete 4506 if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil { 4507 t.Fatalf("err: %v", err) 4508 } 4509 4510 txn := state.db.Txn(false) 4511 status, err := state.getJobStatus(txn, job, true) 4512 if err != nil { 4513 t.Fatalf("getJobStatus() failed: %v", err) 4514 } 4515 4516 if expected := structs.JobStatusRunning; status != expected { 4517 t.Fatalf("getJobStatus() returned %v; expected %v", status, expected) 4518 } 4519 4520 // Stop the job 4521 job.Stop = true 4522 status, err = state.getJobStatus(txn, job, true) 4523 if err != nil { 4524 t.Fatalf("getJobStatus() failed: %v", err) 4525 } 4526 4527 if expected := structs.JobStatusDead; status != expected { 4528 t.Fatalf("getJobStatus() returned %v; expected %v", status, expected) 4529 } 4530 } 4531 4532 func TestStateJobSummary_UpdateJobCount(t *testing.T) { 4533 state := testStateStore(t) 4534 alloc := mock.Alloc() 4535 job := alloc.Job 4536 job.TaskGroups[0].Count = 3 4537 4538 // Create watchsets so we can test that upsert fires the watch 4539 ws := memdb.NewWatchSet() 4540 if _, err := state.JobSummaryByID(ws, job.ID); err != nil { 4541 t.Fatalf("bad: %v", err) 4542 } 4543 4544 if err := state.UpsertJob(1000, job); err != nil { 4545 t.Fatalf("err: %v", err) 4546 } 4547 4548 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc}); err != nil { 4549 t.Fatalf("err: %v", err) 4550 } 4551 4552 if !watchFired(ws) { 4553 t.Fatalf("bad") 4554 } 4555 4556 ws = memdb.NewWatchSet() 4557 summary, _ := state.JobSummaryByID(ws, job.ID) 4558 expectedSummary := structs.JobSummary{ 4559 JobID: job.ID, 4560 Summary: map[string]structs.TaskGroupSummary{ 4561 "web": { 4562 Starting: 1, 4563 }, 4564 }, 4565 Children: new(structs.JobChildrenSummary), 4566 CreateIndex: 1000, 4567 ModifyIndex: 1001, 4568 } 4569 if !reflect.DeepEqual(summary, &expectedSummary) { 4570 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 4571 } 4572 4573 // Create watchsets so we can test that upsert fires the watch 4574 ws2 := memdb.NewWatchSet() 4575 if _, err := state.JobSummaryByID(ws2, job.ID); err != nil { 4576 t.Fatalf("bad: %v", err) 4577 } 4578 4579 alloc2 := mock.Alloc() 4580 alloc2.Job = job 4581 alloc2.JobID = job.ID 4582 4583 alloc3 := mock.Alloc() 4584 alloc3.Job = job 4585 alloc3.JobID = job.ID 4586 4587 if err := state.UpsertAllocs(1002, []*structs.Allocation{alloc2, alloc3}); err != nil { 4588 t.Fatalf("err: %v", err) 4589 } 4590 4591 if !watchFired(ws2) { 4592 t.Fatalf("bad") 4593 } 4594 4595 outA, _ := state.AllocByID(ws, alloc3.ID) 4596 4597 summary, _ = state.JobSummaryByID(ws, job.ID) 4598 expectedSummary = structs.JobSummary{ 4599 JobID: job.ID, 4600 Summary: map[string]structs.TaskGroupSummary{ 4601 "web": { 4602 Starting: 3, 4603 }, 4604 }, 4605 Children: new(structs.JobChildrenSummary), 4606 CreateIndex: job.CreateIndex, 4607 ModifyIndex: outA.ModifyIndex, 4608 } 4609 if !reflect.DeepEqual(summary, &expectedSummary) { 4610 t.Fatalf("expected summary: %v, actual: %v", expectedSummary, summary) 4611 } 4612 4613 // Create watchsets so we can test that upsert fires the watch 4614 ws3 := memdb.NewWatchSet() 4615 if _, err := state.JobSummaryByID(ws3, job.ID); err != nil { 4616 t.Fatalf("bad: %v", err) 4617 } 4618 4619 alloc4 := mock.Alloc() 4620 alloc4.ID = alloc2.ID 4621 alloc4.Job = alloc2.Job 4622 alloc4.JobID = alloc2.JobID 4623 alloc4.ClientStatus = structs.AllocClientStatusComplete 4624 4625 alloc5 := mock.Alloc() 4626 alloc5.ID = alloc3.ID 4627 alloc5.Job = alloc3.Job 4628 alloc5.JobID = alloc3.JobID 4629 alloc5.ClientStatus = structs.AllocClientStatusComplete 4630 4631 if err := state.UpdateAllocsFromClient(1004, []*structs.Allocation{alloc4, alloc5}); err != nil { 4632 t.Fatalf("err: %v", err) 4633 } 4634 4635 if !watchFired(ws2) { 4636 t.Fatalf("bad") 4637 } 4638 4639 outA, _ = state.AllocByID(ws, alloc5.ID) 4640 summary, _ = state.JobSummaryByID(ws, job.ID) 4641 expectedSummary = structs.JobSummary{ 4642 JobID: job.ID, 4643 Summary: map[string]structs.TaskGroupSummary{ 4644 "web": { 4645 Complete: 2, 4646 Starting: 1, 4647 }, 4648 }, 4649 Children: new(structs.JobChildrenSummary), 4650 CreateIndex: job.CreateIndex, 4651 ModifyIndex: outA.ModifyIndex, 4652 } 4653 if !reflect.DeepEqual(summary, &expectedSummary) { 4654 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 4655 } 4656 } 4657 4658 func TestJobSummary_UpdateClientStatus(t *testing.T) { 4659 state := testStateStore(t) 4660 alloc := mock.Alloc() 4661 job := alloc.Job 4662 job.TaskGroups[0].Count = 3 4663 4664 alloc2 := mock.Alloc() 4665 alloc2.Job = job 4666 alloc2.JobID = job.ID 4667 4668 alloc3 := mock.Alloc() 4669 alloc3.Job = job 4670 alloc3.JobID = job.ID 4671 4672 err := state.UpsertJob(1000, job) 4673 if err != nil { 4674 t.Fatalf("err: %v", err) 4675 } 4676 4677 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc, alloc2, alloc3}); err != nil { 4678 t.Fatalf("err: %v", err) 4679 } 4680 4681 ws := memdb.NewWatchSet() 4682 summary, _ := state.JobSummaryByID(ws, job.ID) 4683 if summary.Summary["web"].Starting != 3 { 4684 t.Fatalf("bad job summary: %v", summary) 4685 } 4686 4687 alloc4 := mock.Alloc() 4688 alloc4.ID = alloc2.ID 4689 alloc4.Job = alloc2.Job 4690 alloc4.JobID = alloc2.JobID 4691 alloc4.ClientStatus = structs.AllocClientStatusComplete 4692 4693 alloc5 := mock.Alloc() 4694 alloc5.ID = alloc3.ID 4695 alloc5.Job = alloc3.Job 4696 alloc5.JobID = alloc3.JobID 4697 alloc5.ClientStatus = structs.AllocClientStatusFailed 4698 4699 alloc6 := mock.Alloc() 4700 alloc6.ID = alloc.ID 4701 alloc6.Job = alloc.Job 4702 alloc6.JobID = alloc.JobID 4703 alloc6.ClientStatus = structs.AllocClientStatusRunning 4704 4705 if err := state.UpdateAllocsFromClient(1002, []*structs.Allocation{alloc4, alloc5, alloc6}); err != nil { 4706 t.Fatalf("err: %v", err) 4707 } 4708 4709 if !watchFired(ws) { 4710 t.Fatalf("bad") 4711 } 4712 4713 summary, _ = state.JobSummaryByID(ws, job.ID) 4714 if summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 { 4715 t.Fatalf("bad job summary: %v", summary) 4716 } 4717 4718 alloc7 := mock.Alloc() 4719 alloc7.Job = alloc.Job 4720 alloc7.JobID = alloc.JobID 4721 4722 if err := state.UpsertAllocs(1003, []*structs.Allocation{alloc7}); err != nil { 4723 t.Fatalf("err: %v", err) 4724 } 4725 summary, _ = state.JobSummaryByID(ws, job.ID) 4726 if summary.Summary["web"].Starting != 1 || summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 { 4727 t.Fatalf("bad job summary: %v", summary) 4728 } 4729 } 4730 4731 // Test that non-existant deployment can't be updated 4732 func TestStateStore_UpsertDeploymentStatusUpdate_NonExistant(t *testing.T) { 4733 state := testStateStore(t) 4734 4735 // Update the non-existant deployment 4736 req := &structs.DeploymentStatusUpdateRequest{ 4737 DeploymentUpdate: &structs.DeploymentStatusUpdate{ 4738 DeploymentID: structs.GenerateUUID(), 4739 Status: structs.DeploymentStatusRunning, 4740 }, 4741 } 4742 err := state.UpdateDeploymentStatus(2, req) 4743 if err == nil || !strings.Contains(err.Error(), "does not exist") { 4744 t.Fatalf("expected error updating the status because the deployment doesn't exist") 4745 } 4746 } 4747 4748 // Test that terminal deployment can't be updated 4749 func TestStateStore_UpsertDeploymentStatusUpdate_Terminal(t *testing.T) { 4750 state := testStateStore(t) 4751 4752 // Insert a terminal deployment 4753 d := mock.Deployment() 4754 d.Status = structs.DeploymentStatusFailed 4755 4756 if err := state.UpsertDeployment(1, d); err != nil { 4757 t.Fatalf("bad: %v", err) 4758 } 4759 4760 // Update the deployment 4761 req := &structs.DeploymentStatusUpdateRequest{ 4762 DeploymentUpdate: &structs.DeploymentStatusUpdate{ 4763 DeploymentID: d.ID, 4764 Status: structs.DeploymentStatusRunning, 4765 }, 4766 } 4767 err := state.UpdateDeploymentStatus(2, req) 4768 if err == nil || !strings.Contains(err.Error(), "has terminal status") { 4769 t.Fatalf("expected error updating the status because the deployment is terminal") 4770 } 4771 } 4772 4773 // Test that a non terminal deployment is updated and that a job and eval are 4774 // created. 4775 func TestStateStore_UpsertDeploymentStatusUpdate_NonTerminal(t *testing.T) { 4776 state := testStateStore(t) 4777 4778 // Insert a deployment 4779 d := mock.Deployment() 4780 if err := state.UpsertDeployment(1, d); err != nil { 4781 t.Fatalf("bad: %v", err) 4782 } 4783 4784 // Create an eval and a job 4785 e := mock.Eval() 4786 j := mock.Job() 4787 4788 // Update the deployment 4789 status, desc := structs.DeploymentStatusFailed, "foo" 4790 req := &structs.DeploymentStatusUpdateRequest{ 4791 DeploymentUpdate: &structs.DeploymentStatusUpdate{ 4792 DeploymentID: d.ID, 4793 Status: status, 4794 StatusDescription: desc, 4795 }, 4796 Job: j, 4797 Eval: e, 4798 } 4799 err := state.UpdateDeploymentStatus(2, req) 4800 if err != nil { 4801 t.Fatalf("bad: %v", err) 4802 } 4803 4804 // Check that the status was updated properly 4805 ws := memdb.NewWatchSet() 4806 dout, err := state.DeploymentByID(ws, d.ID) 4807 if err != nil { 4808 t.Fatalf("bad: %v", err) 4809 } 4810 if dout.Status != status || dout.StatusDescription != desc { 4811 t.Fatalf("bad: %#v", dout) 4812 } 4813 4814 // Check that the evaluation was created 4815 eout, _ := state.EvalByID(ws, e.ID) 4816 if err != nil { 4817 t.Fatalf("bad: %v", err) 4818 } 4819 if eout == nil { 4820 t.Fatalf("bad: %#v", eout) 4821 } 4822 4823 // Check that the job was created 4824 jout, _ := state.JobByID(ws, j.ID) 4825 if err != nil { 4826 t.Fatalf("bad: %v", err) 4827 } 4828 if jout == nil { 4829 t.Fatalf("bad: %#v", jout) 4830 } 4831 } 4832 4833 // Test that when a deployment is updated to successful the job is updated to 4834 // stable 4835 func TestStateStore_UpsertDeploymentStatusUpdate_Successful(t *testing.T) { 4836 state := testStateStore(t) 4837 4838 // Insert a job 4839 job := mock.Job() 4840 if err := state.UpsertJob(1, job); err != nil { 4841 t.Fatalf("bad: %v", err) 4842 } 4843 4844 // Insert a deployment 4845 d := structs.NewDeployment(job) 4846 if err := state.UpsertDeployment(2, d); err != nil { 4847 t.Fatalf("bad: %v", err) 4848 } 4849 4850 // Update the deployment 4851 req := &structs.DeploymentStatusUpdateRequest{ 4852 DeploymentUpdate: &structs.DeploymentStatusUpdate{ 4853 DeploymentID: d.ID, 4854 Status: structs.DeploymentStatusSuccessful, 4855 StatusDescription: structs.DeploymentStatusDescriptionSuccessful, 4856 }, 4857 } 4858 err := state.UpdateDeploymentStatus(3, req) 4859 if err != nil { 4860 t.Fatalf("bad: %v", err) 4861 } 4862 4863 // Check that the status was updated properly 4864 ws := memdb.NewWatchSet() 4865 dout, err := state.DeploymentByID(ws, d.ID) 4866 if err != nil { 4867 t.Fatalf("bad: %v", err) 4868 } 4869 if dout.Status != structs.DeploymentStatusSuccessful || 4870 dout.StatusDescription != structs.DeploymentStatusDescriptionSuccessful { 4871 t.Fatalf("bad: %#v", dout) 4872 } 4873 4874 // Check that the job was created 4875 jout, _ := state.JobByID(ws, job.ID) 4876 if err != nil { 4877 t.Fatalf("bad: %v", err) 4878 } 4879 if jout == nil { 4880 t.Fatalf("bad: %#v", jout) 4881 } 4882 if !jout.Stable { 4883 t.Fatalf("job not marked stable %#v", jout) 4884 } 4885 if jout.Version != d.JobVersion { 4886 t.Fatalf("job version changed; got %d; want %d", jout.Version, d.JobVersion) 4887 } 4888 } 4889 4890 func TestStateStore_UpdateJobStability(t *testing.T) { 4891 state := testStateStore(t) 4892 4893 // Insert a job twice to get two versions 4894 job := mock.Job() 4895 if err := state.UpsertJob(1, job); err != nil { 4896 t.Fatalf("bad: %v", err) 4897 } 4898 4899 if err := state.UpsertJob(2, job); err != nil { 4900 t.Fatalf("bad: %v", err) 4901 } 4902 4903 // Update the stability to true 4904 err := state.UpdateJobStability(3, job.ID, 0, true) 4905 if err != nil { 4906 t.Fatalf("bad: %v", err) 4907 } 4908 4909 // Check that the job was updated properly 4910 ws := memdb.NewWatchSet() 4911 jout, _ := state.JobByIDAndVersion(ws, job.ID, 0) 4912 if err != nil { 4913 t.Fatalf("bad: %v", err) 4914 } 4915 if jout == nil { 4916 t.Fatalf("bad: %#v", jout) 4917 } 4918 if !jout.Stable { 4919 t.Fatalf("job not marked stable %#v", jout) 4920 } 4921 4922 // Update the stability to false 4923 err = state.UpdateJobStability(3, job.ID, 0, false) 4924 if err != nil { 4925 t.Fatalf("bad: %v", err) 4926 } 4927 4928 // Check that the job was updated properly 4929 jout, _ = state.JobByIDAndVersion(ws, job.ID, 0) 4930 if err != nil { 4931 t.Fatalf("bad: %v", err) 4932 } 4933 if jout == nil { 4934 t.Fatalf("bad: %#v", jout) 4935 } 4936 if jout.Stable { 4937 t.Fatalf("job marked stable %#v", jout) 4938 } 4939 } 4940 4941 // Test that non-existant deployment can't be promoted 4942 func TestStateStore_UpsertDeploymentPromotion_NonExistant(t *testing.T) { 4943 state := testStateStore(t) 4944 4945 // Promote the non-existant deployment 4946 req := &structs.ApplyDeploymentPromoteRequest{ 4947 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 4948 DeploymentID: structs.GenerateUUID(), 4949 All: true, 4950 }, 4951 } 4952 err := state.UpdateDeploymentPromotion(2, req) 4953 if err == nil || !strings.Contains(err.Error(), "does not exist") { 4954 t.Fatalf("expected error promoting because the deployment doesn't exist") 4955 } 4956 } 4957 4958 // Test that terminal deployment can't be updated 4959 func TestStateStore_UpsertDeploymentPromotion_Terminal(t *testing.T) { 4960 state := testStateStore(t) 4961 4962 // Insert a terminal deployment 4963 d := mock.Deployment() 4964 d.Status = structs.DeploymentStatusFailed 4965 4966 if err := state.UpsertDeployment(1, d); err != nil { 4967 t.Fatalf("bad: %v", err) 4968 } 4969 4970 // Promote the deployment 4971 req := &structs.ApplyDeploymentPromoteRequest{ 4972 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 4973 DeploymentID: d.ID, 4974 All: true, 4975 }, 4976 } 4977 err := state.UpdateDeploymentPromotion(2, req) 4978 if err == nil || !strings.Contains(err.Error(), "has terminal status") { 4979 t.Fatalf("expected error updating the status because the deployment is terminal: %v", err) 4980 } 4981 } 4982 4983 // Test promoting unhealthy canaries in a deployment. 4984 func TestStateStore_UpsertDeploymentPromotion_Unhealthy(t *testing.T) { 4985 state := testStateStore(t) 4986 4987 // Create a job 4988 j := mock.Job() 4989 if err := state.UpsertJob(1, j); err != nil { 4990 t.Fatalf("bad: %v", err) 4991 } 4992 4993 // Create a deployment 4994 d := mock.Deployment() 4995 d.JobID = j.ID 4996 if err := state.UpsertDeployment(2, d); err != nil { 4997 t.Fatalf("bad: %v", err) 4998 } 4999 5000 // Create a set of allocations 5001 c1 := mock.Alloc() 5002 c1.JobID = j.ID 5003 c1.DeploymentID = d.ID 5004 d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID) 5005 c2 := mock.Alloc() 5006 c2.JobID = j.ID 5007 c2.DeploymentID = d.ID 5008 d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID) 5009 5010 if err := state.UpsertAllocs(3, []*structs.Allocation{c1, c2}); err != nil { 5011 t.Fatalf("err: %v", err) 5012 } 5013 5014 // Promote the canaries 5015 req := &structs.ApplyDeploymentPromoteRequest{ 5016 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 5017 DeploymentID: d.ID, 5018 All: true, 5019 }, 5020 } 5021 err := state.UpdateDeploymentPromotion(4, req) 5022 if err == nil { 5023 t.Fatalf("bad: %v", err) 5024 } 5025 if !strings.Contains(err.Error(), c1.ID) { 5026 t.Fatalf("expect canary %q to be listed as unhealth: %v", c1.ID, err) 5027 } 5028 if !strings.Contains(err.Error(), c2.ID) { 5029 t.Fatalf("expect canary %q to be listed as unhealth: %v", c2.ID, err) 5030 } 5031 } 5032 5033 // Test promoting all canaries in a deployment. 5034 func TestStateStore_UpsertDeploymentPromotion_All(t *testing.T) { 5035 state := testStateStore(t) 5036 5037 // Create a job with two task groups 5038 j := mock.Job() 5039 tg1 := j.TaskGroups[0] 5040 tg2 := tg1.Copy() 5041 tg2.Name = "foo" 5042 j.TaskGroups = append(j.TaskGroups, tg2) 5043 if err := state.UpsertJob(1, j); err != nil { 5044 t.Fatalf("bad: %v", err) 5045 } 5046 5047 // Create a deployment 5048 d := mock.Deployment() 5049 d.StatusDescription = structs.DeploymentStatusDescriptionRunningNeedsPromotion 5050 d.JobID = j.ID 5051 d.TaskGroups = map[string]*structs.DeploymentState{ 5052 "web": &structs.DeploymentState{ 5053 DesiredTotal: 10, 5054 DesiredCanaries: 1, 5055 }, 5056 "foo": &structs.DeploymentState{ 5057 DesiredTotal: 10, 5058 DesiredCanaries: 1, 5059 }, 5060 } 5061 if err := state.UpsertDeployment(2, d); err != nil { 5062 t.Fatalf("bad: %v", err) 5063 } 5064 5065 // Create a set of allocations 5066 c1 := mock.Alloc() 5067 c1.JobID = j.ID 5068 c1.DeploymentID = d.ID 5069 d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID) 5070 c1.DeploymentStatus = &structs.AllocDeploymentStatus{ 5071 Healthy: helper.BoolToPtr(true), 5072 } 5073 c2 := mock.Alloc() 5074 c2.JobID = j.ID 5075 c2.DeploymentID = d.ID 5076 d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID) 5077 c2.TaskGroup = tg2.Name 5078 c2.DeploymentStatus = &structs.AllocDeploymentStatus{ 5079 Healthy: helper.BoolToPtr(true), 5080 } 5081 5082 if err := state.UpsertAllocs(3, []*structs.Allocation{c1, c2}); err != nil { 5083 t.Fatalf("err: %v", err) 5084 } 5085 5086 // Create an eval 5087 e := mock.Eval() 5088 5089 // Promote the canaries 5090 req := &structs.ApplyDeploymentPromoteRequest{ 5091 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 5092 DeploymentID: d.ID, 5093 All: true, 5094 }, 5095 Eval: e, 5096 } 5097 err := state.UpdateDeploymentPromotion(4, req) 5098 if err != nil { 5099 t.Fatalf("bad: %v", err) 5100 } 5101 5102 // Check that the status per task group was updated properly 5103 ws := memdb.NewWatchSet() 5104 dout, err := state.DeploymentByID(ws, d.ID) 5105 if err != nil { 5106 t.Fatalf("bad: %v", err) 5107 } 5108 if dout.StatusDescription != structs.DeploymentStatusDescriptionRunning { 5109 t.Fatalf("status description not updated: got %v; want %v", dout.StatusDescription, structs.DeploymentStatusDescriptionRunning) 5110 } 5111 if len(dout.TaskGroups) != 2 { 5112 t.Fatalf("bad: %#v", dout.TaskGroups) 5113 } 5114 for tg, state := range dout.TaskGroups { 5115 if !state.Promoted { 5116 t.Fatalf("bad: group %q not promoted %#v", tg, state) 5117 } 5118 } 5119 5120 // Check that the evaluation was created 5121 eout, _ := state.EvalByID(ws, e.ID) 5122 if err != nil { 5123 t.Fatalf("bad: %v", err) 5124 } 5125 if eout == nil { 5126 t.Fatalf("bad: %#v", eout) 5127 } 5128 } 5129 5130 // Test promoting a subset of canaries in a deployment. 5131 func TestStateStore_UpsertDeploymentPromotion_Subset(t *testing.T) { 5132 state := testStateStore(t) 5133 5134 // Create a job with two task groups 5135 j := mock.Job() 5136 tg1 := j.TaskGroups[0] 5137 tg2 := tg1.Copy() 5138 tg2.Name = "foo" 5139 j.TaskGroups = append(j.TaskGroups, tg2) 5140 if err := state.UpsertJob(1, j); err != nil { 5141 t.Fatalf("bad: %v", err) 5142 } 5143 5144 // Create a deployment 5145 d := mock.Deployment() 5146 d.JobID = j.ID 5147 d.TaskGroups = map[string]*structs.DeploymentState{ 5148 "web": &structs.DeploymentState{ 5149 DesiredTotal: 10, 5150 DesiredCanaries: 1, 5151 }, 5152 "foo": &structs.DeploymentState{ 5153 DesiredTotal: 10, 5154 DesiredCanaries: 1, 5155 }, 5156 } 5157 if err := state.UpsertDeployment(2, d); err != nil { 5158 t.Fatalf("bad: %v", err) 5159 } 5160 5161 // Create a set of allocations 5162 c1 := mock.Alloc() 5163 c1.JobID = j.ID 5164 c1.DeploymentID = d.ID 5165 d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID) 5166 c1.DeploymentStatus = &structs.AllocDeploymentStatus{ 5167 Healthy: helper.BoolToPtr(true), 5168 } 5169 c2 := mock.Alloc() 5170 c2.JobID = j.ID 5171 c2.DeploymentID = d.ID 5172 d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID) 5173 c2.TaskGroup = tg2.Name 5174 c2.DeploymentStatus = &structs.AllocDeploymentStatus{ 5175 Healthy: helper.BoolToPtr(true), 5176 } 5177 5178 if err := state.UpsertAllocs(3, []*structs.Allocation{c1, c2}); err != nil { 5179 t.Fatalf("err: %v", err) 5180 } 5181 5182 // Create an eval 5183 e := mock.Eval() 5184 5185 // Promote the canaries 5186 req := &structs.ApplyDeploymentPromoteRequest{ 5187 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 5188 DeploymentID: d.ID, 5189 Groups: []string{"web"}, 5190 }, 5191 Eval: e, 5192 } 5193 err := state.UpdateDeploymentPromotion(4, req) 5194 if err != nil { 5195 t.Fatalf("bad: %v", err) 5196 } 5197 5198 // Check that the status per task group was updated properly 5199 ws := memdb.NewWatchSet() 5200 dout, err := state.DeploymentByID(ws, d.ID) 5201 if err != nil { 5202 t.Fatalf("bad: %v", err) 5203 } 5204 if len(dout.TaskGroups) != 2 { 5205 t.Fatalf("bad: %#v", dout.TaskGroups) 5206 } 5207 stateout, ok := dout.TaskGroups["web"] 5208 if !ok { 5209 t.Fatalf("bad: no state for task group web") 5210 } 5211 if !stateout.Promoted { 5212 t.Fatalf("bad: task group web not promoted: %#v", stateout) 5213 } 5214 5215 // Check that the evaluation was created 5216 eout, _ := state.EvalByID(ws, e.ID) 5217 if err != nil { 5218 t.Fatalf("bad: %v", err) 5219 } 5220 if eout == nil { 5221 t.Fatalf("bad: %#v", eout) 5222 } 5223 } 5224 5225 // Test that allocation health can't be set against a non-existant deployment 5226 func TestStateStore_UpsertDeploymentAllocHealth_NonExistant(t *testing.T) { 5227 state := testStateStore(t) 5228 5229 // Set health against the non-existant deployment 5230 req := &structs.ApplyDeploymentAllocHealthRequest{ 5231 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 5232 DeploymentID: structs.GenerateUUID(), 5233 HealthyAllocationIDs: []string{structs.GenerateUUID()}, 5234 }, 5235 } 5236 err := state.UpdateDeploymentAllocHealth(2, req) 5237 if err == nil || !strings.Contains(err.Error(), "does not exist") { 5238 t.Fatalf("expected error because the deployment doesn't exist: %v", err) 5239 } 5240 } 5241 5242 // Test that allocation health can't be set against a terminal deployment 5243 func TestStateStore_UpsertDeploymentAllocHealth_Terminal(t *testing.T) { 5244 state := testStateStore(t) 5245 5246 // Insert a terminal deployment 5247 d := mock.Deployment() 5248 d.Status = structs.DeploymentStatusFailed 5249 5250 if err := state.UpsertDeployment(1, d); err != nil { 5251 t.Fatalf("bad: %v", err) 5252 } 5253 5254 // Set health against the terminal deployment 5255 req := &structs.ApplyDeploymentAllocHealthRequest{ 5256 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 5257 DeploymentID: d.ID, 5258 HealthyAllocationIDs: []string{structs.GenerateUUID()}, 5259 }, 5260 } 5261 err := state.UpdateDeploymentAllocHealth(2, req) 5262 if err == nil || !strings.Contains(err.Error(), "has terminal status") { 5263 t.Fatalf("expected error because the deployment is terminal: %v", err) 5264 } 5265 } 5266 5267 // Test that allocation health can't be set against a non-existant alloc 5268 func TestStateStore_UpsertDeploymentAllocHealth_BadAlloc_NonExistant(t *testing.T) { 5269 state := testStateStore(t) 5270 5271 // Insert a deployment 5272 d := mock.Deployment() 5273 if err := state.UpsertDeployment(1, d); err != nil { 5274 t.Fatalf("bad: %v", err) 5275 } 5276 5277 // Set health against the terminal deployment 5278 req := &structs.ApplyDeploymentAllocHealthRequest{ 5279 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 5280 DeploymentID: d.ID, 5281 HealthyAllocationIDs: []string{structs.GenerateUUID()}, 5282 }, 5283 } 5284 err := state.UpdateDeploymentAllocHealth(2, req) 5285 if err == nil || !strings.Contains(err.Error(), "unknown alloc") { 5286 t.Fatalf("expected error because the alloc doesn't exist: %v", err) 5287 } 5288 } 5289 5290 // Test that allocation health can't be set for an alloc with mismatched 5291 // deployment ids 5292 func TestStateStore_UpsertDeploymentAllocHealth_BadAlloc_MismatchDeployment(t *testing.T) { 5293 state := testStateStore(t) 5294 5295 // Insert two deployment 5296 d1 := mock.Deployment() 5297 d2 := mock.Deployment() 5298 if err := state.UpsertDeployment(1, d1); err != nil { 5299 t.Fatalf("bad: %v", err) 5300 } 5301 if err := state.UpsertDeployment(2, d2); err != nil { 5302 t.Fatalf("bad: %v", err) 5303 } 5304 5305 // Insert an alloc for a random deployment 5306 a := mock.Alloc() 5307 a.DeploymentID = d1.ID 5308 if err := state.UpsertAllocs(3, []*structs.Allocation{a}); err != nil { 5309 t.Fatalf("bad: %v", err) 5310 } 5311 5312 // Set health against the terminal deployment 5313 req := &structs.ApplyDeploymentAllocHealthRequest{ 5314 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 5315 DeploymentID: d2.ID, 5316 HealthyAllocationIDs: []string{a.ID}, 5317 }, 5318 } 5319 err := state.UpdateDeploymentAllocHealth(4, req) 5320 if err == nil || !strings.Contains(err.Error(), "not part of deployment") { 5321 t.Fatalf("expected error because the alloc isn't part of the deployment: %v", err) 5322 } 5323 } 5324 5325 // Test that allocation health is properly set 5326 func TestStateStore_UpsertDeploymentAllocHealth(t *testing.T) { 5327 state := testStateStore(t) 5328 5329 // Insert a deployment 5330 d := mock.Deployment() 5331 if err := state.UpsertDeployment(1, d); err != nil { 5332 t.Fatalf("bad: %v", err) 5333 } 5334 5335 // Insert two allocations 5336 a1 := mock.Alloc() 5337 a1.DeploymentID = d.ID 5338 a2 := mock.Alloc() 5339 a2.DeploymentID = d.ID 5340 if err := state.UpsertAllocs(2, []*structs.Allocation{a1, a2}); err != nil { 5341 t.Fatalf("bad: %v", err) 5342 } 5343 5344 // Create a job to roll back to 5345 j := mock.Job() 5346 5347 // Create an eval that should be upserted 5348 e := mock.Eval() 5349 5350 // Create a status update for the deployment 5351 status, desc := structs.DeploymentStatusFailed, "foo" 5352 u := &structs.DeploymentStatusUpdate{ 5353 DeploymentID: d.ID, 5354 Status: status, 5355 StatusDescription: desc, 5356 } 5357 5358 // Set health against the deployment 5359 req := &structs.ApplyDeploymentAllocHealthRequest{ 5360 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 5361 DeploymentID: d.ID, 5362 HealthyAllocationIDs: []string{a1.ID}, 5363 UnhealthyAllocationIDs: []string{a2.ID}, 5364 }, 5365 Job: j, 5366 Eval: e, 5367 DeploymentUpdate: u, 5368 } 5369 err := state.UpdateDeploymentAllocHealth(3, req) 5370 if err != nil { 5371 t.Fatalf("bad: %v", err) 5372 } 5373 5374 // Check that the status was updated properly 5375 ws := memdb.NewWatchSet() 5376 dout, err := state.DeploymentByID(ws, d.ID) 5377 if err != nil { 5378 t.Fatalf("bad: %v", err) 5379 } 5380 if dout.Status != status || dout.StatusDescription != desc { 5381 t.Fatalf("bad: %#v", dout) 5382 } 5383 5384 // Check that the evaluation was created 5385 eout, _ := state.EvalByID(ws, e.ID) 5386 if err != nil { 5387 t.Fatalf("bad: %v", err) 5388 } 5389 if eout == nil { 5390 t.Fatalf("bad: %#v", eout) 5391 } 5392 5393 // Check that the job was created 5394 jout, _ := state.JobByID(ws, j.ID) 5395 if err != nil { 5396 t.Fatalf("bad: %v", err) 5397 } 5398 if jout == nil { 5399 t.Fatalf("bad: %#v", jout) 5400 } 5401 5402 // Check the status of the allocs 5403 out1, err := state.AllocByID(ws, a1.ID) 5404 if err != nil { 5405 t.Fatalf("err: %v", err) 5406 } 5407 out2, err := state.AllocByID(ws, a2.ID) 5408 if err != nil { 5409 t.Fatalf("err: %v", err) 5410 } 5411 5412 if !out1.DeploymentStatus.IsHealthy() { 5413 t.Fatalf("bad: alloc %q not healthy", out1.ID) 5414 } 5415 if !out2.DeploymentStatus.IsUnhealthy() { 5416 t.Fatalf("bad: alloc %q not unhealthy", out2.ID) 5417 } 5418 } 5419 5420 func TestStateStore_UpsertVaultAccessors(t *testing.T) { 5421 state := testStateStore(t) 5422 a := mock.VaultAccessor() 5423 a2 := mock.VaultAccessor() 5424 5425 ws := memdb.NewWatchSet() 5426 if _, err := state.VaultAccessor(ws, a.Accessor); err != nil { 5427 t.Fatalf("err: %v", err) 5428 } 5429 5430 if _, err := state.VaultAccessor(ws, a2.Accessor); err != nil { 5431 t.Fatalf("err: %v", err) 5432 } 5433 5434 err := state.UpsertVaultAccessor(1000, []*structs.VaultAccessor{a, a2}) 5435 if err != nil { 5436 t.Fatalf("err: %v", err) 5437 } 5438 5439 if !watchFired(ws) { 5440 t.Fatalf("bad") 5441 } 5442 5443 ws = memdb.NewWatchSet() 5444 out, err := state.VaultAccessor(ws, a.Accessor) 5445 if err != nil { 5446 t.Fatalf("err: %v", err) 5447 } 5448 5449 if !reflect.DeepEqual(a, out) { 5450 t.Fatalf("bad: %#v %#v", a, out) 5451 } 5452 5453 out, err = state.VaultAccessor(ws, a2.Accessor) 5454 if err != nil { 5455 t.Fatalf("err: %v", err) 5456 } 5457 5458 if !reflect.DeepEqual(a2, out) { 5459 t.Fatalf("bad: %#v %#v", a2, out) 5460 } 5461 5462 iter, err := state.VaultAccessors(ws) 5463 if err != nil { 5464 t.Fatalf("err: %v", err) 5465 } 5466 5467 count := 0 5468 for { 5469 raw := iter.Next() 5470 if raw == nil { 5471 break 5472 } 5473 5474 count++ 5475 accessor := raw.(*structs.VaultAccessor) 5476 5477 if !reflect.DeepEqual(accessor, a) && !reflect.DeepEqual(accessor, a2) { 5478 t.Fatalf("bad: %#v", accessor) 5479 } 5480 } 5481 5482 if count != 2 { 5483 t.Fatalf("bad: %d", count) 5484 } 5485 5486 index, err := state.Index("vault_accessors") 5487 if err != nil { 5488 t.Fatalf("err: %v", err) 5489 } 5490 if index != 1000 { 5491 t.Fatalf("bad: %d", index) 5492 } 5493 5494 if watchFired(ws) { 5495 t.Fatalf("bad") 5496 } 5497 } 5498 5499 func TestStateStore_DeleteVaultAccessors(t *testing.T) { 5500 state := testStateStore(t) 5501 a1 := mock.VaultAccessor() 5502 a2 := mock.VaultAccessor() 5503 accessors := []*structs.VaultAccessor{a1, a2} 5504 5505 err := state.UpsertVaultAccessor(1000, accessors) 5506 if err != nil { 5507 t.Fatalf("err: %v", err) 5508 } 5509 5510 ws := memdb.NewWatchSet() 5511 if _, err := state.VaultAccessor(ws, a1.Accessor); err != nil { 5512 t.Fatalf("err: %v", err) 5513 } 5514 5515 err = state.DeleteVaultAccessors(1001, accessors) 5516 if err != nil { 5517 t.Fatalf("err: %v", err) 5518 } 5519 5520 if !watchFired(ws) { 5521 t.Fatalf("bad") 5522 } 5523 5524 ws = memdb.NewWatchSet() 5525 out, err := state.VaultAccessor(ws, a1.Accessor) 5526 if err != nil { 5527 t.Fatalf("err: %v", err) 5528 } 5529 if out != nil { 5530 t.Fatalf("bad: %#v %#v", a1, out) 5531 } 5532 out, err = state.VaultAccessor(ws, a2.Accessor) 5533 if err != nil { 5534 t.Fatalf("err: %v", err) 5535 } 5536 if out != nil { 5537 t.Fatalf("bad: %#v %#v", a2, out) 5538 } 5539 5540 index, err := state.Index("vault_accessors") 5541 if err != nil { 5542 t.Fatalf("err: %v", err) 5543 } 5544 if index != 1001 { 5545 t.Fatalf("bad: %d", index) 5546 } 5547 5548 if watchFired(ws) { 5549 t.Fatalf("bad") 5550 } 5551 } 5552 5553 func TestStateStore_VaultAccessorsByAlloc(t *testing.T) { 5554 state := testStateStore(t) 5555 alloc := mock.Alloc() 5556 var accessors []*structs.VaultAccessor 5557 var expected []*structs.VaultAccessor 5558 5559 for i := 0; i < 5; i++ { 5560 accessor := mock.VaultAccessor() 5561 accessor.AllocID = alloc.ID 5562 expected = append(expected, accessor) 5563 accessors = append(accessors, accessor) 5564 } 5565 5566 for i := 0; i < 10; i++ { 5567 accessor := mock.VaultAccessor() 5568 accessors = append(accessors, accessor) 5569 } 5570 5571 err := state.UpsertVaultAccessor(1000, accessors) 5572 if err != nil { 5573 t.Fatalf("err: %v", err) 5574 } 5575 5576 ws := memdb.NewWatchSet() 5577 out, err := state.VaultAccessorsByAlloc(ws, alloc.ID) 5578 if err != nil { 5579 t.Fatalf("err: %v", err) 5580 } 5581 5582 if len(expected) != len(out) { 5583 t.Fatalf("bad: %#v %#v", len(expected), len(out)) 5584 } 5585 5586 index, err := state.Index("vault_accessors") 5587 if err != nil { 5588 t.Fatalf("err: %v", err) 5589 } 5590 if index != 1000 { 5591 t.Fatalf("bad: %d", index) 5592 } 5593 5594 if watchFired(ws) { 5595 t.Fatalf("bad") 5596 } 5597 } 5598 5599 func TestStateStore_VaultAccessorsByNode(t *testing.T) { 5600 state := testStateStore(t) 5601 node := mock.Node() 5602 var accessors []*structs.VaultAccessor 5603 var expected []*structs.VaultAccessor 5604 5605 for i := 0; i < 5; i++ { 5606 accessor := mock.VaultAccessor() 5607 accessor.NodeID = node.ID 5608 expected = append(expected, accessor) 5609 accessors = append(accessors, accessor) 5610 } 5611 5612 for i := 0; i < 10; i++ { 5613 accessor := mock.VaultAccessor() 5614 accessors = append(accessors, accessor) 5615 } 5616 5617 err := state.UpsertVaultAccessor(1000, accessors) 5618 if err != nil { 5619 t.Fatalf("err: %v", err) 5620 } 5621 5622 ws := memdb.NewWatchSet() 5623 out, err := state.VaultAccessorsByNode(ws, node.ID) 5624 if err != nil { 5625 t.Fatalf("err: %v", err) 5626 } 5627 5628 if len(expected) != len(out) { 5629 t.Fatalf("bad: %#v %#v", len(expected), len(out)) 5630 } 5631 5632 index, err := state.Index("vault_accessors") 5633 if err != nil { 5634 t.Fatalf("err: %v", err) 5635 } 5636 if index != 1000 { 5637 t.Fatalf("bad: %d", index) 5638 } 5639 5640 if watchFired(ws) { 5641 t.Fatalf("bad") 5642 } 5643 } 5644 5645 func TestStateStore_RestoreVaultAccessor(t *testing.T) { 5646 state := testStateStore(t) 5647 a := mock.VaultAccessor() 5648 5649 restore, err := state.Restore() 5650 if err != nil { 5651 t.Fatalf("err: %v", err) 5652 } 5653 5654 err = restore.VaultAccessorRestore(a) 5655 if err != nil { 5656 t.Fatalf("err: %v", err) 5657 } 5658 restore.Commit() 5659 5660 ws := memdb.NewWatchSet() 5661 out, err := state.VaultAccessor(ws, a.Accessor) 5662 if err != nil { 5663 t.Fatalf("err: %v", err) 5664 } 5665 5666 if !reflect.DeepEqual(out, a) { 5667 t.Fatalf("Bad: %#v %#v", out, a) 5668 } 5669 5670 if watchFired(ws) { 5671 t.Fatalf("bad") 5672 } 5673 } 5674 5675 func TestStateStore_Abandon(t *testing.T) { 5676 s := testStateStore(t) 5677 abandonCh := s.AbandonCh() 5678 s.Abandon() 5679 select { 5680 case <-abandonCh: 5681 default: 5682 t.Fatalf("bad") 5683 } 5684 } 5685 5686 // watchFired is a helper for unit tests that returns if the given watch set 5687 // fired (it doesn't care which watch actually fired). This uses a fixed 5688 // timeout since we already expect the event happened before calling this and 5689 // just need to distinguish a fire from a timeout. We do need a little time to 5690 // allow the watch to set up any goroutines, though. 5691 func watchFired(ws memdb.WatchSet) bool { 5692 timedOut := ws.Watch(time.After(50 * time.Millisecond)) 5693 return !timedOut 5694 } 5695 5696 // NodeIDSort is used to sort nodes by ID 5697 type NodeIDSort []*structs.Node 5698 5699 func (n NodeIDSort) Len() int { 5700 return len(n) 5701 } 5702 5703 func (n NodeIDSort) Less(i, j int) bool { 5704 return n[i].ID < n[j].ID 5705 } 5706 5707 func (n NodeIDSort) Swap(i, j int) { 5708 n[i], n[j] = n[j], n[i] 5709 } 5710 5711 // JobIDis used to sort jobs by id 5712 type JobIDSort []*structs.Job 5713 5714 func (n JobIDSort) Len() int { 5715 return len(n) 5716 } 5717 5718 func (n JobIDSort) Less(i, j int) bool { 5719 return n[i].ID < n[j].ID 5720 } 5721 5722 func (n JobIDSort) Swap(i, j int) { 5723 n[i], n[j] = n[j], n[i] 5724 } 5725 5726 // EvalIDis used to sort evals by id 5727 type EvalIDSort []*structs.Evaluation 5728 5729 func (n EvalIDSort) Len() int { 5730 return len(n) 5731 } 5732 5733 func (n EvalIDSort) Less(i, j int) bool { 5734 return n[i].ID < n[j].ID 5735 } 5736 5737 func (n EvalIDSort) Swap(i, j int) { 5738 n[i], n[j] = n[j], n[i] 5739 } 5740 5741 // AllocIDsort used to sort allocations by id 5742 type AllocIDSort []*structs.Allocation 5743 5744 func (n AllocIDSort) Len() int { 5745 return len(n) 5746 } 5747 5748 func (n AllocIDSort) Less(i, j int) bool { 5749 return n[i].ID < n[j].ID 5750 } 5751 5752 func (n AllocIDSort) Swap(i, j int) { 5753 n[i], n[j] = n[j], n[i] 5754 }