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