github.com/mattyr/nomad@v0.3.3-0.20160919021406-3485a065154a/nomad/state/state_store_test.go (about) 1 package state 2 3 import ( 4 "os" 5 "reflect" 6 "sort" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/go-memdb" 11 "github.com/hashicorp/nomad/nomad/mock" 12 "github.com/hashicorp/nomad/nomad/structs" 13 "github.com/hashicorp/nomad/nomad/watch" 14 ) 15 16 func testStateStore(t *testing.T) *StateStore { 17 state, err := NewStateStore(os.Stderr) 18 if err != nil { 19 t.Fatalf("err: %v", err) 20 } 21 if state == nil { 22 t.Fatalf("missing state") 23 } 24 return state 25 } 26 27 func TestStateStore_UpsertNode_Node(t *testing.T) { 28 state := testStateStore(t) 29 node := mock.Node() 30 31 notify := setupNotifyTest( 32 state, 33 watch.Item{Table: "nodes"}, 34 watch.Item{Node: node.ID}) 35 36 err := state.UpsertNode(1000, node) 37 if err != nil { 38 t.Fatalf("err: %v", err) 39 } 40 41 out, err := state.NodeByID(node.ID) 42 if err != nil { 43 t.Fatalf("err: %v", err) 44 } 45 46 if !reflect.DeepEqual(node, out) { 47 t.Fatalf("bad: %#v %#v", node, out) 48 } 49 50 index, err := state.Index("nodes") 51 if err != nil { 52 t.Fatalf("err: %v", err) 53 } 54 if index != 1000 { 55 t.Fatalf("bad: %d", index) 56 } 57 58 notify.verify(t) 59 } 60 61 func TestStateStore_DeleteNode_Node(t *testing.T) { 62 state := testStateStore(t) 63 node := mock.Node() 64 65 notify := setupNotifyTest( 66 state, 67 watch.Item{Table: "nodes"}, 68 watch.Item{Node: node.ID}) 69 70 err := state.UpsertNode(1000, node) 71 if err != nil { 72 t.Fatalf("err: %v", err) 73 } 74 75 err = state.DeleteNode(1001, node.ID) 76 if err != nil { 77 t.Fatalf("err: %v", err) 78 } 79 80 out, err := state.NodeByID(node.ID) 81 if err != nil { 82 t.Fatalf("err: %v", err) 83 } 84 85 if out != nil { 86 t.Fatalf("bad: %#v %#v", node, out) 87 } 88 89 index, err := state.Index("nodes") 90 if err != nil { 91 t.Fatalf("err: %v", err) 92 } 93 if index != 1001 { 94 t.Fatalf("bad: %d", index) 95 } 96 97 notify.verify(t) 98 } 99 100 func TestStateStore_UpdateNodeStatus_Node(t *testing.T) { 101 state := testStateStore(t) 102 node := mock.Node() 103 104 notify := setupNotifyTest( 105 state, 106 watch.Item{Table: "nodes"}, 107 watch.Item{Node: node.ID}) 108 109 err := state.UpsertNode(800, node) 110 if err != nil { 111 t.Fatalf("err: %v", err) 112 } 113 114 err = state.UpdateNodeStatus(801, node.ID, structs.NodeStatusReady) 115 if err != nil { 116 t.Fatalf("err: %v", err) 117 } 118 119 out, err := state.NodeByID(node.ID) 120 if err != nil { 121 t.Fatalf("err: %v", err) 122 } 123 124 if out.Status != structs.NodeStatusReady { 125 t.Fatalf("bad: %#v", out) 126 } 127 if out.ModifyIndex != 801 { 128 t.Fatalf("bad: %#v", out) 129 } 130 131 index, err := state.Index("nodes") 132 if err != nil { 133 t.Fatalf("err: %v", err) 134 } 135 if index != 801 { 136 t.Fatalf("bad: %d", index) 137 } 138 139 notify.verify(t) 140 } 141 142 func TestStateStore_UpdateNodeDrain_Node(t *testing.T) { 143 state := testStateStore(t) 144 node := mock.Node() 145 146 notify := setupNotifyTest( 147 state, 148 watch.Item{Table: "nodes"}, 149 watch.Item{Node: node.ID}) 150 151 err := state.UpsertNode(1000, node) 152 if err != nil { 153 t.Fatalf("err: %v", err) 154 } 155 156 err = state.UpdateNodeDrain(1001, node.ID, true) 157 if err != nil { 158 t.Fatalf("err: %v", err) 159 } 160 161 out, err := state.NodeByID(node.ID) 162 if err != nil { 163 t.Fatalf("err: %v", err) 164 } 165 166 if !out.Drain { 167 t.Fatalf("bad: %#v", out) 168 } 169 if out.ModifyIndex != 1001 { 170 t.Fatalf("bad: %#v", out) 171 } 172 173 index, err := state.Index("nodes") 174 if err != nil { 175 t.Fatalf("err: %v", err) 176 } 177 if index != 1001 { 178 t.Fatalf("bad: %d", index) 179 } 180 181 notify.verify(t) 182 } 183 184 func TestStateStore_Nodes(t *testing.T) { 185 state := testStateStore(t) 186 var nodes []*structs.Node 187 188 for i := 0; i < 10; i++ { 189 node := mock.Node() 190 nodes = append(nodes, node) 191 192 err := state.UpsertNode(1000+uint64(i), node) 193 if err != nil { 194 t.Fatalf("err: %v", err) 195 } 196 } 197 198 iter, err := state.Nodes() 199 if err != nil { 200 t.Fatalf("err: %v", err) 201 } 202 203 var out []*structs.Node 204 for { 205 raw := iter.Next() 206 if raw == nil { 207 break 208 } 209 out = append(out, raw.(*structs.Node)) 210 } 211 212 sort.Sort(NodeIDSort(nodes)) 213 sort.Sort(NodeIDSort(out)) 214 215 if !reflect.DeepEqual(nodes, out) { 216 t.Fatalf("bad: %#v %#v", nodes, out) 217 } 218 } 219 220 func TestStateStore_NodesByIDPrefix(t *testing.T) { 221 state := testStateStore(t) 222 node := mock.Node() 223 224 node.ID = "11111111-662e-d0ab-d1c9-3e434af7bdb4" 225 err := state.UpsertNode(1000, node) 226 if err != nil { 227 t.Fatalf("err: %v", err) 228 } 229 230 iter, err := state.NodesByIDPrefix(node.ID) 231 if err != nil { 232 t.Fatalf("err: %v", err) 233 } 234 235 gatherNodes := func(iter memdb.ResultIterator) []*structs.Node { 236 var nodes []*structs.Node 237 for { 238 raw := iter.Next() 239 if raw == nil { 240 break 241 } 242 node := raw.(*structs.Node) 243 nodes = append(nodes, node) 244 } 245 return nodes 246 } 247 248 nodes := gatherNodes(iter) 249 if len(nodes) != 1 { 250 t.Fatalf("err: %v", err) 251 } 252 253 iter, err = state.NodesByIDPrefix("11") 254 if err != nil { 255 t.Fatalf("err: %v", err) 256 } 257 258 nodes = gatherNodes(iter) 259 if len(nodes) != 1 { 260 t.Fatalf("err: %v", err) 261 } 262 263 node = mock.Node() 264 node.ID = "11222222-662e-d0ab-d1c9-3e434af7bdb4" 265 err = state.UpsertNode(1001, node) 266 if err != nil { 267 t.Fatalf("err: %v", err) 268 } 269 270 iter, err = state.NodesByIDPrefix("11") 271 if err != nil { 272 t.Fatalf("err: %v", err) 273 } 274 275 nodes = gatherNodes(iter) 276 if len(nodes) != 2 { 277 t.Fatalf("err: %v", err) 278 } 279 280 iter, err = state.NodesByIDPrefix("1111") 281 if err != nil { 282 t.Fatalf("err: %v", err) 283 } 284 285 nodes = gatherNodes(iter) 286 if len(nodes) != 1 { 287 t.Fatalf("err: %v", err) 288 } 289 } 290 291 func TestStateStore_RestoreNode(t *testing.T) { 292 state := testStateStore(t) 293 node := mock.Node() 294 295 notify := setupNotifyTest( 296 state, 297 watch.Item{Table: "nodes"}, 298 watch.Item{Node: node.ID}) 299 300 restore, err := state.Restore() 301 if err != nil { 302 t.Fatalf("err: %v", err) 303 } 304 305 err = restore.NodeRestore(node) 306 if err != nil { 307 t.Fatalf("err: %v", err) 308 } 309 restore.Commit() 310 311 out, err := state.NodeByID(node.ID) 312 if err != nil { 313 t.Fatalf("err: %v", err) 314 } 315 316 if !reflect.DeepEqual(out, node) { 317 t.Fatalf("Bad: %#v %#v", out, node) 318 } 319 320 notify.verify(t) 321 } 322 323 func TestStateStore_UpsertJob_Job(t *testing.T) { 324 state := testStateStore(t) 325 job := mock.Job() 326 327 notify := setupNotifyTest( 328 state, 329 watch.Item{Table: "jobs"}, 330 watch.Item{Job: job.ID}) 331 332 err := state.UpsertJob(1000, job) 333 if err != nil { 334 t.Fatalf("err: %v", err) 335 } 336 337 out, err := state.JobByID(job.ID) 338 if err != nil { 339 t.Fatalf("err: %v", err) 340 } 341 342 if !reflect.DeepEqual(job, out) { 343 t.Fatalf("bad: %#v %#v", job, out) 344 } 345 346 index, err := state.Index("jobs") 347 if err != nil { 348 t.Fatalf("err: %v", err) 349 } 350 if index != 1000 { 351 t.Fatalf("bad: %d", index) 352 } 353 354 summary, err := state.JobSummaryByID(job.ID) 355 if err != nil { 356 t.Fatalf("err: %v", err) 357 } 358 if summary == nil { 359 t.Fatalf("nil summary") 360 } 361 if summary.JobID != job.ID { 362 t.Fatalf("bad summary id: %v", summary.JobID) 363 } 364 _, ok := summary.Summary["web"] 365 if !ok { 366 t.Fatalf("nil summary for task group") 367 } 368 notify.verify(t) 369 } 370 371 func TestStateStore_UpdateUpsertJob_Job(t *testing.T) { 372 state := testStateStore(t) 373 job := mock.Job() 374 375 notify := setupNotifyTest( 376 state, 377 watch.Item{Table: "jobs"}, 378 watch.Item{Job: job.ID}) 379 380 err := state.UpsertJob(1000, job) 381 if err != nil { 382 t.Fatalf("err: %v", err) 383 } 384 385 job2 := mock.Job() 386 job2.ID = job.ID 387 err = state.UpsertJob(1001, job2) 388 if err != nil { 389 t.Fatalf("err: %v", err) 390 } 391 392 out, err := state.JobByID(job.ID) 393 if err != nil { 394 t.Fatalf("err: %v", err) 395 } 396 397 if !reflect.DeepEqual(job2, out) { 398 t.Fatalf("bad: %#v %#v", job2, out) 399 } 400 401 if out.CreateIndex != 1000 { 402 t.Fatalf("bad: %#v", out) 403 } 404 if out.ModifyIndex != 1001 { 405 t.Fatalf("bad: %#v", out) 406 } 407 408 index, err := state.Index("jobs") 409 if err != nil { 410 t.Fatalf("err: %v", err) 411 } 412 if index != 1001 { 413 t.Fatalf("bad: %d", index) 414 } 415 416 // Test that the job summary remains the same if the job is updated but 417 // count remains same 418 summary, err := state.JobSummaryByID(job.ID) 419 if err != nil { 420 t.Fatalf("err: %v", err) 421 } 422 if summary == nil { 423 t.Fatalf("nil summary") 424 } 425 if summary.JobID != job.ID { 426 t.Fatalf("bad summary id: %v", summary.JobID) 427 } 428 _, ok := summary.Summary["web"] 429 if !ok { 430 t.Fatalf("nil summary for task group") 431 } 432 433 notify.verify(t) 434 } 435 436 // This test ensures that UpsertJob creates the EphemeralDisk is a job doesn't have 437 // one and clear out the task's disk resource asks 438 // COMPAT 0.4.1 -> 0.5 439 func TestStateStore_UpsertJob_NoEphemeralDisk(t *testing.T) { 440 state := testStateStore(t) 441 job := mock.Job() 442 443 // Set the EphemeralDisk to nil and set the tasks's DiskMB to 150 444 job.TaskGroups[0].EphemeralDisk = nil 445 job.TaskGroups[0].Tasks[0].Resources.DiskMB = 150 446 447 err := state.UpsertJob(1000, job) 448 if err != nil { 449 t.Fatalf("err: %v", err) 450 } 451 452 out, err := state.JobByID(job.ID) 453 if err != nil { 454 t.Fatalf("err: %v", err) 455 } 456 457 // Expect the state store to create the EphemeralDisk and clear out Tasks's 458 // DiskMB 459 expected := job.Copy() 460 expected.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{ 461 SizeMB: 150, 462 } 463 expected.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 464 465 if !reflect.DeepEqual(expected, out) { 466 t.Fatalf("bad: %#v %#v", expected, out) 467 } 468 } 469 470 func TestStateStore_DeleteJob_Job(t *testing.T) { 471 state := testStateStore(t) 472 job := mock.Job() 473 474 notify := setupNotifyTest( 475 state, 476 watch.Item{Table: "jobs"}, 477 watch.Item{Job: job.ID}) 478 479 err := state.UpsertJob(1000, job) 480 if err != nil { 481 t.Fatalf("err: %v", err) 482 } 483 484 err = state.DeleteJob(1001, job.ID) 485 if err != nil { 486 t.Fatalf("err: %v", err) 487 } 488 489 out, err := state.JobByID(job.ID) 490 if err != nil { 491 t.Fatalf("err: %v", err) 492 } 493 494 if out != nil { 495 t.Fatalf("bad: %#v %#v", job, out) 496 } 497 498 index, err := state.Index("jobs") 499 if err != nil { 500 t.Fatalf("err: %v", err) 501 } 502 if index != 1001 { 503 t.Fatalf("bad: %d", index) 504 } 505 506 summary, err := state.JobSummaryByID(job.ID) 507 if err != nil { 508 t.Fatalf("err: %v", err) 509 } 510 if summary != nil { 511 t.Fatalf("expected summary to be nil, but got: %v", summary) 512 } 513 514 notify.verify(t) 515 } 516 517 func TestStateStore_Jobs(t *testing.T) { 518 state := testStateStore(t) 519 var jobs []*structs.Job 520 521 for i := 0; i < 10; i++ { 522 job := mock.Job() 523 jobs = append(jobs, job) 524 525 err := state.UpsertJob(1000+uint64(i), job) 526 if err != nil { 527 t.Fatalf("err: %v", err) 528 } 529 } 530 531 iter, err := state.Jobs() 532 if err != nil { 533 t.Fatalf("err: %v", err) 534 } 535 536 var out []*structs.Job 537 for { 538 raw := iter.Next() 539 if raw == nil { 540 break 541 } 542 out = append(out, raw.(*structs.Job)) 543 } 544 545 sort.Sort(JobIDSort(jobs)) 546 sort.Sort(JobIDSort(out)) 547 548 if !reflect.DeepEqual(jobs, out) { 549 t.Fatalf("bad: %#v %#v", jobs, out) 550 } 551 } 552 553 func TestStateStore_JobsByIDPrefix(t *testing.T) { 554 state := testStateStore(t) 555 job := mock.Job() 556 557 job.ID = "redis" 558 err := state.UpsertJob(1000, job) 559 if err != nil { 560 t.Fatalf("err: %v", err) 561 } 562 563 iter, err := state.JobsByIDPrefix(job.ID) 564 if err != nil { 565 t.Fatalf("err: %v", err) 566 } 567 568 gatherJobs := func(iter memdb.ResultIterator) []*structs.Job { 569 var jobs []*structs.Job 570 for { 571 raw := iter.Next() 572 if raw == nil { 573 break 574 } 575 jobs = append(jobs, raw.(*structs.Job)) 576 } 577 return jobs 578 } 579 580 jobs := gatherJobs(iter) 581 if len(jobs) != 1 { 582 t.Fatalf("err: %v", err) 583 } 584 585 iter, err = state.JobsByIDPrefix("re") 586 if err != nil { 587 t.Fatalf("err: %v", err) 588 } 589 590 jobs = gatherJobs(iter) 591 if len(jobs) != 1 { 592 t.Fatalf("err: %v", err) 593 } 594 595 job = mock.Job() 596 job.ID = "riak" 597 err = state.UpsertJob(1001, job) 598 if err != nil { 599 t.Fatalf("err: %v", err) 600 } 601 602 iter, err = state.JobsByIDPrefix("r") 603 if err != nil { 604 t.Fatalf("err: %v", err) 605 } 606 607 jobs = gatherJobs(iter) 608 if len(jobs) != 2 { 609 t.Fatalf("err: %v", err) 610 } 611 612 iter, err = state.JobsByIDPrefix("ri") 613 if err != nil { 614 t.Fatalf("err: %v", err) 615 } 616 617 jobs = gatherJobs(iter) 618 if len(jobs) != 1 { 619 t.Fatalf("err: %v", err) 620 } 621 } 622 623 func TestStateStore_JobsByPeriodic(t *testing.T) { 624 state := testStateStore(t) 625 var periodic, nonPeriodic []*structs.Job 626 627 for i := 0; i < 10; i++ { 628 job := mock.Job() 629 nonPeriodic = append(nonPeriodic, job) 630 631 err := state.UpsertJob(1000+uint64(i), job) 632 if err != nil { 633 t.Fatalf("err: %v", err) 634 } 635 } 636 637 for i := 0; i < 10; i++ { 638 job := mock.PeriodicJob() 639 periodic = append(periodic, job) 640 641 err := state.UpsertJob(2000+uint64(i), job) 642 if err != nil { 643 t.Fatalf("err: %v", err) 644 } 645 } 646 647 iter, err := state.JobsByPeriodic(true) 648 if err != nil { 649 t.Fatalf("err: %v", err) 650 } 651 652 var outPeriodic []*structs.Job 653 for { 654 raw := iter.Next() 655 if raw == nil { 656 break 657 } 658 outPeriodic = append(outPeriodic, raw.(*structs.Job)) 659 } 660 661 iter, err = state.JobsByPeriodic(false) 662 if err != nil { 663 t.Fatalf("err: %v", err) 664 } 665 666 var outNonPeriodic []*structs.Job 667 for { 668 raw := iter.Next() 669 if raw == nil { 670 break 671 } 672 outNonPeriodic = append(outNonPeriodic, raw.(*structs.Job)) 673 } 674 675 sort.Sort(JobIDSort(periodic)) 676 sort.Sort(JobIDSort(nonPeriodic)) 677 sort.Sort(JobIDSort(outPeriodic)) 678 sort.Sort(JobIDSort(outNonPeriodic)) 679 680 if !reflect.DeepEqual(periodic, outPeriodic) { 681 t.Fatalf("bad: %#v %#v", periodic, outPeriodic) 682 } 683 684 if !reflect.DeepEqual(nonPeriodic, outNonPeriodic) { 685 t.Fatalf("bad: %#v %#v", nonPeriodic, outNonPeriodic) 686 } 687 } 688 689 func TestStateStore_JobsByScheduler(t *testing.T) { 690 state := testStateStore(t) 691 var serviceJobs []*structs.Job 692 var sysJobs []*structs.Job 693 694 for i := 0; i < 10; i++ { 695 job := mock.Job() 696 serviceJobs = append(serviceJobs, job) 697 698 err := state.UpsertJob(1000+uint64(i), job) 699 if err != nil { 700 t.Fatalf("err: %v", err) 701 } 702 } 703 704 for i := 0; i < 10; i++ { 705 job := mock.SystemJob() 706 sysJobs = append(sysJobs, job) 707 708 err := state.UpsertJob(2000+uint64(i), job) 709 if err != nil { 710 t.Fatalf("err: %v", err) 711 } 712 } 713 714 iter, err := state.JobsByScheduler("service") 715 if err != nil { 716 t.Fatalf("err: %v", err) 717 } 718 719 var outService []*structs.Job 720 for { 721 raw := iter.Next() 722 if raw == nil { 723 break 724 } 725 outService = append(outService, raw.(*structs.Job)) 726 } 727 728 iter, err = state.JobsByScheduler("system") 729 if err != nil { 730 t.Fatalf("err: %v", err) 731 } 732 733 var outSystem []*structs.Job 734 for { 735 raw := iter.Next() 736 if raw == nil { 737 break 738 } 739 outSystem = append(outSystem, raw.(*structs.Job)) 740 } 741 742 sort.Sort(JobIDSort(serviceJobs)) 743 sort.Sort(JobIDSort(sysJobs)) 744 sort.Sort(JobIDSort(outService)) 745 sort.Sort(JobIDSort(outSystem)) 746 747 if !reflect.DeepEqual(serviceJobs, outService) { 748 t.Fatalf("bad: %#v %#v", serviceJobs, outService) 749 } 750 751 if !reflect.DeepEqual(sysJobs, outSystem) { 752 t.Fatalf("bad: %#v %#v", sysJobs, outSystem) 753 } 754 } 755 756 func TestStateStore_JobsByGC(t *testing.T) { 757 state := testStateStore(t) 758 var gc, nonGc []*structs.Job 759 760 for i := 0; i < 20; i++ { 761 var job *structs.Job 762 if i%2 == 0 { 763 job = mock.Job() 764 } else { 765 job = mock.PeriodicJob() 766 } 767 nonGc = append(nonGc, job) 768 769 if err := state.UpsertJob(1000+uint64(i), job); err != nil { 770 t.Fatalf("err: %v", err) 771 } 772 } 773 774 for i := 0; i < 10; i++ { 775 job := mock.Job() 776 job.Type = structs.JobTypeBatch 777 gc = append(gc, job) 778 779 if err := state.UpsertJob(2000+uint64(i), job); err != nil { 780 t.Fatalf("err: %v", err) 781 } 782 } 783 784 iter, err := state.JobsByGC(true) 785 if err != nil { 786 t.Fatalf("err: %v", err) 787 } 788 789 var outGc []*structs.Job 790 for i := iter.Next(); i != nil; i = iter.Next() { 791 outGc = append(outGc, i.(*structs.Job)) 792 } 793 794 iter, err = state.JobsByGC(false) 795 if err != nil { 796 t.Fatalf("err: %v", err) 797 } 798 799 var outNonGc []*structs.Job 800 for i := iter.Next(); i != nil; i = iter.Next() { 801 outNonGc = append(outNonGc, i.(*structs.Job)) 802 } 803 804 sort.Sort(JobIDSort(gc)) 805 sort.Sort(JobIDSort(nonGc)) 806 sort.Sort(JobIDSort(outGc)) 807 sort.Sort(JobIDSort(outNonGc)) 808 809 if !reflect.DeepEqual(gc, outGc) { 810 t.Fatalf("bad: %#v %#v", gc, outGc) 811 } 812 813 if !reflect.DeepEqual(nonGc, outNonGc) { 814 t.Fatalf("bad: %#v %#v", nonGc, outNonGc) 815 } 816 } 817 818 func TestStateStore_RestoreJob(t *testing.T) { 819 state := testStateStore(t) 820 job := mock.Job() 821 822 notify := setupNotifyTest( 823 state, 824 watch.Item{Table: "jobs"}, 825 watch.Item{Job: job.ID}) 826 827 restore, err := state.Restore() 828 if err != nil { 829 t.Fatalf("err: %v", err) 830 } 831 832 err = restore.JobRestore(job) 833 if err != nil { 834 t.Fatalf("err: %v", err) 835 } 836 restore.Commit() 837 838 out, err := state.JobByID(job.ID) 839 if err != nil { 840 t.Fatalf("err: %v", err) 841 } 842 843 if !reflect.DeepEqual(out, job) { 844 t.Fatalf("Bad: %#v %#v", out, job) 845 } 846 847 notify.verify(t) 848 } 849 850 // This test ensures that the state restore creates the EphemeralDisk for a job if 851 // it doesn't have one 852 // COMPAT 0.4.1 -> 0.5 853 func TestStateStore_Jobs_NoEphemeralDisk(t *testing.T) { 854 state := testStateStore(t) 855 job := mock.Job() 856 857 // Set EphemeralDisk to nil and set the DiskMB to 150 858 job.TaskGroups[0].EphemeralDisk = nil 859 job.TaskGroups[0].Tasks[0].Resources.DiskMB = 150 860 861 notify := setupNotifyTest( 862 state, 863 watch.Item{Table: "jobs"}, 864 watch.Item{Job: job.ID}) 865 866 restore, err := state.Restore() 867 if err != nil { 868 t.Fatalf("err: %v", err) 869 } 870 871 err = restore.JobRestore(job) 872 if err != nil { 873 t.Fatalf("err: %v", err) 874 } 875 restore.Commit() 876 877 out, err := state.JobByID(job.ID) 878 if err != nil { 879 t.Fatalf("err: %v", err) 880 } 881 882 // Expect job to have local disk and clear out the task's disk resource ask 883 expected := job.Copy() 884 expected.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{ 885 SizeMB: 150, 886 } 887 expected.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 888 if !reflect.DeepEqual(out, expected) { 889 t.Fatalf("Bad: %#v %#v", out, job) 890 } 891 892 notify.verify(t) 893 } 894 895 func TestStateStore_UpsertPeriodicLaunch(t *testing.T) { 896 state := testStateStore(t) 897 job := mock.Job() 898 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 899 900 notify := setupNotifyTest( 901 state, 902 watch.Item{Table: "periodic_launch"}, 903 watch.Item{Job: job.ID}) 904 905 err := state.UpsertPeriodicLaunch(1000, launch) 906 if err != nil { 907 t.Fatalf("err: %v", err) 908 } 909 910 out, err := state.PeriodicLaunchByID(job.ID) 911 if err != nil { 912 t.Fatalf("err: %v", err) 913 } 914 if out.CreateIndex != 1000 { 915 t.Fatalf("bad: %#v", out) 916 } 917 if out.ModifyIndex != 1000 { 918 t.Fatalf("bad: %#v", out) 919 } 920 921 if !reflect.DeepEqual(launch, out) { 922 t.Fatalf("bad: %#v %#v", job, out) 923 } 924 925 index, err := state.Index("periodic_launch") 926 if err != nil { 927 t.Fatalf("err: %v", err) 928 } 929 if index != 1000 { 930 t.Fatalf("bad: %d", index) 931 } 932 933 notify.verify(t) 934 } 935 936 func TestStateStore_UpdateUpsertPeriodicLaunch(t *testing.T) { 937 state := testStateStore(t) 938 job := mock.Job() 939 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 940 941 notify := setupNotifyTest( 942 state, 943 watch.Item{Table: "periodic_launch"}, 944 watch.Item{Job: job.ID}) 945 946 err := state.UpsertPeriodicLaunch(1000, launch) 947 if err != nil { 948 t.Fatalf("err: %v", err) 949 } 950 951 launch2 := &structs.PeriodicLaunch{ 952 ID: job.ID, 953 Launch: launch.Launch.Add(1 * time.Second), 954 } 955 err = state.UpsertPeriodicLaunch(1001, launch2) 956 if err != nil { 957 t.Fatalf("err: %v", err) 958 } 959 960 out, err := state.PeriodicLaunchByID(job.ID) 961 if err != nil { 962 t.Fatalf("err: %v", err) 963 } 964 if out.CreateIndex != 1000 { 965 t.Fatalf("bad: %#v", out) 966 } 967 if out.ModifyIndex != 1001 { 968 t.Fatalf("bad: %#v", out) 969 } 970 971 if !reflect.DeepEqual(launch2, out) { 972 t.Fatalf("bad: %#v %#v", launch2, out) 973 } 974 975 index, err := state.Index("periodic_launch") 976 if err != nil { 977 t.Fatalf("err: %v", err) 978 } 979 if index != 1001 { 980 t.Fatalf("bad: %d", index) 981 } 982 983 notify.verify(t) 984 } 985 986 func TestStateStore_DeletePeriodicLaunch(t *testing.T) { 987 state := testStateStore(t) 988 job := mock.Job() 989 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 990 991 notify := setupNotifyTest( 992 state, 993 watch.Item{Table: "periodic_launch"}, 994 watch.Item{Job: job.ID}) 995 996 err := state.UpsertPeriodicLaunch(1000, launch) 997 if err != nil { 998 t.Fatalf("err: %v", err) 999 } 1000 1001 err = state.DeletePeriodicLaunch(1001, job.ID) 1002 if err != nil { 1003 t.Fatalf("err: %v", err) 1004 } 1005 1006 out, err := state.PeriodicLaunchByID(job.ID) 1007 if err != nil { 1008 t.Fatalf("err: %v", err) 1009 } 1010 1011 if out != nil { 1012 t.Fatalf("bad: %#v %#v", job, out) 1013 } 1014 1015 index, err := state.Index("periodic_launch") 1016 if err != nil { 1017 t.Fatalf("err: %v", err) 1018 } 1019 if index != 1001 { 1020 t.Fatalf("bad: %d", index) 1021 } 1022 1023 notify.verify(t) 1024 } 1025 1026 func TestStateStore_PeriodicLaunches(t *testing.T) { 1027 state := testStateStore(t) 1028 var launches []*structs.PeriodicLaunch 1029 1030 for i := 0; i < 10; i++ { 1031 job := mock.Job() 1032 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 1033 launches = append(launches, launch) 1034 1035 err := state.UpsertPeriodicLaunch(1000+uint64(i), launch) 1036 if err != nil { 1037 t.Fatalf("err: %v", err) 1038 } 1039 } 1040 1041 iter, err := state.PeriodicLaunches() 1042 if err != nil { 1043 t.Fatalf("err: %v", err) 1044 } 1045 1046 out := make(map[string]*structs.PeriodicLaunch, 10) 1047 for { 1048 raw := iter.Next() 1049 if raw == nil { 1050 break 1051 } 1052 launch := raw.(*structs.PeriodicLaunch) 1053 if _, ok := out[launch.ID]; ok { 1054 t.Fatalf("duplicate: %v", launch.ID) 1055 } 1056 1057 out[launch.ID] = launch 1058 } 1059 1060 for _, launch := range launches { 1061 l, ok := out[launch.ID] 1062 if !ok { 1063 t.Fatalf("bad %v", launch.ID) 1064 } 1065 1066 if !reflect.DeepEqual(launch, l) { 1067 t.Fatalf("bad: %#v %#v", launch, l) 1068 } 1069 1070 delete(out, launch.ID) 1071 } 1072 1073 if len(out) != 0 { 1074 t.Fatalf("leftover: %#v", out) 1075 } 1076 } 1077 1078 func TestStateStore_RestorePeriodicLaunch(t *testing.T) { 1079 state := testStateStore(t) 1080 job := mock.Job() 1081 launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()} 1082 1083 notify := setupNotifyTest( 1084 state, 1085 watch.Item{Table: "periodic_launch"}, 1086 watch.Item{Job: job.ID}) 1087 1088 restore, err := state.Restore() 1089 if err != nil { 1090 t.Fatalf("err: %v", err) 1091 } 1092 1093 err = restore.PeriodicLaunchRestore(launch) 1094 if err != nil { 1095 t.Fatalf("err: %v", err) 1096 } 1097 restore.Commit() 1098 1099 out, err := state.PeriodicLaunchByID(job.ID) 1100 if err != nil { 1101 t.Fatalf("err: %v", err) 1102 } 1103 1104 if !reflect.DeepEqual(out, launch) { 1105 t.Fatalf("Bad: %#v %#v", out, job) 1106 } 1107 1108 notify.verify(t) 1109 } 1110 1111 func TestStateStore_RestoreJobSummary(t *testing.T) { 1112 state := testStateStore(t) 1113 job := mock.Job() 1114 jobSummary := &structs.JobSummary{ 1115 JobID: job.ID, 1116 Summary: map[string]structs.TaskGroupSummary{ 1117 "web": structs.TaskGroupSummary{ 1118 Starting: 10, 1119 }, 1120 }, 1121 } 1122 restore, err := state.Restore() 1123 if err != nil { 1124 t.Fatalf("err: %v", err) 1125 } 1126 1127 err = restore.JobSummaryRestore(jobSummary) 1128 if err != nil { 1129 t.Fatalf("err: %v", err) 1130 } 1131 restore.Commit() 1132 1133 out, err := state.JobSummaryByID(job.ID) 1134 if err != nil { 1135 t.Fatalf("err: %v", err) 1136 } 1137 1138 if !reflect.DeepEqual(out, jobSummary) { 1139 t.Fatalf("Bad: %#v %#v", out, jobSummary) 1140 } 1141 } 1142 1143 func TestStateStore_Indexes(t *testing.T) { 1144 state := testStateStore(t) 1145 node := mock.Node() 1146 1147 err := state.UpsertNode(1000, node) 1148 if err != nil { 1149 t.Fatalf("err: %v", err) 1150 } 1151 1152 iter, err := state.Indexes() 1153 if err != nil { 1154 t.Fatalf("err: %v", err) 1155 } 1156 1157 var out []*IndexEntry 1158 for { 1159 raw := iter.Next() 1160 if raw == nil { 1161 break 1162 } 1163 out = append(out, raw.(*IndexEntry)) 1164 } 1165 1166 expect := []*IndexEntry{ 1167 &IndexEntry{"nodes", 1000}, 1168 } 1169 1170 if !reflect.DeepEqual(expect, out) { 1171 t.Fatalf("bad: %#v %#v", expect, out) 1172 } 1173 } 1174 1175 func TestStateStore_LatestIndex(t *testing.T) { 1176 state := testStateStore(t) 1177 1178 if err := state.UpsertNode(1000, mock.Node()); err != nil { 1179 t.Fatalf("err: %v", err) 1180 } 1181 1182 exp := uint64(2000) 1183 if err := state.UpsertJob(exp, mock.Job()); err != nil { 1184 t.Fatalf("err: %v", err) 1185 } 1186 1187 latest, err := state.LatestIndex() 1188 if err != nil { 1189 t.Fatalf("err: %v", err) 1190 } 1191 1192 if latest != exp { 1193 t.Fatalf("LatestIndex() returned %d; want %d", latest, exp) 1194 } 1195 } 1196 1197 func TestStateStore_RestoreIndex(t *testing.T) { 1198 state := testStateStore(t) 1199 1200 restore, err := state.Restore() 1201 if err != nil { 1202 t.Fatalf("err: %v", err) 1203 } 1204 1205 index := &IndexEntry{"jobs", 1000} 1206 err = restore.IndexRestore(index) 1207 if err != nil { 1208 t.Fatalf("err: %v", err) 1209 } 1210 1211 restore.Commit() 1212 1213 out, err := state.Index("jobs") 1214 if err != nil { 1215 t.Fatalf("err: %v", err) 1216 } 1217 1218 if out != 1000 { 1219 t.Fatalf("Bad: %#v %#v", out, 1000) 1220 } 1221 } 1222 1223 func TestStateStore_UpsertEvals_Eval(t *testing.T) { 1224 state := testStateStore(t) 1225 eval := mock.Eval() 1226 1227 notify := setupNotifyTest( 1228 state, 1229 watch.Item{Table: "evals"}, 1230 watch.Item{Eval: eval.ID}) 1231 1232 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 1233 if err != nil { 1234 t.Fatalf("err: %v", err) 1235 } 1236 1237 out, err := state.EvalByID(eval.ID) 1238 if err != nil { 1239 t.Fatalf("err: %v", err) 1240 } 1241 1242 if !reflect.DeepEqual(eval, out) { 1243 t.Fatalf("bad: %#v %#v", eval, out) 1244 } 1245 1246 index, err := state.Index("evals") 1247 if err != nil { 1248 t.Fatalf("err: %v", err) 1249 } 1250 if index != 1000 { 1251 t.Fatalf("bad: %d", index) 1252 } 1253 1254 notify.verify(t) 1255 } 1256 1257 func TestStateStore_Update_UpsertEvals_Eval(t *testing.T) { 1258 state := testStateStore(t) 1259 eval := mock.Eval() 1260 1261 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 1262 if err != nil { 1263 t.Fatalf("err: %v", err) 1264 } 1265 1266 notify := setupNotifyTest( 1267 state, 1268 watch.Item{Table: "evals"}, 1269 watch.Item{Eval: eval.ID}) 1270 1271 eval2 := mock.Eval() 1272 eval2.ID = eval.ID 1273 err = state.UpsertEvals(1001, []*structs.Evaluation{eval2}) 1274 if err != nil { 1275 t.Fatalf("err: %v", err) 1276 } 1277 1278 out, err := state.EvalByID(eval.ID) 1279 if err != nil { 1280 t.Fatalf("err: %v", err) 1281 } 1282 1283 if !reflect.DeepEqual(eval2, out) { 1284 t.Fatalf("bad: %#v %#v", eval2, out) 1285 } 1286 1287 if out.CreateIndex != 1000 { 1288 t.Fatalf("bad: %#v", out) 1289 } 1290 if out.ModifyIndex != 1001 { 1291 t.Fatalf("bad: %#v", out) 1292 } 1293 1294 index, err := state.Index("evals") 1295 if err != nil { 1296 t.Fatalf("err: %v", err) 1297 } 1298 if index != 1001 { 1299 t.Fatalf("bad: %d", index) 1300 } 1301 1302 notify.verify(t) 1303 } 1304 1305 func TestStateStore_DeleteEval_Eval(t *testing.T) { 1306 state := testStateStore(t) 1307 eval1 := mock.Eval() 1308 eval2 := mock.Eval() 1309 alloc1 := mock.Alloc() 1310 alloc2 := mock.Alloc() 1311 1312 notify := setupNotifyTest( 1313 state, 1314 watch.Item{Table: "evals"}, 1315 watch.Item{Table: "allocs"}, 1316 watch.Item{Eval: eval1.ID}, 1317 watch.Item{Eval: eval2.ID}, 1318 watch.Item{Alloc: alloc1.ID}, 1319 watch.Item{Alloc: alloc2.ID}, 1320 watch.Item{AllocEval: alloc1.EvalID}, 1321 watch.Item{AllocEval: alloc2.EvalID}, 1322 watch.Item{AllocJob: alloc1.JobID}, 1323 watch.Item{AllocJob: alloc2.JobID}, 1324 watch.Item{AllocNode: alloc1.NodeID}, 1325 watch.Item{AllocNode: alloc2.NodeID}) 1326 1327 state.UpsertJobSummary(900, mock.JobSummary(eval1.JobID)) 1328 state.UpsertJobSummary(901, mock.JobSummary(eval2.JobID)) 1329 state.UpsertJobSummary(902, mock.JobSummary(alloc1.JobID)) 1330 state.UpsertJobSummary(903, mock.JobSummary(alloc2.JobID)) 1331 err := state.UpsertEvals(1000, []*structs.Evaluation{eval1, eval2}) 1332 if err != nil { 1333 t.Fatalf("err: %v", err) 1334 } 1335 1336 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc1, alloc2}) 1337 if err != nil { 1338 t.Fatalf("err: %v", err) 1339 } 1340 1341 err = state.DeleteEval(1002, []string{eval1.ID, eval2.ID}, []string{alloc1.ID, alloc2.ID}) 1342 if err != nil { 1343 t.Fatalf("err: %v", err) 1344 } 1345 1346 out, err := state.EvalByID(eval1.ID) 1347 if err != nil { 1348 t.Fatalf("err: %v", err) 1349 } 1350 1351 if out != nil { 1352 t.Fatalf("bad: %#v %#v", eval1, out) 1353 } 1354 1355 out, err = state.EvalByID(eval2.ID) 1356 if err != nil { 1357 t.Fatalf("err: %v", err) 1358 } 1359 1360 if out != nil { 1361 t.Fatalf("bad: %#v %#v", eval1, out) 1362 } 1363 1364 outA, err := state.AllocByID(alloc1.ID) 1365 if err != nil { 1366 t.Fatalf("err: %v", err) 1367 } 1368 1369 if out != nil { 1370 t.Fatalf("bad: %#v %#v", alloc1, outA) 1371 } 1372 1373 outA, err = state.AllocByID(alloc2.ID) 1374 if err != nil { 1375 t.Fatalf("err: %v", err) 1376 } 1377 1378 if out != nil { 1379 t.Fatalf("bad: %#v %#v", alloc1, outA) 1380 } 1381 1382 index, err := state.Index("evals") 1383 if err != nil { 1384 t.Fatalf("err: %v", err) 1385 } 1386 if index != 1002 { 1387 t.Fatalf("bad: %d", index) 1388 } 1389 1390 index, err = state.Index("allocs") 1391 if err != nil { 1392 t.Fatalf("err: %v", err) 1393 } 1394 if index != 1002 { 1395 t.Fatalf("bad: %d", index) 1396 } 1397 1398 notify.verify(t) 1399 } 1400 1401 func TestStateStore_EvalsByJob(t *testing.T) { 1402 state := testStateStore(t) 1403 1404 eval1 := mock.Eval() 1405 eval2 := mock.Eval() 1406 eval2.JobID = eval1.JobID 1407 eval3 := mock.Eval() 1408 evals := []*structs.Evaluation{eval1, eval2} 1409 1410 err := state.UpsertEvals(1000, evals) 1411 if err != nil { 1412 t.Fatalf("err: %v", err) 1413 } 1414 err = state.UpsertEvals(1001, []*structs.Evaluation{eval3}) 1415 if err != nil { 1416 t.Fatalf("err: %v", err) 1417 } 1418 1419 out, err := state.EvalsByJob(eval1.JobID) 1420 if err != nil { 1421 t.Fatalf("err: %v", err) 1422 } 1423 1424 sort.Sort(EvalIDSort(evals)) 1425 sort.Sort(EvalIDSort(out)) 1426 1427 if !reflect.DeepEqual(evals, out) { 1428 t.Fatalf("bad: %#v %#v", evals, out) 1429 } 1430 } 1431 1432 func TestStateStore_Evals(t *testing.T) { 1433 state := testStateStore(t) 1434 var evals []*structs.Evaluation 1435 1436 for i := 0; i < 10; i++ { 1437 eval := mock.Eval() 1438 evals = append(evals, eval) 1439 1440 err := state.UpsertEvals(1000+uint64(i), []*structs.Evaluation{eval}) 1441 if err != nil { 1442 t.Fatalf("err: %v", err) 1443 } 1444 } 1445 1446 iter, err := state.Evals() 1447 if err != nil { 1448 t.Fatalf("err: %v", err) 1449 } 1450 1451 var out []*structs.Evaluation 1452 for { 1453 raw := iter.Next() 1454 if raw == nil { 1455 break 1456 } 1457 out = append(out, raw.(*structs.Evaluation)) 1458 } 1459 1460 sort.Sort(EvalIDSort(evals)) 1461 sort.Sort(EvalIDSort(out)) 1462 1463 if !reflect.DeepEqual(evals, out) { 1464 t.Fatalf("bad: %#v %#v", evals, out) 1465 } 1466 } 1467 1468 func TestStateStore_EvalsByIDPrefix(t *testing.T) { 1469 state := testStateStore(t) 1470 var evals []*structs.Evaluation 1471 1472 ids := []string{ 1473 "aaaaaaaa-7bfb-395d-eb95-0685af2176b2", 1474 "aaaaaaab-7bfb-395d-eb95-0685af2176b2", 1475 "aaaaaabb-7bfb-395d-eb95-0685af2176b2", 1476 "aaaaabbb-7bfb-395d-eb95-0685af2176b2", 1477 "aaaabbbb-7bfb-395d-eb95-0685af2176b2", 1478 "aaabbbbb-7bfb-395d-eb95-0685af2176b2", 1479 "aabbbbbb-7bfb-395d-eb95-0685af2176b2", 1480 "abbbbbbb-7bfb-395d-eb95-0685af2176b2", 1481 "bbbbbbbb-7bfb-395d-eb95-0685af2176b2", 1482 } 1483 for i := 0; i < 9; i++ { 1484 eval := mock.Eval() 1485 eval.ID = ids[i] 1486 evals = append(evals, eval) 1487 } 1488 1489 err := state.UpsertEvals(1000, evals) 1490 if err != nil { 1491 t.Fatalf("err: %v", err) 1492 } 1493 1494 iter, err := state.EvalsByIDPrefix("aaaa") 1495 if err != nil { 1496 t.Fatalf("err: %v", err) 1497 } 1498 1499 gatherEvals := func(iter memdb.ResultIterator) []*structs.Evaluation { 1500 var evals []*structs.Evaluation 1501 for { 1502 raw := iter.Next() 1503 if raw == nil { 1504 break 1505 } 1506 evals = append(evals, raw.(*structs.Evaluation)) 1507 } 1508 return evals 1509 } 1510 1511 out := gatherEvals(iter) 1512 if len(out) != 5 { 1513 t.Fatalf("bad: expected five evaluations, got: %#v", out) 1514 } 1515 1516 sort.Sort(EvalIDSort(evals)) 1517 1518 for index, eval := range out { 1519 if ids[index] != eval.ID { 1520 t.Fatalf("bad: got unexpected id: %s", eval.ID) 1521 } 1522 } 1523 1524 iter, err = state.EvalsByIDPrefix("b-a7bfb") 1525 if err != nil { 1526 t.Fatalf("err: %v", err) 1527 } 1528 1529 out = gatherEvals(iter) 1530 if len(out) != 0 { 1531 t.Fatalf("bad: unexpected zero evaluations, got: %#v", out) 1532 } 1533 1534 } 1535 1536 func TestStateStore_RestoreEval(t *testing.T) { 1537 state := testStateStore(t) 1538 eval := mock.Eval() 1539 1540 notify := setupNotifyTest( 1541 state, 1542 watch.Item{Table: "evals"}, 1543 watch.Item{Eval: eval.ID}) 1544 1545 restore, err := state.Restore() 1546 if err != nil { 1547 t.Fatalf("err: %v", err) 1548 } 1549 1550 err = restore.EvalRestore(eval) 1551 if err != nil { 1552 t.Fatalf("err: %v", err) 1553 } 1554 restore.Commit() 1555 1556 out, err := state.EvalByID(eval.ID) 1557 if err != nil { 1558 t.Fatalf("err: %v", err) 1559 } 1560 1561 if !reflect.DeepEqual(out, eval) { 1562 t.Fatalf("Bad: %#v %#v", out, eval) 1563 } 1564 1565 notify.verify(t) 1566 } 1567 1568 func TestStateStore_UpdateAllocsFromClient(t *testing.T) { 1569 state := testStateStore(t) 1570 alloc := mock.Alloc() 1571 alloc2 := mock.Alloc() 1572 1573 notify := setupNotifyTest( 1574 state, 1575 watch.Item{Table: "allocs"}, 1576 watch.Item{Alloc: alloc.ID}, 1577 watch.Item{AllocEval: alloc.EvalID}, 1578 watch.Item{AllocJob: alloc.JobID}, 1579 watch.Item{AllocNode: alloc.NodeID}, 1580 watch.Item{Alloc: alloc2.ID}, 1581 watch.Item{AllocEval: alloc2.EvalID}, 1582 watch.Item{AllocJob: alloc2.JobID}, 1583 watch.Item{AllocNode: alloc2.NodeID}) 1584 1585 if err := state.UpsertJob(999, alloc.Job); err != nil { 1586 t.Fatalf("err: %v", err) 1587 } 1588 if err := state.UpsertJob(999, alloc2.Job); err != nil { 1589 t.Fatalf("err: %v", err) 1590 } 1591 1592 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc, alloc2}) 1593 if err != nil { 1594 t.Fatalf("err: %v", err) 1595 } 1596 1597 // Create the delta updates 1598 ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}} 1599 update := &structs.Allocation{ 1600 ID: alloc.ID, 1601 ClientStatus: structs.AllocClientStatusFailed, 1602 TaskStates: ts, 1603 JobID: alloc.JobID, 1604 TaskGroup: alloc.TaskGroup, 1605 } 1606 update2 := &structs.Allocation{ 1607 ID: alloc2.ID, 1608 ClientStatus: structs.AllocClientStatusRunning, 1609 TaskStates: ts, 1610 JobID: alloc2.JobID, 1611 TaskGroup: alloc2.TaskGroup, 1612 } 1613 1614 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2}) 1615 if err != nil { 1616 t.Fatalf("err: %v", err) 1617 } 1618 1619 out, err := state.AllocByID(alloc.ID) 1620 if err != nil { 1621 t.Fatalf("err: %v", err) 1622 } 1623 1624 alloc.CreateIndex = 1000 1625 alloc.ModifyIndex = 1001 1626 alloc.TaskStates = ts 1627 alloc.ClientStatus = structs.AllocClientStatusFailed 1628 if !reflect.DeepEqual(alloc, out) { 1629 t.Fatalf("bad: %#v %#v", alloc, out) 1630 } 1631 1632 out, err = state.AllocByID(alloc2.ID) 1633 if err != nil { 1634 t.Fatalf("err: %v", err) 1635 } 1636 1637 alloc2.ModifyIndex = 1000 1638 alloc2.ModifyIndex = 1001 1639 alloc2.ClientStatus = structs.AllocClientStatusRunning 1640 alloc2.TaskStates = ts 1641 if !reflect.DeepEqual(alloc2, out) { 1642 t.Fatalf("bad: %#v %#v", alloc2, out) 1643 } 1644 1645 index, err := state.Index("allocs") 1646 if err != nil { 1647 t.Fatalf("err: %v", err) 1648 } 1649 if index != 1001 { 1650 t.Fatalf("bad: %d", index) 1651 } 1652 1653 // Ensure summaries have been updated 1654 summary, err := state.JobSummaryByID(alloc.JobID) 1655 if err != nil { 1656 t.Fatalf("err: %v", err) 1657 } 1658 tgSummary := summary.Summary["web"] 1659 if tgSummary.Failed != 1 { 1660 t.Fatalf("expected failed: %v, actual: %v, summary: %#v", 1, tgSummary.Failed, tgSummary) 1661 } 1662 1663 summary2, err := state.JobSummaryByID(alloc2.JobID) 1664 if err != nil { 1665 t.Fatalf("err: %v", err) 1666 } 1667 tgSummary2 := summary2.Summary["web"] 1668 if tgSummary2.Running != 1 { 1669 t.Fatalf("expected running: %v, actual: %v", 1, tgSummary2.Running) 1670 } 1671 1672 notify.verify(t) 1673 } 1674 1675 func TestStateStore_UpdateMultipleAllocsFromClient(t *testing.T) { 1676 state := testStateStore(t) 1677 alloc := mock.Alloc() 1678 1679 if err := state.UpsertJob(999, alloc.Job); err != nil { 1680 t.Fatalf("err: %v", err) 1681 } 1682 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1683 if err != nil { 1684 t.Fatalf("err: %v", err) 1685 } 1686 1687 // Create the delta updates 1688 ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}} 1689 update := &structs.Allocation{ 1690 ID: alloc.ID, 1691 ClientStatus: structs.AllocClientStatusRunning, 1692 TaskStates: ts, 1693 JobID: alloc.JobID, 1694 TaskGroup: alloc.TaskGroup, 1695 } 1696 update2 := &structs.Allocation{ 1697 ID: alloc.ID, 1698 ClientStatus: structs.AllocClientStatusPending, 1699 TaskStates: ts, 1700 JobID: alloc.JobID, 1701 TaskGroup: alloc.TaskGroup, 1702 } 1703 1704 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2}) 1705 if err != nil { 1706 t.Fatalf("err: %v", err) 1707 } 1708 1709 out, err := state.AllocByID(alloc.ID) 1710 if err != nil { 1711 t.Fatalf("err: %v", err) 1712 } 1713 1714 alloc.CreateIndex = 1000 1715 alloc.ModifyIndex = 1001 1716 alloc.TaskStates = ts 1717 alloc.ClientStatus = structs.AllocClientStatusPending 1718 if !reflect.DeepEqual(alloc, out) { 1719 t.Fatalf("bad: %#v , actual:%#v", alloc, out) 1720 } 1721 1722 summary, err := state.JobSummaryByID(alloc.JobID) 1723 expectedSummary := &structs.JobSummary{ 1724 JobID: alloc.JobID, 1725 Summary: map[string]structs.TaskGroupSummary{ 1726 "web": structs.TaskGroupSummary{ 1727 Starting: 1, 1728 }, 1729 }, 1730 CreateIndex: 999, 1731 ModifyIndex: 1001, 1732 } 1733 if err != nil { 1734 t.Fatalf("err: %v", err) 1735 } 1736 if !reflect.DeepEqual(summary, expectedSummary) { 1737 t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary) 1738 } 1739 } 1740 1741 func TestStateStore_UpsertAlloc_Alloc(t *testing.T) { 1742 state := testStateStore(t) 1743 alloc := mock.Alloc() 1744 1745 notify := setupNotifyTest( 1746 state, 1747 watch.Item{Table: "allocs"}, 1748 watch.Item{Alloc: alloc.ID}, 1749 watch.Item{AllocEval: alloc.EvalID}, 1750 watch.Item{AllocJob: alloc.JobID}, 1751 watch.Item{AllocNode: alloc.NodeID}) 1752 1753 if err := state.UpsertJob(999, alloc.Job); err != nil { 1754 t.Fatalf("err: %v", err) 1755 } 1756 1757 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1758 if err != nil { 1759 t.Fatalf("err: %v", err) 1760 } 1761 1762 out, err := state.AllocByID(alloc.ID) 1763 if err != nil { 1764 t.Fatalf("err: %v", err) 1765 } 1766 1767 if !reflect.DeepEqual(alloc, out) { 1768 t.Fatalf("bad: %#v %#v", alloc, out) 1769 } 1770 1771 index, err := state.Index("allocs") 1772 if err != nil { 1773 t.Fatalf("err: %v", err) 1774 } 1775 if index != 1000 { 1776 t.Fatalf("bad: %d", index) 1777 } 1778 1779 summary, err := state.JobSummaryByID(alloc.JobID) 1780 if err != nil { 1781 t.Fatalf("err: %v", err) 1782 } 1783 1784 tgSummary, ok := summary.Summary["web"] 1785 if !ok { 1786 t.Fatalf("no summary for task group web") 1787 } 1788 if tgSummary.Starting != 1 { 1789 t.Fatalf("expected queued: %v, actual: %v", 1, tgSummary.Starting) 1790 } 1791 1792 notify.verify(t) 1793 } 1794 1795 func TestStateStore_UpsertAlloc_NoEphemeralDisk(t *testing.T) { 1796 state := testStateStore(t) 1797 alloc := mock.Alloc() 1798 alloc.Job.TaskGroups[0].EphemeralDisk = nil 1799 alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120 1800 1801 if err := state.UpsertJob(999, alloc.Job); err != nil { 1802 t.Fatalf("err: %v", err) 1803 } 1804 1805 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1806 if err != nil { 1807 t.Fatalf("err: %v", err) 1808 } 1809 1810 out, err := state.AllocByID(alloc.ID) 1811 if err != nil { 1812 t.Fatalf("err: %v", err) 1813 } 1814 1815 expected := alloc.Copy() 1816 expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120} 1817 if !reflect.DeepEqual(expected, out) { 1818 t.Fatalf("bad: %#v %#v", expected, out) 1819 } 1820 } 1821 1822 func TestStateStore_UpdateAlloc_Alloc(t *testing.T) { 1823 state := testStateStore(t) 1824 alloc := mock.Alloc() 1825 1826 if err := state.UpsertJob(999, alloc.Job); err != nil { 1827 t.Fatalf("err: %v", err) 1828 } 1829 1830 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1831 if err != nil { 1832 t.Fatalf("err: %v", err) 1833 } 1834 1835 summary, err := state.JobSummaryByID(alloc.JobID) 1836 if err != nil { 1837 t.Fatalf("err: %v", err) 1838 } 1839 tgSummary := summary.Summary["web"] 1840 if tgSummary.Starting != 1 { 1841 t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting) 1842 } 1843 1844 alloc2 := mock.Alloc() 1845 alloc2.ID = alloc.ID 1846 alloc2.NodeID = alloc.NodeID + ".new" 1847 state.UpsertJobSummary(1001, mock.JobSummary(alloc2.JobID)) 1848 1849 notify := setupNotifyTest( 1850 state, 1851 watch.Item{Table: "allocs"}, 1852 watch.Item{Alloc: alloc2.ID}, 1853 watch.Item{AllocEval: alloc2.EvalID}, 1854 watch.Item{AllocJob: alloc2.JobID}, 1855 watch.Item{AllocNode: alloc2.NodeID}) 1856 1857 err = state.UpsertAllocs(1002, []*structs.Allocation{alloc2}) 1858 if err != nil { 1859 t.Fatalf("err: %v", err) 1860 } 1861 1862 out, err := state.AllocByID(alloc.ID) 1863 if err != nil { 1864 t.Fatalf("err: %v", err) 1865 } 1866 1867 if !reflect.DeepEqual(alloc2, out) { 1868 t.Fatalf("bad: %#v %#v", alloc2, out) 1869 } 1870 1871 if out.CreateIndex != 1000 { 1872 t.Fatalf("bad: %#v", out) 1873 } 1874 if out.ModifyIndex != 1002 { 1875 t.Fatalf("bad: %#v", out) 1876 } 1877 1878 index, err := state.Index("allocs") 1879 if err != nil { 1880 t.Fatalf("err: %v", err) 1881 } 1882 if index != 1002 { 1883 t.Fatalf("bad: %d", index) 1884 } 1885 1886 // Ensure that summary hasb't changed 1887 summary, err = state.JobSummaryByID(alloc.JobID) 1888 if err != nil { 1889 t.Fatalf("err: %v", err) 1890 } 1891 tgSummary = summary.Summary["web"] 1892 if tgSummary.Starting != 1 { 1893 t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting) 1894 } 1895 1896 notify.verify(t) 1897 } 1898 1899 // This test ensures that the state store will mark the clients status as lost 1900 // when set rather than preferring the existing status. 1901 func TestStateStore_UpdateAlloc_Lost(t *testing.T) { 1902 state := testStateStore(t) 1903 alloc := mock.Alloc() 1904 alloc.ClientStatus = "foo" 1905 1906 if err := state.UpsertJob(999, alloc.Job); err != nil { 1907 t.Fatalf("err: %v", err) 1908 } 1909 1910 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1911 if err != nil { 1912 t.Fatalf("err: %v", err) 1913 } 1914 1915 alloc2 := new(structs.Allocation) 1916 *alloc2 = *alloc 1917 alloc2.ClientStatus = structs.AllocClientStatusLost 1918 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc2}); err != nil { 1919 t.Fatalf("err: %v", err) 1920 } 1921 1922 out, err := state.AllocByID(alloc2.ID) 1923 if err != nil { 1924 t.Fatalf("err: %v", err) 1925 } 1926 1927 if out.ClientStatus != structs.AllocClientStatusLost { 1928 t.Fatalf("bad: %#v", out) 1929 } 1930 } 1931 1932 // This test ensures an allocation can be updated when there is no job 1933 // associated with it. This will happen when a job is stopped by an user which 1934 // has non-terminal allocations on clients 1935 func TestStateStore_UpdateAlloc_NoJob(t *testing.T) { 1936 state := testStateStore(t) 1937 alloc := mock.Alloc() 1938 1939 // Upsert a job 1940 state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)) 1941 if err := state.UpsertJob(999, alloc.Job); err != nil { 1942 t.Fatalf("err: %v", err) 1943 } 1944 1945 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1946 if err != nil { 1947 t.Fatalf("err: %v", err) 1948 } 1949 1950 if err := state.DeleteJob(1001, alloc.JobID); err != nil { 1951 t.Fatalf("err: %v", err) 1952 } 1953 1954 // Update the desired state of the allocation to stop 1955 allocCopy := alloc.Copy() 1956 allocCopy.DesiredStatus = structs.AllocDesiredStatusStop 1957 if err := state.UpsertAllocs(1002, []*structs.Allocation{allocCopy}); err != nil { 1958 t.Fatalf("err: %v", err) 1959 } 1960 1961 // Update the client state of the allocation to complete 1962 allocCopy1 := allocCopy.Copy() 1963 allocCopy1.ClientStatus = structs.AllocClientStatusComplete 1964 if err := state.UpdateAllocsFromClient(1003, []*structs.Allocation{allocCopy1}); err != nil { 1965 t.Fatalf("err: %v", err) 1966 } 1967 1968 out, _ := state.AllocByID(alloc.ID) 1969 // Update the modify index of the alloc before comparing 1970 allocCopy1.ModifyIndex = 1003 1971 if !reflect.DeepEqual(out, allocCopy1) { 1972 t.Fatalf("expected: %#v \n actual: %#v", allocCopy1, out) 1973 } 1974 } 1975 1976 func TestStateStore_JobSummary(t *testing.T) { 1977 state := testStateStore(t) 1978 1979 // Add a job 1980 job := mock.Job() 1981 state.UpsertJob(900, job) 1982 1983 // Get the job back 1984 outJob, _ := state.JobByID(job.ID) 1985 if outJob.CreateIndex != 900 { 1986 t.Fatalf("bad create index: %v", outJob.CreateIndex) 1987 } 1988 summary, _ := state.JobSummaryByID(job.ID) 1989 if summary.CreateIndex != 900 { 1990 t.Fatalf("bad create index: %v", summary.CreateIndex) 1991 } 1992 1993 // Upser an allocation 1994 alloc := mock.Alloc() 1995 alloc.JobID = job.ID 1996 alloc.Job = job 1997 state.UpsertAllocs(910, []*structs.Allocation{alloc}) 1998 1999 // Update the alloc from client 2000 alloc1 := alloc.Copy() 2001 alloc1.ClientStatus = structs.AllocClientStatusPending 2002 alloc1.DesiredStatus = "" 2003 state.UpdateAllocsFromClient(920, []*structs.Allocation{alloc}) 2004 2005 alloc3 := alloc.Copy() 2006 alloc3.ClientStatus = structs.AllocClientStatusRunning 2007 alloc3.DesiredStatus = "" 2008 state.UpdateAllocsFromClient(930, []*structs.Allocation{alloc3}) 2009 2010 // Upsert the alloc 2011 alloc4 := alloc.Copy() 2012 alloc4.ClientStatus = structs.AllocClientStatusPending 2013 alloc4.DesiredStatus = structs.AllocDesiredStatusRun 2014 state.UpsertAllocs(950, []*structs.Allocation{alloc4}) 2015 2016 // Again upsert the alloc 2017 alloc5 := alloc.Copy() 2018 alloc5.ClientStatus = structs.AllocClientStatusPending 2019 alloc5.DesiredStatus = structs.AllocDesiredStatusRun 2020 state.UpsertAllocs(970, []*structs.Allocation{alloc5}) 2021 2022 expectedSummary := structs.JobSummary{ 2023 JobID: job.ID, 2024 Summary: map[string]structs.TaskGroupSummary{ 2025 "web": structs.TaskGroupSummary{ 2026 Running: 1, 2027 }, 2028 }, 2029 CreateIndex: 900, 2030 ModifyIndex: 930, 2031 } 2032 2033 summary, _ = state.JobSummaryByID(job.ID) 2034 if !reflect.DeepEqual(&expectedSummary, summary) { 2035 t.Fatalf("expected: %#v, actual: %v", expectedSummary, summary) 2036 } 2037 2038 // De-register the job. 2039 state.DeleteJob(980, job.ID) 2040 2041 // Shouldn't have any effect on the summary 2042 alloc6 := alloc.Copy() 2043 alloc6.ClientStatus = structs.AllocClientStatusRunning 2044 alloc6.DesiredStatus = "" 2045 state.UpdateAllocsFromClient(990, []*structs.Allocation{alloc6}) 2046 2047 // We shouldn't have any summary at this point 2048 summary, _ = state.JobSummaryByID(job.ID) 2049 if summary != nil { 2050 t.Fatalf("expected nil, actual: %#v", summary) 2051 } 2052 2053 // Re-register the same job 2054 job1 := mock.Job() 2055 job1.ID = job.ID 2056 state.UpsertJob(1000, job1) 2057 outJob2, _ := state.JobByID(job1.ID) 2058 if outJob2.CreateIndex != 1000 { 2059 t.Fatalf("bad create index: %v", outJob2.CreateIndex) 2060 } 2061 summary, _ = state.JobSummaryByID(job1.ID) 2062 if summary.CreateIndex != 1000 { 2063 t.Fatalf("bad create index: %v", summary.CreateIndex) 2064 } 2065 2066 // Upsert an allocation 2067 alloc7 := alloc.Copy() 2068 alloc7.JobID = outJob.ID 2069 alloc7.Job = outJob 2070 alloc7.ClientStatus = structs.AllocClientStatusComplete 2071 alloc7.DesiredStatus = structs.AllocDesiredStatusRun 2072 state.UpdateAllocsFromClient(1020, []*structs.Allocation{alloc7}) 2073 2074 expectedSummary = structs.JobSummary{ 2075 JobID: job.ID, 2076 Summary: map[string]structs.TaskGroupSummary{ 2077 "web": structs.TaskGroupSummary{}, 2078 }, 2079 CreateIndex: 1000, 2080 ModifyIndex: 1000, 2081 } 2082 2083 summary, _ = state.JobSummaryByID(job1.ID) 2084 if !reflect.DeepEqual(&expectedSummary, summary) { 2085 t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary) 2086 } 2087 } 2088 2089 func TestStateStore_ReconcileJobSummary(t *testing.T) { 2090 state := testStateStore(t) 2091 2092 // Create an alloc 2093 alloc := mock.Alloc() 2094 2095 // Add another task group to the job 2096 tg2 := alloc.Job.TaskGroups[0].Copy() 2097 tg2.Name = "db" 2098 alloc.Job.TaskGroups = append(alloc.Job.TaskGroups, tg2) 2099 state.UpsertJob(100, alloc.Job) 2100 2101 // Create one more alloc for the db task group 2102 alloc2 := mock.Alloc() 2103 alloc2.TaskGroup = "db" 2104 alloc2.JobID = alloc.JobID 2105 alloc2.Job = alloc.Job 2106 2107 // Upserts the alloc 2108 state.UpsertAllocs(110, []*structs.Allocation{alloc, alloc2}) 2109 2110 // Change the state of the first alloc to running 2111 alloc3 := alloc.Copy() 2112 alloc3.ClientStatus = structs.AllocClientStatusRunning 2113 state.UpdateAllocsFromClient(120, []*structs.Allocation{alloc3}) 2114 2115 //Add some more allocs to the second tg 2116 alloc4 := mock.Alloc() 2117 alloc4.JobID = alloc.JobID 2118 alloc4.Job = alloc.Job 2119 alloc4.TaskGroup = "db" 2120 alloc5 := alloc4.Copy() 2121 alloc5.ClientStatus = structs.AllocClientStatusRunning 2122 2123 alloc6 := mock.Alloc() 2124 alloc6.JobID = alloc.JobID 2125 alloc6.Job = alloc.Job 2126 alloc6.TaskGroup = "db" 2127 alloc7 := alloc6.Copy() 2128 alloc7.ClientStatus = structs.AllocClientStatusComplete 2129 2130 alloc8 := mock.Alloc() 2131 alloc8.JobID = alloc.JobID 2132 alloc8.Job = alloc.Job 2133 alloc8.TaskGroup = "db" 2134 alloc9 := alloc8.Copy() 2135 alloc9.ClientStatus = structs.AllocClientStatusFailed 2136 2137 alloc10 := mock.Alloc() 2138 alloc10.JobID = alloc.JobID 2139 alloc10.Job = alloc.Job 2140 alloc10.TaskGroup = "db" 2141 alloc11 := alloc10.Copy() 2142 alloc11.ClientStatus = structs.AllocClientStatusLost 2143 2144 state.UpsertAllocs(130, []*structs.Allocation{alloc4, alloc6, alloc8, alloc10}) 2145 2146 state.UpdateAllocsFromClient(150, []*structs.Allocation{alloc5, alloc7, alloc9, alloc11}) 2147 2148 // DeleteJobSummary is a helper method and doesn't modify the indexes table 2149 state.DeleteJobSummary(130, alloc.Job.ID) 2150 2151 state.ReconcileJobSummaries(120) 2152 2153 summary, _ := state.JobSummaryByID(alloc.Job.ID) 2154 expectedSummary := structs.JobSummary{ 2155 JobID: alloc.Job.ID, 2156 Summary: map[string]structs.TaskGroupSummary{ 2157 "web": structs.TaskGroupSummary{ 2158 Running: 1, 2159 }, 2160 "db": structs.TaskGroupSummary{ 2161 Starting: 1, 2162 Running: 1, 2163 Failed: 1, 2164 Complete: 1, 2165 Lost: 1, 2166 }, 2167 }, 2168 CreateIndex: 100, 2169 ModifyIndex: 120, 2170 } 2171 if !reflect.DeepEqual(&expectedSummary, summary) { 2172 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 2173 } 2174 } 2175 2176 func TestStateStore_UpdateAlloc_JobNotPresent(t *testing.T) { 2177 state := testStateStore(t) 2178 2179 alloc := mock.Alloc() 2180 state.UpsertJob(100, alloc.Job) 2181 state.UpsertAllocs(200, []*structs.Allocation{alloc}) 2182 2183 // Delete the job 2184 state.DeleteJob(300, alloc.Job.ID) 2185 2186 // Update the alloc 2187 alloc1 := alloc.Copy() 2188 alloc1.ClientStatus = structs.AllocClientStatusRunning 2189 2190 // Updating allocation should not throw any error 2191 if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil { 2192 t.Fatalf("expect err: %v", err) 2193 } 2194 2195 // Re-Register the job 2196 state.UpsertJob(500, alloc.Job) 2197 2198 // Update the alloc again 2199 alloc2 := alloc.Copy() 2200 alloc2.ClientStatus = structs.AllocClientStatusComplete 2201 if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil { 2202 t.Fatalf("expect err: %v", err) 2203 } 2204 2205 // Job Summary of the newly registered job shouldn't account for the 2206 // allocation update for the older job 2207 expectedSummary := structs.JobSummary{ 2208 JobID: alloc1.JobID, 2209 Summary: map[string]structs.TaskGroupSummary{ 2210 "web": structs.TaskGroupSummary{}, 2211 }, 2212 CreateIndex: 500, 2213 ModifyIndex: 500, 2214 } 2215 summary, _ := state.JobSummaryByID(alloc.Job.ID) 2216 if !reflect.DeepEqual(&expectedSummary, summary) { 2217 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 2218 } 2219 } 2220 2221 func TestStateStore_EvictAlloc_Alloc(t *testing.T) { 2222 state := testStateStore(t) 2223 alloc := mock.Alloc() 2224 2225 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 2226 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 2227 if err != nil { 2228 t.Fatalf("err: %v", err) 2229 } 2230 2231 alloc2 := new(structs.Allocation) 2232 *alloc2 = *alloc 2233 alloc2.DesiredStatus = structs.AllocDesiredStatusEvict 2234 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc2}) 2235 if err != nil { 2236 t.Fatalf("err: %v", err) 2237 } 2238 2239 out, err := state.AllocByID(alloc.ID) 2240 if err != nil { 2241 t.Fatalf("err: %v", err) 2242 } 2243 2244 if out.DesiredStatus != structs.AllocDesiredStatusEvict { 2245 t.Fatalf("bad: %#v %#v", alloc, out) 2246 } 2247 2248 index, err := state.Index("allocs") 2249 if err != nil { 2250 t.Fatalf("err: %v", err) 2251 } 2252 if index != 1001 { 2253 t.Fatalf("bad: %d", index) 2254 } 2255 } 2256 2257 func TestStateStore_AllocsByNode(t *testing.T) { 2258 state := testStateStore(t) 2259 var allocs []*structs.Allocation 2260 2261 for i := 0; i < 10; i++ { 2262 alloc := mock.Alloc() 2263 alloc.NodeID = "foo" 2264 allocs = append(allocs, alloc) 2265 } 2266 2267 for idx, alloc := range allocs { 2268 state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID)) 2269 } 2270 2271 err := state.UpsertAllocs(1000, allocs) 2272 if err != nil { 2273 t.Fatalf("err: %v", err) 2274 } 2275 2276 out, err := state.AllocsByNode("foo") 2277 if err != nil { 2278 t.Fatalf("err: %v", err) 2279 } 2280 2281 sort.Sort(AllocIDSort(allocs)) 2282 sort.Sort(AllocIDSort(out)) 2283 2284 if !reflect.DeepEqual(allocs, out) { 2285 t.Fatalf("bad: %#v %#v", allocs, out) 2286 } 2287 } 2288 2289 func TestStateStore_AllocsByNodeTerminal(t *testing.T) { 2290 state := testStateStore(t) 2291 var allocs, term, nonterm []*structs.Allocation 2292 2293 for i := 0; i < 10; i++ { 2294 alloc := mock.Alloc() 2295 alloc.NodeID = "foo" 2296 if i%2 == 0 { 2297 alloc.DesiredStatus = structs.AllocDesiredStatusStop 2298 term = append(term, alloc) 2299 } else { 2300 nonterm = append(nonterm, alloc) 2301 } 2302 allocs = append(allocs, alloc) 2303 } 2304 2305 for idx, alloc := range allocs { 2306 state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID)) 2307 } 2308 2309 err := state.UpsertAllocs(1000, allocs) 2310 if err != nil { 2311 t.Fatalf("err: %v", err) 2312 } 2313 2314 // Verify the terminal allocs 2315 out, err := state.AllocsByNodeTerminal("foo", true) 2316 if err != nil { 2317 t.Fatalf("err: %v", err) 2318 } 2319 2320 sort.Sort(AllocIDSort(term)) 2321 sort.Sort(AllocIDSort(out)) 2322 2323 if !reflect.DeepEqual(term, out) { 2324 t.Fatalf("bad: %#v %#v", term, out) 2325 } 2326 2327 // Verify the non-terminal allocs 2328 out, err = state.AllocsByNodeTerminal("foo", false) 2329 if err != nil { 2330 t.Fatalf("err: %v", err) 2331 } 2332 2333 sort.Sort(AllocIDSort(nonterm)) 2334 sort.Sort(AllocIDSort(out)) 2335 2336 if !reflect.DeepEqual(nonterm, out) { 2337 t.Fatalf("bad: %#v %#v", nonterm, out) 2338 } 2339 } 2340 2341 func TestStateStore_AllocsByJob(t *testing.T) { 2342 state := testStateStore(t) 2343 var allocs []*structs.Allocation 2344 2345 for i := 0; i < 10; i++ { 2346 alloc := mock.Alloc() 2347 alloc.JobID = "foo" 2348 allocs = append(allocs, alloc) 2349 } 2350 2351 for i, alloc := range allocs { 2352 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 2353 } 2354 2355 err := state.UpsertAllocs(1000, allocs) 2356 if err != nil { 2357 t.Fatalf("err: %v", err) 2358 } 2359 2360 out, err := state.AllocsByJob("foo") 2361 if err != nil { 2362 t.Fatalf("err: %v", err) 2363 } 2364 2365 sort.Sort(AllocIDSort(allocs)) 2366 sort.Sort(AllocIDSort(out)) 2367 2368 if !reflect.DeepEqual(allocs, out) { 2369 t.Fatalf("bad: %#v %#v", allocs, out) 2370 } 2371 } 2372 2373 func TestStateStore_AllocsByIDPrefix(t *testing.T) { 2374 state := testStateStore(t) 2375 var allocs []*structs.Allocation 2376 2377 ids := []string{ 2378 "aaaaaaaa-7bfb-395d-eb95-0685af2176b2", 2379 "aaaaaaab-7bfb-395d-eb95-0685af2176b2", 2380 "aaaaaabb-7bfb-395d-eb95-0685af2176b2", 2381 "aaaaabbb-7bfb-395d-eb95-0685af2176b2", 2382 "aaaabbbb-7bfb-395d-eb95-0685af2176b2", 2383 "aaabbbbb-7bfb-395d-eb95-0685af2176b2", 2384 "aabbbbbb-7bfb-395d-eb95-0685af2176b2", 2385 "abbbbbbb-7bfb-395d-eb95-0685af2176b2", 2386 "bbbbbbbb-7bfb-395d-eb95-0685af2176b2", 2387 } 2388 for i := 0; i < 9; i++ { 2389 alloc := mock.Alloc() 2390 alloc.ID = ids[i] 2391 allocs = append(allocs, alloc) 2392 } 2393 2394 for i, alloc := range allocs { 2395 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 2396 } 2397 2398 err := state.UpsertAllocs(1000, allocs) 2399 if err != nil { 2400 t.Fatalf("err: %v", err) 2401 } 2402 2403 iter, err := state.AllocsByIDPrefix("aaaa") 2404 if err != nil { 2405 t.Fatalf("err: %v", err) 2406 } 2407 2408 gatherAllocs := func(iter memdb.ResultIterator) []*structs.Allocation { 2409 var allocs []*structs.Allocation 2410 for { 2411 raw := iter.Next() 2412 if raw == nil { 2413 break 2414 } 2415 allocs = append(allocs, raw.(*structs.Allocation)) 2416 } 2417 return allocs 2418 } 2419 2420 out := gatherAllocs(iter) 2421 if len(out) != 5 { 2422 t.Fatalf("bad: expected five allocations, got: %#v", out) 2423 } 2424 2425 sort.Sort(AllocIDSort(allocs)) 2426 2427 for index, alloc := range out { 2428 if ids[index] != alloc.ID { 2429 t.Fatalf("bad: got unexpected id: %s", alloc.ID) 2430 } 2431 } 2432 2433 iter, err = state.AllocsByIDPrefix("b-a7bfb") 2434 if err != nil { 2435 t.Fatalf("err: %v", err) 2436 } 2437 2438 out = gatherAllocs(iter) 2439 if len(out) != 0 { 2440 t.Fatalf("bad: unexpected zero allocations, got: %#v", out) 2441 } 2442 } 2443 2444 func TestStateStore_Allocs(t *testing.T) { 2445 state := testStateStore(t) 2446 var allocs []*structs.Allocation 2447 2448 for i := 0; i < 10; i++ { 2449 alloc := mock.Alloc() 2450 allocs = append(allocs, alloc) 2451 } 2452 for i, alloc := range allocs { 2453 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 2454 } 2455 2456 err := state.UpsertAllocs(1000, allocs) 2457 if err != nil { 2458 t.Fatalf("err: %v", err) 2459 } 2460 2461 iter, err := state.Allocs() 2462 if err != nil { 2463 t.Fatalf("err: %v", err) 2464 } 2465 2466 var out []*structs.Allocation 2467 for { 2468 raw := iter.Next() 2469 if raw == nil { 2470 break 2471 } 2472 out = append(out, raw.(*structs.Allocation)) 2473 } 2474 2475 sort.Sort(AllocIDSort(allocs)) 2476 sort.Sort(AllocIDSort(out)) 2477 2478 if !reflect.DeepEqual(allocs, out) { 2479 t.Fatalf("bad: %#v %#v", allocs, out) 2480 } 2481 } 2482 2483 func TestStateStore_RestoreAlloc(t *testing.T) { 2484 state := testStateStore(t) 2485 alloc := mock.Alloc() 2486 2487 notify := setupNotifyTest( 2488 state, 2489 watch.Item{Table: "allocs"}, 2490 watch.Item{Alloc: alloc.ID}, 2491 watch.Item{AllocEval: alloc.EvalID}, 2492 watch.Item{AllocJob: alloc.JobID}, 2493 watch.Item{AllocNode: alloc.NodeID}) 2494 2495 restore, err := state.Restore() 2496 if err != nil { 2497 t.Fatalf("err: %v", err) 2498 } 2499 2500 err = restore.AllocRestore(alloc) 2501 if err != nil { 2502 t.Fatalf("err: %v", err) 2503 } 2504 2505 restore.Commit() 2506 2507 out, err := state.AllocByID(alloc.ID) 2508 if err != nil { 2509 t.Fatalf("err: %v", err) 2510 } 2511 2512 if !reflect.DeepEqual(out, alloc) { 2513 t.Fatalf("Bad: %#v %#v", out, alloc) 2514 } 2515 2516 notify.verify(t) 2517 } 2518 2519 func TestStateStore_RestoreAlloc_NoEphemeralDisk(t *testing.T) { 2520 state := testStateStore(t) 2521 alloc := mock.Alloc() 2522 alloc.Job.TaskGroups[0].EphemeralDisk = nil 2523 alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120 2524 2525 restore, err := state.Restore() 2526 if err != nil { 2527 t.Fatalf("err: %v", err) 2528 } 2529 2530 err = restore.AllocRestore(alloc) 2531 if err != nil { 2532 t.Fatalf("err: %v", err) 2533 } 2534 2535 restore.Commit() 2536 2537 out, err := state.AllocByID(alloc.ID) 2538 if err != nil { 2539 t.Fatalf("err: %v", err) 2540 } 2541 2542 expected := alloc.Copy() 2543 expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120} 2544 expected.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 2545 2546 if !reflect.DeepEqual(out, expected) { 2547 t.Fatalf("Bad: %#v %#v", out, expected) 2548 } 2549 } 2550 2551 func TestStateStore_SetJobStatus_ForceStatus(t *testing.T) { 2552 state := testStateStore(t) 2553 watcher := watch.NewItems() 2554 txn := state.db.Txn(true) 2555 2556 // Create and insert a mock job. 2557 job := mock.Job() 2558 job.Status = "" 2559 job.ModifyIndex = 0 2560 if err := txn.Insert("jobs", job); err != nil { 2561 t.Fatalf("job insert failed: %v", err) 2562 } 2563 2564 exp := "foobar" 2565 index := uint64(1000) 2566 if err := state.setJobStatus(index, watcher, txn, job, false, exp); err != nil { 2567 t.Fatalf("setJobStatus() failed: %v", err) 2568 } 2569 2570 i, err := txn.First("jobs", "id", job.ID) 2571 if err != nil { 2572 t.Fatalf("job lookup failed: %v", err) 2573 } 2574 updated := i.(*structs.Job) 2575 2576 if updated.Status != exp { 2577 t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, exp) 2578 } 2579 2580 if updated.ModifyIndex != index { 2581 t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index) 2582 } 2583 } 2584 2585 func TestStateStore_SetJobStatus_NoOp(t *testing.T) { 2586 state := testStateStore(t) 2587 watcher := watch.NewItems() 2588 txn := state.db.Txn(true) 2589 2590 // Create and insert a mock job that should be pending. 2591 job := mock.Job() 2592 job.Status = structs.JobStatusPending 2593 job.ModifyIndex = 10 2594 if err := txn.Insert("jobs", job); err != nil { 2595 t.Fatalf("job insert failed: %v", err) 2596 } 2597 2598 index := uint64(1000) 2599 if err := state.setJobStatus(index, watcher, txn, job, false, ""); err != nil { 2600 t.Fatalf("setJobStatus() failed: %v", err) 2601 } 2602 2603 i, err := txn.First("jobs", "id", job.ID) 2604 if err != nil { 2605 t.Fatalf("job lookup failed: %v", err) 2606 } 2607 updated := i.(*structs.Job) 2608 2609 if updated.ModifyIndex == index { 2610 t.Fatalf("setJobStatus() should have been a no-op") 2611 } 2612 } 2613 2614 func TestStateStore_SetJobStatus(t *testing.T) { 2615 state := testStateStore(t) 2616 watcher := watch.NewItems() 2617 txn := state.db.Txn(true) 2618 2619 // Create and insert a mock job that should be pending but has an incorrect 2620 // status. 2621 job := mock.Job() 2622 job.Status = "foobar" 2623 job.ModifyIndex = 10 2624 if err := txn.Insert("jobs", job); err != nil { 2625 t.Fatalf("job insert failed: %v", err) 2626 } 2627 2628 index := uint64(1000) 2629 if err := state.setJobStatus(index, watcher, txn, job, false, ""); err != nil { 2630 t.Fatalf("setJobStatus() failed: %v", err) 2631 } 2632 2633 i, err := txn.First("jobs", "id", job.ID) 2634 if err != nil { 2635 t.Fatalf("job lookup failed: %v", err) 2636 } 2637 updated := i.(*structs.Job) 2638 2639 if updated.Status != structs.JobStatusPending { 2640 t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, structs.JobStatusPending) 2641 } 2642 2643 if updated.ModifyIndex != index { 2644 t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index) 2645 } 2646 } 2647 2648 func TestStateStore_GetJobStatus_NoEvalsOrAllocs(t *testing.T) { 2649 job := mock.Job() 2650 state := testStateStore(t) 2651 txn := state.db.Txn(false) 2652 status, err := state.getJobStatus(txn, job, false) 2653 if err != nil { 2654 t.Fatalf("getJobStatus() failed: %v", err) 2655 } 2656 2657 if status != structs.JobStatusPending { 2658 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending) 2659 } 2660 } 2661 2662 func TestStateStore_GetJobStatus_NoEvalsOrAllocs_Periodic(t *testing.T) { 2663 job := mock.PeriodicJob() 2664 state := testStateStore(t) 2665 txn := state.db.Txn(false) 2666 status, err := state.getJobStatus(txn, job, false) 2667 if err != nil { 2668 t.Fatalf("getJobStatus() failed: %v", err) 2669 } 2670 2671 if status != structs.JobStatusRunning { 2672 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 2673 } 2674 } 2675 2676 func TestStateStore_GetJobStatus_NoEvalsOrAllocs_EvalDelete(t *testing.T) { 2677 job := mock.Job() 2678 state := testStateStore(t) 2679 txn := state.db.Txn(false) 2680 status, err := state.getJobStatus(txn, job, true) 2681 if err != nil { 2682 t.Fatalf("getJobStatus() failed: %v", err) 2683 } 2684 2685 if status != structs.JobStatusDead { 2686 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 2687 } 2688 } 2689 2690 func TestStateStore_GetJobStatus_DeadEvalsAndAllocs(t *testing.T) { 2691 state := testStateStore(t) 2692 job := mock.Job() 2693 2694 // Create a mock alloc that is dead. 2695 alloc := mock.Alloc() 2696 alloc.JobID = job.ID 2697 alloc.DesiredStatus = structs.AllocDesiredStatusStop 2698 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 2699 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { 2700 t.Fatalf("err: %v", err) 2701 } 2702 2703 // Create a mock eval that is complete 2704 eval := mock.Eval() 2705 eval.JobID = job.ID 2706 eval.Status = structs.EvalStatusComplete 2707 if err := state.UpsertEvals(1001, []*structs.Evaluation{eval}); err != nil { 2708 t.Fatalf("err: %v", err) 2709 } 2710 2711 txn := state.db.Txn(false) 2712 status, err := state.getJobStatus(txn, job, false) 2713 if err != nil { 2714 t.Fatalf("getJobStatus() failed: %v", err) 2715 } 2716 2717 if status != structs.JobStatusDead { 2718 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 2719 } 2720 } 2721 2722 func TestStateStore_GetJobStatus_RunningAlloc(t *testing.T) { 2723 state := testStateStore(t) 2724 job := mock.Job() 2725 2726 // Create a mock alloc that is running. 2727 alloc := mock.Alloc() 2728 alloc.JobID = job.ID 2729 alloc.DesiredStatus = structs.AllocDesiredStatusRun 2730 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 2731 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { 2732 t.Fatalf("err: %v", err) 2733 } 2734 2735 txn := state.db.Txn(false) 2736 status, err := state.getJobStatus(txn, job, true) 2737 if err != nil { 2738 t.Fatalf("getJobStatus() failed: %v", err) 2739 } 2740 2741 if status != structs.JobStatusRunning { 2742 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 2743 } 2744 } 2745 2746 func TestStateStore_SetJobStatus_PendingEval(t *testing.T) { 2747 state := testStateStore(t) 2748 job := mock.Job() 2749 2750 // Create a mock eval that is pending. 2751 eval := mock.Eval() 2752 eval.JobID = job.ID 2753 eval.Status = structs.EvalStatusPending 2754 if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil { 2755 t.Fatalf("err: %v", err) 2756 } 2757 2758 txn := state.db.Txn(false) 2759 status, err := state.getJobStatus(txn, job, true) 2760 if err != nil { 2761 t.Fatalf("getJobStatus() failed: %v", err) 2762 } 2763 2764 if status != structs.JobStatusPending { 2765 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending) 2766 } 2767 } 2768 2769 func TestStateWatch_watch(t *testing.T) { 2770 sw := newStateWatch() 2771 notify1 := make(chan struct{}, 1) 2772 notify2 := make(chan struct{}, 1) 2773 notify3 := make(chan struct{}, 1) 2774 2775 // Notifications trigger subscribed channels 2776 sw.watch(watch.NewItems(watch.Item{Table: "foo"}), notify1) 2777 sw.watch(watch.NewItems(watch.Item{Table: "bar"}), notify2) 2778 sw.watch(watch.NewItems(watch.Item{Table: "baz"}), notify3) 2779 2780 items := watch.NewItems() 2781 items.Add(watch.Item{Table: "foo"}) 2782 items.Add(watch.Item{Table: "bar"}) 2783 2784 sw.notify(items) 2785 if len(notify1) != 1 { 2786 t.Fatalf("should notify") 2787 } 2788 if len(notify2) != 1 { 2789 t.Fatalf("should notify") 2790 } 2791 if len(notify3) != 0 { 2792 t.Fatalf("should not notify") 2793 } 2794 } 2795 2796 func TestStateWatch_stopWatch(t *testing.T) { 2797 sw := newStateWatch() 2798 notify := make(chan struct{}) 2799 2800 // First subscribe 2801 sw.watch(watch.NewItems(watch.Item{Table: "foo"}), notify) 2802 2803 // Unsubscribe stop notifications 2804 sw.stopWatch(watch.NewItems(watch.Item{Table: "foo"}), notify) 2805 2806 // Check that the group was removed 2807 if _, ok := sw.items[watch.Item{Table: "foo"}]; ok { 2808 t.Fatalf("should remove group") 2809 } 2810 2811 // Check that we are not notified 2812 sw.notify(watch.NewItems(watch.Item{Table: "foo"})) 2813 if len(notify) != 0 { 2814 t.Fatalf("should not notify") 2815 } 2816 } 2817 2818 func TestStateJobSummary_UpdateJobCount(t *testing.T) { 2819 state := testStateStore(t) 2820 alloc := mock.Alloc() 2821 job := alloc.Job 2822 job.TaskGroups[0].Count = 3 2823 err := state.UpsertJob(1000, job) 2824 if err != nil { 2825 t.Fatalf("err: %v", err) 2826 } 2827 2828 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc}); err != nil { 2829 t.Fatalf("err: %v", err) 2830 } 2831 summary, _ := state.JobSummaryByID(job.ID) 2832 expectedSummary := structs.JobSummary{ 2833 JobID: job.ID, 2834 Summary: map[string]structs.TaskGroupSummary{ 2835 "web": { 2836 Starting: 1, 2837 }, 2838 }, 2839 CreateIndex: 1000, 2840 ModifyIndex: 1001, 2841 } 2842 if !reflect.DeepEqual(summary, &expectedSummary) { 2843 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 2844 } 2845 2846 alloc2 := mock.Alloc() 2847 alloc2.Job = job 2848 alloc2.JobID = job.ID 2849 2850 alloc3 := mock.Alloc() 2851 alloc3.Job = job 2852 alloc3.JobID = job.ID 2853 2854 if err := state.UpsertAllocs(1002, []*structs.Allocation{alloc2, alloc3}); err != nil { 2855 t.Fatalf("err: %v", err) 2856 } 2857 2858 outA, _ := state.AllocByID(alloc3.ID) 2859 2860 summary, _ = state.JobSummaryByID(job.ID) 2861 expectedSummary = structs.JobSummary{ 2862 JobID: job.ID, 2863 Summary: map[string]structs.TaskGroupSummary{ 2864 "web": { 2865 Starting: 3, 2866 }, 2867 }, 2868 CreateIndex: job.CreateIndex, 2869 ModifyIndex: outA.ModifyIndex, 2870 } 2871 if !reflect.DeepEqual(summary, &expectedSummary) { 2872 t.Fatalf("expected summary: %v, actual: %v", expectedSummary, summary) 2873 } 2874 2875 alloc4 := mock.Alloc() 2876 alloc4.ID = alloc2.ID 2877 alloc4.Job = alloc2.Job 2878 alloc4.JobID = alloc2.JobID 2879 alloc4.ClientStatus = structs.AllocClientStatusComplete 2880 2881 alloc5 := mock.Alloc() 2882 alloc5.ID = alloc3.ID 2883 alloc5.Job = alloc3.Job 2884 alloc5.JobID = alloc3.JobID 2885 alloc5.ClientStatus = structs.AllocClientStatusComplete 2886 2887 if err := state.UpdateAllocsFromClient(1004, []*structs.Allocation{alloc4, alloc5}); err != nil { 2888 t.Fatalf("err: %v", err) 2889 } 2890 outA, _ = state.AllocByID(alloc5.ID) 2891 summary, _ = state.JobSummaryByID(job.ID) 2892 expectedSummary = structs.JobSummary{ 2893 JobID: job.ID, 2894 Summary: map[string]structs.TaskGroupSummary{ 2895 "web": { 2896 Complete: 2, 2897 Starting: 1, 2898 }, 2899 }, 2900 CreateIndex: job.CreateIndex, 2901 ModifyIndex: outA.ModifyIndex, 2902 } 2903 if !reflect.DeepEqual(summary, &expectedSummary) { 2904 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 2905 } 2906 } 2907 2908 func TestJobSummary_UpdateClientStatus(t *testing.T) { 2909 state := testStateStore(t) 2910 alloc := mock.Alloc() 2911 job := alloc.Job 2912 job.TaskGroups[0].Count = 3 2913 2914 alloc2 := mock.Alloc() 2915 alloc2.Job = job 2916 alloc2.JobID = job.ID 2917 2918 alloc3 := mock.Alloc() 2919 alloc3.Job = job 2920 alloc3.JobID = job.ID 2921 2922 err := state.UpsertJob(1000, job) 2923 if err != nil { 2924 t.Fatalf("err: %v", err) 2925 } 2926 2927 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc, alloc2, alloc3}); err != nil { 2928 t.Fatalf("err: %v", err) 2929 } 2930 summary, _ := state.JobSummaryByID(job.ID) 2931 if summary.Summary["web"].Starting != 3 { 2932 t.Fatalf("bad job summary: %v", summary) 2933 } 2934 2935 alloc4 := mock.Alloc() 2936 alloc4.ID = alloc2.ID 2937 alloc4.Job = alloc2.Job 2938 alloc4.JobID = alloc2.JobID 2939 alloc4.ClientStatus = structs.AllocClientStatusComplete 2940 2941 alloc5 := mock.Alloc() 2942 alloc5.ID = alloc3.ID 2943 alloc5.Job = alloc3.Job 2944 alloc5.JobID = alloc3.JobID 2945 alloc5.ClientStatus = structs.AllocClientStatusFailed 2946 2947 alloc6 := mock.Alloc() 2948 alloc6.ID = alloc.ID 2949 alloc6.Job = alloc.Job 2950 alloc6.JobID = alloc.JobID 2951 alloc6.ClientStatus = structs.AllocClientStatusRunning 2952 2953 if err := state.UpdateAllocsFromClient(1002, []*structs.Allocation{alloc4, alloc5, alloc6}); err != nil { 2954 t.Fatalf("err: %v", err) 2955 } 2956 summary, _ = state.JobSummaryByID(job.ID) 2957 if summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 { 2958 t.Fatalf("bad job summary: %v", summary) 2959 } 2960 2961 alloc7 := mock.Alloc() 2962 alloc7.Job = alloc.Job 2963 alloc7.JobID = alloc.JobID 2964 2965 if err := state.UpsertAllocs(1003, []*structs.Allocation{alloc7}); err != nil { 2966 t.Fatalf("err: %v", err) 2967 } 2968 summary, _ = state.JobSummaryByID(job.ID) 2969 if summary.Summary["web"].Starting != 1 || summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 { 2970 t.Fatalf("bad job summary: %v", summary) 2971 } 2972 } 2973 2974 func TestStateStore_UpsertVaultAccessors(t *testing.T) { 2975 state := testStateStore(t) 2976 a := mock.VaultAccessor() 2977 a2 := mock.VaultAccessor() 2978 2979 err := state.UpsertVaultAccessor(1000, []*structs.VaultAccessor{a, a2}) 2980 if err != nil { 2981 t.Fatalf("err: %v", err) 2982 } 2983 2984 out, err := state.VaultAccessor(a.Accessor) 2985 if err != nil { 2986 t.Fatalf("err: %v", err) 2987 } 2988 2989 if !reflect.DeepEqual(a, out) { 2990 t.Fatalf("bad: %#v %#v", a, out) 2991 } 2992 2993 out, err = state.VaultAccessor(a2.Accessor) 2994 if err != nil { 2995 t.Fatalf("err: %v", err) 2996 } 2997 2998 if !reflect.DeepEqual(a2, out) { 2999 t.Fatalf("bad: %#v %#v", a2, out) 3000 } 3001 3002 iter, err := state.VaultAccessors() 3003 if err != nil { 3004 t.Fatalf("err: %v", err) 3005 } 3006 3007 count := 0 3008 for { 3009 raw := iter.Next() 3010 if raw == nil { 3011 break 3012 } 3013 3014 count++ 3015 accessor := raw.(*structs.VaultAccessor) 3016 3017 if !reflect.DeepEqual(accessor, a) && !reflect.DeepEqual(accessor, a2) { 3018 t.Fatalf("bad: %#v", accessor) 3019 } 3020 } 3021 3022 if count != 2 { 3023 t.Fatalf("bad: %d", count) 3024 } 3025 3026 index, err := state.Index("vault_accessors") 3027 if err != nil { 3028 t.Fatalf("err: %v", err) 3029 } 3030 if index != 1000 { 3031 t.Fatalf("bad: %d", index) 3032 } 3033 } 3034 3035 func TestStateStore_DeleteVaultAccessors(t *testing.T) { 3036 state := testStateStore(t) 3037 a1 := mock.VaultAccessor() 3038 a2 := mock.VaultAccessor() 3039 accessors := []*structs.VaultAccessor{a1, a2} 3040 3041 err := state.UpsertVaultAccessor(1000, accessors) 3042 if err != nil { 3043 t.Fatalf("err: %v", err) 3044 } 3045 3046 err = state.DeleteVaultAccessors(1001, accessors) 3047 if err != nil { 3048 t.Fatalf("err: %v", err) 3049 } 3050 3051 out, err := state.VaultAccessor(a1.Accessor) 3052 if err != nil { 3053 t.Fatalf("err: %v", err) 3054 } 3055 if out != nil { 3056 t.Fatalf("bad: %#v %#v", a1, out) 3057 } 3058 out, err = state.VaultAccessor(a2.Accessor) 3059 if err != nil { 3060 t.Fatalf("err: %v", err) 3061 } 3062 if out != nil { 3063 t.Fatalf("bad: %#v %#v", a2, out) 3064 } 3065 3066 index, err := state.Index("vault_accessors") 3067 if err != nil { 3068 t.Fatalf("err: %v", err) 3069 } 3070 if index != 1001 { 3071 t.Fatalf("bad: %d", index) 3072 } 3073 } 3074 3075 func TestStateStore_VaultAccessorsByAlloc(t *testing.T) { 3076 state := testStateStore(t) 3077 alloc := mock.Alloc() 3078 var accessors []*structs.VaultAccessor 3079 var expected []*structs.VaultAccessor 3080 3081 for i := 0; i < 5; i++ { 3082 accessor := mock.VaultAccessor() 3083 accessor.AllocID = alloc.ID 3084 expected = append(expected, accessor) 3085 accessors = append(accessors, accessor) 3086 } 3087 3088 for i := 0; i < 10; i++ { 3089 accessor := mock.VaultAccessor() 3090 accessors = append(accessors, accessor) 3091 } 3092 3093 err := state.UpsertVaultAccessor(1000, accessors) 3094 if err != nil { 3095 t.Fatalf("err: %v", err) 3096 } 3097 3098 out, err := state.VaultAccessorsByAlloc(alloc.ID) 3099 if err != nil { 3100 t.Fatalf("err: %v", err) 3101 } 3102 3103 if len(expected) != len(out) { 3104 t.Fatalf("bad: %#v %#v", len(expected), len(out)) 3105 } 3106 3107 index, err := state.Index("vault_accessors") 3108 if err != nil { 3109 t.Fatalf("err: %v", err) 3110 } 3111 if index != 1000 { 3112 t.Fatalf("bad: %d", index) 3113 } 3114 } 3115 3116 func TestStateStore_VaultAccessorsByNode(t *testing.T) { 3117 state := testStateStore(t) 3118 node := mock.Node() 3119 var accessors []*structs.VaultAccessor 3120 var expected []*structs.VaultAccessor 3121 3122 for i := 0; i < 5; i++ { 3123 accessor := mock.VaultAccessor() 3124 accessor.NodeID = node.ID 3125 expected = append(expected, accessor) 3126 accessors = append(accessors, accessor) 3127 } 3128 3129 for i := 0; i < 10; i++ { 3130 accessor := mock.VaultAccessor() 3131 accessors = append(accessors, accessor) 3132 } 3133 3134 err := state.UpsertVaultAccessor(1000, accessors) 3135 if err != nil { 3136 t.Fatalf("err: %v", err) 3137 } 3138 3139 out, err := state.VaultAccessorsByNode(node.ID) 3140 if err != nil { 3141 t.Fatalf("err: %v", err) 3142 } 3143 3144 if len(expected) != len(out) { 3145 t.Fatalf("bad: %#v %#v", len(expected), len(out)) 3146 } 3147 3148 index, err := state.Index("vault_accessors") 3149 if err != nil { 3150 t.Fatalf("err: %v", err) 3151 } 3152 if index != 1000 { 3153 t.Fatalf("bad: %d", index) 3154 } 3155 } 3156 3157 func TestStateStore_RestoreVaultAccessor(t *testing.T) { 3158 state := testStateStore(t) 3159 a := mock.VaultAccessor() 3160 3161 restore, err := state.Restore() 3162 if err != nil { 3163 t.Fatalf("err: %v", err) 3164 } 3165 3166 err = restore.VaultAccessorRestore(a) 3167 if err != nil { 3168 t.Fatalf("err: %v", err) 3169 } 3170 restore.Commit() 3171 3172 out, err := state.VaultAccessor(a.Accessor) 3173 if err != nil { 3174 t.Fatalf("err: %v", err) 3175 } 3176 3177 if !reflect.DeepEqual(out, a) { 3178 t.Fatalf("Bad: %#v %#v", out, a) 3179 } 3180 } 3181 3182 // setupNotifyTest takes a state store and a set of watch items, then creates 3183 // and subscribes a notification channel for each item. 3184 func setupNotifyTest(state *StateStore, items ...watch.Item) notifyTest { 3185 var n notifyTest 3186 for _, item := range items { 3187 ch := make(chan struct{}, 1) 3188 state.Watch(watch.NewItems(item), ch) 3189 n = append(n, ¬ifyTestCase{item, ch}) 3190 } 3191 return n 3192 } 3193 3194 // notifyTestCase is used to set up and verify watch triggers. 3195 type notifyTestCase struct { 3196 item watch.Item 3197 ch chan struct{} 3198 } 3199 3200 // notifyTest is a suite of notifyTestCases. 3201 type notifyTest []*notifyTestCase 3202 3203 // verify ensures that each channel received a notification. 3204 func (n notifyTest) verify(t *testing.T) { 3205 for _, tcase := range n { 3206 if len(tcase.ch) != 1 { 3207 t.Fatalf("should notify %#v", tcase.item) 3208 } 3209 } 3210 } 3211 3212 // NodeIDSort is used to sort nodes by ID 3213 type NodeIDSort []*structs.Node 3214 3215 func (n NodeIDSort) Len() int { 3216 return len(n) 3217 } 3218 3219 func (n NodeIDSort) Less(i, j int) bool { 3220 return n[i].ID < n[j].ID 3221 } 3222 3223 func (n NodeIDSort) Swap(i, j int) { 3224 n[i], n[j] = n[j], n[i] 3225 } 3226 3227 // JobIDis used to sort jobs by id 3228 type JobIDSort []*structs.Job 3229 3230 func (n JobIDSort) Len() int { 3231 return len(n) 3232 } 3233 3234 func (n JobIDSort) Less(i, j int) bool { 3235 return n[i].ID < n[j].ID 3236 } 3237 3238 func (n JobIDSort) Swap(i, j int) { 3239 n[i], n[j] = n[j], n[i] 3240 } 3241 3242 // EvalIDis used to sort evals by id 3243 type EvalIDSort []*structs.Evaluation 3244 3245 func (n EvalIDSort) Len() int { 3246 return len(n) 3247 } 3248 3249 func (n EvalIDSort) Less(i, j int) bool { 3250 return n[i].ID < n[j].ID 3251 } 3252 3253 func (n EvalIDSort) Swap(i, j int) { 3254 n[i], n[j] = n[j], n[i] 3255 } 3256 3257 // AllocIDsort used to sort allocations by id 3258 type AllocIDSort []*structs.Allocation 3259 3260 func (n AllocIDSort) Len() int { 3261 return len(n) 3262 } 3263 3264 func (n AllocIDSort) Less(i, j int) bool { 3265 return n[i].ID < n[j].ID 3266 } 3267 3268 func (n AllocIDSort) Swap(i, j int) { 3269 n[i], n[j] = n[j], n[i] 3270 }