github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/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  		watch.Item{EvalJob: eval.JobID})
  1232  
  1233  	err := state.UpsertEvals(1000, []*structs.Evaluation{eval})
  1234  	if err != nil {
  1235  		t.Fatalf("err: %v", err)
  1236  	}
  1237  
  1238  	out, err := state.EvalByID(eval.ID)
  1239  	if err != nil {
  1240  		t.Fatalf("err: %v", err)
  1241  	}
  1242  
  1243  	if !reflect.DeepEqual(eval, out) {
  1244  		t.Fatalf("bad: %#v %#v", eval, out)
  1245  	}
  1246  
  1247  	index, err := state.Index("evals")
  1248  	if err != nil {
  1249  		t.Fatalf("err: %v", err)
  1250  	}
  1251  	if index != 1000 {
  1252  		t.Fatalf("bad: %d", index)
  1253  	}
  1254  
  1255  	notify.verify(t)
  1256  }
  1257  
  1258  func TestStateStore_Update_UpsertEvals_Eval(t *testing.T) {
  1259  	state := testStateStore(t)
  1260  	eval := mock.Eval()
  1261  
  1262  	err := state.UpsertEvals(1000, []*structs.Evaluation{eval})
  1263  	if err != nil {
  1264  		t.Fatalf("err: %v", err)
  1265  	}
  1266  
  1267  	notify := setupNotifyTest(
  1268  		state,
  1269  		watch.Item{Table: "evals"},
  1270  		watch.Item{Eval: eval.ID},
  1271  		watch.Item{EvalJob: eval.JobID})
  1272  
  1273  	eval2 := mock.Eval()
  1274  	eval2.ID = eval.ID
  1275  	eval2.JobID = eval.JobID
  1276  	err = state.UpsertEvals(1001, []*structs.Evaluation{eval2})
  1277  	if err != nil {
  1278  		t.Fatalf("err: %v", err)
  1279  	}
  1280  
  1281  	out, err := state.EvalByID(eval.ID)
  1282  	if err != nil {
  1283  		t.Fatalf("err: %v", err)
  1284  	}
  1285  
  1286  	if !reflect.DeepEqual(eval2, out) {
  1287  		t.Fatalf("bad: %#v %#v", eval2, out)
  1288  	}
  1289  
  1290  	if out.CreateIndex != 1000 {
  1291  		t.Fatalf("bad: %#v", out)
  1292  	}
  1293  	if out.ModifyIndex != 1001 {
  1294  		t.Fatalf("bad: %#v", out)
  1295  	}
  1296  
  1297  	index, err := state.Index("evals")
  1298  	if err != nil {
  1299  		t.Fatalf("err: %v", err)
  1300  	}
  1301  	if index != 1001 {
  1302  		t.Fatalf("bad: %d", index)
  1303  	}
  1304  
  1305  	notify.verify(t)
  1306  }
  1307  
  1308  func TestStateStore_DeleteEval_Eval(t *testing.T) {
  1309  	state := testStateStore(t)
  1310  	eval1 := mock.Eval()
  1311  	eval2 := mock.Eval()
  1312  	alloc1 := mock.Alloc()
  1313  	alloc2 := mock.Alloc()
  1314  
  1315  	notify := setupNotifyTest(
  1316  		state,
  1317  		watch.Item{Table: "evals"},
  1318  		watch.Item{Table: "allocs"},
  1319  		watch.Item{Eval: eval1.ID},
  1320  		watch.Item{Eval: eval2.ID},
  1321  		watch.Item{EvalJob: eval1.JobID},
  1322  		watch.Item{EvalJob: eval2.JobID},
  1323  		watch.Item{Alloc: alloc1.ID},
  1324  		watch.Item{Alloc: alloc2.ID},
  1325  		watch.Item{AllocEval: alloc1.EvalID},
  1326  		watch.Item{AllocEval: alloc2.EvalID},
  1327  		watch.Item{AllocJob: alloc1.JobID},
  1328  		watch.Item{AllocJob: alloc2.JobID},
  1329  		watch.Item{AllocNode: alloc1.NodeID},
  1330  		watch.Item{AllocNode: alloc2.NodeID})
  1331  
  1332  	state.UpsertJobSummary(900, mock.JobSummary(eval1.JobID))
  1333  	state.UpsertJobSummary(901, mock.JobSummary(eval2.JobID))
  1334  	state.UpsertJobSummary(902, mock.JobSummary(alloc1.JobID))
  1335  	state.UpsertJobSummary(903, mock.JobSummary(alloc2.JobID))
  1336  	err := state.UpsertEvals(1000, []*structs.Evaluation{eval1, eval2})
  1337  	if err != nil {
  1338  		t.Fatalf("err: %v", err)
  1339  	}
  1340  
  1341  	err = state.UpsertAllocs(1001, []*structs.Allocation{alloc1, alloc2})
  1342  	if err != nil {
  1343  		t.Fatalf("err: %v", err)
  1344  	}
  1345  
  1346  	err = state.DeleteEval(1002, []string{eval1.ID, eval2.ID}, []string{alloc1.ID, alloc2.ID})
  1347  	if err != nil {
  1348  		t.Fatalf("err: %v", err)
  1349  	}
  1350  
  1351  	out, err := state.EvalByID(eval1.ID)
  1352  	if err != nil {
  1353  		t.Fatalf("err: %v", err)
  1354  	}
  1355  
  1356  	if out != nil {
  1357  		t.Fatalf("bad: %#v %#v", eval1, out)
  1358  	}
  1359  
  1360  	out, err = state.EvalByID(eval2.ID)
  1361  	if err != nil {
  1362  		t.Fatalf("err: %v", err)
  1363  	}
  1364  
  1365  	if out != nil {
  1366  		t.Fatalf("bad: %#v %#v", eval1, out)
  1367  	}
  1368  
  1369  	outA, err := state.AllocByID(alloc1.ID)
  1370  	if err != nil {
  1371  		t.Fatalf("err: %v", err)
  1372  	}
  1373  
  1374  	if out != nil {
  1375  		t.Fatalf("bad: %#v %#v", alloc1, outA)
  1376  	}
  1377  
  1378  	outA, err = state.AllocByID(alloc2.ID)
  1379  	if err != nil {
  1380  		t.Fatalf("err: %v", err)
  1381  	}
  1382  
  1383  	if out != nil {
  1384  		t.Fatalf("bad: %#v %#v", alloc1, outA)
  1385  	}
  1386  
  1387  	index, err := state.Index("evals")
  1388  	if err != nil {
  1389  		t.Fatalf("err: %v", err)
  1390  	}
  1391  	if index != 1002 {
  1392  		t.Fatalf("bad: %d", index)
  1393  	}
  1394  
  1395  	index, err = state.Index("allocs")
  1396  	if err != nil {
  1397  		t.Fatalf("err: %v", err)
  1398  	}
  1399  	if index != 1002 {
  1400  		t.Fatalf("bad: %d", index)
  1401  	}
  1402  
  1403  	notify.verify(t)
  1404  }
  1405  
  1406  func TestStateStore_EvalsByJob(t *testing.T) {
  1407  	state := testStateStore(t)
  1408  
  1409  	eval1 := mock.Eval()
  1410  	eval2 := mock.Eval()
  1411  	eval2.JobID = eval1.JobID
  1412  	eval3 := mock.Eval()
  1413  	evals := []*structs.Evaluation{eval1, eval2}
  1414  
  1415  	err := state.UpsertEvals(1000, evals)
  1416  	if err != nil {
  1417  		t.Fatalf("err: %v", err)
  1418  	}
  1419  	err = state.UpsertEvals(1001, []*structs.Evaluation{eval3})
  1420  	if err != nil {
  1421  		t.Fatalf("err: %v", err)
  1422  	}
  1423  
  1424  	out, err := state.EvalsByJob(eval1.JobID)
  1425  	if err != nil {
  1426  		t.Fatalf("err: %v", err)
  1427  	}
  1428  
  1429  	sort.Sort(EvalIDSort(evals))
  1430  	sort.Sort(EvalIDSort(out))
  1431  
  1432  	if !reflect.DeepEqual(evals, out) {
  1433  		t.Fatalf("bad: %#v %#v", evals, out)
  1434  	}
  1435  }
  1436  
  1437  func TestStateStore_Evals(t *testing.T) {
  1438  	state := testStateStore(t)
  1439  	var evals []*structs.Evaluation
  1440  
  1441  	for i := 0; i < 10; i++ {
  1442  		eval := mock.Eval()
  1443  		evals = append(evals, eval)
  1444  
  1445  		err := state.UpsertEvals(1000+uint64(i), []*structs.Evaluation{eval})
  1446  		if err != nil {
  1447  			t.Fatalf("err: %v", err)
  1448  		}
  1449  	}
  1450  
  1451  	iter, err := state.Evals()
  1452  	if err != nil {
  1453  		t.Fatalf("err: %v", err)
  1454  	}
  1455  
  1456  	var out []*structs.Evaluation
  1457  	for {
  1458  		raw := iter.Next()
  1459  		if raw == nil {
  1460  			break
  1461  		}
  1462  		out = append(out, raw.(*structs.Evaluation))
  1463  	}
  1464  
  1465  	sort.Sort(EvalIDSort(evals))
  1466  	sort.Sort(EvalIDSort(out))
  1467  
  1468  	if !reflect.DeepEqual(evals, out) {
  1469  		t.Fatalf("bad: %#v %#v", evals, out)
  1470  	}
  1471  }
  1472  
  1473  func TestStateStore_EvalsByIDPrefix(t *testing.T) {
  1474  	state := testStateStore(t)
  1475  	var evals []*structs.Evaluation
  1476  
  1477  	ids := []string{
  1478  		"aaaaaaaa-7bfb-395d-eb95-0685af2176b2",
  1479  		"aaaaaaab-7bfb-395d-eb95-0685af2176b2",
  1480  		"aaaaaabb-7bfb-395d-eb95-0685af2176b2",
  1481  		"aaaaabbb-7bfb-395d-eb95-0685af2176b2",
  1482  		"aaaabbbb-7bfb-395d-eb95-0685af2176b2",
  1483  		"aaabbbbb-7bfb-395d-eb95-0685af2176b2",
  1484  		"aabbbbbb-7bfb-395d-eb95-0685af2176b2",
  1485  		"abbbbbbb-7bfb-395d-eb95-0685af2176b2",
  1486  		"bbbbbbbb-7bfb-395d-eb95-0685af2176b2",
  1487  	}
  1488  	for i := 0; i < 9; i++ {
  1489  		eval := mock.Eval()
  1490  		eval.ID = ids[i]
  1491  		evals = append(evals, eval)
  1492  	}
  1493  
  1494  	err := state.UpsertEvals(1000, evals)
  1495  	if err != nil {
  1496  		t.Fatalf("err: %v", err)
  1497  	}
  1498  
  1499  	iter, err := state.EvalsByIDPrefix("aaaa")
  1500  	if err != nil {
  1501  		t.Fatalf("err: %v", err)
  1502  	}
  1503  
  1504  	gatherEvals := func(iter memdb.ResultIterator) []*structs.Evaluation {
  1505  		var evals []*structs.Evaluation
  1506  		for {
  1507  			raw := iter.Next()
  1508  			if raw == nil {
  1509  				break
  1510  			}
  1511  			evals = append(evals, raw.(*structs.Evaluation))
  1512  		}
  1513  		return evals
  1514  	}
  1515  
  1516  	out := gatherEvals(iter)
  1517  	if len(out) != 5 {
  1518  		t.Fatalf("bad: expected five evaluations, got: %#v", out)
  1519  	}
  1520  
  1521  	sort.Sort(EvalIDSort(evals))
  1522  
  1523  	for index, eval := range out {
  1524  		if ids[index] != eval.ID {
  1525  			t.Fatalf("bad: got unexpected id: %s", eval.ID)
  1526  		}
  1527  	}
  1528  
  1529  	iter, err = state.EvalsByIDPrefix("b-a7bfb")
  1530  	if err != nil {
  1531  		t.Fatalf("err: %v", err)
  1532  	}
  1533  
  1534  	out = gatherEvals(iter)
  1535  	if len(out) != 0 {
  1536  		t.Fatalf("bad: unexpected zero evaluations, got: %#v", out)
  1537  	}
  1538  
  1539  }
  1540  
  1541  func TestStateStore_RestoreEval(t *testing.T) {
  1542  	state := testStateStore(t)
  1543  	eval := mock.Eval()
  1544  
  1545  	notify := setupNotifyTest(
  1546  		state,
  1547  		watch.Item{Table: "evals"},
  1548  		watch.Item{Eval: eval.ID})
  1549  
  1550  	restore, err := state.Restore()
  1551  	if err != nil {
  1552  		t.Fatalf("err: %v", err)
  1553  	}
  1554  
  1555  	err = restore.EvalRestore(eval)
  1556  	if err != nil {
  1557  		t.Fatalf("err: %v", err)
  1558  	}
  1559  	restore.Commit()
  1560  
  1561  	out, err := state.EvalByID(eval.ID)
  1562  	if err != nil {
  1563  		t.Fatalf("err: %v", err)
  1564  	}
  1565  
  1566  	if !reflect.DeepEqual(out, eval) {
  1567  		t.Fatalf("Bad: %#v %#v", out, eval)
  1568  	}
  1569  
  1570  	notify.verify(t)
  1571  }
  1572  
  1573  func TestStateStore_UpdateAllocsFromClient(t *testing.T) {
  1574  	state := testStateStore(t)
  1575  	alloc := mock.Alloc()
  1576  	alloc2 := mock.Alloc()
  1577  
  1578  	notify := setupNotifyTest(
  1579  		state,
  1580  		watch.Item{Table: "allocs"},
  1581  		watch.Item{Alloc: alloc.ID},
  1582  		watch.Item{AllocEval: alloc.EvalID},
  1583  		watch.Item{AllocJob: alloc.JobID},
  1584  		watch.Item{AllocNode: alloc.NodeID},
  1585  		watch.Item{Alloc: alloc2.ID},
  1586  		watch.Item{AllocEval: alloc2.EvalID},
  1587  		watch.Item{AllocJob: alloc2.JobID},
  1588  		watch.Item{AllocNode: alloc2.NodeID})
  1589  
  1590  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1591  		t.Fatalf("err: %v", err)
  1592  	}
  1593  	if err := state.UpsertJob(999, alloc2.Job); err != nil {
  1594  		t.Fatalf("err: %v", err)
  1595  	}
  1596  
  1597  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc, alloc2})
  1598  	if err != nil {
  1599  		t.Fatalf("err: %v", err)
  1600  	}
  1601  
  1602  	// Create the delta updates
  1603  	ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}}
  1604  	update := &structs.Allocation{
  1605  		ID:           alloc.ID,
  1606  		ClientStatus: structs.AllocClientStatusFailed,
  1607  		TaskStates:   ts,
  1608  		JobID:        alloc.JobID,
  1609  		TaskGroup:    alloc.TaskGroup,
  1610  	}
  1611  	update2 := &structs.Allocation{
  1612  		ID:           alloc2.ID,
  1613  		ClientStatus: structs.AllocClientStatusRunning,
  1614  		TaskStates:   ts,
  1615  		JobID:        alloc2.JobID,
  1616  		TaskGroup:    alloc2.TaskGroup,
  1617  	}
  1618  
  1619  	err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2})
  1620  	if err != nil {
  1621  		t.Fatalf("err: %v", err)
  1622  	}
  1623  
  1624  	out, err := state.AllocByID(alloc.ID)
  1625  	if err != nil {
  1626  		t.Fatalf("err: %v", err)
  1627  	}
  1628  
  1629  	alloc.CreateIndex = 1000
  1630  	alloc.ModifyIndex = 1001
  1631  	alloc.TaskStates = ts
  1632  	alloc.ClientStatus = structs.AllocClientStatusFailed
  1633  	if !reflect.DeepEqual(alloc, out) {
  1634  		t.Fatalf("bad: %#v %#v", alloc, out)
  1635  	}
  1636  
  1637  	out, err = state.AllocByID(alloc2.ID)
  1638  	if err != nil {
  1639  		t.Fatalf("err: %v", err)
  1640  	}
  1641  
  1642  	alloc2.ModifyIndex = 1000
  1643  	alloc2.ModifyIndex = 1001
  1644  	alloc2.ClientStatus = structs.AllocClientStatusRunning
  1645  	alloc2.TaskStates = ts
  1646  	if !reflect.DeepEqual(alloc2, out) {
  1647  		t.Fatalf("bad: %#v %#v", alloc2, out)
  1648  	}
  1649  
  1650  	index, err := state.Index("allocs")
  1651  	if err != nil {
  1652  		t.Fatalf("err: %v", err)
  1653  	}
  1654  	if index != 1001 {
  1655  		t.Fatalf("bad: %d", index)
  1656  	}
  1657  
  1658  	// Ensure summaries have been updated
  1659  	summary, err := state.JobSummaryByID(alloc.JobID)
  1660  	if err != nil {
  1661  		t.Fatalf("err: %v", err)
  1662  	}
  1663  	tgSummary := summary.Summary["web"]
  1664  	if tgSummary.Failed != 1 {
  1665  		t.Fatalf("expected failed: %v, actual: %v, summary: %#v", 1, tgSummary.Failed, tgSummary)
  1666  	}
  1667  
  1668  	summary2, err := state.JobSummaryByID(alloc2.JobID)
  1669  	if err != nil {
  1670  		t.Fatalf("err: %v", err)
  1671  	}
  1672  	tgSummary2 := summary2.Summary["web"]
  1673  	if tgSummary2.Running != 1 {
  1674  		t.Fatalf("expected running: %v, actual: %v", 1, tgSummary2.Running)
  1675  	}
  1676  
  1677  	notify.verify(t)
  1678  }
  1679  
  1680  func TestStateStore_UpdateMultipleAllocsFromClient(t *testing.T) {
  1681  	state := testStateStore(t)
  1682  	alloc := mock.Alloc()
  1683  
  1684  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1685  		t.Fatalf("err: %v", err)
  1686  	}
  1687  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1688  	if err != nil {
  1689  		t.Fatalf("err: %v", err)
  1690  	}
  1691  
  1692  	// Create the delta updates
  1693  	ts := map[string]*structs.TaskState{"web": &structs.TaskState{State: structs.TaskStatePending}}
  1694  	update := &structs.Allocation{
  1695  		ID:           alloc.ID,
  1696  		ClientStatus: structs.AllocClientStatusRunning,
  1697  		TaskStates:   ts,
  1698  		JobID:        alloc.JobID,
  1699  		TaskGroup:    alloc.TaskGroup,
  1700  	}
  1701  	update2 := &structs.Allocation{
  1702  		ID:           alloc.ID,
  1703  		ClientStatus: structs.AllocClientStatusPending,
  1704  		TaskStates:   ts,
  1705  		JobID:        alloc.JobID,
  1706  		TaskGroup:    alloc.TaskGroup,
  1707  	}
  1708  
  1709  	err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2})
  1710  	if err != nil {
  1711  		t.Fatalf("err: %v", err)
  1712  	}
  1713  
  1714  	out, err := state.AllocByID(alloc.ID)
  1715  	if err != nil {
  1716  		t.Fatalf("err: %v", err)
  1717  	}
  1718  
  1719  	alloc.CreateIndex = 1000
  1720  	alloc.ModifyIndex = 1001
  1721  	alloc.TaskStates = ts
  1722  	alloc.ClientStatus = structs.AllocClientStatusPending
  1723  	if !reflect.DeepEqual(alloc, out) {
  1724  		t.Fatalf("bad: %#v , actual:%#v", alloc, out)
  1725  	}
  1726  
  1727  	summary, err := state.JobSummaryByID(alloc.JobID)
  1728  	expectedSummary := &structs.JobSummary{
  1729  		JobID: alloc.JobID,
  1730  		Summary: map[string]structs.TaskGroupSummary{
  1731  			"web": structs.TaskGroupSummary{
  1732  				Starting: 1,
  1733  			},
  1734  		},
  1735  		CreateIndex: 999,
  1736  		ModifyIndex: 1001,
  1737  	}
  1738  	if err != nil {
  1739  		t.Fatalf("err: %v", err)
  1740  	}
  1741  	if !reflect.DeepEqual(summary, expectedSummary) {
  1742  		t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary)
  1743  	}
  1744  }
  1745  
  1746  func TestStateStore_UpsertAlloc_Alloc(t *testing.T) {
  1747  	state := testStateStore(t)
  1748  	alloc := mock.Alloc()
  1749  
  1750  	notify := setupNotifyTest(
  1751  		state,
  1752  		watch.Item{Table: "allocs"},
  1753  		watch.Item{Alloc: alloc.ID},
  1754  		watch.Item{AllocEval: alloc.EvalID},
  1755  		watch.Item{AllocJob: alloc.JobID},
  1756  		watch.Item{AllocNode: alloc.NodeID})
  1757  
  1758  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1759  		t.Fatalf("err: %v", err)
  1760  	}
  1761  
  1762  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1763  	if err != nil {
  1764  		t.Fatalf("err: %v", err)
  1765  	}
  1766  
  1767  	out, err := state.AllocByID(alloc.ID)
  1768  	if err != nil {
  1769  		t.Fatalf("err: %v", err)
  1770  	}
  1771  
  1772  	if !reflect.DeepEqual(alloc, out) {
  1773  		t.Fatalf("bad: %#v %#v", alloc, out)
  1774  	}
  1775  
  1776  	index, err := state.Index("allocs")
  1777  	if err != nil {
  1778  		t.Fatalf("err: %v", err)
  1779  	}
  1780  	if index != 1000 {
  1781  		t.Fatalf("bad: %d", index)
  1782  	}
  1783  
  1784  	summary, err := state.JobSummaryByID(alloc.JobID)
  1785  	if err != nil {
  1786  		t.Fatalf("err: %v", err)
  1787  	}
  1788  
  1789  	tgSummary, ok := summary.Summary["web"]
  1790  	if !ok {
  1791  		t.Fatalf("no summary for task group web")
  1792  	}
  1793  	if tgSummary.Starting != 1 {
  1794  		t.Fatalf("expected queued: %v, actual: %v", 1, tgSummary.Starting)
  1795  	}
  1796  
  1797  	notify.verify(t)
  1798  }
  1799  
  1800  func TestStateStore_UpsertAlloc_NoEphemeralDisk(t *testing.T) {
  1801  	state := testStateStore(t)
  1802  	alloc := mock.Alloc()
  1803  	alloc.Job.TaskGroups[0].EphemeralDisk = nil
  1804  	alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120
  1805  
  1806  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1807  		t.Fatalf("err: %v", err)
  1808  	}
  1809  
  1810  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1811  	if err != nil {
  1812  		t.Fatalf("err: %v", err)
  1813  	}
  1814  
  1815  	out, err := state.AllocByID(alloc.ID)
  1816  	if err != nil {
  1817  		t.Fatalf("err: %v", err)
  1818  	}
  1819  
  1820  	expected := alloc.Copy()
  1821  	expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120}
  1822  	if !reflect.DeepEqual(expected, out) {
  1823  		t.Fatalf("bad: %#v %#v", expected, out)
  1824  	}
  1825  }
  1826  
  1827  func TestStateStore_UpdateAlloc_Alloc(t *testing.T) {
  1828  	state := testStateStore(t)
  1829  	alloc := mock.Alloc()
  1830  
  1831  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1832  		t.Fatalf("err: %v", err)
  1833  	}
  1834  
  1835  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1836  	if err != nil {
  1837  		t.Fatalf("err: %v", err)
  1838  	}
  1839  
  1840  	summary, err := state.JobSummaryByID(alloc.JobID)
  1841  	if err != nil {
  1842  		t.Fatalf("err: %v", err)
  1843  	}
  1844  	tgSummary := summary.Summary["web"]
  1845  	if tgSummary.Starting != 1 {
  1846  		t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting)
  1847  	}
  1848  
  1849  	alloc2 := mock.Alloc()
  1850  	alloc2.ID = alloc.ID
  1851  	alloc2.NodeID = alloc.NodeID + ".new"
  1852  	state.UpsertJobSummary(1001, mock.JobSummary(alloc2.JobID))
  1853  
  1854  	notify := setupNotifyTest(
  1855  		state,
  1856  		watch.Item{Table: "allocs"},
  1857  		watch.Item{Alloc: alloc2.ID},
  1858  		watch.Item{AllocEval: alloc2.EvalID},
  1859  		watch.Item{AllocJob: alloc2.JobID},
  1860  		watch.Item{AllocNode: alloc2.NodeID})
  1861  
  1862  	err = state.UpsertAllocs(1002, []*structs.Allocation{alloc2})
  1863  	if err != nil {
  1864  		t.Fatalf("err: %v", err)
  1865  	}
  1866  
  1867  	out, err := state.AllocByID(alloc.ID)
  1868  	if err != nil {
  1869  		t.Fatalf("err: %v", err)
  1870  	}
  1871  
  1872  	if !reflect.DeepEqual(alloc2, out) {
  1873  		t.Fatalf("bad: %#v %#v", alloc2, out)
  1874  	}
  1875  
  1876  	if out.CreateIndex != 1000 {
  1877  		t.Fatalf("bad: %#v", out)
  1878  	}
  1879  	if out.ModifyIndex != 1002 {
  1880  		t.Fatalf("bad: %#v", out)
  1881  	}
  1882  
  1883  	index, err := state.Index("allocs")
  1884  	if err != nil {
  1885  		t.Fatalf("err: %v", err)
  1886  	}
  1887  	if index != 1002 {
  1888  		t.Fatalf("bad: %d", index)
  1889  	}
  1890  
  1891  	// Ensure that summary hasb't changed
  1892  	summary, err = state.JobSummaryByID(alloc.JobID)
  1893  	if err != nil {
  1894  		t.Fatalf("err: %v", err)
  1895  	}
  1896  	tgSummary = summary.Summary["web"]
  1897  	if tgSummary.Starting != 1 {
  1898  		t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting)
  1899  	}
  1900  
  1901  	notify.verify(t)
  1902  }
  1903  
  1904  // This test ensures that the state store will mark the clients status as lost
  1905  // when set rather than preferring the existing status.
  1906  func TestStateStore_UpdateAlloc_Lost(t *testing.T) {
  1907  	state := testStateStore(t)
  1908  	alloc := mock.Alloc()
  1909  	alloc.ClientStatus = "foo"
  1910  
  1911  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1912  		t.Fatalf("err: %v", err)
  1913  	}
  1914  
  1915  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1916  	if err != nil {
  1917  		t.Fatalf("err: %v", err)
  1918  	}
  1919  
  1920  	alloc2 := new(structs.Allocation)
  1921  	*alloc2 = *alloc
  1922  	alloc2.ClientStatus = structs.AllocClientStatusLost
  1923  	if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc2}); err != nil {
  1924  		t.Fatalf("err: %v", err)
  1925  	}
  1926  
  1927  	out, err := state.AllocByID(alloc2.ID)
  1928  	if err != nil {
  1929  		t.Fatalf("err: %v", err)
  1930  	}
  1931  
  1932  	if out.ClientStatus != structs.AllocClientStatusLost {
  1933  		t.Fatalf("bad: %#v", out)
  1934  	}
  1935  }
  1936  
  1937  // This test ensures an allocation can be updated when there is no job
  1938  // associated with it. This will happen when a job is stopped by an user which
  1939  // has non-terminal allocations on clients
  1940  func TestStateStore_UpdateAlloc_NoJob(t *testing.T) {
  1941  	state := testStateStore(t)
  1942  	alloc := mock.Alloc()
  1943  
  1944  	// Upsert a job
  1945  	state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID))
  1946  	if err := state.UpsertJob(999, alloc.Job); err != nil {
  1947  		t.Fatalf("err: %v", err)
  1948  	}
  1949  
  1950  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  1951  	if err != nil {
  1952  		t.Fatalf("err: %v", err)
  1953  	}
  1954  
  1955  	if err := state.DeleteJob(1001, alloc.JobID); err != nil {
  1956  		t.Fatalf("err: %v", err)
  1957  	}
  1958  
  1959  	// Update the desired state of the allocation to stop
  1960  	allocCopy := alloc.Copy()
  1961  	allocCopy.DesiredStatus = structs.AllocDesiredStatusStop
  1962  	if err := state.UpsertAllocs(1002, []*structs.Allocation{allocCopy}); err != nil {
  1963  		t.Fatalf("err: %v", err)
  1964  	}
  1965  
  1966  	// Update the client state of the allocation to complete
  1967  	allocCopy1 := allocCopy.Copy()
  1968  	allocCopy1.ClientStatus = structs.AllocClientStatusComplete
  1969  	if err := state.UpdateAllocsFromClient(1003, []*structs.Allocation{allocCopy1}); err != nil {
  1970  		t.Fatalf("err: %v", err)
  1971  	}
  1972  
  1973  	out, _ := state.AllocByID(alloc.ID)
  1974  	// Update the modify index of the alloc before comparing
  1975  	allocCopy1.ModifyIndex = 1003
  1976  	if !reflect.DeepEqual(out, allocCopy1) {
  1977  		t.Fatalf("expected: %#v \n actual: %#v", allocCopy1, out)
  1978  	}
  1979  }
  1980  
  1981  func TestStateStore_JobSummary(t *testing.T) {
  1982  	state := testStateStore(t)
  1983  
  1984  	// Add a job
  1985  	job := mock.Job()
  1986  	state.UpsertJob(900, job)
  1987  
  1988  	// Get the job back
  1989  	outJob, _ := state.JobByID(job.ID)
  1990  	if outJob.CreateIndex != 900 {
  1991  		t.Fatalf("bad create index: %v", outJob.CreateIndex)
  1992  	}
  1993  	summary, _ := state.JobSummaryByID(job.ID)
  1994  	if summary.CreateIndex != 900 {
  1995  		t.Fatalf("bad create index: %v", summary.CreateIndex)
  1996  	}
  1997  
  1998  	// Upser an allocation
  1999  	alloc := mock.Alloc()
  2000  	alloc.JobID = job.ID
  2001  	alloc.Job = job
  2002  	state.UpsertAllocs(910, []*structs.Allocation{alloc})
  2003  
  2004  	// Update the alloc from client
  2005  	alloc1 := alloc.Copy()
  2006  	alloc1.ClientStatus = structs.AllocClientStatusPending
  2007  	alloc1.DesiredStatus = ""
  2008  	state.UpdateAllocsFromClient(920, []*structs.Allocation{alloc})
  2009  
  2010  	alloc3 := alloc.Copy()
  2011  	alloc3.ClientStatus = structs.AllocClientStatusRunning
  2012  	alloc3.DesiredStatus = ""
  2013  	state.UpdateAllocsFromClient(930, []*structs.Allocation{alloc3})
  2014  
  2015  	// Upsert the alloc
  2016  	alloc4 := alloc.Copy()
  2017  	alloc4.ClientStatus = structs.AllocClientStatusPending
  2018  	alloc4.DesiredStatus = structs.AllocDesiredStatusRun
  2019  	state.UpsertAllocs(950, []*structs.Allocation{alloc4})
  2020  
  2021  	// Again upsert the alloc
  2022  	alloc5 := alloc.Copy()
  2023  	alloc5.ClientStatus = structs.AllocClientStatusPending
  2024  	alloc5.DesiredStatus = structs.AllocDesiredStatusRun
  2025  	state.UpsertAllocs(970, []*structs.Allocation{alloc5})
  2026  
  2027  	expectedSummary := structs.JobSummary{
  2028  		JobID: job.ID,
  2029  		Summary: map[string]structs.TaskGroupSummary{
  2030  			"web": structs.TaskGroupSummary{
  2031  				Running: 1,
  2032  			},
  2033  		},
  2034  		CreateIndex: 900,
  2035  		ModifyIndex: 930,
  2036  	}
  2037  
  2038  	summary, _ = state.JobSummaryByID(job.ID)
  2039  	if !reflect.DeepEqual(&expectedSummary, summary) {
  2040  		t.Fatalf("expected: %#v, actual: %v", expectedSummary, summary)
  2041  	}
  2042  
  2043  	// De-register the job.
  2044  	state.DeleteJob(980, job.ID)
  2045  
  2046  	// Shouldn't have any effect on the summary
  2047  	alloc6 := alloc.Copy()
  2048  	alloc6.ClientStatus = structs.AllocClientStatusRunning
  2049  	alloc6.DesiredStatus = ""
  2050  	state.UpdateAllocsFromClient(990, []*structs.Allocation{alloc6})
  2051  
  2052  	// We shouldn't have any summary at this point
  2053  	summary, _ = state.JobSummaryByID(job.ID)
  2054  	if summary != nil {
  2055  		t.Fatalf("expected nil, actual: %#v", summary)
  2056  	}
  2057  
  2058  	// Re-register the same job
  2059  	job1 := mock.Job()
  2060  	job1.ID = job.ID
  2061  	state.UpsertJob(1000, job1)
  2062  	outJob2, _ := state.JobByID(job1.ID)
  2063  	if outJob2.CreateIndex != 1000 {
  2064  		t.Fatalf("bad create index: %v", outJob2.CreateIndex)
  2065  	}
  2066  	summary, _ = state.JobSummaryByID(job1.ID)
  2067  	if summary.CreateIndex != 1000 {
  2068  		t.Fatalf("bad create index: %v", summary.CreateIndex)
  2069  	}
  2070  
  2071  	// Upsert an allocation
  2072  	alloc7 := alloc.Copy()
  2073  	alloc7.JobID = outJob.ID
  2074  	alloc7.Job = outJob
  2075  	alloc7.ClientStatus = structs.AllocClientStatusComplete
  2076  	alloc7.DesiredStatus = structs.AllocDesiredStatusRun
  2077  	state.UpdateAllocsFromClient(1020, []*structs.Allocation{alloc7})
  2078  
  2079  	expectedSummary = structs.JobSummary{
  2080  		JobID: job.ID,
  2081  		Summary: map[string]structs.TaskGroupSummary{
  2082  			"web": structs.TaskGroupSummary{},
  2083  		},
  2084  		CreateIndex: 1000,
  2085  		ModifyIndex: 1000,
  2086  	}
  2087  
  2088  	summary, _ = state.JobSummaryByID(job1.ID)
  2089  	if !reflect.DeepEqual(&expectedSummary, summary) {
  2090  		t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary)
  2091  	}
  2092  }
  2093  
  2094  func TestStateStore_ReconcileJobSummary(t *testing.T) {
  2095  	state := testStateStore(t)
  2096  
  2097  	// Create an alloc
  2098  	alloc := mock.Alloc()
  2099  
  2100  	// Add another task group to the job
  2101  	tg2 := alloc.Job.TaskGroups[0].Copy()
  2102  	tg2.Name = "db"
  2103  	alloc.Job.TaskGroups = append(alloc.Job.TaskGroups, tg2)
  2104  	state.UpsertJob(100, alloc.Job)
  2105  
  2106  	// Create one more alloc for the db task group
  2107  	alloc2 := mock.Alloc()
  2108  	alloc2.TaskGroup = "db"
  2109  	alloc2.JobID = alloc.JobID
  2110  	alloc2.Job = alloc.Job
  2111  
  2112  	// Upserts the alloc
  2113  	state.UpsertAllocs(110, []*structs.Allocation{alloc, alloc2})
  2114  
  2115  	// Change the state of the first alloc to running
  2116  	alloc3 := alloc.Copy()
  2117  	alloc3.ClientStatus = structs.AllocClientStatusRunning
  2118  	state.UpdateAllocsFromClient(120, []*structs.Allocation{alloc3})
  2119  
  2120  	//Add some more allocs to the second tg
  2121  	alloc4 := mock.Alloc()
  2122  	alloc4.JobID = alloc.JobID
  2123  	alloc4.Job = alloc.Job
  2124  	alloc4.TaskGroup = "db"
  2125  	alloc5 := alloc4.Copy()
  2126  	alloc5.ClientStatus = structs.AllocClientStatusRunning
  2127  
  2128  	alloc6 := mock.Alloc()
  2129  	alloc6.JobID = alloc.JobID
  2130  	alloc6.Job = alloc.Job
  2131  	alloc6.TaskGroup = "db"
  2132  	alloc7 := alloc6.Copy()
  2133  	alloc7.ClientStatus = structs.AllocClientStatusComplete
  2134  
  2135  	alloc8 := mock.Alloc()
  2136  	alloc8.JobID = alloc.JobID
  2137  	alloc8.Job = alloc.Job
  2138  	alloc8.TaskGroup = "db"
  2139  	alloc9 := alloc8.Copy()
  2140  	alloc9.ClientStatus = structs.AllocClientStatusFailed
  2141  
  2142  	alloc10 := mock.Alloc()
  2143  	alloc10.JobID = alloc.JobID
  2144  	alloc10.Job = alloc.Job
  2145  	alloc10.TaskGroup = "db"
  2146  	alloc11 := alloc10.Copy()
  2147  	alloc11.ClientStatus = structs.AllocClientStatusLost
  2148  
  2149  	state.UpsertAllocs(130, []*structs.Allocation{alloc4, alloc6, alloc8, alloc10})
  2150  
  2151  	state.UpdateAllocsFromClient(150, []*structs.Allocation{alloc5, alloc7, alloc9, alloc11})
  2152  
  2153  	// DeleteJobSummary is a helper method and doesn't modify the indexes table
  2154  	state.DeleteJobSummary(130, alloc.Job.ID)
  2155  
  2156  	state.ReconcileJobSummaries(120)
  2157  
  2158  	summary, _ := state.JobSummaryByID(alloc.Job.ID)
  2159  	expectedSummary := structs.JobSummary{
  2160  		JobID: alloc.Job.ID,
  2161  		Summary: map[string]structs.TaskGroupSummary{
  2162  			"web": structs.TaskGroupSummary{
  2163  				Running: 1,
  2164  			},
  2165  			"db": structs.TaskGroupSummary{
  2166  				Starting: 1,
  2167  				Running:  1,
  2168  				Failed:   1,
  2169  				Complete: 1,
  2170  				Lost:     1,
  2171  			},
  2172  		},
  2173  		CreateIndex: 100,
  2174  		ModifyIndex: 120,
  2175  	}
  2176  	if !reflect.DeepEqual(&expectedSummary, summary) {
  2177  		t.Fatalf("expected: %v, actual: %v", expectedSummary, summary)
  2178  	}
  2179  }
  2180  
  2181  func TestStateStore_UpdateAlloc_JobNotPresent(t *testing.T) {
  2182  	state := testStateStore(t)
  2183  
  2184  	alloc := mock.Alloc()
  2185  	state.UpsertJob(100, alloc.Job)
  2186  	state.UpsertAllocs(200, []*structs.Allocation{alloc})
  2187  
  2188  	// Delete the job
  2189  	state.DeleteJob(300, alloc.Job.ID)
  2190  
  2191  	// Update the alloc
  2192  	alloc1 := alloc.Copy()
  2193  	alloc1.ClientStatus = structs.AllocClientStatusRunning
  2194  
  2195  	// Updating allocation should not throw any error
  2196  	if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil {
  2197  		t.Fatalf("expect err: %v", err)
  2198  	}
  2199  
  2200  	// Re-Register the job
  2201  	state.UpsertJob(500, alloc.Job)
  2202  
  2203  	// Update the alloc again
  2204  	alloc2 := alloc.Copy()
  2205  	alloc2.ClientStatus = structs.AllocClientStatusComplete
  2206  	if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil {
  2207  		t.Fatalf("expect err: %v", err)
  2208  	}
  2209  
  2210  	// Job Summary of the newly registered job shouldn't account for the
  2211  	// allocation update for the older job
  2212  	expectedSummary := structs.JobSummary{
  2213  		JobID: alloc1.JobID,
  2214  		Summary: map[string]structs.TaskGroupSummary{
  2215  			"web": structs.TaskGroupSummary{},
  2216  		},
  2217  		CreateIndex: 500,
  2218  		ModifyIndex: 500,
  2219  	}
  2220  	summary, _ := state.JobSummaryByID(alloc.Job.ID)
  2221  	if !reflect.DeepEqual(&expectedSummary, summary) {
  2222  		t.Fatalf("expected: %v, actual: %v", expectedSummary, summary)
  2223  	}
  2224  }
  2225  
  2226  func TestStateStore_EvictAlloc_Alloc(t *testing.T) {
  2227  	state := testStateStore(t)
  2228  	alloc := mock.Alloc()
  2229  
  2230  	state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))
  2231  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
  2232  	if err != nil {
  2233  		t.Fatalf("err: %v", err)
  2234  	}
  2235  
  2236  	alloc2 := new(structs.Allocation)
  2237  	*alloc2 = *alloc
  2238  	alloc2.DesiredStatus = structs.AllocDesiredStatusEvict
  2239  	err = state.UpsertAllocs(1001, []*structs.Allocation{alloc2})
  2240  	if err != nil {
  2241  		t.Fatalf("err: %v", err)
  2242  	}
  2243  
  2244  	out, err := state.AllocByID(alloc.ID)
  2245  	if err != nil {
  2246  		t.Fatalf("err: %v", err)
  2247  	}
  2248  
  2249  	if out.DesiredStatus != structs.AllocDesiredStatusEvict {
  2250  		t.Fatalf("bad: %#v %#v", alloc, out)
  2251  	}
  2252  
  2253  	index, err := state.Index("allocs")
  2254  	if err != nil {
  2255  		t.Fatalf("err: %v", err)
  2256  	}
  2257  	if index != 1001 {
  2258  		t.Fatalf("bad: %d", index)
  2259  	}
  2260  }
  2261  
  2262  func TestStateStore_AllocsByNode(t *testing.T) {
  2263  	state := testStateStore(t)
  2264  	var allocs []*structs.Allocation
  2265  
  2266  	for i := 0; i < 10; i++ {
  2267  		alloc := mock.Alloc()
  2268  		alloc.NodeID = "foo"
  2269  		allocs = append(allocs, alloc)
  2270  	}
  2271  
  2272  	for idx, alloc := range allocs {
  2273  		state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID))
  2274  	}
  2275  
  2276  	err := state.UpsertAllocs(1000, allocs)
  2277  	if err != nil {
  2278  		t.Fatalf("err: %v", err)
  2279  	}
  2280  
  2281  	out, err := state.AllocsByNode("foo")
  2282  	if err != nil {
  2283  		t.Fatalf("err: %v", err)
  2284  	}
  2285  
  2286  	sort.Sort(AllocIDSort(allocs))
  2287  	sort.Sort(AllocIDSort(out))
  2288  
  2289  	if !reflect.DeepEqual(allocs, out) {
  2290  		t.Fatalf("bad: %#v %#v", allocs, out)
  2291  	}
  2292  }
  2293  
  2294  func TestStateStore_AllocsByNodeTerminal(t *testing.T) {
  2295  	state := testStateStore(t)
  2296  	var allocs, term, nonterm []*structs.Allocation
  2297  
  2298  	for i := 0; i < 10; i++ {
  2299  		alloc := mock.Alloc()
  2300  		alloc.NodeID = "foo"
  2301  		if i%2 == 0 {
  2302  			alloc.DesiredStatus = structs.AllocDesiredStatusStop
  2303  			term = append(term, alloc)
  2304  		} else {
  2305  			nonterm = append(nonterm, alloc)
  2306  		}
  2307  		allocs = append(allocs, alloc)
  2308  	}
  2309  
  2310  	for idx, alloc := range allocs {
  2311  		state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID))
  2312  	}
  2313  
  2314  	err := state.UpsertAllocs(1000, allocs)
  2315  	if err != nil {
  2316  		t.Fatalf("err: %v", err)
  2317  	}
  2318  
  2319  	// Verify the terminal allocs
  2320  	out, err := state.AllocsByNodeTerminal("foo", true)
  2321  	if err != nil {
  2322  		t.Fatalf("err: %v", err)
  2323  	}
  2324  
  2325  	sort.Sort(AllocIDSort(term))
  2326  	sort.Sort(AllocIDSort(out))
  2327  
  2328  	if !reflect.DeepEqual(term, out) {
  2329  		t.Fatalf("bad: %#v %#v", term, out)
  2330  	}
  2331  
  2332  	// Verify the non-terminal allocs
  2333  	out, err = state.AllocsByNodeTerminal("foo", false)
  2334  	if err != nil {
  2335  		t.Fatalf("err: %v", err)
  2336  	}
  2337  
  2338  	sort.Sort(AllocIDSort(nonterm))
  2339  	sort.Sort(AllocIDSort(out))
  2340  
  2341  	if !reflect.DeepEqual(nonterm, out) {
  2342  		t.Fatalf("bad: %#v %#v", nonterm, out)
  2343  	}
  2344  }
  2345  
  2346  func TestStateStore_AllocsByJob(t *testing.T) {
  2347  	state := testStateStore(t)
  2348  	var allocs []*structs.Allocation
  2349  
  2350  	for i := 0; i < 10; i++ {
  2351  		alloc := mock.Alloc()
  2352  		alloc.JobID = "foo"
  2353  		allocs = append(allocs, alloc)
  2354  	}
  2355  
  2356  	for i, alloc := range allocs {
  2357  		state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID))
  2358  	}
  2359  
  2360  	err := state.UpsertAllocs(1000, allocs)
  2361  	if err != nil {
  2362  		t.Fatalf("err: %v", err)
  2363  	}
  2364  
  2365  	out, err := state.AllocsByJob("foo")
  2366  	if err != nil {
  2367  		t.Fatalf("err: %v", err)
  2368  	}
  2369  
  2370  	sort.Sort(AllocIDSort(allocs))
  2371  	sort.Sort(AllocIDSort(out))
  2372  
  2373  	if !reflect.DeepEqual(allocs, out) {
  2374  		t.Fatalf("bad: %#v %#v", allocs, out)
  2375  	}
  2376  }
  2377  
  2378  func TestStateStore_AllocsByIDPrefix(t *testing.T) {
  2379  	state := testStateStore(t)
  2380  	var allocs []*structs.Allocation
  2381  
  2382  	ids := []string{
  2383  		"aaaaaaaa-7bfb-395d-eb95-0685af2176b2",
  2384  		"aaaaaaab-7bfb-395d-eb95-0685af2176b2",
  2385  		"aaaaaabb-7bfb-395d-eb95-0685af2176b2",
  2386  		"aaaaabbb-7bfb-395d-eb95-0685af2176b2",
  2387  		"aaaabbbb-7bfb-395d-eb95-0685af2176b2",
  2388  		"aaabbbbb-7bfb-395d-eb95-0685af2176b2",
  2389  		"aabbbbbb-7bfb-395d-eb95-0685af2176b2",
  2390  		"abbbbbbb-7bfb-395d-eb95-0685af2176b2",
  2391  		"bbbbbbbb-7bfb-395d-eb95-0685af2176b2",
  2392  	}
  2393  	for i := 0; i < 9; i++ {
  2394  		alloc := mock.Alloc()
  2395  		alloc.ID = ids[i]
  2396  		allocs = append(allocs, alloc)
  2397  	}
  2398  
  2399  	for i, alloc := range allocs {
  2400  		state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID))
  2401  	}
  2402  
  2403  	err := state.UpsertAllocs(1000, allocs)
  2404  	if err != nil {
  2405  		t.Fatalf("err: %v", err)
  2406  	}
  2407  
  2408  	iter, err := state.AllocsByIDPrefix("aaaa")
  2409  	if err != nil {
  2410  		t.Fatalf("err: %v", err)
  2411  	}
  2412  
  2413  	gatherAllocs := func(iter memdb.ResultIterator) []*structs.Allocation {
  2414  		var allocs []*structs.Allocation
  2415  		for {
  2416  			raw := iter.Next()
  2417  			if raw == nil {
  2418  				break
  2419  			}
  2420  			allocs = append(allocs, raw.(*structs.Allocation))
  2421  		}
  2422  		return allocs
  2423  	}
  2424  
  2425  	out := gatherAllocs(iter)
  2426  	if len(out) != 5 {
  2427  		t.Fatalf("bad: expected five allocations, got: %#v", out)
  2428  	}
  2429  
  2430  	sort.Sort(AllocIDSort(allocs))
  2431  
  2432  	for index, alloc := range out {
  2433  		if ids[index] != alloc.ID {
  2434  			t.Fatalf("bad: got unexpected id: %s", alloc.ID)
  2435  		}
  2436  	}
  2437  
  2438  	iter, err = state.AllocsByIDPrefix("b-a7bfb")
  2439  	if err != nil {
  2440  		t.Fatalf("err: %v", err)
  2441  	}
  2442  
  2443  	out = gatherAllocs(iter)
  2444  	if len(out) != 0 {
  2445  		t.Fatalf("bad: unexpected zero allocations, got: %#v", out)
  2446  	}
  2447  }
  2448  
  2449  func TestStateStore_Allocs(t *testing.T) {
  2450  	state := testStateStore(t)
  2451  	var allocs []*structs.Allocation
  2452  
  2453  	for i := 0; i < 10; i++ {
  2454  		alloc := mock.Alloc()
  2455  		allocs = append(allocs, alloc)
  2456  	}
  2457  	for i, alloc := range allocs {
  2458  		state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID))
  2459  	}
  2460  
  2461  	err := state.UpsertAllocs(1000, allocs)
  2462  	if err != nil {
  2463  		t.Fatalf("err: %v", err)
  2464  	}
  2465  
  2466  	iter, err := state.Allocs()
  2467  	if err != nil {
  2468  		t.Fatalf("err: %v", err)
  2469  	}
  2470  
  2471  	var out []*structs.Allocation
  2472  	for {
  2473  		raw := iter.Next()
  2474  		if raw == nil {
  2475  			break
  2476  		}
  2477  		out = append(out, raw.(*structs.Allocation))
  2478  	}
  2479  
  2480  	sort.Sort(AllocIDSort(allocs))
  2481  	sort.Sort(AllocIDSort(out))
  2482  
  2483  	if !reflect.DeepEqual(allocs, out) {
  2484  		t.Fatalf("bad: %#v %#v", allocs, out)
  2485  	}
  2486  }
  2487  
  2488  func TestStateStore_RestoreAlloc(t *testing.T) {
  2489  	state := testStateStore(t)
  2490  	alloc := mock.Alloc()
  2491  
  2492  	notify := setupNotifyTest(
  2493  		state,
  2494  		watch.Item{Table: "allocs"},
  2495  		watch.Item{Alloc: alloc.ID},
  2496  		watch.Item{AllocEval: alloc.EvalID},
  2497  		watch.Item{AllocJob: alloc.JobID},
  2498  		watch.Item{AllocNode: alloc.NodeID})
  2499  
  2500  	restore, err := state.Restore()
  2501  	if err != nil {
  2502  		t.Fatalf("err: %v", err)
  2503  	}
  2504  
  2505  	err = restore.AllocRestore(alloc)
  2506  	if err != nil {
  2507  		t.Fatalf("err: %v", err)
  2508  	}
  2509  
  2510  	restore.Commit()
  2511  
  2512  	out, err := state.AllocByID(alloc.ID)
  2513  	if err != nil {
  2514  		t.Fatalf("err: %v", err)
  2515  	}
  2516  
  2517  	if !reflect.DeepEqual(out, alloc) {
  2518  		t.Fatalf("Bad: %#v %#v", out, alloc)
  2519  	}
  2520  
  2521  	notify.verify(t)
  2522  }
  2523  
  2524  func TestStateStore_RestoreAlloc_NoEphemeralDisk(t *testing.T) {
  2525  	state := testStateStore(t)
  2526  	alloc := mock.Alloc()
  2527  	alloc.Job.TaskGroups[0].EphemeralDisk = nil
  2528  	alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120
  2529  
  2530  	restore, err := state.Restore()
  2531  	if err != nil {
  2532  		t.Fatalf("err: %v", err)
  2533  	}
  2534  
  2535  	err = restore.AllocRestore(alloc)
  2536  	if err != nil {
  2537  		t.Fatalf("err: %v", err)
  2538  	}
  2539  
  2540  	restore.Commit()
  2541  
  2542  	out, err := state.AllocByID(alloc.ID)
  2543  	if err != nil {
  2544  		t.Fatalf("err: %v", err)
  2545  	}
  2546  
  2547  	expected := alloc.Copy()
  2548  	expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120}
  2549  	expected.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 0
  2550  
  2551  	if !reflect.DeepEqual(out, expected) {
  2552  		t.Fatalf("Bad: %#v %#v", out, expected)
  2553  	}
  2554  }
  2555  
  2556  func TestStateStore_SetJobStatus_ForceStatus(t *testing.T) {
  2557  	state := testStateStore(t)
  2558  	watcher := watch.NewItems()
  2559  	txn := state.db.Txn(true)
  2560  
  2561  	// Create and insert a mock job.
  2562  	job := mock.Job()
  2563  	job.Status = ""
  2564  	job.ModifyIndex = 0
  2565  	if err := txn.Insert("jobs", job); err != nil {
  2566  		t.Fatalf("job insert failed: %v", err)
  2567  	}
  2568  
  2569  	exp := "foobar"
  2570  	index := uint64(1000)
  2571  	if err := state.setJobStatus(index, watcher, txn, job, false, exp); err != nil {
  2572  		t.Fatalf("setJobStatus() failed: %v", err)
  2573  	}
  2574  
  2575  	i, err := txn.First("jobs", "id", job.ID)
  2576  	if err != nil {
  2577  		t.Fatalf("job lookup failed: %v", err)
  2578  	}
  2579  	updated := i.(*structs.Job)
  2580  
  2581  	if updated.Status != exp {
  2582  		t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, exp)
  2583  	}
  2584  
  2585  	if updated.ModifyIndex != index {
  2586  		t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index)
  2587  	}
  2588  }
  2589  
  2590  func TestStateStore_SetJobStatus_NoOp(t *testing.T) {
  2591  	state := testStateStore(t)
  2592  	watcher := watch.NewItems()
  2593  	txn := state.db.Txn(true)
  2594  
  2595  	// Create and insert a mock job that should be pending.
  2596  	job := mock.Job()
  2597  	job.Status = structs.JobStatusPending
  2598  	job.ModifyIndex = 10
  2599  	if err := txn.Insert("jobs", job); err != nil {
  2600  		t.Fatalf("job insert failed: %v", err)
  2601  	}
  2602  
  2603  	index := uint64(1000)
  2604  	if err := state.setJobStatus(index, watcher, txn, job, false, ""); err != nil {
  2605  		t.Fatalf("setJobStatus() failed: %v", err)
  2606  	}
  2607  
  2608  	i, err := txn.First("jobs", "id", job.ID)
  2609  	if err != nil {
  2610  		t.Fatalf("job lookup failed: %v", err)
  2611  	}
  2612  	updated := i.(*structs.Job)
  2613  
  2614  	if updated.ModifyIndex == index {
  2615  		t.Fatalf("setJobStatus() should have been a no-op")
  2616  	}
  2617  }
  2618  
  2619  func TestStateStore_SetJobStatus(t *testing.T) {
  2620  	state := testStateStore(t)
  2621  	watcher := watch.NewItems()
  2622  	txn := state.db.Txn(true)
  2623  
  2624  	// Create and insert a mock job that should be pending but has an incorrect
  2625  	// status.
  2626  	job := mock.Job()
  2627  	job.Status = "foobar"
  2628  	job.ModifyIndex = 10
  2629  	if err := txn.Insert("jobs", job); err != nil {
  2630  		t.Fatalf("job insert failed: %v", err)
  2631  	}
  2632  
  2633  	index := uint64(1000)
  2634  	if err := state.setJobStatus(index, watcher, txn, job, false, ""); err != nil {
  2635  		t.Fatalf("setJobStatus() failed: %v", err)
  2636  	}
  2637  
  2638  	i, err := txn.First("jobs", "id", job.ID)
  2639  	if err != nil {
  2640  		t.Fatalf("job lookup failed: %v", err)
  2641  	}
  2642  	updated := i.(*structs.Job)
  2643  
  2644  	if updated.Status != structs.JobStatusPending {
  2645  		t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, structs.JobStatusPending)
  2646  	}
  2647  
  2648  	if updated.ModifyIndex != index {
  2649  		t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index)
  2650  	}
  2651  }
  2652  
  2653  func TestStateStore_GetJobStatus_NoEvalsOrAllocs(t *testing.T) {
  2654  	job := mock.Job()
  2655  	state := testStateStore(t)
  2656  	txn := state.db.Txn(false)
  2657  	status, err := state.getJobStatus(txn, job, false)
  2658  	if err != nil {
  2659  		t.Fatalf("getJobStatus() failed: %v", err)
  2660  	}
  2661  
  2662  	if status != structs.JobStatusPending {
  2663  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending)
  2664  	}
  2665  }
  2666  
  2667  func TestStateStore_GetJobStatus_NoEvalsOrAllocs_Periodic(t *testing.T) {
  2668  	job := mock.PeriodicJob()
  2669  	state := testStateStore(t)
  2670  	txn := state.db.Txn(false)
  2671  	status, err := state.getJobStatus(txn, job, false)
  2672  	if err != nil {
  2673  		t.Fatalf("getJobStatus() failed: %v", err)
  2674  	}
  2675  
  2676  	if status != structs.JobStatusRunning {
  2677  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning)
  2678  	}
  2679  }
  2680  
  2681  func TestStateStore_GetJobStatus_NoEvalsOrAllocs_EvalDelete(t *testing.T) {
  2682  	job := mock.Job()
  2683  	state := testStateStore(t)
  2684  	txn := state.db.Txn(false)
  2685  	status, err := state.getJobStatus(txn, job, true)
  2686  	if err != nil {
  2687  		t.Fatalf("getJobStatus() failed: %v", err)
  2688  	}
  2689  
  2690  	if status != structs.JobStatusDead {
  2691  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead)
  2692  	}
  2693  }
  2694  
  2695  func TestStateStore_GetJobStatus_DeadEvalsAndAllocs(t *testing.T) {
  2696  	state := testStateStore(t)
  2697  	job := mock.Job()
  2698  
  2699  	// Create a mock alloc that is dead.
  2700  	alloc := mock.Alloc()
  2701  	alloc.JobID = job.ID
  2702  	alloc.DesiredStatus = structs.AllocDesiredStatusStop
  2703  	state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))
  2704  	if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil {
  2705  		t.Fatalf("err: %v", err)
  2706  	}
  2707  
  2708  	// Create a mock eval that is complete
  2709  	eval := mock.Eval()
  2710  	eval.JobID = job.ID
  2711  	eval.Status = structs.EvalStatusComplete
  2712  	if err := state.UpsertEvals(1001, []*structs.Evaluation{eval}); err != nil {
  2713  		t.Fatalf("err: %v", err)
  2714  	}
  2715  
  2716  	txn := state.db.Txn(false)
  2717  	status, err := state.getJobStatus(txn, job, false)
  2718  	if err != nil {
  2719  		t.Fatalf("getJobStatus() failed: %v", err)
  2720  	}
  2721  
  2722  	if status != structs.JobStatusDead {
  2723  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead)
  2724  	}
  2725  }
  2726  
  2727  func TestStateStore_GetJobStatus_RunningAlloc(t *testing.T) {
  2728  	state := testStateStore(t)
  2729  	job := mock.Job()
  2730  
  2731  	// Create a mock alloc that is running.
  2732  	alloc := mock.Alloc()
  2733  	alloc.JobID = job.ID
  2734  	alloc.DesiredStatus = structs.AllocDesiredStatusRun
  2735  	state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))
  2736  	if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil {
  2737  		t.Fatalf("err: %v", err)
  2738  	}
  2739  
  2740  	txn := state.db.Txn(false)
  2741  	status, err := state.getJobStatus(txn, job, true)
  2742  	if err != nil {
  2743  		t.Fatalf("getJobStatus() failed: %v", err)
  2744  	}
  2745  
  2746  	if status != structs.JobStatusRunning {
  2747  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning)
  2748  	}
  2749  }
  2750  
  2751  func TestStateStore_SetJobStatus_PendingEval(t *testing.T) {
  2752  	state := testStateStore(t)
  2753  	job := mock.Job()
  2754  
  2755  	// Create a mock eval that is pending.
  2756  	eval := mock.Eval()
  2757  	eval.JobID = job.ID
  2758  	eval.Status = structs.EvalStatusPending
  2759  	if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil {
  2760  		t.Fatalf("err: %v", err)
  2761  	}
  2762  
  2763  	txn := state.db.Txn(false)
  2764  	status, err := state.getJobStatus(txn, job, true)
  2765  	if err != nil {
  2766  		t.Fatalf("getJobStatus() failed: %v", err)
  2767  	}
  2768  
  2769  	if status != structs.JobStatusPending {
  2770  		t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending)
  2771  	}
  2772  }
  2773  
  2774  func TestStateWatch_watch(t *testing.T) {
  2775  	sw := newStateWatch()
  2776  	notify1 := make(chan struct{}, 1)
  2777  	notify2 := make(chan struct{}, 1)
  2778  	notify3 := make(chan struct{}, 1)
  2779  
  2780  	// Notifications trigger subscribed channels
  2781  	sw.watch(watch.NewItems(watch.Item{Table: "foo"}), notify1)
  2782  	sw.watch(watch.NewItems(watch.Item{Table: "bar"}), notify2)
  2783  	sw.watch(watch.NewItems(watch.Item{Table: "baz"}), notify3)
  2784  
  2785  	items := watch.NewItems()
  2786  	items.Add(watch.Item{Table: "foo"})
  2787  	items.Add(watch.Item{Table: "bar"})
  2788  
  2789  	sw.notify(items)
  2790  	if len(notify1) != 1 {
  2791  		t.Fatalf("should notify")
  2792  	}
  2793  	if len(notify2) != 1 {
  2794  		t.Fatalf("should notify")
  2795  	}
  2796  	if len(notify3) != 0 {
  2797  		t.Fatalf("should not notify")
  2798  	}
  2799  }
  2800  
  2801  func TestStateWatch_stopWatch(t *testing.T) {
  2802  	sw := newStateWatch()
  2803  	notify := make(chan struct{})
  2804  
  2805  	// First subscribe
  2806  	sw.watch(watch.NewItems(watch.Item{Table: "foo"}), notify)
  2807  
  2808  	// Unsubscribe stop notifications
  2809  	sw.stopWatch(watch.NewItems(watch.Item{Table: "foo"}), notify)
  2810  
  2811  	// Check that the group was removed
  2812  	if _, ok := sw.items[watch.Item{Table: "foo"}]; ok {
  2813  		t.Fatalf("should remove group")
  2814  	}
  2815  
  2816  	// Check that we are not notified
  2817  	sw.notify(watch.NewItems(watch.Item{Table: "foo"}))
  2818  	if len(notify) != 0 {
  2819  		t.Fatalf("should not notify")
  2820  	}
  2821  }
  2822  
  2823  func TestStateJobSummary_UpdateJobCount(t *testing.T) {
  2824  	state := testStateStore(t)
  2825  	alloc := mock.Alloc()
  2826  	job := alloc.Job
  2827  	job.TaskGroups[0].Count = 3
  2828  	err := state.UpsertJob(1000, job)
  2829  	if err != nil {
  2830  		t.Fatalf("err: %v", err)
  2831  	}
  2832  
  2833  	if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc}); err != nil {
  2834  		t.Fatalf("err: %v", err)
  2835  	}
  2836  	summary, _ := state.JobSummaryByID(job.ID)
  2837  	expectedSummary := structs.JobSummary{
  2838  		JobID: job.ID,
  2839  		Summary: map[string]structs.TaskGroupSummary{
  2840  			"web": {
  2841  				Starting: 1,
  2842  			},
  2843  		},
  2844  		CreateIndex: 1000,
  2845  		ModifyIndex: 1001,
  2846  	}
  2847  	if !reflect.DeepEqual(summary, &expectedSummary) {
  2848  		t.Fatalf("expected: %v, actual: %v", expectedSummary, summary)
  2849  	}
  2850  
  2851  	alloc2 := mock.Alloc()
  2852  	alloc2.Job = job
  2853  	alloc2.JobID = job.ID
  2854  
  2855  	alloc3 := mock.Alloc()
  2856  	alloc3.Job = job
  2857  	alloc3.JobID = job.ID
  2858  
  2859  	if err := state.UpsertAllocs(1002, []*structs.Allocation{alloc2, alloc3}); err != nil {
  2860  		t.Fatalf("err: %v", err)
  2861  	}
  2862  
  2863  	outA, _ := state.AllocByID(alloc3.ID)
  2864  
  2865  	summary, _ = state.JobSummaryByID(job.ID)
  2866  	expectedSummary = structs.JobSummary{
  2867  		JobID: job.ID,
  2868  		Summary: map[string]structs.TaskGroupSummary{
  2869  			"web": {
  2870  				Starting: 3,
  2871  			},
  2872  		},
  2873  		CreateIndex: job.CreateIndex,
  2874  		ModifyIndex: outA.ModifyIndex,
  2875  	}
  2876  	if !reflect.DeepEqual(summary, &expectedSummary) {
  2877  		t.Fatalf("expected summary: %v, actual: %v", expectedSummary, summary)
  2878  	}
  2879  
  2880  	alloc4 := mock.Alloc()
  2881  	alloc4.ID = alloc2.ID
  2882  	alloc4.Job = alloc2.Job
  2883  	alloc4.JobID = alloc2.JobID
  2884  	alloc4.ClientStatus = structs.AllocClientStatusComplete
  2885  
  2886  	alloc5 := mock.Alloc()
  2887  	alloc5.ID = alloc3.ID
  2888  	alloc5.Job = alloc3.Job
  2889  	alloc5.JobID = alloc3.JobID
  2890  	alloc5.ClientStatus = structs.AllocClientStatusComplete
  2891  
  2892  	if err := state.UpdateAllocsFromClient(1004, []*structs.Allocation{alloc4, alloc5}); err != nil {
  2893  		t.Fatalf("err: %v", err)
  2894  	}
  2895  	outA, _ = state.AllocByID(alloc5.ID)
  2896  	summary, _ = state.JobSummaryByID(job.ID)
  2897  	expectedSummary = structs.JobSummary{
  2898  		JobID: job.ID,
  2899  		Summary: map[string]structs.TaskGroupSummary{
  2900  			"web": {
  2901  				Complete: 2,
  2902  				Starting: 1,
  2903  			},
  2904  		},
  2905  		CreateIndex: job.CreateIndex,
  2906  		ModifyIndex: outA.ModifyIndex,
  2907  	}
  2908  	if !reflect.DeepEqual(summary, &expectedSummary) {
  2909  		t.Fatalf("expected: %v, actual: %v", expectedSummary, summary)
  2910  	}
  2911  }
  2912  
  2913  func TestJobSummary_UpdateClientStatus(t *testing.T) {
  2914  	state := testStateStore(t)
  2915  	alloc := mock.Alloc()
  2916  	job := alloc.Job
  2917  	job.TaskGroups[0].Count = 3
  2918  
  2919  	alloc2 := mock.Alloc()
  2920  	alloc2.Job = job
  2921  	alloc2.JobID = job.ID
  2922  
  2923  	alloc3 := mock.Alloc()
  2924  	alloc3.Job = job
  2925  	alloc3.JobID = job.ID
  2926  
  2927  	err := state.UpsertJob(1000, job)
  2928  	if err != nil {
  2929  		t.Fatalf("err: %v", err)
  2930  	}
  2931  
  2932  	if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc, alloc2, alloc3}); err != nil {
  2933  		t.Fatalf("err: %v", err)
  2934  	}
  2935  	summary, _ := state.JobSummaryByID(job.ID)
  2936  	if summary.Summary["web"].Starting != 3 {
  2937  		t.Fatalf("bad job summary: %v", summary)
  2938  	}
  2939  
  2940  	alloc4 := mock.Alloc()
  2941  	alloc4.ID = alloc2.ID
  2942  	alloc4.Job = alloc2.Job
  2943  	alloc4.JobID = alloc2.JobID
  2944  	alloc4.ClientStatus = structs.AllocClientStatusComplete
  2945  
  2946  	alloc5 := mock.Alloc()
  2947  	alloc5.ID = alloc3.ID
  2948  	alloc5.Job = alloc3.Job
  2949  	alloc5.JobID = alloc3.JobID
  2950  	alloc5.ClientStatus = structs.AllocClientStatusFailed
  2951  
  2952  	alloc6 := mock.Alloc()
  2953  	alloc6.ID = alloc.ID
  2954  	alloc6.Job = alloc.Job
  2955  	alloc6.JobID = alloc.JobID
  2956  	alloc6.ClientStatus = structs.AllocClientStatusRunning
  2957  
  2958  	if err := state.UpdateAllocsFromClient(1002, []*structs.Allocation{alloc4, alloc5, alloc6}); err != nil {
  2959  		t.Fatalf("err: %v", err)
  2960  	}
  2961  	summary, _ = state.JobSummaryByID(job.ID)
  2962  	if summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 {
  2963  		t.Fatalf("bad job summary: %v", summary)
  2964  	}
  2965  
  2966  	alloc7 := mock.Alloc()
  2967  	alloc7.Job = alloc.Job
  2968  	alloc7.JobID = alloc.JobID
  2969  
  2970  	if err := state.UpsertAllocs(1003, []*structs.Allocation{alloc7}); err != nil {
  2971  		t.Fatalf("err: %v", err)
  2972  	}
  2973  	summary, _ = state.JobSummaryByID(job.ID)
  2974  	if summary.Summary["web"].Starting != 1 || summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 {
  2975  		t.Fatalf("bad job summary: %v", summary)
  2976  	}
  2977  }
  2978  
  2979  func TestStateStore_UpsertVaultAccessors(t *testing.T) {
  2980  	state := testStateStore(t)
  2981  	a := mock.VaultAccessor()
  2982  	a2 := mock.VaultAccessor()
  2983  
  2984  	err := state.UpsertVaultAccessor(1000, []*structs.VaultAccessor{a, a2})
  2985  	if err != nil {
  2986  		t.Fatalf("err: %v", err)
  2987  	}
  2988  
  2989  	out, err := state.VaultAccessor(a.Accessor)
  2990  	if err != nil {
  2991  		t.Fatalf("err: %v", err)
  2992  	}
  2993  
  2994  	if !reflect.DeepEqual(a, out) {
  2995  		t.Fatalf("bad: %#v %#v", a, out)
  2996  	}
  2997  
  2998  	out, err = state.VaultAccessor(a2.Accessor)
  2999  	if err != nil {
  3000  		t.Fatalf("err: %v", err)
  3001  	}
  3002  
  3003  	if !reflect.DeepEqual(a2, out) {
  3004  		t.Fatalf("bad: %#v %#v", a2, out)
  3005  	}
  3006  
  3007  	iter, err := state.VaultAccessors()
  3008  	if err != nil {
  3009  		t.Fatalf("err: %v", err)
  3010  	}
  3011  
  3012  	count := 0
  3013  	for {
  3014  		raw := iter.Next()
  3015  		if raw == nil {
  3016  			break
  3017  		}
  3018  
  3019  		count++
  3020  		accessor := raw.(*structs.VaultAccessor)
  3021  
  3022  		if !reflect.DeepEqual(accessor, a) && !reflect.DeepEqual(accessor, a2) {
  3023  			t.Fatalf("bad: %#v", accessor)
  3024  		}
  3025  	}
  3026  
  3027  	if count != 2 {
  3028  		t.Fatalf("bad: %d", count)
  3029  	}
  3030  
  3031  	index, err := state.Index("vault_accessors")
  3032  	if err != nil {
  3033  		t.Fatalf("err: %v", err)
  3034  	}
  3035  	if index != 1000 {
  3036  		t.Fatalf("bad: %d", index)
  3037  	}
  3038  }
  3039  
  3040  func TestStateStore_DeleteVaultAccessors(t *testing.T) {
  3041  	state := testStateStore(t)
  3042  	a1 := mock.VaultAccessor()
  3043  	a2 := mock.VaultAccessor()
  3044  	accessors := []*structs.VaultAccessor{a1, a2}
  3045  
  3046  	err := state.UpsertVaultAccessor(1000, accessors)
  3047  	if err != nil {
  3048  		t.Fatalf("err: %v", err)
  3049  	}
  3050  
  3051  	err = state.DeleteVaultAccessors(1001, accessors)
  3052  	if err != nil {
  3053  		t.Fatalf("err: %v", err)
  3054  	}
  3055  
  3056  	out, err := state.VaultAccessor(a1.Accessor)
  3057  	if err != nil {
  3058  		t.Fatalf("err: %v", err)
  3059  	}
  3060  	if out != nil {
  3061  		t.Fatalf("bad: %#v %#v", a1, out)
  3062  	}
  3063  	out, err = state.VaultAccessor(a2.Accessor)
  3064  	if err != nil {
  3065  		t.Fatalf("err: %v", err)
  3066  	}
  3067  	if out != nil {
  3068  		t.Fatalf("bad: %#v %#v", a2, out)
  3069  	}
  3070  
  3071  	index, err := state.Index("vault_accessors")
  3072  	if err != nil {
  3073  		t.Fatalf("err: %v", err)
  3074  	}
  3075  	if index != 1001 {
  3076  		t.Fatalf("bad: %d", index)
  3077  	}
  3078  }
  3079  
  3080  func TestStateStore_VaultAccessorsByAlloc(t *testing.T) {
  3081  	state := testStateStore(t)
  3082  	alloc := mock.Alloc()
  3083  	var accessors []*structs.VaultAccessor
  3084  	var expected []*structs.VaultAccessor
  3085  
  3086  	for i := 0; i < 5; i++ {
  3087  		accessor := mock.VaultAccessor()
  3088  		accessor.AllocID = alloc.ID
  3089  		expected = append(expected, accessor)
  3090  		accessors = append(accessors, accessor)
  3091  	}
  3092  
  3093  	for i := 0; i < 10; i++ {
  3094  		accessor := mock.VaultAccessor()
  3095  		accessors = append(accessors, accessor)
  3096  	}
  3097  
  3098  	err := state.UpsertVaultAccessor(1000, accessors)
  3099  	if err != nil {
  3100  		t.Fatalf("err: %v", err)
  3101  	}
  3102  
  3103  	out, err := state.VaultAccessorsByAlloc(alloc.ID)
  3104  	if err != nil {
  3105  		t.Fatalf("err: %v", err)
  3106  	}
  3107  
  3108  	if len(expected) != len(out) {
  3109  		t.Fatalf("bad: %#v %#v", len(expected), len(out))
  3110  	}
  3111  
  3112  	index, err := state.Index("vault_accessors")
  3113  	if err != nil {
  3114  		t.Fatalf("err: %v", err)
  3115  	}
  3116  	if index != 1000 {
  3117  		t.Fatalf("bad: %d", index)
  3118  	}
  3119  }
  3120  
  3121  func TestStateStore_VaultAccessorsByNode(t *testing.T) {
  3122  	state := testStateStore(t)
  3123  	node := mock.Node()
  3124  	var accessors []*structs.VaultAccessor
  3125  	var expected []*structs.VaultAccessor
  3126  
  3127  	for i := 0; i < 5; i++ {
  3128  		accessor := mock.VaultAccessor()
  3129  		accessor.NodeID = node.ID
  3130  		expected = append(expected, accessor)
  3131  		accessors = append(accessors, accessor)
  3132  	}
  3133  
  3134  	for i := 0; i < 10; i++ {
  3135  		accessor := mock.VaultAccessor()
  3136  		accessors = append(accessors, accessor)
  3137  	}
  3138  
  3139  	err := state.UpsertVaultAccessor(1000, accessors)
  3140  	if err != nil {
  3141  		t.Fatalf("err: %v", err)
  3142  	}
  3143  
  3144  	out, err := state.VaultAccessorsByNode(node.ID)
  3145  	if err != nil {
  3146  		t.Fatalf("err: %v", err)
  3147  	}
  3148  
  3149  	if len(expected) != len(out) {
  3150  		t.Fatalf("bad: %#v %#v", len(expected), len(out))
  3151  	}
  3152  
  3153  	index, err := state.Index("vault_accessors")
  3154  	if err != nil {
  3155  		t.Fatalf("err: %v", err)
  3156  	}
  3157  	if index != 1000 {
  3158  		t.Fatalf("bad: %d", index)
  3159  	}
  3160  }
  3161  
  3162  func TestStateStore_RestoreVaultAccessor(t *testing.T) {
  3163  	state := testStateStore(t)
  3164  	a := mock.VaultAccessor()
  3165  
  3166  	restore, err := state.Restore()
  3167  	if err != nil {
  3168  		t.Fatalf("err: %v", err)
  3169  	}
  3170  
  3171  	err = restore.VaultAccessorRestore(a)
  3172  	if err != nil {
  3173  		t.Fatalf("err: %v", err)
  3174  	}
  3175  	restore.Commit()
  3176  
  3177  	out, err := state.VaultAccessor(a.Accessor)
  3178  	if err != nil {
  3179  		t.Fatalf("err: %v", err)
  3180  	}
  3181  
  3182  	if !reflect.DeepEqual(out, a) {
  3183  		t.Fatalf("Bad: %#v %#v", out, a)
  3184  	}
  3185  }
  3186  
  3187  // setupNotifyTest takes a state store and a set of watch items, then creates
  3188  // and subscribes a notification channel for each item.
  3189  func setupNotifyTest(state *StateStore, items ...watch.Item) notifyTest {
  3190  	var n notifyTest
  3191  	for _, item := range items {
  3192  		ch := make(chan struct{}, 1)
  3193  		state.Watch(watch.NewItems(item), ch)
  3194  		n = append(n, &notifyTestCase{item, ch})
  3195  	}
  3196  	return n
  3197  }
  3198  
  3199  // notifyTestCase is used to set up and verify watch triggers.
  3200  type notifyTestCase struct {
  3201  	item watch.Item
  3202  	ch   chan struct{}
  3203  }
  3204  
  3205  // notifyTest is a suite of notifyTestCases.
  3206  type notifyTest []*notifyTestCase
  3207  
  3208  // verify ensures that each channel received a notification.
  3209  func (n notifyTest) verify(t *testing.T) {
  3210  	for _, tcase := range n {
  3211  		if len(tcase.ch) != 1 {
  3212  			t.Fatalf("should notify %#v", tcase.item)
  3213  		}
  3214  	}
  3215  }
  3216  
  3217  // NodeIDSort is used to sort nodes by ID
  3218  type NodeIDSort []*structs.Node
  3219  
  3220  func (n NodeIDSort) Len() int {
  3221  	return len(n)
  3222  }
  3223  
  3224  func (n NodeIDSort) Less(i, j int) bool {
  3225  	return n[i].ID < n[j].ID
  3226  }
  3227  
  3228  func (n NodeIDSort) Swap(i, j int) {
  3229  	n[i], n[j] = n[j], n[i]
  3230  }
  3231  
  3232  // JobIDis used to sort jobs by id
  3233  type JobIDSort []*structs.Job
  3234  
  3235  func (n JobIDSort) Len() int {
  3236  	return len(n)
  3237  }
  3238  
  3239  func (n JobIDSort) Less(i, j int) bool {
  3240  	return n[i].ID < n[j].ID
  3241  }
  3242  
  3243  func (n JobIDSort) Swap(i, j int) {
  3244  	n[i], n[j] = n[j], n[i]
  3245  }
  3246  
  3247  // EvalIDis used to sort evals by id
  3248  type EvalIDSort []*structs.Evaluation
  3249  
  3250  func (n EvalIDSort) Len() int {
  3251  	return len(n)
  3252  }
  3253  
  3254  func (n EvalIDSort) Less(i, j int) bool {
  3255  	return n[i].ID < n[j].ID
  3256  }
  3257  
  3258  func (n EvalIDSort) Swap(i, j int) {
  3259  	n[i], n[j] = n[j], n[i]
  3260  }
  3261  
  3262  // AllocIDsort used to sort allocations by id
  3263  type AllocIDSort []*structs.Allocation
  3264  
  3265  func (n AllocIDSort) Len() int {
  3266  	return len(n)
  3267  }
  3268  
  3269  func (n AllocIDSort) Less(i, j int) bool {
  3270  	return n[i].ID < n[j].ID
  3271  }
  3272  
  3273  func (n AllocIDSort) Swap(i, j int) {
  3274  	n[i], n[j] = n[j], n[i]
  3275  }