github.com/mattyr/nomad@v0.3.3-0.20160919021406-3485a065154a/nomad/state/state_store_test.go (about)

     1  package state
     2  
     3  import (
     4  	"os"
     5  	"reflect"
     6  	"sort"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/hashicorp/go-memdb"
    11  	"github.com/hashicorp/nomad/nomad/mock"
    12  	"github.com/hashicorp/nomad/nomad/structs"
    13  	"github.com/hashicorp/nomad/nomad/watch"
    14  )
    15  
    16  func testStateStore(t *testing.T) *StateStore {
    17  	state, err := NewStateStore(os.Stderr)
    18  	if err != nil {
    19  		t.Fatalf("err: %v", err)
    20  	}
    21  	if state == nil {
    22  		t.Fatalf("missing state")
    23  	}
    24  	return state
    25  }
    26  
    27  func TestStateStore_UpsertNode_Node(t *testing.T) {
    28  	state := testStateStore(t)
    29  	node := mock.Node()
    30  
    31  	notify := setupNotifyTest(
    32  		state,
    33  		watch.Item{Table: "nodes"},
    34  		watch.Item{Node: node.ID})
    35  
    36  	err := state.UpsertNode(1000, node)
    37  	if err != nil {
    38  		t.Fatalf("err: %v", err)
    39  	}
    40  
    41  	out, err := state.NodeByID(node.ID)
    42  	if err != nil {
    43  		t.Fatalf("err: %v", err)
    44  	}
    45  
    46  	if !reflect.DeepEqual(node, out) {
    47  		t.Fatalf("bad: %#v %#v", node, out)
    48  	}
    49  
    50  	index, err := state.Index("nodes")
    51  	if err != nil {
    52  		t.Fatalf("err: %v", err)
    53  	}
    54  	if index != 1000 {
    55  		t.Fatalf("bad: %d", index)
    56  	}
    57  
    58  	notify.verify(t)
    59  }
    60  
    61  func TestStateStore_DeleteNode_Node(t *testing.T) {
    62  	state := testStateStore(t)
    63  	node := mock.Node()
    64  
    65  	notify := setupNotifyTest(
    66  		state,
    67  		watch.Item{Table: "nodes"},
    68  		watch.Item{Node: node.ID})
    69  
    70  	err := state.UpsertNode(1000, node)
    71  	if err != nil {
    72  		t.Fatalf("err: %v", err)
    73  	}
    74  
    75  	err = state.DeleteNode(1001, node.ID)
    76  	if err != nil {
    77  		t.Fatalf("err: %v", err)
    78  	}
    79  
    80  	out, err := state.NodeByID(node.ID)
    81  	if err != nil {
    82  		t.Fatalf("err: %v", err)
    83  	}
    84  
    85  	if out != nil {
    86  		t.Fatalf("bad: %#v %#v", node, out)
    87  	}
    88  
    89  	index, err := state.Index("nodes")
    90  	if err != nil {
    91  		t.Fatalf("err: %v", err)
    92  	}
    93  	if index != 1001 {
    94  		t.Fatalf("bad: %d", index)
    95  	}
    96  
    97  	notify.verify(t)
    98  }
    99  
   100  func TestStateStore_UpdateNodeStatus_Node(t *testing.T) {
   101  	state := testStateStore(t)
   102  	node := mock.Node()
   103  
   104  	notify := setupNotifyTest(
   105  		state,
   106  		watch.Item{Table: "nodes"},
   107  		watch.Item{Node: node.ID})
   108  
   109  	err := state.UpsertNode(800, node)
   110  	if err != nil {
   111  		t.Fatalf("err: %v", err)
   112  	}
   113  
   114  	err = state.UpdateNodeStatus(801, node.ID, structs.NodeStatusReady)
   115  	if err != nil {
   116  		t.Fatalf("err: %v", err)
   117  	}
   118  
   119  	out, err := state.NodeByID(node.ID)
   120  	if err != nil {
   121  		t.Fatalf("err: %v", err)
   122  	}
   123  
   124  	if out.Status != structs.NodeStatusReady {
   125  		t.Fatalf("bad: %#v", out)
   126  	}
   127  	if out.ModifyIndex != 801 {
   128  		t.Fatalf("bad: %#v", out)
   129  	}
   130  
   131  	index, err := state.Index("nodes")
   132  	if err != nil {
   133  		t.Fatalf("err: %v", err)
   134  	}
   135  	if index != 801 {
   136  		t.Fatalf("bad: %d", index)
   137  	}
   138  
   139  	notify.verify(t)
   140  }
   141  
   142  func TestStateStore_UpdateNodeDrain_Node(t *testing.T) {
   143  	state := testStateStore(t)
   144  	node := mock.Node()
   145  
   146  	notify := setupNotifyTest(
   147  		state,
   148  		watch.Item{Table: "nodes"},
   149  		watch.Item{Node: node.ID})
   150  
   151  	err := state.UpsertNode(1000, node)
   152  	if err != nil {
   153  		t.Fatalf("err: %v", err)
   154  	}
   155  
   156  	err = state.UpdateNodeDrain(1001, node.ID, true)
   157  	if err != nil {
   158  		t.Fatalf("err: %v", err)
   159  	}
   160  
   161  	out, err := state.NodeByID(node.ID)
   162  	if err != nil {
   163  		t.Fatalf("err: %v", err)
   164  	}
   165  
   166  	if !out.Drain {
   167  		t.Fatalf("bad: %#v", out)
   168  	}
   169  	if out.ModifyIndex != 1001 {
   170  		t.Fatalf("bad: %#v", out)
   171  	}
   172  
   173  	index, err := state.Index("nodes")
   174  	if err != nil {
   175  		t.Fatalf("err: %v", err)
   176  	}
   177  	if index != 1001 {
   178  		t.Fatalf("bad: %d", index)
   179  	}
   180  
   181  	notify.verify(t)
   182  }
   183  
   184  func TestStateStore_Nodes(t *testing.T) {
   185  	state := testStateStore(t)
   186  	var nodes []*structs.Node
   187  
   188  	for i := 0; i < 10; i++ {
   189  		node := mock.Node()
   190  		nodes = append(nodes, node)
   191  
   192  		err := state.UpsertNode(1000+uint64(i), node)
   193  		if err != nil {
   194  			t.Fatalf("err: %v", err)
   195  		}
   196  	}
   197  
   198  	iter, err := state.Nodes()
   199  	if err != nil {
   200  		t.Fatalf("err: %v", err)
   201  	}
   202  
   203  	var out []*structs.Node
   204  	for {
   205  		raw := iter.Next()
   206  		if raw == nil {
   207  			break
   208  		}
   209  		out = append(out, raw.(*structs.Node))
   210  	}
   211  
   212  	sort.Sort(NodeIDSort(nodes))
   213  	sort.Sort(NodeIDSort(out))
   214  
   215  	if !reflect.DeepEqual(nodes, out) {
   216  		t.Fatalf("bad: %#v %#v", nodes, out)
   217  	}
   218  }
   219  
   220  func TestStateStore_NodesByIDPrefix(t *testing.T) {
   221  	state := testStateStore(t)
   222  	node := mock.Node()
   223  
   224  	node.ID = "11111111-662e-d0ab-d1c9-3e434af7bdb4"
   225  	err := state.UpsertNode(1000, node)
   226  	if err != nil {
   227  		t.Fatalf("err: %v", err)
   228  	}
   229  
   230  	iter, err := state.NodesByIDPrefix(node.ID)
   231  	if err != nil {
   232  		t.Fatalf("err: %v", err)
   233  	}
   234  
   235  	gatherNodes := func(iter memdb.ResultIterator) []*structs.Node {
   236  		var nodes []*structs.Node
   237  		for {
   238  			raw := iter.Next()
   239  			if raw == nil {
   240  				break
   241  			}
   242  			node := raw.(*structs.Node)
   243  			nodes = append(nodes, node)
   244  		}
   245  		return nodes
   246  	}
   247  
   248  	nodes := gatherNodes(iter)
   249  	if len(nodes) != 1 {
   250  		t.Fatalf("err: %v", err)
   251  	}
   252  
   253  	iter, err = state.NodesByIDPrefix("11")
   254  	if err != nil {
   255  		t.Fatalf("err: %v", err)
   256  	}
   257  
   258  	nodes = gatherNodes(iter)
   259  	if len(nodes) != 1 {
   260  		t.Fatalf("err: %v", err)
   261  	}
   262  
   263  	node = mock.Node()
   264  	node.ID = "11222222-662e-d0ab-d1c9-3e434af7bdb4"
   265  	err = state.UpsertNode(1001, node)
   266  	if err != nil {
   267  		t.Fatalf("err: %v", err)
   268  	}
   269  
   270  	iter, err = state.NodesByIDPrefix("11")
   271  	if err != nil {
   272  		t.Fatalf("err: %v", err)
   273  	}
   274  
   275  	nodes = gatherNodes(iter)
   276  	if len(nodes) != 2 {
   277  		t.Fatalf("err: %v", err)
   278  	}
   279  
   280  	iter, err = state.NodesByIDPrefix("1111")
   281  	if err != nil {
   282  		t.Fatalf("err: %v", err)
   283  	}
   284  
   285  	nodes = gatherNodes(iter)
   286  	if len(nodes) != 1 {
   287  		t.Fatalf("err: %v", err)
   288  	}
   289  }
   290  
   291  func TestStateStore_RestoreNode(t *testing.T) {
   292  	state := testStateStore(t)
   293  	node := mock.Node()
   294  
   295  	notify := setupNotifyTest(
   296  		state,
   297  		watch.Item{Table: "nodes"},
   298  		watch.Item{Node: node.ID})
   299  
   300  	restore, err := state.Restore()
   301  	if err != nil {
   302  		t.Fatalf("err: %v", err)
   303  	}
   304  
   305  	err = restore.NodeRestore(node)
   306  	if err != nil {
   307  		t.Fatalf("err: %v", err)
   308  	}
   309  	restore.Commit()
   310  
   311  	out, err := state.NodeByID(node.ID)
   312  	if err != nil {
   313  		t.Fatalf("err: %v", err)
   314  	}
   315  
   316  	if !reflect.DeepEqual(out, node) {
   317  		t.Fatalf("Bad: %#v %#v", out, node)
   318  	}
   319  
   320  	notify.verify(t)
   321  }
   322  
   323  func TestStateStore_UpsertJob_Job(t *testing.T) {
   324  	state := testStateStore(t)
   325  	job := mock.Job()
   326  
   327  	notify := setupNotifyTest(
   328  		state,
   329  		watch.Item{Table: "jobs"},
   330  		watch.Item{Job: job.ID})
   331  
   332  	err := state.UpsertJob(1000, job)
   333  	if err != nil {
   334  		t.Fatalf("err: %v", err)
   335  	}
   336  
   337  	out, err := state.JobByID(job.ID)
   338  	if err != nil {
   339  		t.Fatalf("err: %v", err)
   340  	}
   341  
   342  	if !reflect.DeepEqual(job, out) {
   343  		t.Fatalf("bad: %#v %#v", job, out)
   344  	}
   345  
   346  	index, err := state.Index("jobs")
   347  	if err != nil {
   348  		t.Fatalf("err: %v", err)
   349  	}
   350  	if index != 1000 {
   351  		t.Fatalf("bad: %d", index)
   352  	}
   353  
   354  	summary, err := state.JobSummaryByID(job.ID)
   355  	if err != nil {
   356  		t.Fatalf("err: %v", err)
   357  	}
   358  	if summary == nil {
   359  		t.Fatalf("nil summary")
   360  	}
   361  	if summary.JobID != job.ID {
   362  		t.Fatalf("bad summary id: %v", summary.JobID)
   363  	}
   364  	_, ok := summary.Summary["web"]
   365  	if !ok {
   366  		t.Fatalf("nil summary for task group")
   367  	}
   368  	notify.verify(t)
   369  }
   370  
   371  func TestStateStore_UpdateUpsertJob_Job(t *testing.T) {
   372  	state := testStateStore(t)
   373  	job := mock.Job()
   374  
   375  	notify := setupNotifyTest(
   376  		state,
   377  		watch.Item{Table: "jobs"},
   378  		watch.Item{Job: job.ID})
   379  
   380  	err := state.UpsertJob(1000, job)
   381  	if err != nil {
   382  		t.Fatalf("err: %v", err)
   383  	}
   384  
   385  	job2 := mock.Job()
   386  	job2.ID = job.ID
   387  	err = state.UpsertJob(1001, job2)
   388  	if err != nil {
   389  		t.Fatalf("err: %v", err)
   390  	}
   391  
   392  	out, err := state.JobByID(job.ID)
   393  	if err != nil {
   394  		t.Fatalf("err: %v", err)
   395  	}
   396  
   397  	if !reflect.DeepEqual(job2, out) {
   398  		t.Fatalf("bad: %#v %#v", job2, out)
   399  	}
   400  
   401  	if out.CreateIndex != 1000 {
   402  		t.Fatalf("bad: %#v", out)
   403  	}
   404  	if out.ModifyIndex != 1001 {
   405  		t.Fatalf("bad: %#v", out)
   406  	}
   407  
   408  	index, err := state.Index("jobs")
   409  	if err != nil {
   410  		t.Fatalf("err: %v", err)
   411  	}
   412  	if index != 1001 {
   413  		t.Fatalf("bad: %d", index)
   414  	}
   415  
   416  	// Test that the job summary remains the same if the job is updated but
   417  	// count remains same
   418  	summary, err := state.JobSummaryByID(job.ID)
   419  	if err != nil {
   420  		t.Fatalf("err: %v", err)
   421  	}
   422  	if summary == nil {
   423  		t.Fatalf("nil summary")
   424  	}
   425  	if summary.JobID != job.ID {
   426  		t.Fatalf("bad summary id: %v", summary.JobID)
   427  	}
   428  	_, ok := summary.Summary["web"]
   429  	if !ok {
   430  		t.Fatalf("nil summary for task group")
   431  	}
   432  
   433  	notify.verify(t)
   434  }
   435  
   436  // This test ensures that UpsertJob creates the EphemeralDisk is a job doesn't have
   437  // one and clear out the task's disk resource asks
   438  // COMPAT 0.4.1 -> 0.5
   439  func TestStateStore_UpsertJob_NoEphemeralDisk(t *testing.T) {
   440  	state := testStateStore(t)
   441  	job := mock.Job()
   442  
   443  	// Set the EphemeralDisk to nil and set the tasks's DiskMB to 150
   444  	job.TaskGroups[0].EphemeralDisk = nil
   445  	job.TaskGroups[0].Tasks[0].Resources.DiskMB = 150
   446  
   447  	err := state.UpsertJob(1000, job)
   448  	if err != nil {
   449  		t.Fatalf("err: %v", err)
   450  	}
   451  
   452  	out, err := state.JobByID(job.ID)
   453  	if err != nil {
   454  		t.Fatalf("err: %v", err)
   455  	}
   456  
   457  	// Expect the state store to create the EphemeralDisk and clear out Tasks's
   458  	// DiskMB
   459  	expected := job.Copy()
   460  	expected.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{
   461  		SizeMB: 150,
   462  	}
   463  	expected.TaskGroups[0].Tasks[0].Resources.DiskMB = 0
   464  
   465  	if !reflect.DeepEqual(expected, out) {
   466  		t.Fatalf("bad: %#v %#v", expected, out)
   467  	}
   468  }
   469  
   470  func TestStateStore_DeleteJob_Job(t *testing.T) {
   471  	state := testStateStore(t)
   472  	job := mock.Job()
   473  
   474  	notify := setupNotifyTest(
   475  		state,
   476  		watch.Item{Table: "jobs"},
   477  		watch.Item{Job: job.ID})
   478  
   479  	err := state.UpsertJob(1000, job)
   480  	if err != nil {
   481  		t.Fatalf("err: %v", err)
   482  	}
   483  
   484  	err = state.DeleteJob(1001, job.ID)
   485  	if err != nil {
   486  		t.Fatalf("err: %v", err)
   487  	}
   488  
   489  	out, err := state.JobByID(job.ID)
   490  	if err != nil {
   491  		t.Fatalf("err: %v", err)
   492  	}
   493  
   494  	if out != nil {
   495  		t.Fatalf("bad: %#v %#v", job, out)
   496  	}
   497  
   498  	index, err := state.Index("jobs")
   499  	if err != nil {
   500  		t.Fatalf("err: %v", err)
   501  	}
   502  	if index != 1001 {
   503  		t.Fatalf("bad: %d", index)
   504  	}
   505  
   506  	summary, err := state.JobSummaryByID(job.ID)
   507  	if err != nil {
   508  		t.Fatalf("err: %v", err)
   509  	}
   510  	if summary != nil {
   511  		t.Fatalf("expected summary to be nil, but got: %v", summary)
   512  	}
   513  
   514  	notify.verify(t)
   515  }
   516  
   517  func TestStateStore_Jobs(t *testing.T) {
   518  	state := testStateStore(t)
   519  	var jobs []*structs.Job
   520  
   521  	for i := 0; i < 10; i++ {
   522  		job := mock.Job()
   523  		jobs = append(jobs, job)
   524  
   525  		err := state.UpsertJob(1000+uint64(i), job)
   526  		if err != nil {
   527  			t.Fatalf("err: %v", err)
   528  		}
   529  	}
   530  
   531  	iter, err := state.Jobs()
   532  	if err != nil {
   533  		t.Fatalf("err: %v", err)
   534  	}
   535  
   536  	var out []*structs.Job
   537  	for {
   538  		raw := iter.Next()
   539  		if raw == nil {
   540  			break
   541  		}
   542  		out = append(out, raw.(*structs.Job))
   543  	}
   544  
   545  	sort.Sort(JobIDSort(jobs))
   546  	sort.Sort(JobIDSort(out))
   547  
   548  	if !reflect.DeepEqual(jobs, out) {
   549  		t.Fatalf("bad: %#v %#v", jobs, out)
   550  	}
   551  }
   552  
   553  func TestStateStore_JobsByIDPrefix(t *testing.T) {
   554  	state := testStateStore(t)
   555  	job := mock.Job()
   556  
   557  	job.ID = "redis"
   558  	err := state.UpsertJob(1000, job)
   559  	if err != nil {
   560  		t.Fatalf("err: %v", err)
   561  	}
   562  
   563  	iter, err := state.JobsByIDPrefix(job.ID)
   564  	if err != nil {
   565  		t.Fatalf("err: %v", err)
   566  	}
   567  
   568  	gatherJobs := func(iter memdb.ResultIterator) []*structs.Job {
   569  		var jobs []*structs.Job
   570  		for {
   571  			raw := iter.Next()
   572  			if raw == nil {
   573  				break
   574  			}
   575  			jobs = append(jobs, raw.(*structs.Job))
   576  		}
   577  		return jobs
   578  	}
   579  
   580  	jobs := gatherJobs(iter)
   581  	if len(jobs) != 1 {
   582  		t.Fatalf("err: %v", err)
   583  	}
   584  
   585  	iter, err = state.JobsByIDPrefix("re")
   586  	if err != nil {
   587  		t.Fatalf("err: %v", err)
   588  	}
   589  
   590  	jobs = gatherJobs(iter)
   591  	if len(jobs) != 1 {
   592  		t.Fatalf("err: %v", err)
   593  	}
   594  
   595  	job = mock.Job()
   596  	job.ID = "riak"
   597  	err = state.UpsertJob(1001, job)
   598  	if err != nil {
   599  		t.Fatalf("err: %v", err)
   600  	}
   601  
   602  	iter, err = state.JobsByIDPrefix("r")
   603  	if err != nil {
   604  		t.Fatalf("err: %v", err)
   605  	}
   606  
   607  	jobs = gatherJobs(iter)
   608  	if len(jobs) != 2 {
   609  		t.Fatalf("err: %v", err)
   610  	}
   611  
   612  	iter, err = state.JobsByIDPrefix("ri")
   613  	if err != nil {
   614  		t.Fatalf("err: %v", err)
   615  	}
   616  
   617  	jobs = gatherJobs(iter)
   618  	if len(jobs) != 1 {
   619  		t.Fatalf("err: %v", err)
   620  	}
   621  }
   622  
   623  func TestStateStore_JobsByPeriodic(t *testing.T) {
   624  	state := testStateStore(t)
   625  	var periodic, nonPeriodic []*structs.Job
   626  
   627  	for i := 0; i < 10; i++ {
   628  		job := mock.Job()
   629  		nonPeriodic = append(nonPeriodic, job)
   630  
   631  		err := state.UpsertJob(1000+uint64(i), job)
   632  		if err != nil {
   633  			t.Fatalf("err: %v", err)
   634  		}
   635  	}
   636  
   637  	for i := 0; i < 10; i++ {
   638  		job := mock.PeriodicJob()
   639  		periodic = append(periodic, job)
   640  
   641  		err := state.UpsertJob(2000+uint64(i), job)
   642  		if err != nil {
   643  			t.Fatalf("err: %v", err)
   644  		}
   645  	}
   646  
   647  	iter, err := state.JobsByPeriodic(true)
   648  	if err != nil {
   649  		t.Fatalf("err: %v", err)
   650  	}
   651  
   652  	var outPeriodic []*structs.Job
   653  	for {
   654  		raw := iter.Next()
   655  		if raw == nil {
   656  			break
   657  		}
   658  		outPeriodic = append(outPeriodic, raw.(*structs.Job))
   659  	}
   660  
   661  	iter, err = state.JobsByPeriodic(false)
   662  	if err != nil {
   663  		t.Fatalf("err: %v", err)
   664  	}
   665  
   666  	var outNonPeriodic []*structs.Job
   667  	for {
   668  		raw := iter.Next()
   669  		if raw == nil {
   670  			break
   671  		}
   672  		outNonPeriodic = append(outNonPeriodic, raw.(*structs.Job))
   673  	}
   674  
   675  	sort.Sort(JobIDSort(periodic))
   676  	sort.Sort(JobIDSort(nonPeriodic))
   677  	sort.Sort(JobIDSort(outPeriodic))
   678  	sort.Sort(JobIDSort(outNonPeriodic))
   679  
   680  	if !reflect.DeepEqual(periodic, outPeriodic) {
   681  		t.Fatalf("bad: %#v %#v", periodic, outPeriodic)
   682  	}
   683  
   684  	if !reflect.DeepEqual(nonPeriodic, outNonPeriodic) {
   685  		t.Fatalf("bad: %#v %#v", nonPeriodic, outNonPeriodic)
   686  	}
   687  }
   688  
   689  func TestStateStore_JobsByScheduler(t *testing.T) {
   690  	state := testStateStore(t)
   691  	var serviceJobs []*structs.Job
   692  	var sysJobs []*structs.Job
   693  
   694  	for i := 0; i < 10; i++ {
   695  		job := mock.Job()
   696  		serviceJobs = append(serviceJobs, job)
   697  
   698  		err := state.UpsertJob(1000+uint64(i), job)
   699  		if err != nil {
   700  			t.Fatalf("err: %v", err)
   701  		}
   702  	}
   703  
   704  	for i := 0; i < 10; i++ {
   705  		job := mock.SystemJob()
   706  		sysJobs = append(sysJobs, job)
   707  
   708  		err := state.UpsertJob(2000+uint64(i), job)
   709  		if err != nil {
   710  			t.Fatalf("err: %v", err)
   711  		}
   712  	}
   713  
   714  	iter, err := state.JobsByScheduler("service")
   715  	if err != nil {
   716  		t.Fatalf("err: %v", err)
   717  	}
   718  
   719  	var outService []*structs.Job
   720  	for {
   721  		raw := iter.Next()
   722  		if raw == nil {
   723  			break
   724  		}
   725  		outService = append(outService, raw.(*structs.Job))
   726  	}
   727  
   728  	iter, err = state.JobsByScheduler("system")
   729  	if err != nil {
   730  		t.Fatalf("err: %v", err)
   731  	}
   732  
   733  	var outSystem []*structs.Job
   734  	for {
   735  		raw := iter.Next()
   736  		if raw == nil {
   737  			break
   738  		}
   739  		outSystem = append(outSystem, raw.(*structs.Job))
   740  	}
   741  
   742  	sort.Sort(JobIDSort(serviceJobs))
   743  	sort.Sort(JobIDSort(sysJobs))
   744  	sort.Sort(JobIDSort(outService))
   745  	sort.Sort(JobIDSort(outSystem))
   746  
   747  	if !reflect.DeepEqual(serviceJobs, outService) {
   748  		t.Fatalf("bad: %#v %#v", serviceJobs, outService)
   749  	}
   750  
   751  	if !reflect.DeepEqual(sysJobs, outSystem) {
   752  		t.Fatalf("bad: %#v %#v", sysJobs, outSystem)
   753  	}
   754  }
   755  
   756  func TestStateStore_JobsByGC(t *testing.T) {
   757  	state := testStateStore(t)
   758  	var gc, nonGc []*structs.Job
   759  
   760  	for i := 0; i < 20; i++ {
   761  		var job *structs.Job
   762  		if i%2 == 0 {
   763  			job = mock.Job()
   764  		} else {
   765  			job = mock.PeriodicJob()
   766  		}
   767  		nonGc = append(nonGc, job)
   768  
   769  		if err := state.UpsertJob(1000+uint64(i), job); err != nil {
   770  			t.Fatalf("err: %v", err)
   771  		}
   772  	}
   773  
   774  	for i := 0; i < 10; i++ {
   775  		job := mock.Job()
   776  		job.Type = structs.JobTypeBatch
   777  		gc = append(gc, job)
   778  
   779  		if err := state.UpsertJob(2000+uint64(i), job); err != nil {
   780  			t.Fatalf("err: %v", err)
   781  		}
   782  	}
   783  
   784  	iter, err := state.JobsByGC(true)
   785  	if err != nil {
   786  		t.Fatalf("err: %v", err)
   787  	}
   788  
   789  	var outGc []*structs.Job
   790  	for i := iter.Next(); i != nil; i = iter.Next() {
   791  		outGc = append(outGc, i.(*structs.Job))
   792  	}
   793  
   794  	iter, err = state.JobsByGC(false)
   795  	if err != nil {
   796  		t.Fatalf("err: %v", err)
   797  	}
   798  
   799  	var outNonGc []*structs.Job
   800  	for i := iter.Next(); i != nil; i = iter.Next() {
   801  		outNonGc = append(outNonGc, i.(*structs.Job))
   802  	}
   803  
   804  	sort.Sort(JobIDSort(gc))
   805  	sort.Sort(JobIDSort(nonGc))
   806  	sort.Sort(JobIDSort(outGc))
   807  	sort.Sort(JobIDSort(outNonGc))
   808  
   809  	if !reflect.DeepEqual(gc, outGc) {
   810  		t.Fatalf("bad: %#v %#v", gc, outGc)
   811  	}
   812  
   813  	if !reflect.DeepEqual(nonGc, outNonGc) {
   814  		t.Fatalf("bad: %#v %#v", nonGc, outNonGc)
   815  	}
   816  }
   817  
   818  func TestStateStore_RestoreJob(t *testing.T) {
   819  	state := testStateStore(t)
   820  	job := mock.Job()
   821  
   822  	notify := setupNotifyTest(
   823  		state,
   824  		watch.Item{Table: "jobs"},
   825  		watch.Item{Job: job.ID})
   826  
   827  	restore, err := state.Restore()
   828  	if err != nil {
   829  		t.Fatalf("err: %v", err)
   830  	}
   831  
   832  	err = restore.JobRestore(job)
   833  	if err != nil {
   834  		t.Fatalf("err: %v", err)
   835  	}
   836  	restore.Commit()
   837  
   838  	out, err := state.JobByID(job.ID)
   839  	if err != nil {
   840  		t.Fatalf("err: %v", err)
   841  	}
   842  
   843  	if !reflect.DeepEqual(out, job) {
   844  		t.Fatalf("Bad: %#v %#v", out, job)
   845  	}
   846  
   847  	notify.verify(t)
   848  }
   849  
   850  // This test ensures that the state restore creates the EphemeralDisk for a job if
   851  // it doesn't have one
   852  // COMPAT 0.4.1 -> 0.5
   853  func TestStateStore_Jobs_NoEphemeralDisk(t *testing.T) {
   854  	state := testStateStore(t)
   855  	job := mock.Job()
   856  
   857  	// Set EphemeralDisk to nil and set the DiskMB to 150
   858  	job.TaskGroups[0].EphemeralDisk = nil
   859  	job.TaskGroups[0].Tasks[0].Resources.DiskMB = 150
   860  
   861  	notify := setupNotifyTest(
   862  		state,
   863  		watch.Item{Table: "jobs"},
   864  		watch.Item{Job: job.ID})
   865  
   866  	restore, err := state.Restore()
   867  	if err != nil {
   868  		t.Fatalf("err: %v", err)
   869  	}
   870  
   871  	err = restore.JobRestore(job)
   872  	if err != nil {
   873  		t.Fatalf("err: %v", err)
   874  	}
   875  	restore.Commit()
   876  
   877  	out, err := state.JobByID(job.ID)
   878  	if err != nil {
   879  		t.Fatalf("err: %v", err)
   880  	}
   881  
   882  	// Expect job to have local disk and clear out the task's disk resource ask
   883  	expected := job.Copy()
   884  	expected.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{
   885  		SizeMB: 150,
   886  	}
   887  	expected.TaskGroups[0].Tasks[0].Resources.DiskMB = 0
   888  	if !reflect.DeepEqual(out, expected) {
   889  		t.Fatalf("Bad: %#v %#v", out, job)
   890  	}
   891  
   892  	notify.verify(t)
   893  }
   894  
   895  func TestStateStore_UpsertPeriodicLaunch(t *testing.T) {
   896  	state := testStateStore(t)
   897  	job := mock.Job()
   898  	launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()}
   899  
   900  	notify := setupNotifyTest(
   901  		state,
   902  		watch.Item{Table: "periodic_launch"},
   903  		watch.Item{Job: job.ID})
   904  
   905  	err := state.UpsertPeriodicLaunch(1000, launch)
   906  	if err != nil {
   907  		t.Fatalf("err: %v", err)
   908  	}
   909  
   910  	out, err := state.PeriodicLaunchByID(job.ID)
   911  	if err != nil {
   912  		t.Fatalf("err: %v", err)
   913  	}
   914  	if out.CreateIndex != 1000 {
   915  		t.Fatalf("bad: %#v", out)
   916  	}
   917  	if out.ModifyIndex != 1000 {
   918  		t.Fatalf("bad: %#v", out)
   919  	}
   920  
   921  	if !reflect.DeepEqual(launch, out) {
   922  		t.Fatalf("bad: %#v %#v", job, out)
   923  	}
   924  
   925  	index, err := state.Index("periodic_launch")
   926  	if err != nil {
   927  		t.Fatalf("err: %v", err)
   928  	}
   929  	if index != 1000 {
   930  		t.Fatalf("bad: %d", index)
   931  	}
   932  
   933  	notify.verify(t)
   934  }
   935  
   936  func TestStateStore_UpdateUpsertPeriodicLaunch(t *testing.T) {
   937  	state := testStateStore(t)
   938  	job := mock.Job()
   939  	launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()}
   940  
   941  	notify := setupNotifyTest(
   942  		state,
   943  		watch.Item{Table: "periodic_launch"},
   944  		watch.Item{Job: job.ID})
   945  
   946  	err := state.UpsertPeriodicLaunch(1000, launch)
   947  	if err != nil {
   948  		t.Fatalf("err: %v", err)
   949  	}
   950  
   951  	launch2 := &structs.PeriodicLaunch{
   952  		ID:     job.ID,
   953  		Launch: launch.Launch.Add(1 * time.Second),
   954  	}
   955  	err = state.UpsertPeriodicLaunch(1001, launch2)
   956  	if err != nil {
   957  		t.Fatalf("err: %v", err)
   958  	}
   959  
   960  	out, err := state.PeriodicLaunchByID(job.ID)
   961  	if err != nil {
   962  		t.Fatalf("err: %v", err)
   963  	}
   964  	if out.CreateIndex != 1000 {
   965  		t.Fatalf("bad: %#v", out)
   966  	}
   967  	if out.ModifyIndex != 1001 {
   968  		t.Fatalf("bad: %#v", out)
   969  	}
   970  
   971  	if !reflect.DeepEqual(launch2, out) {
   972  		t.Fatalf("bad: %#v %#v", launch2, out)
   973  	}
   974  
   975  	index, err := state.Index("periodic_launch")
   976  	if err != nil {
   977  		t.Fatalf("err: %v", err)
   978  	}
   979  	if index != 1001 {
   980  		t.Fatalf("bad: %d", index)
   981  	}
   982  
   983  	notify.verify(t)
   984  }
   985  
   986  func TestStateStore_DeletePeriodicLaunch(t *testing.T) {
   987  	state := testStateStore(t)
   988  	job := mock.Job()
   989  	launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()}
   990  
   991  	notify := setupNotifyTest(
   992  		state,
   993  		watch.Item{Table: "periodic_launch"},
   994  		watch.Item{Job: job.ID})
   995  
   996  	err := state.UpsertPeriodicLaunch(1000, launch)
   997  	if err != nil {
   998  		t.Fatalf("err: %v", err)
   999  	}
  1000  
  1001  	err = state.DeletePeriodicLaunch(1001, job.ID)
  1002  	if err != nil {
  1003  		t.Fatalf("err: %v", err)
  1004  	}
  1005  
  1006  	out, err := state.PeriodicLaunchByID(job.ID)
  1007  	if err != nil {
  1008  		t.Fatalf("err: %v", err)
  1009  	}
  1010  
  1011  	if out != nil {
  1012  		t.Fatalf("bad: %#v %#v", job, out)
  1013  	}
  1014  
  1015  	index, err := state.Index("periodic_launch")
  1016  	if err != nil {
  1017  		t.Fatalf("err: %v", err)
  1018  	}
  1019  	if index != 1001 {
  1020  		t.Fatalf("bad: %d", index)
  1021  	}
  1022  
  1023  	notify.verify(t)
  1024  }
  1025  
  1026  func TestStateStore_PeriodicLaunches(t *testing.T) {
  1027  	state := testStateStore(t)
  1028  	var launches []*structs.PeriodicLaunch
  1029  
  1030  	for i := 0; i < 10; i++ {
  1031  		job := mock.Job()
  1032  		launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()}
  1033  		launches = append(launches, launch)
  1034  
  1035  		err := state.UpsertPeriodicLaunch(1000+uint64(i), launch)
  1036  		if err != nil {
  1037  			t.Fatalf("err: %v", err)
  1038  		}
  1039  	}
  1040  
  1041  	iter, err := state.PeriodicLaunches()
  1042  	if err != nil {
  1043  		t.Fatalf("err: %v", err)
  1044  	}
  1045  
  1046  	out := make(map[string]*structs.PeriodicLaunch, 10)
  1047  	for {
  1048  		raw := iter.Next()
  1049  		if raw == nil {
  1050  			break
  1051  		}
  1052  		launch := raw.(*structs.PeriodicLaunch)
  1053  		if _, ok := out[launch.ID]; ok {
  1054  			t.Fatalf("duplicate: %v", launch.ID)
  1055  		}
  1056  
  1057  		out[launch.ID] = launch
  1058  	}
  1059  
  1060  	for _, launch := range launches {
  1061  		l, ok := out[launch.ID]
  1062  		if !ok {
  1063  			t.Fatalf("bad %v", launch.ID)
  1064  		}
  1065  
  1066  		if !reflect.DeepEqual(launch, l) {
  1067  			t.Fatalf("bad: %#v %#v", launch, l)
  1068  		}
  1069  
  1070  		delete(out, launch.ID)
  1071  	}
  1072  
  1073  	if len(out) != 0 {
  1074  		t.Fatalf("leftover: %#v", out)
  1075  	}
  1076  }
  1077  
  1078  func TestStateStore_RestorePeriodicLaunch(t *testing.T) {
  1079  	state := testStateStore(t)
  1080  	job := mock.Job()
  1081  	launch := &structs.PeriodicLaunch{ID: job.ID, Launch: time.Now()}
  1082  
  1083  	notify := setupNotifyTest(
  1084  		state,
  1085  		watch.Item{Table: "periodic_launch"},
  1086  		watch.Item{Job: job.ID})
  1087  
  1088  	restore, err := state.Restore()
  1089  	if err != nil {
  1090  		t.Fatalf("err: %v", err)
  1091  	}
  1092  
  1093  	err = restore.PeriodicLaunchRestore(launch)
  1094  	if err != nil {
  1095  		t.Fatalf("err: %v", err)
  1096  	}
  1097  	restore.Commit()
  1098  
  1099  	out, err := state.PeriodicLaunchByID(job.ID)
  1100  	if err != nil {
  1101  		t.Fatalf("err: %v", err)
  1102  	}
  1103  
  1104  	if !reflect.DeepEqual(out, launch) {
  1105  		t.Fatalf("Bad: %#v %#v", out, job)
  1106  	}
  1107  
  1108  	notify.verify(t)
  1109  }
  1110  
  1111  func TestStateStore_RestoreJobSummary(t *testing.T) {
  1112  	state := testStateStore(t)
  1113  	job := mock.Job()
  1114  	jobSummary := &structs.JobSummary{
  1115  		JobID: job.ID,
  1116  		Summary: map[string]structs.TaskGroupSummary{
  1117  			"web": structs.TaskGroupSummary{
  1118  				Starting: 10,
  1119  			},
  1120  		},
  1121  	}
  1122  	restore, err := state.Restore()
  1123  	if err != nil {
  1124  		t.Fatalf("err: %v", err)
  1125  	}
  1126  
  1127  	err = restore.JobSummaryRestore(jobSummary)
  1128  	if err != nil {
  1129  		t.Fatalf("err: %v", err)
  1130  	}
  1131  	restore.Commit()
  1132  
  1133  	out, err := state.JobSummaryByID(job.ID)
  1134  	if err != nil {
  1135  		t.Fatalf("err: %v", err)
  1136  	}
  1137  
  1138  	if !reflect.DeepEqual(out, jobSummary) {
  1139  		t.Fatalf("Bad: %#v %#v", out, jobSummary)
  1140  	}
  1141  }
  1142  
  1143  func TestStateStore_Indexes(t *testing.T) {
  1144  	state := testStateStore(t)
  1145  	node := mock.Node()
  1146  
  1147  	err := state.UpsertNode(1000, node)
  1148  	if err != nil {
  1149  		t.Fatalf("err: %v", err)
  1150  	}
  1151  
  1152  	iter, err := state.Indexes()
  1153  	if err != nil {
  1154  		t.Fatalf("err: %v", err)
  1155  	}
  1156  
  1157  	var out []*IndexEntry
  1158  	for {
  1159  		raw := iter.Next()
  1160  		if raw == nil {
  1161  			break
  1162  		}
  1163  		out = append(out, raw.(*IndexEntry))
  1164  	}
  1165  
  1166  	expect := []*IndexEntry{
  1167  		&IndexEntry{"nodes", 1000},
  1168  	}
  1169  
  1170  	if !reflect.DeepEqual(expect, out) {
  1171  		t.Fatalf("bad: %#v %#v", expect, out)
  1172  	}
  1173  }
  1174  
  1175  func TestStateStore_LatestIndex(t *testing.T) {
  1176  	state := testStateStore(t)
  1177  
  1178  	if err := state.UpsertNode(1000, mock.Node()); err != nil {
  1179  		t.Fatalf("err: %v", err)
  1180  	}
  1181  
  1182  	exp := uint64(2000)
  1183  	if err := state.UpsertJob(exp, mock.Job()); err != nil {
  1184  		t.Fatalf("err: %v", err)
  1185  	}
  1186  
  1187  	latest, err := state.LatestIndex()
  1188  	if err != nil {
  1189  		t.Fatalf("err: %v", err)
  1190  	}
  1191  
  1192  	if latest != exp {
  1193  		t.Fatalf("LatestIndex() returned %d; want %d", latest, exp)
  1194  	}
  1195  }
  1196  
  1197  func TestStateStore_RestoreIndex(t *testing.T) {
  1198  	state := testStateStore(t)
  1199  
  1200  	restore, err := state.Restore()
  1201  	if err != nil {
  1202  		t.Fatalf("err: %v", err)
  1203  	}
  1204  
  1205  	index := &IndexEntry{"jobs", 1000}
  1206  	err = restore.IndexRestore(index)
  1207  	if err != nil {
  1208  		t.Fatalf("err: %v", err)
  1209  	}
  1210  
  1211  	restore.Commit()
  1212  
  1213  	out, err := state.Index("jobs")
  1214  	if err != nil {
  1215  		t.Fatalf("err: %v", err)
  1216  	}
  1217  
  1218  	if out != 1000 {
  1219  		t.Fatalf("Bad: %#v %#v", out, 1000)
  1220  	}
  1221  }
  1222  
  1223  func TestStateStore_UpsertEvals_Eval(t *testing.T) {
  1224  	state := testStateStore(t)
  1225  	eval := mock.Eval()
  1226  
  1227  	notify := setupNotifyTest(
  1228  		state,
  1229  		watch.Item{Table: "evals"},
  1230  		watch.Item{Eval: eval.ID})
  1231  
  1232  	err := state.UpsertEvals(1000, []*structs.Evaluation{eval})
  1233  	if err != nil {
  1234  		t.Fatalf("err: %v", err)
  1235  	}
  1236  
  1237  	out, err := state.EvalByID(eval.ID)
  1238  	if err != nil {
  1239  		t.Fatalf("err: %v", err)
  1240  	}
  1241  
  1242  	if !reflect.DeepEqual(eval, out) {
  1243  		t.Fatalf("bad: %#v %#v", eval, out)
  1244  	}
  1245  
  1246  	index, err := state.Index("evals")
  1247  	if err != nil {
  1248  		t.Fatalf("err: %v", err)
  1249  	}
  1250  	if index != 1000 {
  1251  		t.Fatalf("bad: %d", index)
  1252  	}
  1253  
  1254  	notify.verify(t)
  1255  }
  1256  
  1257  func TestStateStore_Update_UpsertEvals_Eval(t *testing.T) {
  1258  	state := testStateStore(t)
  1259  	eval := mock.Eval()
  1260  
  1261  	err := state.UpsertEvals(1000, []*structs.Evaluation{eval})
  1262  	if err != nil {
  1263  		t.Fatalf("err: %v", err)
  1264  	}
  1265  
  1266  	notify := setupNotifyTest(
  1267  		state,
  1268  		watch.Item{Table: "evals"},
  1269  		watch.Item{Eval: eval.ID})
  1270  
  1271  	eval2 := mock.Eval()
  1272  	eval2.ID = eval.ID
  1273  	err = state.UpsertEvals(1001, []*structs.Evaluation{eval2})
  1274  	if err != nil {
  1275  		t.Fatalf("err: %v", err)
  1276  	}
  1277  
  1278  	out, err := state.EvalByID(eval.ID)
  1279  	if err != nil {
  1280  		t.Fatalf("err: %v", err)
  1281  	}
  1282  
  1283  	if !reflect.DeepEqual(eval2, out) {
  1284  		t.Fatalf("bad: %#v %#v", eval2, out)
  1285  	}
  1286  
  1287  	if out.CreateIndex != 1000 {
  1288  		t.Fatalf("bad: %#v", out)
  1289  	}
  1290  	if out.ModifyIndex != 1001 {
  1291  		t.Fatalf("bad: %#v", out)
  1292  	}
  1293  
  1294  	index, err := state.Index("evals")
  1295  	if err != nil {
  1296  		t.Fatalf("err: %v", err)
  1297  	}
  1298  	if index != 1001 {
  1299  		t.Fatalf("bad: %d", index)
  1300  	}
  1301  
  1302  	notify.verify(t)
  1303  }
  1304  
  1305  func TestStateStore_DeleteEval_Eval(t *testing.T) {
  1306  	state := testStateStore(t)
  1307  	eval1 := mock.Eval()
  1308  	eval2 := mock.Eval()
  1309  	alloc1 := mock.Alloc()
  1310  	alloc2 := mock.Alloc()
  1311  
  1312  	notify := setupNotifyTest(
  1313  		state,
  1314  		watch.Item{Table: "evals"},
  1315  		watch.Item{Table: "allocs"},
  1316  		watch.Item{Eval: eval1.ID},
  1317  		watch.Item{Eval: eval2.ID},
  1318  		watch.Item{Alloc: alloc1.ID},
  1319  		watch.Item{Alloc: alloc2.ID},
  1320  		watch.Item{AllocEval: alloc1.EvalID},
  1321  		watch.Item{AllocEval: alloc2.EvalID},
  1322  		watch.Item{AllocJob: alloc1.JobID},
  1323  		watch.Item{AllocJob: alloc2.JobID},
  1324  		watch.Item{AllocNode: alloc1.NodeID},
  1325  		watch.Item{AllocNode: alloc2.NodeID})
  1326  
  1327  	state.UpsertJobSummary(900, mock.JobSummary(eval1.JobID))
  1328  	state.UpsertJobSummary(901, mock.JobSummary(eval2.JobID))
  1329  	state.UpsertJobSummary(902, mock.JobSummary(alloc1.JobID))
  1330  	state.UpsertJobSummary(903, mock.JobSummary(alloc2.JobID))
  1331  	err := state.UpsertEvals(1000, []*structs.Evaluation{eval1, eval2})
  1332  	if err != nil {
  1333  		t.Fatalf("err: %v", err)
  1334  	}
  1335  
  1336  	err = state.UpsertAllocs(1001, []*structs.Allocation{alloc1, alloc2})
  1337  	if err != nil {
  1338  		t.Fatalf("err: %v", err)
  1339  	}
  1340  
  1341  	err = state.DeleteEval(1002, []string{eval1.ID, eval2.ID}, []string{alloc1.ID, alloc2.ID})
  1342  	if err != nil {
  1343  		t.Fatalf("err: %v", err)
  1344  	}
  1345  
  1346  	out, err := state.EvalByID(eval1.ID)
  1347  	if err != nil {
  1348  		t.Fatalf("err: %v", err)
  1349  	}
  1350  
  1351  	if out != nil {
  1352  		t.Fatalf("bad: %#v %#v", eval1, out)
  1353  	}
  1354  
  1355  	out, err = state.EvalByID(eval2.ID)
  1356  	if err != nil {
  1357  		t.Fatalf("err: %v", err)
  1358  	}
  1359  
  1360  	if out != nil {
  1361  		t.Fatalf("bad: %#v %#v", eval1, out)
  1362  	}
  1363  
  1364  	outA, err := state.AllocByID(alloc1.ID)
  1365  	if err != nil {
  1366  		t.Fatalf("err: %v", err)
  1367  	}
  1368  
  1369  	if out != nil {
  1370  		t.Fatalf("bad: %#v %#v", alloc1, outA)
  1371  	}
  1372  
  1373  	outA, err = state.AllocByID(alloc2.ID)
  1374  	if err != nil {
  1375  		t.Fatalf("err: %v", err)
  1376  	}
  1377  
  1378  	if out != nil {
  1379  		t.Fatalf("bad: %#v %#v", alloc1, outA)
  1380  	}
  1381  
  1382  	index, err := state.Index("evals")
  1383  	if err != nil {
  1384  		t.Fatalf("err: %v", err)
  1385  	}
  1386  	if index != 1002 {
  1387  		t.Fatalf("bad: %d", index)
  1388  	}
  1389  
  1390  	index, err = state.Index("allocs")
  1391  	if err != nil {
  1392  		t.Fatalf("err: %v", err)
  1393  	}
  1394  	if index != 1002 {
  1395  		t.Fatalf("bad: %d", index)
  1396  	}
  1397  
  1398  	notify.verify(t)
  1399  }
  1400  
  1401  func TestStateStore_EvalsByJob(t *testing.T) {
  1402  	state := testStateStore(t)
  1403  
  1404  	eval1 := mock.Eval()
  1405  	eval2 := mock.Eval()
  1406  	eval2.JobID = eval1.JobID
  1407  	eval3 := mock.Eval()
  1408  	evals := []*structs.Evaluation{eval1, eval2}
  1409  
  1410  	err := state.UpsertEvals(1000, evals)
  1411  	if err != nil {
  1412  		t.Fatalf("err: %v", err)
  1413  	}
  1414  	err = state.UpsertEvals(1001, []*structs.Evaluation{eval3})
  1415  	if err != nil {
  1416  		t.Fatalf("err: %v", err)
  1417  	}
  1418  
  1419  	out, err := state.EvalsByJob(eval1.JobID)
  1420  	if err != nil {
  1421  		t.Fatalf("err: %v", err)
  1422  	}
  1423  
  1424  	sort.Sort(EvalIDSort(evals))
  1425  	sort.Sort(EvalIDSort(out))
  1426  
  1427  	if !reflect.DeepEqual(evals, out) {
  1428  		t.Fatalf("bad: %#v %#v", evals, out)
  1429  	}
  1430  }
  1431  
  1432  func TestStateStore_Evals(t *testing.T) {
  1433  	state := testStateStore(t)
  1434  	var evals []*structs.Evaluation
  1435  
  1436  	for i := 0; i < 10; i++ {
  1437  		eval := mock.Eval()
  1438  		evals = append(evals, eval)
  1439  
  1440  		err := state.UpsertEvals(1000+uint64(i), []*structs.Evaluation{eval})
  1441  		if err != nil {
  1442  			t.Fatalf("err: %v", err)
  1443  		}
  1444  	}
  1445  
  1446  	iter, err := state.Evals()
  1447  	if err != nil {
  1448  		t.Fatalf("err: %v", err)
  1449  	}
  1450  
  1451  	var out []*structs.Evaluation
  1452  	for {
  1453  		raw := iter.Next()
  1454  		if raw == nil {
  1455  			break
  1456  		}
  1457  		out = append(out, raw.(*structs.Evaluation))
  1458  	}
  1459  
  1460  	sort.Sort(EvalIDSort(evals))
  1461  	sort.Sort(EvalIDSort(out))
  1462  
  1463  	if !reflect.DeepEqual(evals, out) {
  1464  		t.Fatalf("bad: %#v %#v", evals, out)
  1465  	}
  1466  }
  1467  
  1468  func TestStateStore_EvalsByIDPrefix(t *testing.T) {
  1469  	state := testStateStore(t)
  1470  	var evals []*structs.Evaluation
  1471  
  1472  	ids := []string{
  1473  		"aaaaaaaa-7bfb-395d-eb95-0685af2176b2",
  1474  		"aaaaaaab-7bfb-395d-eb95-0685af2176b2",
  1475  		"aaaaaabb-7bfb-395d-eb95-0685af2176b2",
  1476  		"aaaaabbb-7bfb-395d-eb95-0685af2176b2",
  1477  		"aaaabbbb-7bfb-395d-eb95-0685af2176b2",
  1478  		"aaabbbbb-7bfb-395d-eb95-0685af2176b2",
  1479  		"aabbbbbb-7bfb-395d-eb95-0685af2176b2",
  1480  		"abbbbbbb-7bfb-395d-eb95-0685af2176b2",
  1481  		"bbbbbbbb-7bfb-395d-eb95-0685af2176b2",
  1482  	}
  1483  	for i := 0; i < 9; i++ {
  1484  		eval := mock.Eval()
  1485  		eval.ID = ids[i]
  1486  		evals = append(evals, eval)
  1487  	}
  1488  
  1489  	err := state.UpsertEvals(1000, evals)
  1490  	if err != nil {
  1491  		t.Fatalf("err: %v", err)
  1492  	}
  1493  
  1494  	iter, err := state.EvalsByIDPrefix("aaaa")
  1495  	if err != nil {
  1496  		t.Fatalf("err: %v", err)
  1497  	}
  1498  
  1499  	gatherEvals := func(iter memdb.ResultIterator) []*structs.Evaluation {
  1500  		var evals []*structs.Evaluation
  1501  		for {
  1502  			raw := iter.Next()
  1503  			if raw == nil {
  1504  				break
  1505  			}
  1506  			evals = append(evals, raw.(*structs.Evaluation))
  1507  		}
  1508  		return evals
  1509  	}
  1510  
  1511  	out := gatherEvals(iter)
  1512  	if len(out) != 5 {
  1513  		t.Fatalf("bad: expected five evaluations, got: %#v", out)
  1514  	}
  1515  
  1516  	sort.Sort(EvalIDSort(evals))
  1517  
  1518  	for index, eval := range out {
  1519  		if ids[index] != eval.ID {
  1520  			t.Fatalf("bad: got unexpected id: %s", eval.ID)
  1521  		}
  1522  	}
  1523  
  1524  	iter, err = state.EvalsByIDPrefix("b-a7bfb")
  1525  	if err != nil {
  1526  		t.Fatalf("err: %v", err)
  1527  	}
  1528  
  1529  	out = gatherEvals(iter)
  1530  	if len(out) != 0 {
  1531  		t.Fatalf("bad: unexpected zero evaluations, got: %#v", out)
  1532  	}
  1533  
  1534  }
  1535  
  1536  func TestStateStore_RestoreEval(t *testing.T) {
  1537  	state := testStateStore(t)
  1538  	eval := mock.Eval()
  1539  
  1540  	notify := setupNotifyTest(
  1541  		state,
  1542  		watch.Item{Table: "evals"},
  1543  		watch.Item{Eval: eval.ID})
  1544  
  1545  	restore, err := state.Restore()
  1546  	if err != nil {
  1547  		t.Fatalf("err: %v", err)
  1548  	}
  1549  
  1550  	err = restore.EvalRestore(eval)
  1551  	if err != nil {
  1552  		t.Fatalf("err: %v", err)
  1553  	}
  1554  	restore.Commit()
  1555  
  1556  	out, err := state.EvalByID(eval.ID)
  1557  	if err != nil {
  1558  		t.Fatalf("err: %v", err)
  1559  	}
  1560  
  1561  	if !reflect.DeepEqual(out, eval) {
  1562  		t.Fatalf("Bad: %#v %#v", out, eval)
  1563  	}
  1564  
  1565  	notify.verify(t)
  1566  }
  1567  
  1568  func TestStateStore_UpdateAllocsFromClient(t *testing.T) {
  1569  	state := testStateStore(t)
  1570  	alloc := mock.Alloc()
  1571  	alloc2 := mock.Alloc()
  1572  
  1573  	notify := setupNotifyTest(
  1574  		state,
  1575  		watch.Item{Table: "allocs"},
  1576  		watch.Item{Alloc: alloc.ID},
  1577  		watch.Item{AllocEval: alloc.EvalID},
  1578  		watch.Item{AllocJob: alloc.JobID},
  1579  		watch.Item{AllocNode: alloc.NodeID},
  1580  		watch.Item{Alloc: alloc2.ID},
  1581  		watch.Item{AllocEval: alloc2.EvalID},
  1582  		watch.Item{AllocJob: alloc2.JobID},
  1583  		watch.Item{AllocNode: alloc2.NodeID})
  1584  
  1585  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1586  		t.Fatalf("err: %v", err)
  1587  	}
  1588  	if err := state.UpsertJob(999, alloc2.Job); err != nil {
  1589  		t.Fatalf("err: %v", err)
  1590  	}
  1591  
  1592  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc, alloc2})
  1593  	if err != nil {
  1594  		t.Fatalf("err: %v", err)
  1595  	}
  1596  
  1597  	// Create the delta updates
  1598  	ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}}
  1599  	update := &structs.Allocation{
  1600  		ID:           alloc.ID,
  1601  		ClientStatus: structs.AllocClientStatusFailed,
  1602  		TaskStates:   ts,
  1603  		JobID:        alloc.JobID,
  1604  		TaskGroup:    alloc.TaskGroup,
  1605  	}
  1606  	update2 := &structs.Allocation{
  1607  		ID:           alloc2.ID,
  1608  		ClientStatus: structs.AllocClientStatusRunning,
  1609  		TaskStates:   ts,
  1610  		JobID:        alloc2.JobID,
  1611  		TaskGroup:    alloc2.TaskGroup,
  1612  	}
  1613  
  1614  	err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2})
  1615  	if err != nil {
  1616  		t.Fatalf("err: %v", err)
  1617  	}
  1618  
  1619  	out, err := state.AllocByID(alloc.ID)
  1620  	if err != nil {
  1621  		t.Fatalf("err: %v", err)
  1622  	}
  1623  
  1624  	alloc.CreateIndex = 1000
  1625  	alloc.ModifyIndex = 1001
  1626  	alloc.TaskStates = ts
  1627  	alloc.ClientStatus = structs.AllocClientStatusFailed
  1628  	if !reflect.DeepEqual(alloc, out) {
  1629  		t.Fatalf("bad: %#v %#v", alloc, out)
  1630  	}
  1631  
  1632  	out, err = state.AllocByID(alloc2.ID)
  1633  	if err != nil {
  1634  		t.Fatalf("err: %v", err)
  1635  	}
  1636  
  1637  	alloc2.ModifyIndex = 1000
  1638  	alloc2.ModifyIndex = 1001
  1639  	alloc2.ClientStatus = structs.AllocClientStatusRunning
  1640  	alloc2.TaskStates = ts
  1641  	if !reflect.DeepEqual(alloc2, out) {
  1642  		t.Fatalf("bad: %#v %#v", alloc2, out)
  1643  	}
  1644  
  1645  	index, err := state.Index("allocs")
  1646  	if err != nil {
  1647  		t.Fatalf("err: %v", err)
  1648  	}
  1649  	if index != 1001 {
  1650  		t.Fatalf("bad: %d", index)
  1651  	}
  1652  
  1653  	// Ensure summaries have been updated
  1654  	summary, err := state.JobSummaryByID(alloc.JobID)
  1655  	if err != nil {
  1656  		t.Fatalf("err: %v", err)
  1657  	}
  1658  	tgSummary := summary.Summary["web"]
  1659  	if tgSummary.Failed != 1 {
  1660  		t.Fatalf("expected failed: %v, actual: %v, summary: %#v", 1, tgSummary.Failed, tgSummary)
  1661  	}
  1662  
  1663  	summary2, err := state.JobSummaryByID(alloc2.JobID)
  1664  	if err != nil {
  1665  		t.Fatalf("err: %v", err)
  1666  	}
  1667  	tgSummary2 := summary2.Summary["web"]
  1668  	if tgSummary2.Running != 1 {
  1669  		t.Fatalf("expected running: %v, actual: %v", 1, tgSummary2.Running)
  1670  	}
  1671  
  1672  	notify.verify(t)
  1673  }
  1674  
  1675  func TestStateStore_UpdateMultipleAllocsFromClient(t *testing.T) {
  1676  	state := testStateStore(t)
  1677  	alloc := mock.Alloc()
  1678  
  1679  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1680  		t.Fatalf("err: %v", err)
  1681  	}
  1682  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1683  	if err != nil {
  1684  		t.Fatalf("err: %v", err)
  1685  	}
  1686  
  1687  	// Create the delta updates
  1688  	ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}}
  1689  	update := &structs.Allocation{
  1690  		ID:           alloc.ID,
  1691  		ClientStatus: structs.AllocClientStatusRunning,
  1692  		TaskStates:   ts,
  1693  		JobID:        alloc.JobID,
  1694  		TaskGroup:    alloc.TaskGroup,
  1695  	}
  1696  	update2 := &structs.Allocation{
  1697  		ID:           alloc.ID,
  1698  		ClientStatus: structs.AllocClientStatusPending,
  1699  		TaskStates:   ts,
  1700  		JobID:        alloc.JobID,
  1701  		TaskGroup:    alloc.TaskGroup,
  1702  	}
  1703  
  1704  	err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2})
  1705  	if err != nil {
  1706  		t.Fatalf("err: %v", err)
  1707  	}
  1708  
  1709  	out, err := state.AllocByID(alloc.ID)
  1710  	if err != nil {
  1711  		t.Fatalf("err: %v", err)
  1712  	}
  1713  
  1714  	alloc.CreateIndex = 1000
  1715  	alloc.ModifyIndex = 1001
  1716  	alloc.TaskStates = ts
  1717  	alloc.ClientStatus = structs.AllocClientStatusPending
  1718  	if !reflect.DeepEqual(alloc, out) {
  1719  		t.Fatalf("bad: %#v , actual:%#v", alloc, out)
  1720  	}
  1721  
  1722  	summary, err := state.JobSummaryByID(alloc.JobID)
  1723  	expectedSummary := &structs.JobSummary{
  1724  		JobID: alloc.JobID,
  1725  		Summary: map[string]structs.TaskGroupSummary{
  1726  			"web": structs.TaskGroupSummary{
  1727  				Starting: 1,
  1728  			},
  1729  		},
  1730  		CreateIndex: 999,
  1731  		ModifyIndex: 1001,
  1732  	}
  1733  	if err != nil {
  1734  		t.Fatalf("err: %v", err)
  1735  	}
  1736  	if !reflect.DeepEqual(summary, expectedSummary) {
  1737  		t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary)
  1738  	}
  1739  }
  1740  
  1741  func TestStateStore_UpsertAlloc_Alloc(t *testing.T) {
  1742  	state := testStateStore(t)
  1743  	alloc := mock.Alloc()
  1744  
  1745  	notify := setupNotifyTest(
  1746  		state,
  1747  		watch.Item{Table: "allocs"},
  1748  		watch.Item{Alloc: alloc.ID},
  1749  		watch.Item{AllocEval: alloc.EvalID},
  1750  		watch.Item{AllocJob: alloc.JobID},
  1751  		watch.Item{AllocNode: alloc.NodeID})
  1752  
  1753  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1754  		t.Fatalf("err: %v", err)
  1755  	}
  1756  
  1757  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1758  	if err != nil {
  1759  		t.Fatalf("err: %v", err)
  1760  	}
  1761  
  1762  	out, err := state.AllocByID(alloc.ID)
  1763  	if err != nil {
  1764  		t.Fatalf("err: %v", err)
  1765  	}
  1766  
  1767  	if !reflect.DeepEqual(alloc, out) {
  1768  		t.Fatalf("bad: %#v %#v", alloc, out)
  1769  	}
  1770  
  1771  	index, err := state.Index("allocs")
  1772  	if err != nil {
  1773  		t.Fatalf("err: %v", err)
  1774  	}
  1775  	if index != 1000 {
  1776  		t.Fatalf("bad: %d", index)
  1777  	}
  1778  
  1779  	summary, err := state.JobSummaryByID(alloc.JobID)
  1780  	if err != nil {
  1781  		t.Fatalf("err: %v", err)
  1782  	}
  1783  
  1784  	tgSummary, ok := summary.Summary["web"]
  1785  	if !ok {
  1786  		t.Fatalf("no summary for task group web")
  1787  	}
  1788  	if tgSummary.Starting != 1 {
  1789  		t.Fatalf("expected queued: %v, actual: %v", 1, tgSummary.Starting)
  1790  	}
  1791  
  1792  	notify.verify(t)
  1793  }
  1794  
  1795  func TestStateStore_UpsertAlloc_NoEphemeralDisk(t *testing.T) {
  1796  	state := testStateStore(t)
  1797  	alloc := mock.Alloc()
  1798  	alloc.Job.TaskGroups[0].EphemeralDisk = nil
  1799  	alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120
  1800  
  1801  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1802  		t.Fatalf("err: %v", err)
  1803  	}
  1804  
  1805  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1806  	if err != nil {
  1807  		t.Fatalf("err: %v", err)
  1808  	}
  1809  
  1810  	out, err := state.AllocByID(alloc.ID)
  1811  	if err != nil {
  1812  		t.Fatalf("err: %v", err)
  1813  	}
  1814  
  1815  	expected := alloc.Copy()
  1816  	expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120}
  1817  	if !reflect.DeepEqual(expected, out) {
  1818  		t.Fatalf("bad: %#v %#v", expected, out)
  1819  	}
  1820  }
  1821  
  1822  func TestStateStore_UpdateAlloc_Alloc(t *testing.T) {
  1823  	state := testStateStore(t)
  1824  	alloc := mock.Alloc()
  1825  
  1826  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1827  		t.Fatalf("err: %v", err)
  1828  	}
  1829  
  1830  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1831  	if err != nil {
  1832  		t.Fatalf("err: %v", err)
  1833  	}
  1834  
  1835  	summary, err := state.JobSummaryByID(alloc.JobID)
  1836  	if err != nil {
  1837  		t.Fatalf("err: %v", err)
  1838  	}
  1839  	tgSummary := summary.Summary["web"]
  1840  	if tgSummary.Starting != 1 {
  1841  		t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting)
  1842  	}
  1843  
  1844  	alloc2 := mock.Alloc()
  1845  	alloc2.ID = alloc.ID
  1846  	alloc2.NodeID = alloc.NodeID + ".new"
  1847  	state.UpsertJobSummary(1001, mock.JobSummary(alloc2.JobID))
  1848  
  1849  	notify := setupNotifyTest(
  1850  		state,
  1851  		watch.Item{Table: "allocs"},
  1852  		watch.Item{Alloc: alloc2.ID},
  1853  		watch.Item{AllocEval: alloc2.EvalID},
  1854  		watch.Item{AllocJob: alloc2.JobID},
  1855  		watch.Item{AllocNode: alloc2.NodeID})
  1856  
  1857  	err = state.UpsertAllocs(1002, []*structs.Allocation{alloc2})
  1858  	if err != nil {
  1859  		t.Fatalf("err: %v", err)
  1860  	}
  1861  
  1862  	out, err := state.AllocByID(alloc.ID)
  1863  	if err != nil {
  1864  		t.Fatalf("err: %v", err)
  1865  	}
  1866  
  1867  	if !reflect.DeepEqual(alloc2, out) {
  1868  		t.Fatalf("bad: %#v %#v", alloc2, out)
  1869  	}
  1870  
  1871  	if out.CreateIndex != 1000 {
  1872  		t.Fatalf("bad: %#v", out)
  1873  	}
  1874  	if out.ModifyIndex != 1002 {
  1875  		t.Fatalf("bad: %#v", out)
  1876  	}
  1877  
  1878  	index, err := state.Index("allocs")
  1879  	if err != nil {
  1880  		t.Fatalf("err: %v", err)
  1881  	}
  1882  	if index != 1002 {
  1883  		t.Fatalf("bad: %d", index)
  1884  	}
  1885  
  1886  	// Ensure that summary hasb't changed
  1887  	summary, err = state.JobSummaryByID(alloc.JobID)
  1888  	if err != nil {
  1889  		t.Fatalf("err: %v", err)
  1890  	}
  1891  	tgSummary = summary.Summary["web"]
  1892  	if tgSummary.Starting != 1 {
  1893  		t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting)
  1894  	}
  1895  
  1896  	notify.verify(t)
  1897  }
  1898  
  1899  // This test ensures that the state store will mark the clients status as lost
  1900  // when set rather than preferring the existing status.
  1901  func TestStateStore_UpdateAlloc_Lost(t *testing.T) {
  1902  	state := testStateStore(t)
  1903  	alloc := mock.Alloc()
  1904  	alloc.ClientStatus = "foo"
  1905  
  1906  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1907  		t.Fatalf("err: %v", err)
  1908  	}
  1909  
  1910  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1911  	if err != nil {
  1912  		t.Fatalf("err: %v", err)
  1913  	}
  1914  
  1915  	alloc2 := new(structs.Allocation)
  1916  	*alloc2 = *alloc
  1917  	alloc2.ClientStatus = structs.AllocClientStatusLost
  1918  	if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc2}); err != nil {
  1919  		t.Fatalf("err: %v", err)
  1920  	}
  1921  
  1922  	out, err := state.AllocByID(alloc2.ID)
  1923  	if err != nil {
  1924  		t.Fatalf("err: %v", err)
  1925  	}
  1926  
  1927  	if out.ClientStatus != structs.AllocClientStatusLost {
  1928  		t.Fatalf("bad: %#v", out)
  1929  	}
  1930  }
  1931  
  1932  // This test ensures an allocation can be updated when there is no job
  1933  // associated with it. This will happen when a job is stopped by an user which
  1934  // has non-terminal allocations on clients
  1935  func TestStateStore_UpdateAlloc_NoJob(t *testing.T) {
  1936  	state := testStateStore(t)
  1937  	alloc := mock.Alloc()
  1938  
  1939  	// Upsert a job
  1940  	state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID))
  1941  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1942  		t.Fatalf("err: %v", err)
  1943  	}
  1944  
  1945  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1946  	if err != nil {
  1947  		t.Fatalf("err: %v", err)
  1948  	}
  1949  
  1950  	if err := state.DeleteJob(1001, alloc.JobID); err != nil {
  1951  		t.Fatalf("err: %v", err)
  1952  	}
  1953  
  1954  	// Update the desired state of the allocation to stop
  1955  	allocCopy := alloc.Copy()
  1956  	allocCopy.DesiredStatus = structs.AllocDesiredStatusStop
  1957  	if err := state.UpsertAllocs(1002, []*structs.Allocation{allocCopy}); err != nil {
  1958  		t.Fatalf("err: %v", err)
  1959  	}
  1960  
  1961  	// Update the client state of the allocation to complete
  1962  	allocCopy1 := allocCopy.Copy()
  1963  	allocCopy1.ClientStatus = structs.AllocClientStatusComplete
  1964  	if err := state.UpdateAllocsFromClient(1003, []*structs.Allocation{allocCopy1}); err != nil {
  1965  		t.Fatalf("err: %v", err)
  1966  	}
  1967  
  1968  	out, _ := state.AllocByID(alloc.ID)
  1969  	// Update the modify index of the alloc before comparing
  1970  	allocCopy1.ModifyIndex = 1003
  1971  	if !reflect.DeepEqual(out, allocCopy1) {
  1972  		t.Fatalf("expected: %#v \n actual: %#v", allocCopy1, out)
  1973  	}
  1974  }
  1975  
  1976  func TestStateStore_JobSummary(t *testing.T) {
  1977  	state := testStateStore(t)
  1978  
  1979  	// Add a job
  1980  	job := mock.Job()
  1981  	state.UpsertJob(900, job)
  1982  
  1983  	// Get the job back
  1984  	outJob, _ := state.JobByID(job.ID)
  1985  	if outJob.CreateIndex != 900 {
  1986  		t.Fatalf("bad create index: %v", outJob.CreateIndex)
  1987  	}
  1988  	summary, _ := state.JobSummaryByID(job.ID)
  1989  	if summary.CreateIndex != 900 {
  1990  		t.Fatalf("bad create index: %v", summary.CreateIndex)
  1991  	}
  1992  
  1993  	// Upser an allocation
  1994  	alloc := mock.Alloc()
  1995  	alloc.JobID = job.ID
  1996  	alloc.Job = job
  1997  	state.UpsertAllocs(910, []*structs.Allocation{alloc})
  1998  
  1999  	// Update the alloc from client
  2000  	alloc1 := alloc.Copy()
  2001  	alloc1.ClientStatus = structs.AllocClientStatusPending
  2002  	alloc1.DesiredStatus = ""
  2003  	state.UpdateAllocsFromClient(920, []*structs.Allocation{alloc})
  2004  
  2005  	alloc3 := alloc.Copy()
  2006  	alloc3.ClientStatus = structs.AllocClientStatusRunning
  2007  	alloc3.DesiredStatus = ""
  2008  	state.UpdateAllocsFromClient(930, []*structs.Allocation{alloc3})
  2009  
  2010  	// Upsert the alloc
  2011  	alloc4 := alloc.Copy()
  2012  	alloc4.ClientStatus = structs.AllocClientStatusPending
  2013  	alloc4.DesiredStatus = structs.AllocDesiredStatusRun
  2014  	state.UpsertAllocs(950, []*structs.Allocation{alloc4})
  2015  
  2016  	// Again upsert the alloc
  2017  	alloc5 := alloc.Copy()
  2018  	alloc5.ClientStatus = structs.AllocClientStatusPending
  2019  	alloc5.DesiredStatus = structs.AllocDesiredStatusRun
  2020  	state.UpsertAllocs(970, []*structs.Allocation{alloc5})
  2021  
  2022  	expectedSummary := structs.JobSummary{
  2023  		JobID: job.ID,
  2024  		Summary: map[string]structs.TaskGroupSummary{
  2025  			"web": structs.TaskGroupSummary{
  2026  				Running: 1,
  2027  			},
  2028  		},
  2029  		CreateIndex: 900,
  2030  		ModifyIndex: 930,
  2031  	}
  2032  
  2033  	summary, _ = state.JobSummaryByID(job.ID)
  2034  	if !reflect.DeepEqual(&expectedSummary, summary) {
  2035  		t.Fatalf("expected: %#v, actual: %v", expectedSummary, summary)
  2036  	}
  2037  
  2038  	// De-register the job.
  2039  	state.DeleteJob(980, job.ID)
  2040  
  2041  	// Shouldn't have any effect on the summary
  2042  	alloc6 := alloc.Copy()
  2043  	alloc6.ClientStatus = structs.AllocClientStatusRunning
  2044  	alloc6.DesiredStatus = ""
  2045  	state.UpdateAllocsFromClient(990, []*structs.Allocation{alloc6})
  2046  
  2047  	// We shouldn't have any summary at this point
  2048  	summary, _ = state.JobSummaryByID(job.ID)
  2049  	if summary != nil {
  2050  		t.Fatalf("expected nil, actual: %#v", summary)
  2051  	}
  2052  
  2053  	// Re-register the same job
  2054  	job1 := mock.Job()
  2055  	job1.ID = job.ID
  2056  	state.UpsertJob(1000, job1)
  2057  	outJob2, _ := state.JobByID(job1.ID)
  2058  	if outJob2.CreateIndex != 1000 {
  2059  		t.Fatalf("bad create index: %v", outJob2.CreateIndex)
  2060  	}
  2061  	summary, _ = state.JobSummaryByID(job1.ID)
  2062  	if summary.CreateIndex != 1000 {
  2063  		t.Fatalf("bad create index: %v", summary.CreateIndex)
  2064  	}
  2065  
  2066  	// Upsert an allocation
  2067  	alloc7 := alloc.Copy()
  2068  	alloc7.JobID = outJob.ID
  2069  	alloc7.Job = outJob
  2070  	alloc7.ClientStatus = structs.AllocClientStatusComplete
  2071  	alloc7.DesiredStatus = structs.AllocDesiredStatusRun
  2072  	state.UpdateAllocsFromClient(1020, []*structs.Allocation{alloc7})
  2073  
  2074  	expectedSummary = structs.JobSummary{
  2075  		JobID: job.ID,
  2076  		Summary: map[string]structs.TaskGroupSummary{
  2077  			"web": structs.TaskGroupSummary{},
  2078  		},
  2079  		CreateIndex: 1000,
  2080  		ModifyIndex: 1000,
  2081  	}
  2082  
  2083  	summary, _ = state.JobSummaryByID(job1.ID)
  2084  	if !reflect.DeepEqual(&expectedSummary, summary) {
  2085  		t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary)
  2086  	}
  2087  }
  2088  
  2089  func TestStateStore_ReconcileJobSummary(t *testing.T) {
  2090  	state := testStateStore(t)
  2091  
  2092  	// Create an alloc
  2093  	alloc := mock.Alloc()
  2094  
  2095  	// Add another task group to the job
  2096  	tg2 := alloc.Job.TaskGroups[0].Copy()
  2097  	tg2.Name = "db"
  2098  	alloc.Job.TaskGroups = append(alloc.Job.TaskGroups, tg2)
  2099  	state.UpsertJob(100, alloc.Job)
  2100  
  2101  	// Create one more alloc for the db task group
  2102  	alloc2 := mock.Alloc()
  2103  	alloc2.TaskGroup = "db"
  2104  	alloc2.JobID = alloc.JobID
  2105  	alloc2.Job = alloc.Job
  2106  
  2107  	// Upserts the alloc
  2108  	state.UpsertAllocs(110, []*structs.Allocation{alloc, alloc2})
  2109  
  2110  	// Change the state of the first alloc to running
  2111  	alloc3 := alloc.Copy()
  2112  	alloc3.ClientStatus = structs.AllocClientStatusRunning
  2113  	state.UpdateAllocsFromClient(120, []*structs.Allocation{alloc3})
  2114  
  2115  	//Add some more allocs to the second tg
  2116  	alloc4 := mock.Alloc()
  2117  	alloc4.JobID = alloc.JobID
  2118  	alloc4.Job = alloc.Job
  2119  	alloc4.TaskGroup = "db"
  2120  	alloc5 := alloc4.Copy()
  2121  	alloc5.ClientStatus = structs.AllocClientStatusRunning
  2122  
  2123  	alloc6 := mock.Alloc()
  2124  	alloc6.JobID = alloc.JobID
  2125  	alloc6.Job = alloc.Job
  2126  	alloc6.TaskGroup = "db"
  2127  	alloc7 := alloc6.Copy()
  2128  	alloc7.ClientStatus = structs.AllocClientStatusComplete
  2129  
  2130  	alloc8 := mock.Alloc()
  2131  	alloc8.JobID = alloc.JobID
  2132  	alloc8.Job = alloc.Job
  2133  	alloc8.TaskGroup = "db"
  2134  	alloc9 := alloc8.Copy()
  2135  	alloc9.ClientStatus = structs.AllocClientStatusFailed
  2136  
  2137  	alloc10 := mock.Alloc()
  2138  	alloc10.JobID = alloc.JobID
  2139  	alloc10.Job = alloc.Job
  2140  	alloc10.TaskGroup = "db"
  2141  	alloc11 := alloc10.Copy()
  2142  	alloc11.ClientStatus = structs.AllocClientStatusLost
  2143  
  2144  	state.UpsertAllocs(130, []*structs.Allocation{alloc4, alloc6, alloc8, alloc10})
  2145  
  2146  	state.UpdateAllocsFromClient(150, []*structs.Allocation{alloc5, alloc7, alloc9, alloc11})
  2147  
  2148  	// DeleteJobSummary is a helper method and doesn't modify the indexes table
  2149  	state.DeleteJobSummary(130, alloc.Job.ID)
  2150  
  2151  	state.ReconcileJobSummaries(120)
  2152  
  2153  	summary, _ := state.JobSummaryByID(alloc.Job.ID)
  2154  	expectedSummary := structs.JobSummary{
  2155  		JobID: alloc.Job.ID,
  2156  		Summary: map[string]structs.TaskGroupSummary{
  2157  			"web": structs.TaskGroupSummary{
  2158  				Running: 1,
  2159  			},
  2160  			"db": structs.TaskGroupSummary{
  2161  				Starting: 1,
  2162  				Running:  1,
  2163  				Failed:   1,
  2164  				Complete: 1,
  2165  				Lost:     1,
  2166  			},
  2167  		},
  2168  		CreateIndex: 100,
  2169  		ModifyIndex: 120,
  2170  	}
  2171  	if !reflect.DeepEqual(&expectedSummary, summary) {
  2172  		t.Fatalf("expected: %v, actual: %v", expectedSummary, summary)
  2173  	}
  2174  }
  2175  
  2176  func TestStateStore_UpdateAlloc_JobNotPresent(t *testing.T) {
  2177  	state := testStateStore(t)
  2178  
  2179  	alloc := mock.Alloc()
  2180  	state.UpsertJob(100, alloc.Job)
  2181  	state.UpsertAllocs(200, []*structs.Allocation{alloc})
  2182  
  2183  	// Delete the job
  2184  	state.DeleteJob(300, alloc.Job.ID)
  2185  
  2186  	// Update the alloc
  2187  	alloc1 := alloc.Copy()
  2188  	alloc1.ClientStatus = structs.AllocClientStatusRunning
  2189  
  2190  	// Updating allocation should not throw any error
  2191  	if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil {
  2192  		t.Fatalf("expect err: %v", err)
  2193  	}
  2194  
  2195  	// Re-Register the job
  2196  	state.UpsertJob(500, alloc.Job)
  2197  
  2198  	// Update the alloc again
  2199  	alloc2 := alloc.Copy()
  2200  	alloc2.ClientStatus = structs.AllocClientStatusComplete
  2201  	if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil {
  2202  		t.Fatalf("expect err: %v", err)
  2203  	}
  2204  
  2205  	// Job Summary of the newly registered job shouldn't account for the
  2206  	// allocation update for the older job
  2207  	expectedSummary := structs.JobSummary{
  2208  		JobID: alloc1.JobID,
  2209  		Summary: map[string]structs.TaskGroupSummary{
  2210  			"web": structs.TaskGroupSummary{},
  2211  		},
  2212  		CreateIndex: 500,
  2213  		ModifyIndex: 500,
  2214  	}
  2215  	summary, _ := state.JobSummaryByID(alloc.Job.ID)
  2216  	if !reflect.DeepEqual(&expectedSummary, summary) {
  2217  		t.Fatalf("expected: %v, actual: %v", expectedSummary, summary)
  2218  	}
  2219  }
  2220  
  2221  func TestStateStore_EvictAlloc_Alloc(t *testing.T) {
  2222  	state := testStateStore(t)
  2223  	alloc := mock.Alloc()
  2224  
  2225  	state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))
  2226  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  2227  	if err != nil {
  2228  		t.Fatalf("err: %v", err)
  2229  	}
  2230  
  2231  	alloc2 := new(structs.Allocation)
  2232  	*alloc2 = *alloc
  2233  	alloc2.DesiredStatus = structs.AllocDesiredStatusEvict
  2234  	err = state.UpsertAllocs(1001, []*structs.Allocation{alloc2})
  2235  	if err != nil {
  2236  		t.Fatalf("err: %v", err)
  2237  	}
  2238  
  2239  	out, err := state.AllocByID(alloc.ID)
  2240  	if err != nil {
  2241  		t.Fatalf("err: %v", err)
  2242  	}
  2243  
  2244  	if out.DesiredStatus != structs.AllocDesiredStatusEvict {
  2245  		t.Fatalf("bad: %#v %#v", alloc, out)
  2246  	}
  2247  
  2248  	index, err := state.Index("allocs")
  2249  	if err != nil {
  2250  		t.Fatalf("err: %v", err)
  2251  	}
  2252  	if index != 1001 {
  2253  		t.Fatalf("bad: %d", index)
  2254  	}
  2255  }
  2256  
  2257  func TestStateStore_AllocsByNode(t *testing.T) {
  2258  	state := testStateStore(t)
  2259  	var allocs []*structs.Allocation
  2260  
  2261  	for i := 0; i < 10; i++ {
  2262  		alloc := mock.Alloc()
  2263  		alloc.NodeID = "foo"
  2264  		allocs = append(allocs, alloc)
  2265  	}
  2266  
  2267  	for idx, alloc := range allocs {
  2268  		state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID))
  2269  	}
  2270  
  2271  	err := state.UpsertAllocs(1000, allocs)
  2272  	if err != nil {
  2273  		t.Fatalf("err: %v", err)
  2274  	}
  2275  
  2276  	out, err := state.AllocsByNode("foo")
  2277  	if err != nil {
  2278  		t.Fatalf("err: %v", err)
  2279  	}
  2280  
  2281  	sort.Sort(AllocIDSort(allocs))
  2282  	sort.Sort(AllocIDSort(out))
  2283  
  2284  	if !reflect.DeepEqual(allocs, out) {
  2285  		t.Fatalf("bad: %#v %#v", allocs, out)
  2286  	}
  2287  }
  2288  
  2289  func TestStateStore_AllocsByNodeTerminal(t *testing.T) {
  2290  	state := testStateStore(t)
  2291  	var allocs, term, nonterm []*structs.Allocation
  2292  
  2293  	for i := 0; i < 10; i++ {
  2294  		alloc := mock.Alloc()
  2295  		alloc.NodeID = "foo"
  2296  		if i%2 == 0 {
  2297  			alloc.DesiredStatus = structs.AllocDesiredStatusStop
  2298  			term = append(term, alloc)
  2299  		} else {
  2300  			nonterm = append(nonterm, alloc)
  2301  		}
  2302  		allocs = append(allocs, alloc)
  2303  	}
  2304  
  2305  	for idx, alloc := range allocs {
  2306  		state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID))
  2307  	}
  2308  
  2309  	err := state.UpsertAllocs(1000, allocs)
  2310  	if err != nil {
  2311  		t.Fatalf("err: %v", err)
  2312  	}
  2313  
  2314  	// Verify the terminal allocs
  2315  	out, err := state.AllocsByNodeTerminal("foo", true)
  2316  	if err != nil {
  2317  		t.Fatalf("err: %v", err)
  2318  	}
  2319  
  2320  	sort.Sort(AllocIDSort(term))
  2321  	sort.Sort(AllocIDSort(out))
  2322  
  2323  	if !reflect.DeepEqual(term, out) {
  2324  		t.Fatalf("bad: %#v %#v", term, out)
  2325  	}
  2326  
  2327  	// Verify the non-terminal allocs
  2328  	out, err = state.AllocsByNodeTerminal("foo", false)
  2329  	if err != nil {
  2330  		t.Fatalf("err: %v", err)
  2331  	}
  2332  
  2333  	sort.Sort(AllocIDSort(nonterm))
  2334  	sort.Sort(AllocIDSort(out))
  2335  
  2336  	if !reflect.DeepEqual(nonterm, out) {
  2337  		t.Fatalf("bad: %#v %#v", nonterm, out)
  2338  	}
  2339  }
  2340  
  2341  func TestStateStore_AllocsByJob(t *testing.T) {
  2342  	state := testStateStore(t)
  2343  	var allocs []*structs.Allocation
  2344  
  2345  	for i := 0; i < 10; i++ {
  2346  		alloc := mock.Alloc()
  2347  		alloc.JobID = "foo"
  2348  		allocs = append(allocs, alloc)
  2349  	}
  2350  
  2351  	for i, alloc := range allocs {
  2352  		state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID))
  2353  	}
  2354  
  2355  	err := state.UpsertAllocs(1000, allocs)
  2356  	if err != nil {
  2357  		t.Fatalf("err: %v", err)
  2358  	}
  2359  
  2360  	out, err := state.AllocsByJob("foo")
  2361  	if err != nil {
  2362  		t.Fatalf("err: %v", err)
  2363  	}
  2364  
  2365  	sort.Sort(AllocIDSort(allocs))
  2366  	sort.Sort(AllocIDSort(out))
  2367  
  2368  	if !reflect.DeepEqual(allocs, out) {
  2369  		t.Fatalf("bad: %#v %#v", allocs, out)
  2370  	}
  2371  }
  2372  
  2373  func TestStateStore_AllocsByIDPrefix(t *testing.T) {
  2374  	state := testStateStore(t)
  2375  	var allocs []*structs.Allocation
  2376  
  2377  	ids := []string{
  2378  		"aaaaaaaa-7bfb-395d-eb95-0685af2176b2",
  2379  		"aaaaaaab-7bfb-395d-eb95-0685af2176b2",
  2380  		"aaaaaabb-7bfb-395d-eb95-0685af2176b2",
  2381  		"aaaaabbb-7bfb-395d-eb95-0685af2176b2",
  2382  		"aaaabbbb-7bfb-395d-eb95-0685af2176b2",
  2383  		"aaabbbbb-7bfb-395d-eb95-0685af2176b2",
  2384  		"aabbbbbb-7bfb-395d-eb95-0685af2176b2",
  2385  		"abbbbbbb-7bfb-395d-eb95-0685af2176b2",
  2386  		"bbbbbbbb-7bfb-395d-eb95-0685af2176b2",
  2387  	}
  2388  	for i := 0; i < 9; i++ {
  2389  		alloc := mock.Alloc()
  2390  		alloc.ID = ids[i]
  2391  		allocs = append(allocs, alloc)
  2392  	}
  2393  
  2394  	for i, alloc := range allocs {
  2395  		state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID))
  2396  	}
  2397  
  2398  	err := state.UpsertAllocs(1000, allocs)
  2399  	if err != nil {
  2400  		t.Fatalf("err: %v", err)
  2401  	}
  2402  
  2403  	iter, err := state.AllocsByIDPrefix("aaaa")
  2404  	if err != nil {
  2405  		t.Fatalf("err: %v", err)
  2406  	}
  2407  
  2408  	gatherAllocs := func(iter memdb.ResultIterator) []*structs.Allocation {
  2409  		var allocs []*structs.Allocation
  2410  		for {
  2411  			raw := iter.Next()
  2412  			if raw == nil {
  2413  				break
  2414  			}
  2415  			allocs = append(allocs, raw.(*structs.Allocation))
  2416  		}
  2417  		return allocs
  2418  	}
  2419  
  2420  	out := gatherAllocs(iter)
  2421  	if len(out) != 5 {
  2422  		t.Fatalf("bad: expected five allocations, got: %#v", out)
  2423  	}
  2424  
  2425  	sort.Sort(AllocIDSort(allocs))
  2426  
  2427  	for index, alloc := range out {
  2428  		if ids[index] != alloc.ID {
  2429  			t.Fatalf("bad: got unexpected id: %s", alloc.ID)
  2430  		}
  2431  	}
  2432  
  2433  	iter, err = state.AllocsByIDPrefix("b-a7bfb")
  2434  	if err != nil {
  2435  		t.Fatalf("err: %v", err)
  2436  	}
  2437  
  2438  	out = gatherAllocs(iter)
  2439  	if len(out) != 0 {
  2440  		t.Fatalf("bad: unexpected zero allocations, got: %#v", out)
  2441  	}
  2442  }
  2443  
  2444  func TestStateStore_Allocs(t *testing.T) {
  2445  	state := testStateStore(t)
  2446  	var allocs []*structs.Allocation
  2447  
  2448  	for i := 0; i < 10; i++ {
  2449  		alloc := mock.Alloc()
  2450  		allocs = append(allocs, alloc)
  2451  	}
  2452  	for i, alloc := range allocs {
  2453  		state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID))
  2454  	}
  2455  
  2456  	err := state.UpsertAllocs(1000, allocs)
  2457  	if err != nil {
  2458  		t.Fatalf("err: %v", err)
  2459  	}
  2460  
  2461  	iter, err := state.Allocs()
  2462  	if err != nil {
  2463  		t.Fatalf("err: %v", err)
  2464  	}
  2465  
  2466  	var out []*structs.Allocation
  2467  	for {
  2468  		raw := iter.Next()
  2469  		if raw == nil {
  2470  			break
  2471  		}
  2472  		out = append(out, raw.(*structs.Allocation))
  2473  	}
  2474  
  2475  	sort.Sort(AllocIDSort(allocs))
  2476  	sort.Sort(AllocIDSort(out))
  2477  
  2478  	if !reflect.DeepEqual(allocs, out) {
  2479  		t.Fatalf("bad: %#v %#v", allocs, out)
  2480  	}
  2481  }
  2482  
  2483  func TestStateStore_RestoreAlloc(t *testing.T) {
  2484  	state := testStateStore(t)
  2485  	alloc := mock.Alloc()
  2486  
  2487  	notify := setupNotifyTest(
  2488  		state,
  2489  		watch.Item{Table: "allocs"},
  2490  		watch.Item{Alloc: alloc.ID},
  2491  		watch.Item{AllocEval: alloc.EvalID},
  2492  		watch.Item{AllocJob: alloc.JobID},
  2493  		watch.Item{AllocNode: alloc.NodeID})
  2494  
  2495  	restore, err := state.Restore()
  2496  	if err != nil {
  2497  		t.Fatalf("err: %v", err)
  2498  	}
  2499  
  2500  	err = restore.AllocRestore(alloc)
  2501  	if err != nil {
  2502  		t.Fatalf("err: %v", err)
  2503  	}
  2504  
  2505  	restore.Commit()
  2506  
  2507  	out, err := state.AllocByID(alloc.ID)
  2508  	if err != nil {
  2509  		t.Fatalf("err: %v", err)
  2510  	}
  2511  
  2512  	if !reflect.DeepEqual(out, alloc) {
  2513  		t.Fatalf("Bad: %#v %#v", out, alloc)
  2514  	}
  2515  
  2516  	notify.verify(t)
  2517  }
  2518  
  2519  func TestStateStore_RestoreAlloc_NoEphemeralDisk(t *testing.T) {
  2520  	state := testStateStore(t)
  2521  	alloc := mock.Alloc()
  2522  	alloc.Job.TaskGroups[0].EphemeralDisk = nil
  2523  	alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120
  2524  
  2525  	restore, err := state.Restore()
  2526  	if err != nil {
  2527  		t.Fatalf("err: %v", err)
  2528  	}
  2529  
  2530  	err = restore.AllocRestore(alloc)
  2531  	if err != nil {
  2532  		t.Fatalf("err: %v", err)
  2533  	}
  2534  
  2535  	restore.Commit()
  2536  
  2537  	out, err := state.AllocByID(alloc.ID)
  2538  	if err != nil {
  2539  		t.Fatalf("err: %v", err)
  2540  	}
  2541  
  2542  	expected := alloc.Copy()
  2543  	expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120}
  2544  	expected.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 0
  2545  
  2546  	if !reflect.DeepEqual(out, expected) {
  2547  		t.Fatalf("Bad: %#v %#v", out, expected)
  2548  	}
  2549  }
  2550  
  2551  func TestStateStore_SetJobStatus_ForceStatus(t *testing.T) {
  2552  	state := testStateStore(t)
  2553  	watcher := watch.NewItems()
  2554  	txn := state.db.Txn(true)
  2555  
  2556  	// Create and insert a mock job.
  2557  	job := mock.Job()
  2558  	job.Status = ""
  2559  	job.ModifyIndex = 0
  2560  	if err := txn.Insert("jobs", job); err != nil {
  2561  		t.Fatalf("job insert failed: %v", err)
  2562  	}
  2563  
  2564  	exp := "foobar"
  2565  	index := uint64(1000)
  2566  	if err := state.setJobStatus(index, watcher, txn, job, false, exp); err != nil {
  2567  		t.Fatalf("setJobStatus() failed: %v", err)
  2568  	}
  2569  
  2570  	i, err := txn.First("jobs", "id", job.ID)
  2571  	if err != nil {
  2572  		t.Fatalf("job lookup failed: %v", err)
  2573  	}
  2574  	updated := i.(*structs.Job)
  2575  
  2576  	if updated.Status != exp {
  2577  		t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, exp)
  2578  	}
  2579  
  2580  	if updated.ModifyIndex != index {
  2581  		t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index)
  2582  	}
  2583  }
  2584  
  2585  func TestStateStore_SetJobStatus_NoOp(t *testing.T) {
  2586  	state := testStateStore(t)
  2587  	watcher := watch.NewItems()
  2588  	txn := state.db.Txn(true)
  2589  
  2590  	// Create and insert a mock job that should be pending.
  2591  	job := mock.Job()
  2592  	job.Status = structs.JobStatusPending
  2593  	job.ModifyIndex = 10
  2594  	if err := txn.Insert("jobs", job); err != nil {
  2595  		t.Fatalf("job insert failed: %v", err)
  2596  	}
  2597  
  2598  	index := uint64(1000)
  2599  	if err := state.setJobStatus(index, watcher, txn, job, false, ""); err != nil {
  2600  		t.Fatalf("setJobStatus() failed: %v", err)
  2601  	}
  2602  
  2603  	i, err := txn.First("jobs", "id", job.ID)
  2604  	if err != nil {
  2605  		t.Fatalf("job lookup failed: %v", err)
  2606  	}
  2607  	updated := i.(*structs.Job)
  2608  
  2609  	if updated.ModifyIndex == index {
  2610  		t.Fatalf("setJobStatus() should have been a no-op")
  2611  	}
  2612  }
  2613  
  2614  func TestStateStore_SetJobStatus(t *testing.T) {
  2615  	state := testStateStore(t)
  2616  	watcher := watch.NewItems()
  2617  	txn := state.db.Txn(true)
  2618  
  2619  	// Create and insert a mock job that should be pending but has an incorrect
  2620  	// status.
  2621  	job := mock.Job()
  2622  	job.Status = "foobar"
  2623  	job.ModifyIndex = 10
  2624  	if err := txn.Insert("jobs", job); err != nil {
  2625  		t.Fatalf("job insert failed: %v", err)
  2626  	}
  2627  
  2628  	index := uint64(1000)
  2629  	if err := state.setJobStatus(index, watcher, txn, job, false, ""); err != nil {
  2630  		t.Fatalf("setJobStatus() failed: %v", err)
  2631  	}
  2632  
  2633  	i, err := txn.First("jobs", "id", job.ID)
  2634  	if err != nil {
  2635  		t.Fatalf("job lookup failed: %v", err)
  2636  	}
  2637  	updated := i.(*structs.Job)
  2638  
  2639  	if updated.Status != structs.JobStatusPending {
  2640  		t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, structs.JobStatusPending)
  2641  	}
  2642  
  2643  	if updated.ModifyIndex != index {
  2644  		t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index)
  2645  	}
  2646  }
  2647  
  2648  func TestStateStore_GetJobStatus_NoEvalsOrAllocs(t *testing.T) {
  2649  	job := mock.Job()
  2650  	state := testStateStore(t)
  2651  	txn := state.db.Txn(false)
  2652  	status, err := state.getJobStatus(txn, job, false)
  2653  	if err != nil {
  2654  		t.Fatalf("getJobStatus() failed: %v", err)
  2655  	}
  2656  
  2657  	if status != structs.JobStatusPending {
  2658  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending)
  2659  	}
  2660  }
  2661  
  2662  func TestStateStore_GetJobStatus_NoEvalsOrAllocs_Periodic(t *testing.T) {
  2663  	job := mock.PeriodicJob()
  2664  	state := testStateStore(t)
  2665  	txn := state.db.Txn(false)
  2666  	status, err := state.getJobStatus(txn, job, false)
  2667  	if err != nil {
  2668  		t.Fatalf("getJobStatus() failed: %v", err)
  2669  	}
  2670  
  2671  	if status != structs.JobStatusRunning {
  2672  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning)
  2673  	}
  2674  }
  2675  
  2676  func TestStateStore_GetJobStatus_NoEvalsOrAllocs_EvalDelete(t *testing.T) {
  2677  	job := mock.Job()
  2678  	state := testStateStore(t)
  2679  	txn := state.db.Txn(false)
  2680  	status, err := state.getJobStatus(txn, job, true)
  2681  	if err != nil {
  2682  		t.Fatalf("getJobStatus() failed: %v", err)
  2683  	}
  2684  
  2685  	if status != structs.JobStatusDead {
  2686  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead)
  2687  	}
  2688  }
  2689  
  2690  func TestStateStore_GetJobStatus_DeadEvalsAndAllocs(t *testing.T) {
  2691  	state := testStateStore(t)
  2692  	job := mock.Job()
  2693  
  2694  	// Create a mock alloc that is dead.
  2695  	alloc := mock.Alloc()
  2696  	alloc.JobID = job.ID
  2697  	alloc.DesiredStatus = structs.AllocDesiredStatusStop
  2698  	state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))
  2699  	if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil {
  2700  		t.Fatalf("err: %v", err)
  2701  	}
  2702  
  2703  	// Create a mock eval that is complete
  2704  	eval := mock.Eval()
  2705  	eval.JobID = job.ID
  2706  	eval.Status = structs.EvalStatusComplete
  2707  	if err := state.UpsertEvals(1001, []*structs.Evaluation{eval}); err != nil {
  2708  		t.Fatalf("err: %v", err)
  2709  	}
  2710  
  2711  	txn := state.db.Txn(false)
  2712  	status, err := state.getJobStatus(txn, job, false)
  2713  	if err != nil {
  2714  		t.Fatalf("getJobStatus() failed: %v", err)
  2715  	}
  2716  
  2717  	if status != structs.JobStatusDead {
  2718  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead)
  2719  	}
  2720  }
  2721  
  2722  func TestStateStore_GetJobStatus_RunningAlloc(t *testing.T) {
  2723  	state := testStateStore(t)
  2724  	job := mock.Job()
  2725  
  2726  	// Create a mock alloc that is running.
  2727  	alloc := mock.Alloc()
  2728  	alloc.JobID = job.ID
  2729  	alloc.DesiredStatus = structs.AllocDesiredStatusRun
  2730  	state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))
  2731  	if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil {
  2732  		t.Fatalf("err: %v", err)
  2733  	}
  2734  
  2735  	txn := state.db.Txn(false)
  2736  	status, err := state.getJobStatus(txn, job, true)
  2737  	if err != nil {
  2738  		t.Fatalf("getJobStatus() failed: %v", err)
  2739  	}
  2740  
  2741  	if status != structs.JobStatusRunning {
  2742  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning)
  2743  	}
  2744  }
  2745  
  2746  func TestStateStore_SetJobStatus_PendingEval(t *testing.T) {
  2747  	state := testStateStore(t)
  2748  	job := mock.Job()
  2749  
  2750  	// Create a mock eval that is pending.
  2751  	eval := mock.Eval()
  2752  	eval.JobID = job.ID
  2753  	eval.Status = structs.EvalStatusPending
  2754  	if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil {
  2755  		t.Fatalf("err: %v", err)
  2756  	}
  2757  
  2758  	txn := state.db.Txn(false)
  2759  	status, err := state.getJobStatus(txn, job, true)
  2760  	if err != nil {
  2761  		t.Fatalf("getJobStatus() failed: %v", err)
  2762  	}
  2763  
  2764  	if status != structs.JobStatusPending {
  2765  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending)
  2766  	}
  2767  }
  2768  
  2769  func TestStateWatch_watch(t *testing.T) {
  2770  	sw := newStateWatch()
  2771  	notify1 := make(chan struct{}, 1)
  2772  	notify2 := make(chan struct{}, 1)
  2773  	notify3 := make(chan struct{}, 1)
  2774  
  2775  	// Notifications trigger subscribed channels
  2776  	sw.watch(watch.NewItems(watch.Item{Table: "foo"}), notify1)
  2777  	sw.watch(watch.NewItems(watch.Item{Table: "bar"}), notify2)
  2778  	sw.watch(watch.NewItems(watch.Item{Table: "baz"}), notify3)
  2779  
  2780  	items := watch.NewItems()
  2781  	items.Add(watch.Item{Table: "foo"})
  2782  	items.Add(watch.Item{Table: "bar"})
  2783  
  2784  	sw.notify(items)
  2785  	if len(notify1) != 1 {
  2786  		t.Fatalf("should notify")
  2787  	}
  2788  	if len(notify2) != 1 {
  2789  		t.Fatalf("should notify")
  2790  	}
  2791  	if len(notify3) != 0 {
  2792  		t.Fatalf("should not notify")
  2793  	}
  2794  }
  2795  
  2796  func TestStateWatch_stopWatch(t *testing.T) {
  2797  	sw := newStateWatch()
  2798  	notify := make(chan struct{})
  2799  
  2800  	// First subscribe
  2801  	sw.watch(watch.NewItems(watch.Item{Table: "foo"}), notify)
  2802  
  2803  	// Unsubscribe stop notifications
  2804  	sw.stopWatch(watch.NewItems(watch.Item{Table: "foo"}), notify)
  2805  
  2806  	// Check that the group was removed
  2807  	if _, ok := sw.items[watch.Item{Table: "foo"}]; ok {
  2808  		t.Fatalf("should remove group")
  2809  	}
  2810  
  2811  	// Check that we are not notified
  2812  	sw.notify(watch.NewItems(watch.Item{Table: "foo"}))
  2813  	if len(notify) != 0 {
  2814  		t.Fatalf("should not notify")
  2815  	}
  2816  }
  2817  
  2818  func TestStateJobSummary_UpdateJobCount(t *testing.T) {
  2819  	state := testStateStore(t)
  2820  	alloc := mock.Alloc()
  2821  	job := alloc.Job
  2822  	job.TaskGroups[0].Count = 3
  2823  	err := state.UpsertJob(1000, job)
  2824  	if err != nil {
  2825  		t.Fatalf("err: %v", err)
  2826  	}
  2827  
  2828  	if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc}); err != nil {
  2829  		t.Fatalf("err: %v", err)
  2830  	}
  2831  	summary, _ := state.JobSummaryByID(job.ID)
  2832  	expectedSummary := structs.JobSummary{
  2833  		JobID: job.ID,
  2834  		Summary: map[string]structs.TaskGroupSummary{
  2835  			"web": {
  2836  				Starting: 1,
  2837  			},
  2838  		},
  2839  		CreateIndex: 1000,
  2840  		ModifyIndex: 1001,
  2841  	}
  2842  	if !reflect.DeepEqual(summary, &expectedSummary) {
  2843  		t.Fatalf("expected: %v, actual: %v", expectedSummary, summary)
  2844  	}
  2845  
  2846  	alloc2 := mock.Alloc()
  2847  	alloc2.Job = job
  2848  	alloc2.JobID = job.ID
  2849  
  2850  	alloc3 := mock.Alloc()
  2851  	alloc3.Job = job
  2852  	alloc3.JobID = job.ID
  2853  
  2854  	if err := state.UpsertAllocs(1002, []*structs.Allocation{alloc2, alloc3}); err != nil {
  2855  		t.Fatalf("err: %v", err)
  2856  	}
  2857  
  2858  	outA, _ := state.AllocByID(alloc3.ID)
  2859  
  2860  	summary, _ = state.JobSummaryByID(job.ID)
  2861  	expectedSummary = structs.JobSummary{
  2862  		JobID: job.ID,
  2863  		Summary: map[string]structs.TaskGroupSummary{
  2864  			"web": {
  2865  				Starting: 3,
  2866  			},
  2867  		},
  2868  		CreateIndex: job.CreateIndex,
  2869  		ModifyIndex: outA.ModifyIndex,
  2870  	}
  2871  	if !reflect.DeepEqual(summary, &expectedSummary) {
  2872  		t.Fatalf("expected summary: %v, actual: %v", expectedSummary, summary)
  2873  	}
  2874  
  2875  	alloc4 := mock.Alloc()
  2876  	alloc4.ID = alloc2.ID
  2877  	alloc4.Job = alloc2.Job
  2878  	alloc4.JobID = alloc2.JobID
  2879  	alloc4.ClientStatus = structs.AllocClientStatusComplete
  2880  
  2881  	alloc5 := mock.Alloc()
  2882  	alloc5.ID = alloc3.ID
  2883  	alloc5.Job = alloc3.Job
  2884  	alloc5.JobID = alloc3.JobID
  2885  	alloc5.ClientStatus = structs.AllocClientStatusComplete
  2886  
  2887  	if err := state.UpdateAllocsFromClient(1004, []*structs.Allocation{alloc4, alloc5}); err != nil {
  2888  		t.Fatalf("err: %v", err)
  2889  	}
  2890  	outA, _ = state.AllocByID(alloc5.ID)
  2891  	summary, _ = state.JobSummaryByID(job.ID)
  2892  	expectedSummary = structs.JobSummary{
  2893  		JobID: job.ID,
  2894  		Summary: map[string]structs.TaskGroupSummary{
  2895  			"web": {
  2896  				Complete: 2,
  2897  				Starting: 1,
  2898  			},
  2899  		},
  2900  		CreateIndex: job.CreateIndex,
  2901  		ModifyIndex: outA.ModifyIndex,
  2902  	}
  2903  	if !reflect.DeepEqual(summary, &expectedSummary) {
  2904  		t.Fatalf("expected: %v, actual: %v", expectedSummary, summary)
  2905  	}
  2906  }
  2907  
  2908  func TestJobSummary_UpdateClientStatus(t *testing.T) {
  2909  	state := testStateStore(t)
  2910  	alloc := mock.Alloc()
  2911  	job := alloc.Job
  2912  	job.TaskGroups[0].Count = 3
  2913  
  2914  	alloc2 := mock.Alloc()
  2915  	alloc2.Job = job
  2916  	alloc2.JobID = job.ID
  2917  
  2918  	alloc3 := mock.Alloc()
  2919  	alloc3.Job = job
  2920  	alloc3.JobID = job.ID
  2921  
  2922  	err := state.UpsertJob(1000, job)
  2923  	if err != nil {
  2924  		t.Fatalf("err: %v", err)
  2925  	}
  2926  
  2927  	if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc, alloc2, alloc3}); err != nil {
  2928  		t.Fatalf("err: %v", err)
  2929  	}
  2930  	summary, _ := state.JobSummaryByID(job.ID)
  2931  	if summary.Summary["web"].Starting != 3 {
  2932  		t.Fatalf("bad job summary: %v", summary)
  2933  	}
  2934  
  2935  	alloc4 := mock.Alloc()
  2936  	alloc4.ID = alloc2.ID
  2937  	alloc4.Job = alloc2.Job
  2938  	alloc4.JobID = alloc2.JobID
  2939  	alloc4.ClientStatus = structs.AllocClientStatusComplete
  2940  
  2941  	alloc5 := mock.Alloc()
  2942  	alloc5.ID = alloc3.ID
  2943  	alloc5.Job = alloc3.Job
  2944  	alloc5.JobID = alloc3.JobID
  2945  	alloc5.ClientStatus = structs.AllocClientStatusFailed
  2946  
  2947  	alloc6 := mock.Alloc()
  2948  	alloc6.ID = alloc.ID
  2949  	alloc6.Job = alloc.Job
  2950  	alloc6.JobID = alloc.JobID
  2951  	alloc6.ClientStatus = structs.AllocClientStatusRunning
  2952  
  2953  	if err := state.UpdateAllocsFromClient(1002, []*structs.Allocation{alloc4, alloc5, alloc6}); err != nil {
  2954  		t.Fatalf("err: %v", err)
  2955  	}
  2956  	summary, _ = state.JobSummaryByID(job.ID)
  2957  	if summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 {
  2958  		t.Fatalf("bad job summary: %v", summary)
  2959  	}
  2960  
  2961  	alloc7 := mock.Alloc()
  2962  	alloc7.Job = alloc.Job
  2963  	alloc7.JobID = alloc.JobID
  2964  
  2965  	if err := state.UpsertAllocs(1003, []*structs.Allocation{alloc7}); err != nil {
  2966  		t.Fatalf("err: %v", err)
  2967  	}
  2968  	summary, _ = state.JobSummaryByID(job.ID)
  2969  	if summary.Summary["web"].Starting != 1 || summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 {
  2970  		t.Fatalf("bad job summary: %v", summary)
  2971  	}
  2972  }
  2973  
  2974  func TestStateStore_UpsertVaultAccessors(t *testing.T) {
  2975  	state := testStateStore(t)
  2976  	a := mock.VaultAccessor()
  2977  	a2 := mock.VaultAccessor()
  2978  
  2979  	err := state.UpsertVaultAccessor(1000, []*structs.VaultAccessor{a, a2})
  2980  	if err != nil {
  2981  		t.Fatalf("err: %v", err)
  2982  	}
  2983  
  2984  	out, err := state.VaultAccessor(a.Accessor)
  2985  	if err != nil {
  2986  		t.Fatalf("err: %v", err)
  2987  	}
  2988  
  2989  	if !reflect.DeepEqual(a, out) {
  2990  		t.Fatalf("bad: %#v %#v", a, out)
  2991  	}
  2992  
  2993  	out, err = state.VaultAccessor(a2.Accessor)
  2994  	if err != nil {
  2995  		t.Fatalf("err: %v", err)
  2996  	}
  2997  
  2998  	if !reflect.DeepEqual(a2, out) {
  2999  		t.Fatalf("bad: %#v %#v", a2, out)
  3000  	}
  3001  
  3002  	iter, err := state.VaultAccessors()
  3003  	if err != nil {
  3004  		t.Fatalf("err: %v", err)
  3005  	}
  3006  
  3007  	count := 0
  3008  	for {
  3009  		raw := iter.Next()
  3010  		if raw == nil {
  3011  			break
  3012  		}
  3013  
  3014  		count++
  3015  		accessor := raw.(*structs.VaultAccessor)
  3016  
  3017  		if !reflect.DeepEqual(accessor, a) && !reflect.DeepEqual(accessor, a2) {
  3018  			t.Fatalf("bad: %#v", accessor)
  3019  		}
  3020  	}
  3021  
  3022  	if count != 2 {
  3023  		t.Fatalf("bad: %d", count)
  3024  	}
  3025  
  3026  	index, err := state.Index("vault_accessors")
  3027  	if err != nil {
  3028  		t.Fatalf("err: %v", err)
  3029  	}
  3030  	if index != 1000 {
  3031  		t.Fatalf("bad: %d", index)
  3032  	}
  3033  }
  3034  
  3035  func TestStateStore_DeleteVaultAccessors(t *testing.T) {
  3036  	state := testStateStore(t)
  3037  	a1 := mock.VaultAccessor()
  3038  	a2 := mock.VaultAccessor()
  3039  	accessors := []*structs.VaultAccessor{a1, a2}
  3040  
  3041  	err := state.UpsertVaultAccessor(1000, accessors)
  3042  	if err != nil {
  3043  		t.Fatalf("err: %v", err)
  3044  	}
  3045  
  3046  	err = state.DeleteVaultAccessors(1001, accessors)
  3047  	if err != nil {
  3048  		t.Fatalf("err: %v", err)
  3049  	}
  3050  
  3051  	out, err := state.VaultAccessor(a1.Accessor)
  3052  	if err != nil {
  3053  		t.Fatalf("err: %v", err)
  3054  	}
  3055  	if out != nil {
  3056  		t.Fatalf("bad: %#v %#v", a1, out)
  3057  	}
  3058  	out, err = state.VaultAccessor(a2.Accessor)
  3059  	if err != nil {
  3060  		t.Fatalf("err: %v", err)
  3061  	}
  3062  	if out != nil {
  3063  		t.Fatalf("bad: %#v %#v", a2, out)
  3064  	}
  3065  
  3066  	index, err := state.Index("vault_accessors")
  3067  	if err != nil {
  3068  		t.Fatalf("err: %v", err)
  3069  	}
  3070  	if index != 1001 {
  3071  		t.Fatalf("bad: %d", index)
  3072  	}
  3073  }
  3074  
  3075  func TestStateStore_VaultAccessorsByAlloc(t *testing.T) {
  3076  	state := testStateStore(t)
  3077  	alloc := mock.Alloc()
  3078  	var accessors []*structs.VaultAccessor
  3079  	var expected []*structs.VaultAccessor
  3080  
  3081  	for i := 0; i < 5; i++ {
  3082  		accessor := mock.VaultAccessor()
  3083  		accessor.AllocID = alloc.ID
  3084  		expected = append(expected, accessor)
  3085  		accessors = append(accessors, accessor)
  3086  	}
  3087  
  3088  	for i := 0; i < 10; i++ {
  3089  		accessor := mock.VaultAccessor()
  3090  		accessors = append(accessors, accessor)
  3091  	}
  3092  
  3093  	err := state.UpsertVaultAccessor(1000, accessors)
  3094  	if err != nil {
  3095  		t.Fatalf("err: %v", err)
  3096  	}
  3097  
  3098  	out, err := state.VaultAccessorsByAlloc(alloc.ID)
  3099  	if err != nil {
  3100  		t.Fatalf("err: %v", err)
  3101  	}
  3102  
  3103  	if len(expected) != len(out) {
  3104  		t.Fatalf("bad: %#v %#v", len(expected), len(out))
  3105  	}
  3106  
  3107  	index, err := state.Index("vault_accessors")
  3108  	if err != nil {
  3109  		t.Fatalf("err: %v", err)
  3110  	}
  3111  	if index != 1000 {
  3112  		t.Fatalf("bad: %d", index)
  3113  	}
  3114  }
  3115  
  3116  func TestStateStore_VaultAccessorsByNode(t *testing.T) {
  3117  	state := testStateStore(t)
  3118  	node := mock.Node()
  3119  	var accessors []*structs.VaultAccessor
  3120  	var expected []*structs.VaultAccessor
  3121  
  3122  	for i := 0; i < 5; i++ {
  3123  		accessor := mock.VaultAccessor()
  3124  		accessor.NodeID = node.ID
  3125  		expected = append(expected, accessor)
  3126  		accessors = append(accessors, accessor)
  3127  	}
  3128  
  3129  	for i := 0; i < 10; i++ {
  3130  		accessor := mock.VaultAccessor()
  3131  		accessors = append(accessors, accessor)
  3132  	}
  3133  
  3134  	err := state.UpsertVaultAccessor(1000, accessors)
  3135  	if err != nil {
  3136  		t.Fatalf("err: %v", err)
  3137  	}
  3138  
  3139  	out, err := state.VaultAccessorsByNode(node.ID)
  3140  	if err != nil {
  3141  		t.Fatalf("err: %v", err)
  3142  	}
  3143  
  3144  	if len(expected) != len(out) {
  3145  		t.Fatalf("bad: %#v %#v", len(expected), len(out))
  3146  	}
  3147  
  3148  	index, err := state.Index("vault_accessors")
  3149  	if err != nil {
  3150  		t.Fatalf("err: %v", err)
  3151  	}
  3152  	if index != 1000 {
  3153  		t.Fatalf("bad: %d", index)
  3154  	}
  3155  }
  3156  
  3157  func TestStateStore_RestoreVaultAccessor(t *testing.T) {
  3158  	state := testStateStore(t)
  3159  	a := mock.VaultAccessor()
  3160  
  3161  	restore, err := state.Restore()
  3162  	if err != nil {
  3163  		t.Fatalf("err: %v", err)
  3164  	}
  3165  
  3166  	err = restore.VaultAccessorRestore(a)
  3167  	if err != nil {
  3168  		t.Fatalf("err: %v", err)
  3169  	}
  3170  	restore.Commit()
  3171  
  3172  	out, err := state.VaultAccessor(a.Accessor)
  3173  	if err != nil {
  3174  		t.Fatalf("err: %v", err)
  3175  	}
  3176  
  3177  	if !reflect.DeepEqual(out, a) {
  3178  		t.Fatalf("Bad: %#v %#v", out, a)
  3179  	}
  3180  }
  3181  
  3182  // setupNotifyTest takes a state store and a set of watch items, then creates
  3183  // and subscribes a notification channel for each item.
  3184  func setupNotifyTest(state *StateStore, items ...watch.Item) notifyTest {
  3185  	var n notifyTest
  3186  	for _, item := range items {
  3187  		ch := make(chan struct{}, 1)
  3188  		state.Watch(watch.NewItems(item), ch)
  3189  		n = append(n, &notifyTestCase{item, ch})
  3190  	}
  3191  	return n
  3192  }
  3193  
  3194  // notifyTestCase is used to set up and verify watch triggers.
  3195  type notifyTestCase struct {
  3196  	item watch.Item
  3197  	ch   chan struct{}
  3198  }
  3199  
  3200  // notifyTest is a suite of notifyTestCases.
  3201  type notifyTest []*notifyTestCase
  3202  
  3203  // verify ensures that each channel received a notification.
  3204  func (n notifyTest) verify(t *testing.T) {
  3205  	for _, tcase := range n {
  3206  		if len(tcase.ch) != 1 {
  3207  			t.Fatalf("should notify %#v", tcase.item)
  3208  		}
  3209  	}
  3210  }
  3211  
  3212  // NodeIDSort is used to sort nodes by ID
  3213  type NodeIDSort []*structs.Node
  3214  
  3215  func (n NodeIDSort) Len() int {
  3216  	return len(n)
  3217  }
  3218  
  3219  func (n NodeIDSort) Less(i, j int) bool {
  3220  	return n[i].ID < n[j].ID
  3221  }
  3222  
  3223  func (n NodeIDSort) Swap(i, j int) {
  3224  	n[i], n[j] = n[j], n[i]
  3225  }
  3226  
  3227  // JobIDis used to sort jobs by id
  3228  type JobIDSort []*structs.Job
  3229  
  3230  func (n JobIDSort) Len() int {
  3231  	return len(n)
  3232  }
  3233  
  3234  func (n JobIDSort) Less(i, j int) bool {
  3235  	return n[i].ID < n[j].ID
  3236  }
  3237  
  3238  func (n JobIDSort) Swap(i, j int) {
  3239  	n[i], n[j] = n[j], n[i]
  3240  }
  3241  
  3242  // EvalIDis used to sort evals by id
  3243  type EvalIDSort []*structs.Evaluation
  3244  
  3245  func (n EvalIDSort) Len() int {
  3246  	return len(n)
  3247  }
  3248  
  3249  func (n EvalIDSort) Less(i, j int) bool {
  3250  	return n[i].ID < n[j].ID
  3251  }
  3252  
  3253  func (n EvalIDSort) Swap(i, j int) {
  3254  	n[i], n[j] = n[j], n[i]
  3255  }
  3256  
  3257  // AllocIDsort used to sort allocations by id
  3258  type AllocIDSort []*structs.Allocation
  3259  
  3260  func (n AllocIDSort) Len() int {
  3261  	return len(n)
  3262  }
  3263  
  3264  func (n AllocIDSort) Less(i, j int) bool {
  3265  	return n[i].ID < n[j].ID
  3266  }
  3267  
  3268  func (n AllocIDSort) Swap(i, j int) {
  3269  	n[i], n[j] = n[j], n[i]
  3270  }