github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/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 watch.Item{EvalJob: eval.JobID}) 1232 1233 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 1234 if err != nil { 1235 t.Fatalf("err: %v", err) 1236 } 1237 1238 out, err := state.EvalByID(eval.ID) 1239 if err != nil { 1240 t.Fatalf("err: %v", err) 1241 } 1242 1243 if !reflect.DeepEqual(eval, out) { 1244 t.Fatalf("bad: %#v %#v", eval, out) 1245 } 1246 1247 index, err := state.Index("evals") 1248 if err != nil { 1249 t.Fatalf("err: %v", err) 1250 } 1251 if index != 1000 { 1252 t.Fatalf("bad: %d", index) 1253 } 1254 1255 notify.verify(t) 1256 } 1257 1258 func TestStateStore_Update_UpsertEvals_Eval(t *testing.T) { 1259 state := testStateStore(t) 1260 eval := mock.Eval() 1261 1262 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 1263 if err != nil { 1264 t.Fatalf("err: %v", err) 1265 } 1266 1267 notify := setupNotifyTest( 1268 state, 1269 watch.Item{Table: "evals"}, 1270 watch.Item{Eval: eval.ID}, 1271 watch.Item{EvalJob: eval.JobID}) 1272 1273 eval2 := mock.Eval() 1274 eval2.ID = eval.ID 1275 eval2.JobID = eval.JobID 1276 err = state.UpsertEvals(1001, []*structs.Evaluation{eval2}) 1277 if err != nil { 1278 t.Fatalf("err: %v", err) 1279 } 1280 1281 out, err := state.EvalByID(eval.ID) 1282 if err != nil { 1283 t.Fatalf("err: %v", err) 1284 } 1285 1286 if !reflect.DeepEqual(eval2, out) { 1287 t.Fatalf("bad: %#v %#v", eval2, out) 1288 } 1289 1290 if out.CreateIndex != 1000 { 1291 t.Fatalf("bad: %#v", out) 1292 } 1293 if out.ModifyIndex != 1001 { 1294 t.Fatalf("bad: %#v", out) 1295 } 1296 1297 index, err := state.Index("evals") 1298 if err != nil { 1299 t.Fatalf("err: %v", err) 1300 } 1301 if index != 1001 { 1302 t.Fatalf("bad: %d", index) 1303 } 1304 1305 notify.verify(t) 1306 } 1307 1308 func TestStateStore_DeleteEval_Eval(t *testing.T) { 1309 state := testStateStore(t) 1310 eval1 := mock.Eval() 1311 eval2 := mock.Eval() 1312 alloc1 := mock.Alloc() 1313 alloc2 := mock.Alloc() 1314 1315 notify := setupNotifyTest( 1316 state, 1317 watch.Item{Table: "evals"}, 1318 watch.Item{Table: "allocs"}, 1319 watch.Item{Eval: eval1.ID}, 1320 watch.Item{Eval: eval2.ID}, 1321 watch.Item{EvalJob: eval1.JobID}, 1322 watch.Item{EvalJob: eval2.JobID}, 1323 watch.Item{Alloc: alloc1.ID}, 1324 watch.Item{Alloc: alloc2.ID}, 1325 watch.Item{AllocEval: alloc1.EvalID}, 1326 watch.Item{AllocEval: alloc2.EvalID}, 1327 watch.Item{AllocJob: alloc1.JobID}, 1328 watch.Item{AllocJob: alloc2.JobID}, 1329 watch.Item{AllocNode: alloc1.NodeID}, 1330 watch.Item{AllocNode: alloc2.NodeID}) 1331 1332 state.UpsertJobSummary(900, mock.JobSummary(eval1.JobID)) 1333 state.UpsertJobSummary(901, mock.JobSummary(eval2.JobID)) 1334 state.UpsertJobSummary(902, mock.JobSummary(alloc1.JobID)) 1335 state.UpsertJobSummary(903, mock.JobSummary(alloc2.JobID)) 1336 err := state.UpsertEvals(1000, []*structs.Evaluation{eval1, eval2}) 1337 if err != nil { 1338 t.Fatalf("err: %v", err) 1339 } 1340 1341 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc1, alloc2}) 1342 if err != nil { 1343 t.Fatalf("err: %v", err) 1344 } 1345 1346 err = state.DeleteEval(1002, []string{eval1.ID, eval2.ID}, []string{alloc1.ID, alloc2.ID}) 1347 if err != nil { 1348 t.Fatalf("err: %v", err) 1349 } 1350 1351 out, err := state.EvalByID(eval1.ID) 1352 if err != nil { 1353 t.Fatalf("err: %v", err) 1354 } 1355 1356 if out != nil { 1357 t.Fatalf("bad: %#v %#v", eval1, out) 1358 } 1359 1360 out, err = state.EvalByID(eval2.ID) 1361 if err != nil { 1362 t.Fatalf("err: %v", err) 1363 } 1364 1365 if out != nil { 1366 t.Fatalf("bad: %#v %#v", eval1, out) 1367 } 1368 1369 outA, err := state.AllocByID(alloc1.ID) 1370 if err != nil { 1371 t.Fatalf("err: %v", err) 1372 } 1373 1374 if out != nil { 1375 t.Fatalf("bad: %#v %#v", alloc1, outA) 1376 } 1377 1378 outA, err = state.AllocByID(alloc2.ID) 1379 if err != nil { 1380 t.Fatalf("err: %v", err) 1381 } 1382 1383 if out != nil { 1384 t.Fatalf("bad: %#v %#v", alloc1, outA) 1385 } 1386 1387 index, err := state.Index("evals") 1388 if err != nil { 1389 t.Fatalf("err: %v", err) 1390 } 1391 if index != 1002 { 1392 t.Fatalf("bad: %d", index) 1393 } 1394 1395 index, err = state.Index("allocs") 1396 if err != nil { 1397 t.Fatalf("err: %v", err) 1398 } 1399 if index != 1002 { 1400 t.Fatalf("bad: %d", index) 1401 } 1402 1403 notify.verify(t) 1404 } 1405 1406 func TestStateStore_EvalsByJob(t *testing.T) { 1407 state := testStateStore(t) 1408 1409 eval1 := mock.Eval() 1410 eval2 := mock.Eval() 1411 eval2.JobID = eval1.JobID 1412 eval3 := mock.Eval() 1413 evals := []*structs.Evaluation{eval1, eval2} 1414 1415 err := state.UpsertEvals(1000, evals) 1416 if err != nil { 1417 t.Fatalf("err: %v", err) 1418 } 1419 err = state.UpsertEvals(1001, []*structs.Evaluation{eval3}) 1420 if err != nil { 1421 t.Fatalf("err: %v", err) 1422 } 1423 1424 out, err := state.EvalsByJob(eval1.JobID) 1425 if err != nil { 1426 t.Fatalf("err: %v", err) 1427 } 1428 1429 sort.Sort(EvalIDSort(evals)) 1430 sort.Sort(EvalIDSort(out)) 1431 1432 if !reflect.DeepEqual(evals, out) { 1433 t.Fatalf("bad: %#v %#v", evals, out) 1434 } 1435 } 1436 1437 func TestStateStore_Evals(t *testing.T) { 1438 state := testStateStore(t) 1439 var evals []*structs.Evaluation 1440 1441 for i := 0; i < 10; i++ { 1442 eval := mock.Eval() 1443 evals = append(evals, eval) 1444 1445 err := state.UpsertEvals(1000+uint64(i), []*structs.Evaluation{eval}) 1446 if err != nil { 1447 t.Fatalf("err: %v", err) 1448 } 1449 } 1450 1451 iter, err := state.Evals() 1452 if err != nil { 1453 t.Fatalf("err: %v", err) 1454 } 1455 1456 var out []*structs.Evaluation 1457 for { 1458 raw := iter.Next() 1459 if raw == nil { 1460 break 1461 } 1462 out = append(out, raw.(*structs.Evaluation)) 1463 } 1464 1465 sort.Sort(EvalIDSort(evals)) 1466 sort.Sort(EvalIDSort(out)) 1467 1468 if !reflect.DeepEqual(evals, out) { 1469 t.Fatalf("bad: %#v %#v", evals, out) 1470 } 1471 } 1472 1473 func TestStateStore_EvalsByIDPrefix(t *testing.T) { 1474 state := testStateStore(t) 1475 var evals []*structs.Evaluation 1476 1477 ids := []string{ 1478 "aaaaaaaa-7bfb-395d-eb95-0685af2176b2", 1479 "aaaaaaab-7bfb-395d-eb95-0685af2176b2", 1480 "aaaaaabb-7bfb-395d-eb95-0685af2176b2", 1481 "aaaaabbb-7bfb-395d-eb95-0685af2176b2", 1482 "aaaabbbb-7bfb-395d-eb95-0685af2176b2", 1483 "aaabbbbb-7bfb-395d-eb95-0685af2176b2", 1484 "aabbbbbb-7bfb-395d-eb95-0685af2176b2", 1485 "abbbbbbb-7bfb-395d-eb95-0685af2176b2", 1486 "bbbbbbbb-7bfb-395d-eb95-0685af2176b2", 1487 } 1488 for i := 0; i < 9; i++ { 1489 eval := mock.Eval() 1490 eval.ID = ids[i] 1491 evals = append(evals, eval) 1492 } 1493 1494 err := state.UpsertEvals(1000, evals) 1495 if err != nil { 1496 t.Fatalf("err: %v", err) 1497 } 1498 1499 iter, err := state.EvalsByIDPrefix("aaaa") 1500 if err != nil { 1501 t.Fatalf("err: %v", err) 1502 } 1503 1504 gatherEvals := func(iter memdb.ResultIterator) []*structs.Evaluation { 1505 var evals []*structs.Evaluation 1506 for { 1507 raw := iter.Next() 1508 if raw == nil { 1509 break 1510 } 1511 evals = append(evals, raw.(*structs.Evaluation)) 1512 } 1513 return evals 1514 } 1515 1516 out := gatherEvals(iter) 1517 if len(out) != 5 { 1518 t.Fatalf("bad: expected five evaluations, got: %#v", out) 1519 } 1520 1521 sort.Sort(EvalIDSort(evals)) 1522 1523 for index, eval := range out { 1524 if ids[index] != eval.ID { 1525 t.Fatalf("bad: got unexpected id: %s", eval.ID) 1526 } 1527 } 1528 1529 iter, err = state.EvalsByIDPrefix("b-a7bfb") 1530 if err != nil { 1531 t.Fatalf("err: %v", err) 1532 } 1533 1534 out = gatherEvals(iter) 1535 if len(out) != 0 { 1536 t.Fatalf("bad: unexpected zero evaluations, got: %#v", out) 1537 } 1538 1539 } 1540 1541 func TestStateStore_RestoreEval(t *testing.T) { 1542 state := testStateStore(t) 1543 eval := mock.Eval() 1544 1545 notify := setupNotifyTest( 1546 state, 1547 watch.Item{Table: "evals"}, 1548 watch.Item{Eval: eval.ID}) 1549 1550 restore, err := state.Restore() 1551 if err != nil { 1552 t.Fatalf("err: %v", err) 1553 } 1554 1555 err = restore.EvalRestore(eval) 1556 if err != nil { 1557 t.Fatalf("err: %v", err) 1558 } 1559 restore.Commit() 1560 1561 out, err := state.EvalByID(eval.ID) 1562 if err != nil { 1563 t.Fatalf("err: %v", err) 1564 } 1565 1566 if !reflect.DeepEqual(out, eval) { 1567 t.Fatalf("Bad: %#v %#v", out, eval) 1568 } 1569 1570 notify.verify(t) 1571 } 1572 1573 func TestStateStore_UpdateAllocsFromClient(t *testing.T) { 1574 state := testStateStore(t) 1575 alloc := mock.Alloc() 1576 alloc2 := mock.Alloc() 1577 1578 notify := setupNotifyTest( 1579 state, 1580 watch.Item{Table: "allocs"}, 1581 watch.Item{Alloc: alloc.ID}, 1582 watch.Item{AllocEval: alloc.EvalID}, 1583 watch.Item{AllocJob: alloc.JobID}, 1584 watch.Item{AllocNode: alloc.NodeID}, 1585 watch.Item{Alloc: alloc2.ID}, 1586 watch.Item{AllocEval: alloc2.EvalID}, 1587 watch.Item{AllocJob: alloc2.JobID}, 1588 watch.Item{AllocNode: alloc2.NodeID}) 1589 1590 if err := state.UpsertJob(999, alloc.Job); err != nil { 1591 t.Fatalf("err: %v", err) 1592 } 1593 if err := state.UpsertJob(999, alloc2.Job); err != nil { 1594 t.Fatalf("err: %v", err) 1595 } 1596 1597 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc, alloc2}) 1598 if err != nil { 1599 t.Fatalf("err: %v", err) 1600 } 1601 1602 // Create the delta updates 1603 ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}} 1604 update := &structs.Allocation{ 1605 ID: alloc.ID, 1606 ClientStatus: structs.AllocClientStatusFailed, 1607 TaskStates: ts, 1608 JobID: alloc.JobID, 1609 TaskGroup: alloc.TaskGroup, 1610 } 1611 update2 := &structs.Allocation{ 1612 ID: alloc2.ID, 1613 ClientStatus: structs.AllocClientStatusRunning, 1614 TaskStates: ts, 1615 JobID: alloc2.JobID, 1616 TaskGroup: alloc2.TaskGroup, 1617 } 1618 1619 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2}) 1620 if err != nil { 1621 t.Fatalf("err: %v", err) 1622 } 1623 1624 out, err := state.AllocByID(alloc.ID) 1625 if err != nil { 1626 t.Fatalf("err: %v", err) 1627 } 1628 1629 alloc.CreateIndex = 1000 1630 alloc.ModifyIndex = 1001 1631 alloc.TaskStates = ts 1632 alloc.ClientStatus = structs.AllocClientStatusFailed 1633 if !reflect.DeepEqual(alloc, out) { 1634 t.Fatalf("bad: %#v %#v", alloc, out) 1635 } 1636 1637 out, err = state.AllocByID(alloc2.ID) 1638 if err != nil { 1639 t.Fatalf("err: %v", err) 1640 } 1641 1642 alloc2.ModifyIndex = 1000 1643 alloc2.ModifyIndex = 1001 1644 alloc2.ClientStatus = structs.AllocClientStatusRunning 1645 alloc2.TaskStates = ts 1646 if !reflect.DeepEqual(alloc2, out) { 1647 t.Fatalf("bad: %#v %#v", alloc2, out) 1648 } 1649 1650 index, err := state.Index("allocs") 1651 if err != nil { 1652 t.Fatalf("err: %v", err) 1653 } 1654 if index != 1001 { 1655 t.Fatalf("bad: %d", index) 1656 } 1657 1658 // Ensure summaries have been updated 1659 summary, err := state.JobSummaryByID(alloc.JobID) 1660 if err != nil { 1661 t.Fatalf("err: %v", err) 1662 } 1663 tgSummary := summary.Summary["web"] 1664 if tgSummary.Failed != 1 { 1665 t.Fatalf("expected failed: %v, actual: %v, summary: %#v", 1, tgSummary.Failed, tgSummary) 1666 } 1667 1668 summary2, err := state.JobSummaryByID(alloc2.JobID) 1669 if err != nil { 1670 t.Fatalf("err: %v", err) 1671 } 1672 tgSummary2 := summary2.Summary["web"] 1673 if tgSummary2.Running != 1 { 1674 t.Fatalf("expected running: %v, actual: %v", 1, tgSummary2.Running) 1675 } 1676 1677 notify.verify(t) 1678 } 1679 1680 func TestStateStore_UpdateMultipleAllocsFromClient(t *testing.T) { 1681 state := testStateStore(t) 1682 alloc := mock.Alloc() 1683 1684 if err := state.UpsertJob(999, alloc.Job); err != nil { 1685 t.Fatalf("err: %v", err) 1686 } 1687 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1688 if err != nil { 1689 t.Fatalf("err: %v", err) 1690 } 1691 1692 // Create the delta updates 1693 ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}} 1694 update := &structs.Allocation{ 1695 ID: alloc.ID, 1696 ClientStatus: structs.AllocClientStatusRunning, 1697 TaskStates: ts, 1698 JobID: alloc.JobID, 1699 TaskGroup: alloc.TaskGroup, 1700 } 1701 update2 := &structs.Allocation{ 1702 ID: alloc.ID, 1703 ClientStatus: structs.AllocClientStatusPending, 1704 TaskStates: ts, 1705 JobID: alloc.JobID, 1706 TaskGroup: alloc.TaskGroup, 1707 } 1708 1709 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2}) 1710 if err != nil { 1711 t.Fatalf("err: %v", err) 1712 } 1713 1714 out, err := state.AllocByID(alloc.ID) 1715 if err != nil { 1716 t.Fatalf("err: %v", err) 1717 } 1718 1719 alloc.CreateIndex = 1000 1720 alloc.ModifyIndex = 1001 1721 alloc.TaskStates = ts 1722 alloc.ClientStatus = structs.AllocClientStatusPending 1723 if !reflect.DeepEqual(alloc, out) { 1724 t.Fatalf("bad: %#v , actual:%#v", alloc, out) 1725 } 1726 1727 summary, err := state.JobSummaryByID(alloc.JobID) 1728 expectedSummary := &structs.JobSummary{ 1729 JobID: alloc.JobID, 1730 Summary: map[string]structs.TaskGroupSummary{ 1731 "web": structs.TaskGroupSummary{ 1732 Starting: 1, 1733 }, 1734 }, 1735 CreateIndex: 999, 1736 ModifyIndex: 1001, 1737 } 1738 if err != nil { 1739 t.Fatalf("err: %v", err) 1740 } 1741 if !reflect.DeepEqual(summary, expectedSummary) { 1742 t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary) 1743 } 1744 } 1745 1746 func TestStateStore_UpsertAlloc_Alloc(t *testing.T) { 1747 state := testStateStore(t) 1748 alloc := mock.Alloc() 1749 1750 notify := setupNotifyTest( 1751 state, 1752 watch.Item{Table: "allocs"}, 1753 watch.Item{Alloc: alloc.ID}, 1754 watch.Item{AllocEval: alloc.EvalID}, 1755 watch.Item{AllocJob: alloc.JobID}, 1756 watch.Item{AllocNode: alloc.NodeID}) 1757 1758 if err := state.UpsertJob(999, alloc.Job); err != nil { 1759 t.Fatalf("err: %v", err) 1760 } 1761 1762 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1763 if err != nil { 1764 t.Fatalf("err: %v", err) 1765 } 1766 1767 out, err := state.AllocByID(alloc.ID) 1768 if err != nil { 1769 t.Fatalf("err: %v", err) 1770 } 1771 1772 if !reflect.DeepEqual(alloc, out) { 1773 t.Fatalf("bad: %#v %#v", alloc, out) 1774 } 1775 1776 index, err := state.Index("allocs") 1777 if err != nil { 1778 t.Fatalf("err: %v", err) 1779 } 1780 if index != 1000 { 1781 t.Fatalf("bad: %d", index) 1782 } 1783 1784 summary, err := state.JobSummaryByID(alloc.JobID) 1785 if err != nil { 1786 t.Fatalf("err: %v", err) 1787 } 1788 1789 tgSummary, ok := summary.Summary["web"] 1790 if !ok { 1791 t.Fatalf("no summary for task group web") 1792 } 1793 if tgSummary.Starting != 1 { 1794 t.Fatalf("expected queued: %v, actual: %v", 1, tgSummary.Starting) 1795 } 1796 1797 notify.verify(t) 1798 } 1799 1800 func TestStateStore_UpsertAlloc_NoEphemeralDisk(t *testing.T) { 1801 state := testStateStore(t) 1802 alloc := mock.Alloc() 1803 alloc.Job.TaskGroups[0].EphemeralDisk = nil 1804 alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120 1805 1806 if err := state.UpsertJob(999, alloc.Job); err != nil { 1807 t.Fatalf("err: %v", err) 1808 } 1809 1810 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1811 if err != nil { 1812 t.Fatalf("err: %v", err) 1813 } 1814 1815 out, err := state.AllocByID(alloc.ID) 1816 if err != nil { 1817 t.Fatalf("err: %v", err) 1818 } 1819 1820 expected := alloc.Copy() 1821 expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120} 1822 if !reflect.DeepEqual(expected, out) { 1823 t.Fatalf("bad: %#v %#v", expected, out) 1824 } 1825 } 1826 1827 func TestStateStore_UpdateAlloc_Alloc(t *testing.T) { 1828 state := testStateStore(t) 1829 alloc := mock.Alloc() 1830 1831 if err := state.UpsertJob(999, alloc.Job); err != nil { 1832 t.Fatalf("err: %v", err) 1833 } 1834 1835 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1836 if err != nil { 1837 t.Fatalf("err: %v", err) 1838 } 1839 1840 summary, err := state.JobSummaryByID(alloc.JobID) 1841 if err != nil { 1842 t.Fatalf("err: %v", err) 1843 } 1844 tgSummary := summary.Summary["web"] 1845 if tgSummary.Starting != 1 { 1846 t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting) 1847 } 1848 1849 alloc2 := mock.Alloc() 1850 alloc2.ID = alloc.ID 1851 alloc2.NodeID = alloc.NodeID + ".new" 1852 state.UpsertJobSummary(1001, mock.JobSummary(alloc2.JobID)) 1853 1854 notify := setupNotifyTest( 1855 state, 1856 watch.Item{Table: "allocs"}, 1857 watch.Item{Alloc: alloc2.ID}, 1858 watch.Item{AllocEval: alloc2.EvalID}, 1859 watch.Item{AllocJob: alloc2.JobID}, 1860 watch.Item{AllocNode: alloc2.NodeID}) 1861 1862 err = state.UpsertAllocs(1002, []*structs.Allocation{alloc2}) 1863 if err != nil { 1864 t.Fatalf("err: %v", err) 1865 } 1866 1867 out, err := state.AllocByID(alloc.ID) 1868 if err != nil { 1869 t.Fatalf("err: %v", err) 1870 } 1871 1872 if !reflect.DeepEqual(alloc2, out) { 1873 t.Fatalf("bad: %#v %#v", alloc2, out) 1874 } 1875 1876 if out.CreateIndex != 1000 { 1877 t.Fatalf("bad: %#v", out) 1878 } 1879 if out.ModifyIndex != 1002 { 1880 t.Fatalf("bad: %#v", out) 1881 } 1882 1883 index, err := state.Index("allocs") 1884 if err != nil { 1885 t.Fatalf("err: %v", err) 1886 } 1887 if index != 1002 { 1888 t.Fatalf("bad: %d", index) 1889 } 1890 1891 // Ensure that summary hasb't changed 1892 summary, err = state.JobSummaryByID(alloc.JobID) 1893 if err != nil { 1894 t.Fatalf("err: %v", err) 1895 } 1896 tgSummary = summary.Summary["web"] 1897 if tgSummary.Starting != 1 { 1898 t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting) 1899 } 1900 1901 notify.verify(t) 1902 } 1903 1904 // This test ensures that the state store will mark the clients status as lost 1905 // when set rather than preferring the existing status. 1906 func TestStateStore_UpdateAlloc_Lost(t *testing.T) { 1907 state := testStateStore(t) 1908 alloc := mock.Alloc() 1909 alloc.ClientStatus = "foo" 1910 1911 if err := state.UpsertJob(999, alloc.Job); err != nil { 1912 t.Fatalf("err: %v", err) 1913 } 1914 1915 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1916 if err != nil { 1917 t.Fatalf("err: %v", err) 1918 } 1919 1920 alloc2 := new(structs.Allocation) 1921 *alloc2 = *alloc 1922 alloc2.ClientStatus = structs.AllocClientStatusLost 1923 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc2}); err != nil { 1924 t.Fatalf("err: %v", err) 1925 } 1926 1927 out, err := state.AllocByID(alloc2.ID) 1928 if err != nil { 1929 t.Fatalf("err: %v", err) 1930 } 1931 1932 if out.ClientStatus != structs.AllocClientStatusLost { 1933 t.Fatalf("bad: %#v", out) 1934 } 1935 } 1936 1937 // This test ensures an allocation can be updated when there is no job 1938 // associated with it. This will happen when a job is stopped by an user which 1939 // has non-terminal allocations on clients 1940 func TestStateStore_UpdateAlloc_NoJob(t *testing.T) { 1941 state := testStateStore(t) 1942 alloc := mock.Alloc() 1943 1944 // Upsert a job 1945 state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)) 1946 if err := state.UpsertJob(999, alloc.Job); err != nil { 1947 t.Fatalf("err: %v", err) 1948 } 1949 1950 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 1951 if err != nil { 1952 t.Fatalf("err: %v", err) 1953 } 1954 1955 if err := state.DeleteJob(1001, alloc.JobID); err != nil { 1956 t.Fatalf("err: %v", err) 1957 } 1958 1959 // Update the desired state of the allocation to stop 1960 allocCopy := alloc.Copy() 1961 allocCopy.DesiredStatus = structs.AllocDesiredStatusStop 1962 if err := state.UpsertAllocs(1002, []*structs.Allocation{allocCopy}); err != nil { 1963 t.Fatalf("err: %v", err) 1964 } 1965 1966 // Update the client state of the allocation to complete 1967 allocCopy1 := allocCopy.Copy() 1968 allocCopy1.ClientStatus = structs.AllocClientStatusComplete 1969 if err := state.UpdateAllocsFromClient(1003, []*structs.Allocation{allocCopy1}); err != nil { 1970 t.Fatalf("err: %v", err) 1971 } 1972 1973 out, _ := state.AllocByID(alloc.ID) 1974 // Update the modify index of the alloc before comparing 1975 allocCopy1.ModifyIndex = 1003 1976 if !reflect.DeepEqual(out, allocCopy1) { 1977 t.Fatalf("expected: %#v \n actual: %#v", allocCopy1, out) 1978 } 1979 } 1980 1981 func TestStateStore_JobSummary(t *testing.T) { 1982 state := testStateStore(t) 1983 1984 // Add a job 1985 job := mock.Job() 1986 state.UpsertJob(900, job) 1987 1988 // Get the job back 1989 outJob, _ := state.JobByID(job.ID) 1990 if outJob.CreateIndex != 900 { 1991 t.Fatalf("bad create index: %v", outJob.CreateIndex) 1992 } 1993 summary, _ := state.JobSummaryByID(job.ID) 1994 if summary.CreateIndex != 900 { 1995 t.Fatalf("bad create index: %v", summary.CreateIndex) 1996 } 1997 1998 // Upser an allocation 1999 alloc := mock.Alloc() 2000 alloc.JobID = job.ID 2001 alloc.Job = job 2002 state.UpsertAllocs(910, []*structs.Allocation{alloc}) 2003 2004 // Update the alloc from client 2005 alloc1 := alloc.Copy() 2006 alloc1.ClientStatus = structs.AllocClientStatusPending 2007 alloc1.DesiredStatus = "" 2008 state.UpdateAllocsFromClient(920, []*structs.Allocation{alloc}) 2009 2010 alloc3 := alloc.Copy() 2011 alloc3.ClientStatus = structs.AllocClientStatusRunning 2012 alloc3.DesiredStatus = "" 2013 state.UpdateAllocsFromClient(930, []*structs.Allocation{alloc3}) 2014 2015 // Upsert the alloc 2016 alloc4 := alloc.Copy() 2017 alloc4.ClientStatus = structs.AllocClientStatusPending 2018 alloc4.DesiredStatus = structs.AllocDesiredStatusRun 2019 state.UpsertAllocs(950, []*structs.Allocation{alloc4}) 2020 2021 // Again upsert the alloc 2022 alloc5 := alloc.Copy() 2023 alloc5.ClientStatus = structs.AllocClientStatusPending 2024 alloc5.DesiredStatus = structs.AllocDesiredStatusRun 2025 state.UpsertAllocs(970, []*structs.Allocation{alloc5}) 2026 2027 expectedSummary := structs.JobSummary{ 2028 JobID: job.ID, 2029 Summary: map[string]structs.TaskGroupSummary{ 2030 "web": structs.TaskGroupSummary{ 2031 Running: 1, 2032 }, 2033 }, 2034 CreateIndex: 900, 2035 ModifyIndex: 930, 2036 } 2037 2038 summary, _ = state.JobSummaryByID(job.ID) 2039 if !reflect.DeepEqual(&expectedSummary, summary) { 2040 t.Fatalf("expected: %#v, actual: %v", expectedSummary, summary) 2041 } 2042 2043 // De-register the job. 2044 state.DeleteJob(980, job.ID) 2045 2046 // Shouldn't have any effect on the summary 2047 alloc6 := alloc.Copy() 2048 alloc6.ClientStatus = structs.AllocClientStatusRunning 2049 alloc6.DesiredStatus = "" 2050 state.UpdateAllocsFromClient(990, []*structs.Allocation{alloc6}) 2051 2052 // We shouldn't have any summary at this point 2053 summary, _ = state.JobSummaryByID(job.ID) 2054 if summary != nil { 2055 t.Fatalf("expected nil, actual: %#v", summary) 2056 } 2057 2058 // Re-register the same job 2059 job1 := mock.Job() 2060 job1.ID = job.ID 2061 state.UpsertJob(1000, job1) 2062 outJob2, _ := state.JobByID(job1.ID) 2063 if outJob2.CreateIndex != 1000 { 2064 t.Fatalf("bad create index: %v", outJob2.CreateIndex) 2065 } 2066 summary, _ = state.JobSummaryByID(job1.ID) 2067 if summary.CreateIndex != 1000 { 2068 t.Fatalf("bad create index: %v", summary.CreateIndex) 2069 } 2070 2071 // Upsert an allocation 2072 alloc7 := alloc.Copy() 2073 alloc7.JobID = outJob.ID 2074 alloc7.Job = outJob 2075 alloc7.ClientStatus = structs.AllocClientStatusComplete 2076 alloc7.DesiredStatus = structs.AllocDesiredStatusRun 2077 state.UpdateAllocsFromClient(1020, []*structs.Allocation{alloc7}) 2078 2079 expectedSummary = structs.JobSummary{ 2080 JobID: job.ID, 2081 Summary: map[string]structs.TaskGroupSummary{ 2082 "web": structs.TaskGroupSummary{}, 2083 }, 2084 CreateIndex: 1000, 2085 ModifyIndex: 1000, 2086 } 2087 2088 summary, _ = state.JobSummaryByID(job1.ID) 2089 if !reflect.DeepEqual(&expectedSummary, summary) { 2090 t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary) 2091 } 2092 } 2093 2094 func TestStateStore_ReconcileJobSummary(t *testing.T) { 2095 state := testStateStore(t) 2096 2097 // Create an alloc 2098 alloc := mock.Alloc() 2099 2100 // Add another task group to the job 2101 tg2 := alloc.Job.TaskGroups[0].Copy() 2102 tg2.Name = "db" 2103 alloc.Job.TaskGroups = append(alloc.Job.TaskGroups, tg2) 2104 state.UpsertJob(100, alloc.Job) 2105 2106 // Create one more alloc for the db task group 2107 alloc2 := mock.Alloc() 2108 alloc2.TaskGroup = "db" 2109 alloc2.JobID = alloc.JobID 2110 alloc2.Job = alloc.Job 2111 2112 // Upserts the alloc 2113 state.UpsertAllocs(110, []*structs.Allocation{alloc, alloc2}) 2114 2115 // Change the state of the first alloc to running 2116 alloc3 := alloc.Copy() 2117 alloc3.ClientStatus = structs.AllocClientStatusRunning 2118 state.UpdateAllocsFromClient(120, []*structs.Allocation{alloc3}) 2119 2120 //Add some more allocs to the second tg 2121 alloc4 := mock.Alloc() 2122 alloc4.JobID = alloc.JobID 2123 alloc4.Job = alloc.Job 2124 alloc4.TaskGroup = "db" 2125 alloc5 := alloc4.Copy() 2126 alloc5.ClientStatus = structs.AllocClientStatusRunning 2127 2128 alloc6 := mock.Alloc() 2129 alloc6.JobID = alloc.JobID 2130 alloc6.Job = alloc.Job 2131 alloc6.TaskGroup = "db" 2132 alloc7 := alloc6.Copy() 2133 alloc7.ClientStatus = structs.AllocClientStatusComplete 2134 2135 alloc8 := mock.Alloc() 2136 alloc8.JobID = alloc.JobID 2137 alloc8.Job = alloc.Job 2138 alloc8.TaskGroup = "db" 2139 alloc9 := alloc8.Copy() 2140 alloc9.ClientStatus = structs.AllocClientStatusFailed 2141 2142 alloc10 := mock.Alloc() 2143 alloc10.JobID = alloc.JobID 2144 alloc10.Job = alloc.Job 2145 alloc10.TaskGroup = "db" 2146 alloc11 := alloc10.Copy() 2147 alloc11.ClientStatus = structs.AllocClientStatusLost 2148 2149 state.UpsertAllocs(130, []*structs.Allocation{alloc4, alloc6, alloc8, alloc10}) 2150 2151 state.UpdateAllocsFromClient(150, []*structs.Allocation{alloc5, alloc7, alloc9, alloc11}) 2152 2153 // DeleteJobSummary is a helper method and doesn't modify the indexes table 2154 state.DeleteJobSummary(130, alloc.Job.ID) 2155 2156 state.ReconcileJobSummaries(120) 2157 2158 summary, _ := state.JobSummaryByID(alloc.Job.ID) 2159 expectedSummary := structs.JobSummary{ 2160 JobID: alloc.Job.ID, 2161 Summary: map[string]structs.TaskGroupSummary{ 2162 "web": structs.TaskGroupSummary{ 2163 Running: 1, 2164 }, 2165 "db": structs.TaskGroupSummary{ 2166 Starting: 1, 2167 Running: 1, 2168 Failed: 1, 2169 Complete: 1, 2170 Lost: 1, 2171 }, 2172 }, 2173 CreateIndex: 100, 2174 ModifyIndex: 120, 2175 } 2176 if !reflect.DeepEqual(&expectedSummary, summary) { 2177 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 2178 } 2179 } 2180 2181 func TestStateStore_UpdateAlloc_JobNotPresent(t *testing.T) { 2182 state := testStateStore(t) 2183 2184 alloc := mock.Alloc() 2185 state.UpsertJob(100, alloc.Job) 2186 state.UpsertAllocs(200, []*structs.Allocation{alloc}) 2187 2188 // Delete the job 2189 state.DeleteJob(300, alloc.Job.ID) 2190 2191 // Update the alloc 2192 alloc1 := alloc.Copy() 2193 alloc1.ClientStatus = structs.AllocClientStatusRunning 2194 2195 // Updating allocation should not throw any error 2196 if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil { 2197 t.Fatalf("expect err: %v", err) 2198 } 2199 2200 // Re-Register the job 2201 state.UpsertJob(500, alloc.Job) 2202 2203 // Update the alloc again 2204 alloc2 := alloc.Copy() 2205 alloc2.ClientStatus = structs.AllocClientStatusComplete 2206 if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil { 2207 t.Fatalf("expect err: %v", err) 2208 } 2209 2210 // Job Summary of the newly registered job shouldn't account for the 2211 // allocation update for the older job 2212 expectedSummary := structs.JobSummary{ 2213 JobID: alloc1.JobID, 2214 Summary: map[string]structs.TaskGroupSummary{ 2215 "web": structs.TaskGroupSummary{}, 2216 }, 2217 CreateIndex: 500, 2218 ModifyIndex: 500, 2219 } 2220 summary, _ := state.JobSummaryByID(alloc.Job.ID) 2221 if !reflect.DeepEqual(&expectedSummary, summary) { 2222 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 2223 } 2224 } 2225 2226 func TestStateStore_EvictAlloc_Alloc(t *testing.T) { 2227 state := testStateStore(t) 2228 alloc := mock.Alloc() 2229 2230 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 2231 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 2232 if err != nil { 2233 t.Fatalf("err: %v", err) 2234 } 2235 2236 alloc2 := new(structs.Allocation) 2237 *alloc2 = *alloc 2238 alloc2.DesiredStatus = structs.AllocDesiredStatusEvict 2239 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc2}) 2240 if err != nil { 2241 t.Fatalf("err: %v", err) 2242 } 2243 2244 out, err := state.AllocByID(alloc.ID) 2245 if err != nil { 2246 t.Fatalf("err: %v", err) 2247 } 2248 2249 if out.DesiredStatus != structs.AllocDesiredStatusEvict { 2250 t.Fatalf("bad: %#v %#v", alloc, out) 2251 } 2252 2253 index, err := state.Index("allocs") 2254 if err != nil { 2255 t.Fatalf("err: %v", err) 2256 } 2257 if index != 1001 { 2258 t.Fatalf("bad: %d", index) 2259 } 2260 } 2261 2262 func TestStateStore_AllocsByNode(t *testing.T) { 2263 state := testStateStore(t) 2264 var allocs []*structs.Allocation 2265 2266 for i := 0; i < 10; i++ { 2267 alloc := mock.Alloc() 2268 alloc.NodeID = "foo" 2269 allocs = append(allocs, alloc) 2270 } 2271 2272 for idx, alloc := range allocs { 2273 state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID)) 2274 } 2275 2276 err := state.UpsertAllocs(1000, allocs) 2277 if err != nil { 2278 t.Fatalf("err: %v", err) 2279 } 2280 2281 out, err := state.AllocsByNode("foo") 2282 if err != nil { 2283 t.Fatalf("err: %v", err) 2284 } 2285 2286 sort.Sort(AllocIDSort(allocs)) 2287 sort.Sort(AllocIDSort(out)) 2288 2289 if !reflect.DeepEqual(allocs, out) { 2290 t.Fatalf("bad: %#v %#v", allocs, out) 2291 } 2292 } 2293 2294 func TestStateStore_AllocsByNodeTerminal(t *testing.T) { 2295 state := testStateStore(t) 2296 var allocs, term, nonterm []*structs.Allocation 2297 2298 for i := 0; i < 10; i++ { 2299 alloc := mock.Alloc() 2300 alloc.NodeID = "foo" 2301 if i%2 == 0 { 2302 alloc.DesiredStatus = structs.AllocDesiredStatusStop 2303 term = append(term, alloc) 2304 } else { 2305 nonterm = append(nonterm, alloc) 2306 } 2307 allocs = append(allocs, alloc) 2308 } 2309 2310 for idx, alloc := range allocs { 2311 state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID)) 2312 } 2313 2314 err := state.UpsertAllocs(1000, allocs) 2315 if err != nil { 2316 t.Fatalf("err: %v", err) 2317 } 2318 2319 // Verify the terminal allocs 2320 out, err := state.AllocsByNodeTerminal("foo", true) 2321 if err != nil { 2322 t.Fatalf("err: %v", err) 2323 } 2324 2325 sort.Sort(AllocIDSort(term)) 2326 sort.Sort(AllocIDSort(out)) 2327 2328 if !reflect.DeepEqual(term, out) { 2329 t.Fatalf("bad: %#v %#v", term, out) 2330 } 2331 2332 // Verify the non-terminal allocs 2333 out, err = state.AllocsByNodeTerminal("foo", false) 2334 if err != nil { 2335 t.Fatalf("err: %v", err) 2336 } 2337 2338 sort.Sort(AllocIDSort(nonterm)) 2339 sort.Sort(AllocIDSort(out)) 2340 2341 if !reflect.DeepEqual(nonterm, out) { 2342 t.Fatalf("bad: %#v %#v", nonterm, out) 2343 } 2344 } 2345 2346 func TestStateStore_AllocsByJob(t *testing.T) { 2347 state := testStateStore(t) 2348 var allocs []*structs.Allocation 2349 2350 for i := 0; i < 10; i++ { 2351 alloc := mock.Alloc() 2352 alloc.JobID = "foo" 2353 allocs = append(allocs, alloc) 2354 } 2355 2356 for i, alloc := range allocs { 2357 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 2358 } 2359 2360 err := state.UpsertAllocs(1000, allocs) 2361 if err != nil { 2362 t.Fatalf("err: %v", err) 2363 } 2364 2365 out, err := state.AllocsByJob("foo") 2366 if err != nil { 2367 t.Fatalf("err: %v", err) 2368 } 2369 2370 sort.Sort(AllocIDSort(allocs)) 2371 sort.Sort(AllocIDSort(out)) 2372 2373 if !reflect.DeepEqual(allocs, out) { 2374 t.Fatalf("bad: %#v %#v", allocs, out) 2375 } 2376 } 2377 2378 func TestStateStore_AllocsByIDPrefix(t *testing.T) { 2379 state := testStateStore(t) 2380 var allocs []*structs.Allocation 2381 2382 ids := []string{ 2383 "aaaaaaaa-7bfb-395d-eb95-0685af2176b2", 2384 "aaaaaaab-7bfb-395d-eb95-0685af2176b2", 2385 "aaaaaabb-7bfb-395d-eb95-0685af2176b2", 2386 "aaaaabbb-7bfb-395d-eb95-0685af2176b2", 2387 "aaaabbbb-7bfb-395d-eb95-0685af2176b2", 2388 "aaabbbbb-7bfb-395d-eb95-0685af2176b2", 2389 "aabbbbbb-7bfb-395d-eb95-0685af2176b2", 2390 "abbbbbbb-7bfb-395d-eb95-0685af2176b2", 2391 "bbbbbbbb-7bfb-395d-eb95-0685af2176b2", 2392 } 2393 for i := 0; i < 9; i++ { 2394 alloc := mock.Alloc() 2395 alloc.ID = ids[i] 2396 allocs = append(allocs, alloc) 2397 } 2398 2399 for i, alloc := range allocs { 2400 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 2401 } 2402 2403 err := state.UpsertAllocs(1000, allocs) 2404 if err != nil { 2405 t.Fatalf("err: %v", err) 2406 } 2407 2408 iter, err := state.AllocsByIDPrefix("aaaa") 2409 if err != nil { 2410 t.Fatalf("err: %v", err) 2411 } 2412 2413 gatherAllocs := func(iter memdb.ResultIterator) []*structs.Allocation { 2414 var allocs []*structs.Allocation 2415 for { 2416 raw := iter.Next() 2417 if raw == nil { 2418 break 2419 } 2420 allocs = append(allocs, raw.(*structs.Allocation)) 2421 } 2422 return allocs 2423 } 2424 2425 out := gatherAllocs(iter) 2426 if len(out) != 5 { 2427 t.Fatalf("bad: expected five allocations, got: %#v", out) 2428 } 2429 2430 sort.Sort(AllocIDSort(allocs)) 2431 2432 for index, alloc := range out { 2433 if ids[index] != alloc.ID { 2434 t.Fatalf("bad: got unexpected id: %s", alloc.ID) 2435 } 2436 } 2437 2438 iter, err = state.AllocsByIDPrefix("b-a7bfb") 2439 if err != nil { 2440 t.Fatalf("err: %v", err) 2441 } 2442 2443 out = gatherAllocs(iter) 2444 if len(out) != 0 { 2445 t.Fatalf("bad: unexpected zero allocations, got: %#v", out) 2446 } 2447 } 2448 2449 func TestStateStore_Allocs(t *testing.T) { 2450 state := testStateStore(t) 2451 var allocs []*structs.Allocation 2452 2453 for i := 0; i < 10; i++ { 2454 alloc := mock.Alloc() 2455 allocs = append(allocs, alloc) 2456 } 2457 for i, alloc := range allocs { 2458 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 2459 } 2460 2461 err := state.UpsertAllocs(1000, allocs) 2462 if err != nil { 2463 t.Fatalf("err: %v", err) 2464 } 2465 2466 iter, err := state.Allocs() 2467 if err != nil { 2468 t.Fatalf("err: %v", err) 2469 } 2470 2471 var out []*structs.Allocation 2472 for { 2473 raw := iter.Next() 2474 if raw == nil { 2475 break 2476 } 2477 out = append(out, raw.(*structs.Allocation)) 2478 } 2479 2480 sort.Sort(AllocIDSort(allocs)) 2481 sort.Sort(AllocIDSort(out)) 2482 2483 if !reflect.DeepEqual(allocs, out) { 2484 t.Fatalf("bad: %#v %#v", allocs, out) 2485 } 2486 } 2487 2488 func TestStateStore_RestoreAlloc(t *testing.T) { 2489 state := testStateStore(t) 2490 alloc := mock.Alloc() 2491 2492 notify := setupNotifyTest( 2493 state, 2494 watch.Item{Table: "allocs"}, 2495 watch.Item{Alloc: alloc.ID}, 2496 watch.Item{AllocEval: alloc.EvalID}, 2497 watch.Item{AllocJob: alloc.JobID}, 2498 watch.Item{AllocNode: alloc.NodeID}) 2499 2500 restore, err := state.Restore() 2501 if err != nil { 2502 t.Fatalf("err: %v", err) 2503 } 2504 2505 err = restore.AllocRestore(alloc) 2506 if err != nil { 2507 t.Fatalf("err: %v", err) 2508 } 2509 2510 restore.Commit() 2511 2512 out, err := state.AllocByID(alloc.ID) 2513 if err != nil { 2514 t.Fatalf("err: %v", err) 2515 } 2516 2517 if !reflect.DeepEqual(out, alloc) { 2518 t.Fatalf("Bad: %#v %#v", out, alloc) 2519 } 2520 2521 notify.verify(t) 2522 } 2523 2524 func TestStateStore_RestoreAlloc_NoEphemeralDisk(t *testing.T) { 2525 state := testStateStore(t) 2526 alloc := mock.Alloc() 2527 alloc.Job.TaskGroups[0].EphemeralDisk = nil 2528 alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120 2529 2530 restore, err := state.Restore() 2531 if err != nil { 2532 t.Fatalf("err: %v", err) 2533 } 2534 2535 err = restore.AllocRestore(alloc) 2536 if err != nil { 2537 t.Fatalf("err: %v", err) 2538 } 2539 2540 restore.Commit() 2541 2542 out, err := state.AllocByID(alloc.ID) 2543 if err != nil { 2544 t.Fatalf("err: %v", err) 2545 } 2546 2547 expected := alloc.Copy() 2548 expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120} 2549 expected.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 2550 2551 if !reflect.DeepEqual(out, expected) { 2552 t.Fatalf("Bad: %#v %#v", out, expected) 2553 } 2554 } 2555 2556 func TestStateStore_SetJobStatus_ForceStatus(t *testing.T) { 2557 state := testStateStore(t) 2558 watcher := watch.NewItems() 2559 txn := state.db.Txn(true) 2560 2561 // Create and insert a mock job. 2562 job := mock.Job() 2563 job.Status = "" 2564 job.ModifyIndex = 0 2565 if err := txn.Insert("jobs", job); err != nil { 2566 t.Fatalf("job insert failed: %v", err) 2567 } 2568 2569 exp := "foobar" 2570 index := uint64(1000) 2571 if err := state.setJobStatus(index, watcher, txn, job, false, exp); err != nil { 2572 t.Fatalf("setJobStatus() failed: %v", err) 2573 } 2574 2575 i, err := txn.First("jobs", "id", job.ID) 2576 if err != nil { 2577 t.Fatalf("job lookup failed: %v", err) 2578 } 2579 updated := i.(*structs.Job) 2580 2581 if updated.Status != exp { 2582 t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, exp) 2583 } 2584 2585 if updated.ModifyIndex != index { 2586 t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index) 2587 } 2588 } 2589 2590 func TestStateStore_SetJobStatus_NoOp(t *testing.T) { 2591 state := testStateStore(t) 2592 watcher := watch.NewItems() 2593 txn := state.db.Txn(true) 2594 2595 // Create and insert a mock job that should be pending. 2596 job := mock.Job() 2597 job.Status = structs.JobStatusPending 2598 job.ModifyIndex = 10 2599 if err := txn.Insert("jobs", job); err != nil { 2600 t.Fatalf("job insert failed: %v", err) 2601 } 2602 2603 index := uint64(1000) 2604 if err := state.setJobStatus(index, watcher, txn, job, false, ""); err != nil { 2605 t.Fatalf("setJobStatus() failed: %v", err) 2606 } 2607 2608 i, err := txn.First("jobs", "id", job.ID) 2609 if err != nil { 2610 t.Fatalf("job lookup failed: %v", err) 2611 } 2612 updated := i.(*structs.Job) 2613 2614 if updated.ModifyIndex == index { 2615 t.Fatalf("setJobStatus() should have been a no-op") 2616 } 2617 } 2618 2619 func TestStateStore_SetJobStatus(t *testing.T) { 2620 state := testStateStore(t) 2621 watcher := watch.NewItems() 2622 txn := state.db.Txn(true) 2623 2624 // Create and insert a mock job that should be pending but has an incorrect 2625 // status. 2626 job := mock.Job() 2627 job.Status = "foobar" 2628 job.ModifyIndex = 10 2629 if err := txn.Insert("jobs", job); err != nil { 2630 t.Fatalf("job insert failed: %v", err) 2631 } 2632 2633 index := uint64(1000) 2634 if err := state.setJobStatus(index, watcher, txn, job, false, ""); err != nil { 2635 t.Fatalf("setJobStatus() failed: %v", err) 2636 } 2637 2638 i, err := txn.First("jobs", "id", job.ID) 2639 if err != nil { 2640 t.Fatalf("job lookup failed: %v", err) 2641 } 2642 updated := i.(*structs.Job) 2643 2644 if updated.Status != structs.JobStatusPending { 2645 t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, structs.JobStatusPending) 2646 } 2647 2648 if updated.ModifyIndex != index { 2649 t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index) 2650 } 2651 } 2652 2653 func TestStateStore_GetJobStatus_NoEvalsOrAllocs(t *testing.T) { 2654 job := mock.Job() 2655 state := testStateStore(t) 2656 txn := state.db.Txn(false) 2657 status, err := state.getJobStatus(txn, job, false) 2658 if err != nil { 2659 t.Fatalf("getJobStatus() failed: %v", err) 2660 } 2661 2662 if status != structs.JobStatusPending { 2663 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending) 2664 } 2665 } 2666 2667 func TestStateStore_GetJobStatus_NoEvalsOrAllocs_Periodic(t *testing.T) { 2668 job := mock.PeriodicJob() 2669 state := testStateStore(t) 2670 txn := state.db.Txn(false) 2671 status, err := state.getJobStatus(txn, job, false) 2672 if err != nil { 2673 t.Fatalf("getJobStatus() failed: %v", err) 2674 } 2675 2676 if status != structs.JobStatusRunning { 2677 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 2678 } 2679 } 2680 2681 func TestStateStore_GetJobStatus_NoEvalsOrAllocs_EvalDelete(t *testing.T) { 2682 job := mock.Job() 2683 state := testStateStore(t) 2684 txn := state.db.Txn(false) 2685 status, err := state.getJobStatus(txn, job, true) 2686 if err != nil { 2687 t.Fatalf("getJobStatus() failed: %v", err) 2688 } 2689 2690 if status != structs.JobStatusDead { 2691 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 2692 } 2693 } 2694 2695 func TestStateStore_GetJobStatus_DeadEvalsAndAllocs(t *testing.T) { 2696 state := testStateStore(t) 2697 job := mock.Job() 2698 2699 // Create a mock alloc that is dead. 2700 alloc := mock.Alloc() 2701 alloc.JobID = job.ID 2702 alloc.DesiredStatus = structs.AllocDesiredStatusStop 2703 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 2704 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { 2705 t.Fatalf("err: %v", err) 2706 } 2707 2708 // Create a mock eval that is complete 2709 eval := mock.Eval() 2710 eval.JobID = job.ID 2711 eval.Status = structs.EvalStatusComplete 2712 if err := state.UpsertEvals(1001, []*structs.Evaluation{eval}); err != nil { 2713 t.Fatalf("err: %v", err) 2714 } 2715 2716 txn := state.db.Txn(false) 2717 status, err := state.getJobStatus(txn, job, false) 2718 if err != nil { 2719 t.Fatalf("getJobStatus() failed: %v", err) 2720 } 2721 2722 if status != structs.JobStatusDead { 2723 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 2724 } 2725 } 2726 2727 func TestStateStore_GetJobStatus_RunningAlloc(t *testing.T) { 2728 state := testStateStore(t) 2729 job := mock.Job() 2730 2731 // Create a mock alloc that is running. 2732 alloc := mock.Alloc() 2733 alloc.JobID = job.ID 2734 alloc.DesiredStatus = structs.AllocDesiredStatusRun 2735 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 2736 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { 2737 t.Fatalf("err: %v", err) 2738 } 2739 2740 txn := state.db.Txn(false) 2741 status, err := state.getJobStatus(txn, job, true) 2742 if err != nil { 2743 t.Fatalf("getJobStatus() failed: %v", err) 2744 } 2745 2746 if status != structs.JobStatusRunning { 2747 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 2748 } 2749 } 2750 2751 func TestStateStore_SetJobStatus_PendingEval(t *testing.T) { 2752 state := testStateStore(t) 2753 job := mock.Job() 2754 2755 // Create a mock eval that is pending. 2756 eval := mock.Eval() 2757 eval.JobID = job.ID 2758 eval.Status = structs.EvalStatusPending 2759 if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil { 2760 t.Fatalf("err: %v", err) 2761 } 2762 2763 txn := state.db.Txn(false) 2764 status, err := state.getJobStatus(txn, job, true) 2765 if err != nil { 2766 t.Fatalf("getJobStatus() failed: %v", err) 2767 } 2768 2769 if status != structs.JobStatusPending { 2770 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending) 2771 } 2772 } 2773 2774 func TestStateWatch_watch(t *testing.T) { 2775 sw := newStateWatch() 2776 notify1 := make(chan struct{}, 1) 2777 notify2 := make(chan struct{}, 1) 2778 notify3 := make(chan struct{}, 1) 2779 2780 // Notifications trigger subscribed channels 2781 sw.watch(watch.NewItems(watch.Item{Table: "foo"}), notify1) 2782 sw.watch(watch.NewItems(watch.Item{Table: "bar"}), notify2) 2783 sw.watch(watch.NewItems(watch.Item{Table: "baz"}), notify3) 2784 2785 items := watch.NewItems() 2786 items.Add(watch.Item{Table: "foo"}) 2787 items.Add(watch.Item{Table: "bar"}) 2788 2789 sw.notify(items) 2790 if len(notify1) != 1 { 2791 t.Fatalf("should notify") 2792 } 2793 if len(notify2) != 1 { 2794 t.Fatalf("should notify") 2795 } 2796 if len(notify3) != 0 { 2797 t.Fatalf("should not notify") 2798 } 2799 } 2800 2801 func TestStateWatch_stopWatch(t *testing.T) { 2802 sw := newStateWatch() 2803 notify := make(chan struct{}) 2804 2805 // First subscribe 2806 sw.watch(watch.NewItems(watch.Item{Table: "foo"}), notify) 2807 2808 // Unsubscribe stop notifications 2809 sw.stopWatch(watch.NewItems(watch.Item{Table: "foo"}), notify) 2810 2811 // Check that the group was removed 2812 if _, ok := sw.items[watch.Item{Table: "foo"}]; ok { 2813 t.Fatalf("should remove group") 2814 } 2815 2816 // Check that we are not notified 2817 sw.notify(watch.NewItems(watch.Item{Table: "foo"})) 2818 if len(notify) != 0 { 2819 t.Fatalf("should not notify") 2820 } 2821 } 2822 2823 func TestStateJobSummary_UpdateJobCount(t *testing.T) { 2824 state := testStateStore(t) 2825 alloc := mock.Alloc() 2826 job := alloc.Job 2827 job.TaskGroups[0].Count = 3 2828 err := state.UpsertJob(1000, job) 2829 if err != nil { 2830 t.Fatalf("err: %v", err) 2831 } 2832 2833 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc}); err != nil { 2834 t.Fatalf("err: %v", err) 2835 } 2836 summary, _ := state.JobSummaryByID(job.ID) 2837 expectedSummary := structs.JobSummary{ 2838 JobID: job.ID, 2839 Summary: map[string]structs.TaskGroupSummary{ 2840 "web": { 2841 Starting: 1, 2842 }, 2843 }, 2844 CreateIndex: 1000, 2845 ModifyIndex: 1001, 2846 } 2847 if !reflect.DeepEqual(summary, &expectedSummary) { 2848 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 2849 } 2850 2851 alloc2 := mock.Alloc() 2852 alloc2.Job = job 2853 alloc2.JobID = job.ID 2854 2855 alloc3 := mock.Alloc() 2856 alloc3.Job = job 2857 alloc3.JobID = job.ID 2858 2859 if err := state.UpsertAllocs(1002, []*structs.Allocation{alloc2, alloc3}); err != nil { 2860 t.Fatalf("err: %v", err) 2861 } 2862 2863 outA, _ := state.AllocByID(alloc3.ID) 2864 2865 summary, _ = state.JobSummaryByID(job.ID) 2866 expectedSummary = structs.JobSummary{ 2867 JobID: job.ID, 2868 Summary: map[string]structs.TaskGroupSummary{ 2869 "web": { 2870 Starting: 3, 2871 }, 2872 }, 2873 CreateIndex: job.CreateIndex, 2874 ModifyIndex: outA.ModifyIndex, 2875 } 2876 if !reflect.DeepEqual(summary, &expectedSummary) { 2877 t.Fatalf("expected summary: %v, actual: %v", expectedSummary, summary) 2878 } 2879 2880 alloc4 := mock.Alloc() 2881 alloc4.ID = alloc2.ID 2882 alloc4.Job = alloc2.Job 2883 alloc4.JobID = alloc2.JobID 2884 alloc4.ClientStatus = structs.AllocClientStatusComplete 2885 2886 alloc5 := mock.Alloc() 2887 alloc5.ID = alloc3.ID 2888 alloc5.Job = alloc3.Job 2889 alloc5.JobID = alloc3.JobID 2890 alloc5.ClientStatus = structs.AllocClientStatusComplete 2891 2892 if err := state.UpdateAllocsFromClient(1004, []*structs.Allocation{alloc4, alloc5}); err != nil { 2893 t.Fatalf("err: %v", err) 2894 } 2895 outA, _ = state.AllocByID(alloc5.ID) 2896 summary, _ = state.JobSummaryByID(job.ID) 2897 expectedSummary = structs.JobSummary{ 2898 JobID: job.ID, 2899 Summary: map[string]structs.TaskGroupSummary{ 2900 "web": { 2901 Complete: 2, 2902 Starting: 1, 2903 }, 2904 }, 2905 CreateIndex: job.CreateIndex, 2906 ModifyIndex: outA.ModifyIndex, 2907 } 2908 if !reflect.DeepEqual(summary, &expectedSummary) { 2909 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 2910 } 2911 } 2912 2913 func TestJobSummary_UpdateClientStatus(t *testing.T) { 2914 state := testStateStore(t) 2915 alloc := mock.Alloc() 2916 job := alloc.Job 2917 job.TaskGroups[0].Count = 3 2918 2919 alloc2 := mock.Alloc() 2920 alloc2.Job = job 2921 alloc2.JobID = job.ID 2922 2923 alloc3 := mock.Alloc() 2924 alloc3.Job = job 2925 alloc3.JobID = job.ID 2926 2927 err := state.UpsertJob(1000, job) 2928 if err != nil { 2929 t.Fatalf("err: %v", err) 2930 } 2931 2932 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc, alloc2, alloc3}); err != nil { 2933 t.Fatalf("err: %v", err) 2934 } 2935 summary, _ := state.JobSummaryByID(job.ID) 2936 if summary.Summary["web"].Starting != 3 { 2937 t.Fatalf("bad job summary: %v", summary) 2938 } 2939 2940 alloc4 := mock.Alloc() 2941 alloc4.ID = alloc2.ID 2942 alloc4.Job = alloc2.Job 2943 alloc4.JobID = alloc2.JobID 2944 alloc4.ClientStatus = structs.AllocClientStatusComplete 2945 2946 alloc5 := mock.Alloc() 2947 alloc5.ID = alloc3.ID 2948 alloc5.Job = alloc3.Job 2949 alloc5.JobID = alloc3.JobID 2950 alloc5.ClientStatus = structs.AllocClientStatusFailed 2951 2952 alloc6 := mock.Alloc() 2953 alloc6.ID = alloc.ID 2954 alloc6.Job = alloc.Job 2955 alloc6.JobID = alloc.JobID 2956 alloc6.ClientStatus = structs.AllocClientStatusRunning 2957 2958 if err := state.UpdateAllocsFromClient(1002, []*structs.Allocation{alloc4, alloc5, alloc6}); err != nil { 2959 t.Fatalf("err: %v", err) 2960 } 2961 summary, _ = state.JobSummaryByID(job.ID) 2962 if summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 { 2963 t.Fatalf("bad job summary: %v", summary) 2964 } 2965 2966 alloc7 := mock.Alloc() 2967 alloc7.Job = alloc.Job 2968 alloc7.JobID = alloc.JobID 2969 2970 if err := state.UpsertAllocs(1003, []*structs.Allocation{alloc7}); err != nil { 2971 t.Fatalf("err: %v", err) 2972 } 2973 summary, _ = state.JobSummaryByID(job.ID) 2974 if summary.Summary["web"].Starting != 1 || summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 { 2975 t.Fatalf("bad job summary: %v", summary) 2976 } 2977 } 2978 2979 func TestStateStore_UpsertVaultAccessors(t *testing.T) { 2980 state := testStateStore(t) 2981 a := mock.VaultAccessor() 2982 a2 := mock.VaultAccessor() 2983 2984 err := state.UpsertVaultAccessor(1000, []*structs.VaultAccessor{a, a2}) 2985 if err != nil { 2986 t.Fatalf("err: %v", err) 2987 } 2988 2989 out, err := state.VaultAccessor(a.Accessor) 2990 if err != nil { 2991 t.Fatalf("err: %v", err) 2992 } 2993 2994 if !reflect.DeepEqual(a, out) { 2995 t.Fatalf("bad: %#v %#v", a, out) 2996 } 2997 2998 out, err = state.VaultAccessor(a2.Accessor) 2999 if err != nil { 3000 t.Fatalf("err: %v", err) 3001 } 3002 3003 if !reflect.DeepEqual(a2, out) { 3004 t.Fatalf("bad: %#v %#v", a2, out) 3005 } 3006 3007 iter, err := state.VaultAccessors() 3008 if err != nil { 3009 t.Fatalf("err: %v", err) 3010 } 3011 3012 count := 0 3013 for { 3014 raw := iter.Next() 3015 if raw == nil { 3016 break 3017 } 3018 3019 count++ 3020 accessor := raw.(*structs.VaultAccessor) 3021 3022 if !reflect.DeepEqual(accessor, a) && !reflect.DeepEqual(accessor, a2) { 3023 t.Fatalf("bad: %#v", accessor) 3024 } 3025 } 3026 3027 if count != 2 { 3028 t.Fatalf("bad: %d", count) 3029 } 3030 3031 index, err := state.Index("vault_accessors") 3032 if err != nil { 3033 t.Fatalf("err: %v", err) 3034 } 3035 if index != 1000 { 3036 t.Fatalf("bad: %d", index) 3037 } 3038 } 3039 3040 func TestStateStore_DeleteVaultAccessors(t *testing.T) { 3041 state := testStateStore(t) 3042 a1 := mock.VaultAccessor() 3043 a2 := mock.VaultAccessor() 3044 accessors := []*structs.VaultAccessor{a1, a2} 3045 3046 err := state.UpsertVaultAccessor(1000, accessors) 3047 if err != nil { 3048 t.Fatalf("err: %v", err) 3049 } 3050 3051 err = state.DeleteVaultAccessors(1001, accessors) 3052 if err != nil { 3053 t.Fatalf("err: %v", err) 3054 } 3055 3056 out, err := state.VaultAccessor(a1.Accessor) 3057 if err != nil { 3058 t.Fatalf("err: %v", err) 3059 } 3060 if out != nil { 3061 t.Fatalf("bad: %#v %#v", a1, out) 3062 } 3063 out, err = state.VaultAccessor(a2.Accessor) 3064 if err != nil { 3065 t.Fatalf("err: %v", err) 3066 } 3067 if out != nil { 3068 t.Fatalf("bad: %#v %#v", a2, out) 3069 } 3070 3071 index, err := state.Index("vault_accessors") 3072 if err != nil { 3073 t.Fatalf("err: %v", err) 3074 } 3075 if index != 1001 { 3076 t.Fatalf("bad: %d", index) 3077 } 3078 } 3079 3080 func TestStateStore_VaultAccessorsByAlloc(t *testing.T) { 3081 state := testStateStore(t) 3082 alloc := mock.Alloc() 3083 var accessors []*structs.VaultAccessor 3084 var expected []*structs.VaultAccessor 3085 3086 for i := 0; i < 5; i++ { 3087 accessor := mock.VaultAccessor() 3088 accessor.AllocID = alloc.ID 3089 expected = append(expected, accessor) 3090 accessors = append(accessors, accessor) 3091 } 3092 3093 for i := 0; i < 10; i++ { 3094 accessor := mock.VaultAccessor() 3095 accessors = append(accessors, accessor) 3096 } 3097 3098 err := state.UpsertVaultAccessor(1000, accessors) 3099 if err != nil { 3100 t.Fatalf("err: %v", err) 3101 } 3102 3103 out, err := state.VaultAccessorsByAlloc(alloc.ID) 3104 if err != nil { 3105 t.Fatalf("err: %v", err) 3106 } 3107 3108 if len(expected) != len(out) { 3109 t.Fatalf("bad: %#v %#v", len(expected), len(out)) 3110 } 3111 3112 index, err := state.Index("vault_accessors") 3113 if err != nil { 3114 t.Fatalf("err: %v", err) 3115 } 3116 if index != 1000 { 3117 t.Fatalf("bad: %d", index) 3118 } 3119 } 3120 3121 func TestStateStore_VaultAccessorsByNode(t *testing.T) { 3122 state := testStateStore(t) 3123 node := mock.Node() 3124 var accessors []*structs.VaultAccessor 3125 var expected []*structs.VaultAccessor 3126 3127 for i := 0; i < 5; i++ { 3128 accessor := mock.VaultAccessor() 3129 accessor.NodeID = node.ID 3130 expected = append(expected, accessor) 3131 accessors = append(accessors, accessor) 3132 } 3133 3134 for i := 0; i < 10; i++ { 3135 accessor := mock.VaultAccessor() 3136 accessors = append(accessors, accessor) 3137 } 3138 3139 err := state.UpsertVaultAccessor(1000, accessors) 3140 if err != nil { 3141 t.Fatalf("err: %v", err) 3142 } 3143 3144 out, err := state.VaultAccessorsByNode(node.ID) 3145 if err != nil { 3146 t.Fatalf("err: %v", err) 3147 } 3148 3149 if len(expected) != len(out) { 3150 t.Fatalf("bad: %#v %#v", len(expected), len(out)) 3151 } 3152 3153 index, err := state.Index("vault_accessors") 3154 if err != nil { 3155 t.Fatalf("err: %v", err) 3156 } 3157 if index != 1000 { 3158 t.Fatalf("bad: %d", index) 3159 } 3160 } 3161 3162 func TestStateStore_RestoreVaultAccessor(t *testing.T) { 3163 state := testStateStore(t) 3164 a := mock.VaultAccessor() 3165 3166 restore, err := state.Restore() 3167 if err != nil { 3168 t.Fatalf("err: %v", err) 3169 } 3170 3171 err = restore.VaultAccessorRestore(a) 3172 if err != nil { 3173 t.Fatalf("err: %v", err) 3174 } 3175 restore.Commit() 3176 3177 out, err := state.VaultAccessor(a.Accessor) 3178 if err != nil { 3179 t.Fatalf("err: %v", err) 3180 } 3181 3182 if !reflect.DeepEqual(out, a) { 3183 t.Fatalf("Bad: %#v %#v", out, a) 3184 } 3185 } 3186 3187 // setupNotifyTest takes a state store and a set of watch items, then creates 3188 // and subscribes a notification channel for each item. 3189 func setupNotifyTest(state *StateStore, items ...watch.Item) notifyTest { 3190 var n notifyTest 3191 for _, item := range items { 3192 ch := make(chan struct{}, 1) 3193 state.Watch(watch.NewItems(item), ch) 3194 n = append(n, ¬ifyTestCase{item, ch}) 3195 } 3196 return n 3197 } 3198 3199 // notifyTestCase is used to set up and verify watch triggers. 3200 type notifyTestCase struct { 3201 item watch.Item 3202 ch chan struct{} 3203 } 3204 3205 // notifyTest is a suite of notifyTestCases. 3206 type notifyTest []*notifyTestCase 3207 3208 // verify ensures that each channel received a notification. 3209 func (n notifyTest) verify(t *testing.T) { 3210 for _, tcase := range n { 3211 if len(tcase.ch) != 1 { 3212 t.Fatalf("should notify %#v", tcase.item) 3213 } 3214 } 3215 } 3216 3217 // NodeIDSort is used to sort nodes by ID 3218 type NodeIDSort []*structs.Node 3219 3220 func (n NodeIDSort) Len() int { 3221 return len(n) 3222 } 3223 3224 func (n NodeIDSort) Less(i, j int) bool { 3225 return n[i].ID < n[j].ID 3226 } 3227 3228 func (n NodeIDSort) Swap(i, j int) { 3229 n[i], n[j] = n[j], n[i] 3230 } 3231 3232 // JobIDis used to sort jobs by id 3233 type JobIDSort []*structs.Job 3234 3235 func (n JobIDSort) Len() int { 3236 return len(n) 3237 } 3238 3239 func (n JobIDSort) Less(i, j int) bool { 3240 return n[i].ID < n[j].ID 3241 } 3242 3243 func (n JobIDSort) Swap(i, j int) { 3244 n[i], n[j] = n[j], n[i] 3245 } 3246 3247 // EvalIDis used to sort evals by id 3248 type EvalIDSort []*structs.Evaluation 3249 3250 func (n EvalIDSort) Len() int { 3251 return len(n) 3252 } 3253 3254 func (n EvalIDSort) Less(i, j int) bool { 3255 return n[i].ID < n[j].ID 3256 } 3257 3258 func (n EvalIDSort) Swap(i, j int) { 3259 n[i], n[j] = n[j], n[i] 3260 } 3261 3262 // AllocIDsort used to sort allocations by id 3263 type AllocIDSort []*structs.Allocation 3264 3265 func (n AllocIDSort) Len() int { 3266 return len(n) 3267 } 3268 3269 func (n AllocIDSort) Less(i, j int) bool { 3270 return n[i].ID < n[j].ID 3271 } 3272 3273 func (n AllocIDSort) Swap(i, j int) { 3274 n[i], n[j] = n[j], n[i] 3275 }