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