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