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