github.com/hspak/nomad@v0.7.2-0.20180309000617-bc4ae22a39a5/nomad/fsm_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/google/go-cmp/cmp"
    13  	memdb "github.com/hashicorp/go-memdb"
    14  	"github.com/hashicorp/nomad/helper"
    15  	"github.com/hashicorp/nomad/nomad/mock"
    16  	"github.com/hashicorp/nomad/nomad/state"
    17  	"github.com/hashicorp/nomad/nomad/structs"
    18  	"github.com/hashicorp/nomad/testutil"
    19  	"github.com/hashicorp/raft"
    20  	"github.com/kr/pretty"
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  type MockSink struct {
    26  	*bytes.Buffer
    27  	cancel bool
    28  }
    29  
    30  func (m *MockSink) ID() string {
    31  	return "Mock"
    32  }
    33  
    34  func (m *MockSink) Cancel() error {
    35  	m.cancel = true
    36  	return nil
    37  }
    38  
    39  func (m *MockSink) Close() error {
    40  	return nil
    41  }
    42  
    43  func testStateStore(t *testing.T) *state.StateStore {
    44  	return state.TestStateStore(t)
    45  }
    46  
    47  func testFSM(t *testing.T) *nomadFSM {
    48  	broker := testBroker(t, 0)
    49  	dispatcher, _ := testPeriodicDispatcher()
    50  	fsmConfig := &FSMConfig{
    51  		EvalBroker: broker,
    52  		Periodic:   dispatcher,
    53  		Blocked:    NewBlockedEvals(broker),
    54  		LogOutput:  os.Stderr,
    55  		Region:     "global",
    56  	}
    57  	fsm, err := NewFSM(fsmConfig)
    58  	if err != nil {
    59  		t.Fatalf("err: %v", err)
    60  	}
    61  	if fsm == nil {
    62  		t.Fatalf("missing fsm")
    63  	}
    64  	state.TestInitState(t, fsm.state)
    65  	return fsm
    66  }
    67  
    68  func makeLog(buf []byte) *raft.Log {
    69  	return &raft.Log{
    70  		Index: 1,
    71  		Term:  1,
    72  		Type:  raft.LogCommand,
    73  		Data:  buf,
    74  	}
    75  }
    76  
    77  func TestFSM_UpsertNode(t *testing.T) {
    78  	t.Parallel()
    79  	fsm := testFSM(t)
    80  	fsm.blockedEvals.SetEnabled(true)
    81  
    82  	node := mock.Node()
    83  
    84  	// Mark an eval as blocked.
    85  	eval := mock.Eval()
    86  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
    87  	fsm.blockedEvals.Block(eval)
    88  
    89  	req := structs.NodeRegisterRequest{
    90  		Node: node,
    91  	}
    92  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
    93  	if err != nil {
    94  		t.Fatalf("err: %v", err)
    95  	}
    96  
    97  	resp := fsm.Apply(makeLog(buf))
    98  	if resp != nil {
    99  		t.Fatalf("resp: %v", resp)
   100  	}
   101  
   102  	// Verify we are registered
   103  	ws := memdb.NewWatchSet()
   104  	n, err := fsm.State().NodeByID(ws, req.Node.ID)
   105  	if err != nil {
   106  		t.Fatalf("err: %v", err)
   107  	}
   108  	if n == nil {
   109  		t.Fatalf("not found!")
   110  	}
   111  	if n.CreateIndex != 1 {
   112  		t.Fatalf("bad index: %d", node.CreateIndex)
   113  	}
   114  
   115  	tt := fsm.TimeTable()
   116  	index := tt.NearestIndex(time.Now().UTC())
   117  	if index != 1 {
   118  		t.Fatalf("bad: %d", index)
   119  	}
   120  
   121  	// Verify the eval was unblocked.
   122  	testutil.WaitForResult(func() (bool, error) {
   123  		bStats := fsm.blockedEvals.Stats()
   124  		if bStats.TotalBlocked != 0 {
   125  			return false, fmt.Errorf("bad: %#v", bStats)
   126  		}
   127  		return true, nil
   128  	}, func(err error) {
   129  		t.Fatalf("err: %s", err)
   130  	})
   131  
   132  }
   133  
   134  func TestFSM_DeregisterNode(t *testing.T) {
   135  	t.Parallel()
   136  	fsm := testFSM(t)
   137  
   138  	node := mock.Node()
   139  	req := structs.NodeRegisterRequest{
   140  		Node: node,
   141  	}
   142  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   143  	if err != nil {
   144  		t.Fatalf("err: %v", err)
   145  	}
   146  
   147  	resp := fsm.Apply(makeLog(buf))
   148  	if resp != nil {
   149  		t.Fatalf("resp: %v", resp)
   150  	}
   151  
   152  	req2 := structs.NodeDeregisterRequest{
   153  		NodeID: node.ID,
   154  	}
   155  	buf, err = structs.Encode(structs.NodeDeregisterRequestType, req2)
   156  	if err != nil {
   157  		t.Fatalf("err: %v", err)
   158  	}
   159  
   160  	resp = fsm.Apply(makeLog(buf))
   161  	if resp != nil {
   162  		t.Fatalf("resp: %v", resp)
   163  	}
   164  
   165  	// Verify we are NOT registered
   166  	ws := memdb.NewWatchSet()
   167  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   168  	if err != nil {
   169  		t.Fatalf("err: %v", err)
   170  	}
   171  	if node != nil {
   172  		t.Fatalf("node found!")
   173  	}
   174  }
   175  
   176  func TestFSM_UpdateNodeStatus(t *testing.T) {
   177  	t.Parallel()
   178  	fsm := testFSM(t)
   179  	fsm.blockedEvals.SetEnabled(true)
   180  
   181  	node := mock.Node()
   182  	req := structs.NodeRegisterRequest{
   183  		Node: node,
   184  	}
   185  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   186  	if err != nil {
   187  		t.Fatalf("err: %v", err)
   188  	}
   189  
   190  	resp := fsm.Apply(makeLog(buf))
   191  	if resp != nil {
   192  		t.Fatalf("resp: %v", resp)
   193  	}
   194  
   195  	// Mark an eval as blocked.
   196  	eval := mock.Eval()
   197  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
   198  	fsm.blockedEvals.Block(eval)
   199  
   200  	req2 := structs.NodeUpdateStatusRequest{
   201  		NodeID: node.ID,
   202  		Status: structs.NodeStatusReady,
   203  	}
   204  	buf, err = structs.Encode(structs.NodeUpdateStatusRequestType, req2)
   205  	if err != nil {
   206  		t.Fatalf("err: %v", err)
   207  	}
   208  
   209  	resp = fsm.Apply(makeLog(buf))
   210  	if resp != nil {
   211  		t.Fatalf("resp: %v", resp)
   212  	}
   213  
   214  	// Verify the status is ready.
   215  	ws := memdb.NewWatchSet()
   216  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   217  	if err != nil {
   218  		t.Fatalf("err: %v", err)
   219  	}
   220  	if node.Status != structs.NodeStatusReady {
   221  		t.Fatalf("bad node: %#v", node)
   222  	}
   223  
   224  	// Verify the eval was unblocked.
   225  	testutil.WaitForResult(func() (bool, error) {
   226  		bStats := fsm.blockedEvals.Stats()
   227  		if bStats.TotalBlocked != 0 {
   228  			return false, fmt.Errorf("bad: %#v", bStats)
   229  		}
   230  		return true, nil
   231  	}, func(err error) {
   232  		t.Fatalf("err: %s", err)
   233  	})
   234  }
   235  
   236  func TestFSM_UpdateNodeDrain(t *testing.T) {
   237  	t.Parallel()
   238  	fsm := testFSM(t)
   239  
   240  	node := mock.Node()
   241  	req := structs.NodeRegisterRequest{
   242  		Node: node,
   243  	}
   244  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   245  	if err != nil {
   246  		t.Fatalf("err: %v", err)
   247  	}
   248  
   249  	resp := fsm.Apply(makeLog(buf))
   250  	if resp != nil {
   251  		t.Fatalf("resp: %v", resp)
   252  	}
   253  
   254  	req2 := structs.NodeUpdateDrainRequest{
   255  		NodeID: node.ID,
   256  		Drain:  true,
   257  	}
   258  	buf, err = structs.Encode(structs.NodeUpdateDrainRequestType, req2)
   259  	if err != nil {
   260  		t.Fatalf("err: %v", err)
   261  	}
   262  
   263  	resp = fsm.Apply(makeLog(buf))
   264  	if resp != nil {
   265  		t.Fatalf("resp: %v", resp)
   266  	}
   267  
   268  	// Verify we are NOT registered
   269  	ws := memdb.NewWatchSet()
   270  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   271  	if err != nil {
   272  		t.Fatalf("err: %v", err)
   273  	}
   274  	if !node.Drain {
   275  		t.Fatalf("bad node: %#v", node)
   276  	}
   277  }
   278  
   279  func TestFSM_RegisterJob(t *testing.T) {
   280  	t.Parallel()
   281  	fsm := testFSM(t)
   282  
   283  	job := mock.PeriodicJob()
   284  	req := structs.JobRegisterRequest{
   285  		Job: job,
   286  		WriteRequest: structs.WriteRequest{
   287  			Namespace: job.Namespace,
   288  		},
   289  	}
   290  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   291  	if err != nil {
   292  		t.Fatalf("err: %v", err)
   293  	}
   294  
   295  	resp := fsm.Apply(makeLog(buf))
   296  	if resp != nil {
   297  		t.Fatalf("resp: %v", resp)
   298  	}
   299  
   300  	// Verify we are registered
   301  	ws := memdb.NewWatchSet()
   302  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   303  	if err != nil {
   304  		t.Fatalf("err: %v", err)
   305  	}
   306  	if jobOut == nil {
   307  		t.Fatalf("not found!")
   308  	}
   309  	if jobOut.CreateIndex != 1 {
   310  		t.Fatalf("bad index: %d", jobOut.CreateIndex)
   311  	}
   312  
   313  	// Verify it was added to the periodic runner.
   314  	tuple := structs.NamespacedID{
   315  		ID:        job.ID,
   316  		Namespace: job.Namespace,
   317  	}
   318  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; !ok {
   319  		t.Fatal("job not added to periodic runner")
   320  	}
   321  
   322  	// Verify the launch time was tracked.
   323  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   324  	if err != nil {
   325  		t.Fatalf("err: %v", err)
   326  	}
   327  	if launchOut == nil {
   328  		t.Fatalf("not found!")
   329  	}
   330  	if launchOut.Launch.IsZero() {
   331  		t.Fatalf("bad launch time: %v", launchOut.Launch)
   332  	}
   333  }
   334  
   335  func TestFSM_RegisterPeriodicJob_NonLeader(t *testing.T) {
   336  	t.Parallel()
   337  	fsm := testFSM(t)
   338  
   339  	// Disable the dispatcher
   340  	fsm.periodicDispatcher.SetEnabled(false)
   341  
   342  	job := mock.PeriodicJob()
   343  	req := structs.JobRegisterRequest{
   344  		Job: job,
   345  		WriteRequest: structs.WriteRequest{
   346  			Namespace: job.Namespace,
   347  		},
   348  	}
   349  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   350  	if err != nil {
   351  		t.Fatalf("err: %v", err)
   352  	}
   353  
   354  	resp := fsm.Apply(makeLog(buf))
   355  	if resp != nil {
   356  		t.Fatalf("resp: %v", resp)
   357  	}
   358  
   359  	// Verify we are registered
   360  	ws := memdb.NewWatchSet()
   361  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   362  	if err != nil {
   363  		t.Fatalf("err: %v", err)
   364  	}
   365  	if jobOut == nil {
   366  		t.Fatalf("not found!")
   367  	}
   368  	if jobOut.CreateIndex != 1 {
   369  		t.Fatalf("bad index: %d", jobOut.CreateIndex)
   370  	}
   371  
   372  	// Verify it wasn't added to the periodic runner.
   373  	tuple := structs.NamespacedID{
   374  		ID:        job.ID,
   375  		Namespace: job.Namespace,
   376  	}
   377  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; ok {
   378  		t.Fatal("job added to periodic runner")
   379  	}
   380  
   381  	// Verify the launch time was tracked.
   382  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   383  	if err != nil {
   384  		t.Fatalf("err: %v", err)
   385  	}
   386  	if launchOut == nil {
   387  		t.Fatalf("not found!")
   388  	}
   389  	if launchOut.Launch.IsZero() {
   390  		t.Fatalf("bad launch time: %v", launchOut.Launch)
   391  	}
   392  }
   393  
   394  func TestFSM_RegisterJob_BadNamespace(t *testing.T) {
   395  	t.Parallel()
   396  	fsm := testFSM(t)
   397  
   398  	job := mock.Job()
   399  	job.Namespace = "foo"
   400  	req := structs.JobRegisterRequest{
   401  		Job: job,
   402  		WriteRequest: structs.WriteRequest{
   403  			Namespace: job.Namespace,
   404  		},
   405  	}
   406  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   407  	if err != nil {
   408  		t.Fatalf("err: %v", err)
   409  	}
   410  
   411  	resp := fsm.Apply(makeLog(buf))
   412  	if resp == nil {
   413  		t.Fatalf("no resp: %v", resp)
   414  	}
   415  	err, ok := resp.(error)
   416  	if !ok {
   417  		t.Fatalf("resp not of error type: %T %v", resp, resp)
   418  	}
   419  	if !strings.Contains(err.Error(), "non-existent namespace") {
   420  		t.Fatalf("bad error: %v", err)
   421  	}
   422  
   423  	// Verify we are not registered
   424  	ws := memdb.NewWatchSet()
   425  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   426  	if err != nil {
   427  		t.Fatalf("err: %v", err)
   428  	}
   429  	if jobOut != nil {
   430  		t.Fatalf("job found!")
   431  	}
   432  }
   433  
   434  func TestFSM_DeregisterJob_Purge(t *testing.T) {
   435  	t.Parallel()
   436  	fsm := testFSM(t)
   437  
   438  	job := mock.PeriodicJob()
   439  	req := structs.JobRegisterRequest{
   440  		Job: job,
   441  		WriteRequest: structs.WriteRequest{
   442  			Namespace: job.Namespace,
   443  		},
   444  	}
   445  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   446  	if err != nil {
   447  		t.Fatalf("err: %v", err)
   448  	}
   449  
   450  	resp := fsm.Apply(makeLog(buf))
   451  	if resp != nil {
   452  		t.Fatalf("resp: %v", resp)
   453  	}
   454  
   455  	req2 := structs.JobDeregisterRequest{
   456  		JobID: job.ID,
   457  		Purge: true,
   458  		WriteRequest: structs.WriteRequest{
   459  			Namespace: job.Namespace,
   460  		},
   461  	}
   462  	buf, err = structs.Encode(structs.JobDeregisterRequestType, req2)
   463  	if err != nil {
   464  		t.Fatalf("err: %v", err)
   465  	}
   466  
   467  	resp = fsm.Apply(makeLog(buf))
   468  	if resp != nil {
   469  		t.Fatalf("resp: %v", resp)
   470  	}
   471  
   472  	// Verify we are NOT registered
   473  	ws := memdb.NewWatchSet()
   474  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   475  	if err != nil {
   476  		t.Fatalf("err: %v", err)
   477  	}
   478  	if jobOut != nil {
   479  		t.Fatalf("job found!")
   480  	}
   481  
   482  	// Verify it was removed from the periodic runner.
   483  	tuple := structs.NamespacedID{
   484  		ID:        job.ID,
   485  		Namespace: job.Namespace,
   486  	}
   487  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; ok {
   488  		t.Fatal("job not removed from periodic runner")
   489  	}
   490  
   491  	// Verify it was removed from the periodic launch table.
   492  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   493  	if err != nil {
   494  		t.Fatalf("err: %v", err)
   495  	}
   496  	if launchOut != nil {
   497  		t.Fatalf("launch found!")
   498  	}
   499  }
   500  
   501  func TestFSM_DeregisterJob_NoPurge(t *testing.T) {
   502  	t.Parallel()
   503  	fsm := testFSM(t)
   504  
   505  	job := mock.PeriodicJob()
   506  	req := structs.JobRegisterRequest{
   507  		Job: job,
   508  		WriteRequest: structs.WriteRequest{
   509  			Namespace: job.Namespace,
   510  		},
   511  	}
   512  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   513  	if err != nil {
   514  		t.Fatalf("err: %v", err)
   515  	}
   516  
   517  	resp := fsm.Apply(makeLog(buf))
   518  	if resp != nil {
   519  		t.Fatalf("resp: %v", resp)
   520  	}
   521  
   522  	req2 := structs.JobDeregisterRequest{
   523  		JobID: job.ID,
   524  		Purge: false,
   525  		WriteRequest: structs.WriteRequest{
   526  			Namespace: job.Namespace,
   527  		},
   528  	}
   529  	buf, err = structs.Encode(structs.JobDeregisterRequestType, req2)
   530  	if err != nil {
   531  		t.Fatalf("err: %v", err)
   532  	}
   533  
   534  	resp = fsm.Apply(makeLog(buf))
   535  	if resp != nil {
   536  		t.Fatalf("resp: %v", resp)
   537  	}
   538  
   539  	// Verify we are NOT registered
   540  	ws := memdb.NewWatchSet()
   541  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   542  	if err != nil {
   543  		t.Fatalf("err: %v", err)
   544  	}
   545  	if jobOut == nil {
   546  		t.Fatalf("job not found!")
   547  	}
   548  	if !jobOut.Stop {
   549  		t.Fatalf("job not stopped found!")
   550  	}
   551  
   552  	// Verify it was removed from the periodic runner.
   553  	tuple := structs.NamespacedID{
   554  		ID:        job.ID,
   555  		Namespace: job.Namespace,
   556  	}
   557  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; ok {
   558  		t.Fatal("job not removed from periodic runner")
   559  	}
   560  
   561  	// Verify it was removed from the periodic launch table.
   562  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   563  	if err != nil {
   564  		t.Fatalf("err: %v", err)
   565  	}
   566  	if launchOut == nil {
   567  		t.Fatalf("launch not found!")
   568  	}
   569  }
   570  
   571  func TestFSM_UpdateEval(t *testing.T) {
   572  	t.Parallel()
   573  	fsm := testFSM(t)
   574  	fsm.evalBroker.SetEnabled(true)
   575  
   576  	req := structs.EvalUpdateRequest{
   577  		Evals: []*structs.Evaluation{mock.Eval()},
   578  	}
   579  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
   580  	if err != nil {
   581  		t.Fatalf("err: %v", err)
   582  	}
   583  
   584  	resp := fsm.Apply(makeLog(buf))
   585  	if resp != nil {
   586  		t.Fatalf("resp: %v", resp)
   587  	}
   588  
   589  	// Verify we are registered
   590  	ws := memdb.NewWatchSet()
   591  	eval, err := fsm.State().EvalByID(ws, req.Evals[0].ID)
   592  	if err != nil {
   593  		t.Fatalf("err: %v", err)
   594  	}
   595  	if eval == nil {
   596  		t.Fatalf("not found!")
   597  	}
   598  	if eval.CreateIndex != 1 {
   599  		t.Fatalf("bad index: %d", eval.CreateIndex)
   600  	}
   601  
   602  	// Verify enqueued
   603  	stats := fsm.evalBroker.Stats()
   604  	if stats.TotalReady != 1 {
   605  		t.Fatalf("bad: %#v %#v", stats, eval)
   606  	}
   607  }
   608  
   609  func TestFSM_UpdateEval_Blocked(t *testing.T) {
   610  	t.Parallel()
   611  	fsm := testFSM(t)
   612  	fsm.evalBroker.SetEnabled(true)
   613  	fsm.blockedEvals.SetEnabled(true)
   614  
   615  	// Create a blocked eval.
   616  	eval := mock.Eval()
   617  	eval.Status = structs.EvalStatusBlocked
   618  
   619  	req := structs.EvalUpdateRequest{
   620  		Evals: []*structs.Evaluation{eval},
   621  	}
   622  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
   623  	if err != nil {
   624  		t.Fatalf("err: %v", err)
   625  	}
   626  
   627  	resp := fsm.Apply(makeLog(buf))
   628  	if resp != nil {
   629  		t.Fatalf("resp: %v", resp)
   630  	}
   631  
   632  	// Verify we are registered
   633  	ws := memdb.NewWatchSet()
   634  	out, err := fsm.State().EvalByID(ws, eval.ID)
   635  	if err != nil {
   636  		t.Fatalf("err: %v", err)
   637  	}
   638  	if out == nil {
   639  		t.Fatalf("not found!")
   640  	}
   641  	if out.CreateIndex != 1 {
   642  		t.Fatalf("bad index: %d", out.CreateIndex)
   643  	}
   644  
   645  	// Verify the eval wasn't enqueued
   646  	stats := fsm.evalBroker.Stats()
   647  	if stats.TotalReady != 0 {
   648  		t.Fatalf("bad: %#v %#v", stats, out)
   649  	}
   650  
   651  	// Verify the eval was added to the blocked tracker.
   652  	bStats := fsm.blockedEvals.Stats()
   653  	if bStats.TotalBlocked != 1 {
   654  		t.Fatalf("bad: %#v %#v", bStats, out)
   655  	}
   656  }
   657  
   658  func TestFSM_UpdateEval_Untrack(t *testing.T) {
   659  	t.Parallel()
   660  	fsm := testFSM(t)
   661  	fsm.evalBroker.SetEnabled(true)
   662  	fsm.blockedEvals.SetEnabled(true)
   663  
   664  	// Mark an eval as blocked.
   665  	bEval := mock.Eval()
   666  	bEval.ClassEligibility = map[string]bool{"v1:123": true}
   667  	fsm.blockedEvals.Block(bEval)
   668  
   669  	// Create a successful eval for the same job
   670  	eval := mock.Eval()
   671  	eval.JobID = bEval.JobID
   672  	eval.Status = structs.EvalStatusComplete
   673  
   674  	req := structs.EvalUpdateRequest{
   675  		Evals: []*structs.Evaluation{eval},
   676  	}
   677  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
   678  	if err != nil {
   679  		t.Fatalf("err: %v", err)
   680  	}
   681  
   682  	resp := fsm.Apply(makeLog(buf))
   683  	if resp != nil {
   684  		t.Fatalf("resp: %v", resp)
   685  	}
   686  
   687  	// Verify we are registered
   688  	ws := memdb.NewWatchSet()
   689  	out, err := fsm.State().EvalByID(ws, eval.ID)
   690  	if err != nil {
   691  		t.Fatalf("err: %v", err)
   692  	}
   693  	if out == nil {
   694  		t.Fatalf("not found!")
   695  	}
   696  	if out.CreateIndex != 1 {
   697  		t.Fatalf("bad index: %d", out.CreateIndex)
   698  	}
   699  
   700  	// Verify the eval wasn't enqueued
   701  	stats := fsm.evalBroker.Stats()
   702  	if stats.TotalReady != 0 {
   703  		t.Fatalf("bad: %#v %#v", stats, out)
   704  	}
   705  
   706  	// Verify the eval was untracked in the blocked tracker.
   707  	bStats := fsm.blockedEvals.Stats()
   708  	if bStats.TotalBlocked != 0 {
   709  		t.Fatalf("bad: %#v %#v", bStats, out)
   710  	}
   711  }
   712  
   713  func TestFSM_UpdateEval_NoUntrack(t *testing.T) {
   714  	t.Parallel()
   715  	fsm := testFSM(t)
   716  	fsm.evalBroker.SetEnabled(true)
   717  	fsm.blockedEvals.SetEnabled(true)
   718  
   719  	// Mark an eval as blocked.
   720  	bEval := mock.Eval()
   721  	bEval.ClassEligibility = map[string]bool{"v1:123": true}
   722  	fsm.blockedEvals.Block(bEval)
   723  
   724  	// Create a successful eval for the same job but with placement failures
   725  	eval := mock.Eval()
   726  	eval.JobID = bEval.JobID
   727  	eval.Status = structs.EvalStatusComplete
   728  	eval.FailedTGAllocs = make(map[string]*structs.AllocMetric)
   729  	eval.FailedTGAllocs["test"] = new(structs.AllocMetric)
   730  
   731  	req := structs.EvalUpdateRequest{
   732  		Evals: []*structs.Evaluation{eval},
   733  	}
   734  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
   735  	if err != nil {
   736  		t.Fatalf("err: %v", err)
   737  	}
   738  
   739  	resp := fsm.Apply(makeLog(buf))
   740  	if resp != nil {
   741  		t.Fatalf("resp: %v", resp)
   742  	}
   743  
   744  	// Verify we are registered
   745  	ws := memdb.NewWatchSet()
   746  	out, err := fsm.State().EvalByID(ws, eval.ID)
   747  	if err != nil {
   748  		t.Fatalf("err: %v", err)
   749  	}
   750  	if out == nil {
   751  		t.Fatalf("not found!")
   752  	}
   753  	if out.CreateIndex != 1 {
   754  		t.Fatalf("bad index: %d", out.CreateIndex)
   755  	}
   756  
   757  	// Verify the eval wasn't enqueued
   758  	stats := fsm.evalBroker.Stats()
   759  	if stats.TotalReady != 0 {
   760  		t.Fatalf("bad: %#v %#v", stats, out)
   761  	}
   762  
   763  	// Verify the eval was not untracked in the blocked tracker.
   764  	bStats := fsm.blockedEvals.Stats()
   765  	if bStats.TotalBlocked != 1 {
   766  		t.Fatalf("bad: %#v %#v", bStats, out)
   767  	}
   768  }
   769  
   770  func TestFSM_DeleteEval(t *testing.T) {
   771  	t.Parallel()
   772  	fsm := testFSM(t)
   773  
   774  	eval := mock.Eval()
   775  	req := structs.EvalUpdateRequest{
   776  		Evals: []*structs.Evaluation{eval},
   777  	}
   778  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
   779  	if err != nil {
   780  		t.Fatalf("err: %v", err)
   781  	}
   782  
   783  	resp := fsm.Apply(makeLog(buf))
   784  	if resp != nil {
   785  		t.Fatalf("resp: %v", resp)
   786  	}
   787  
   788  	req2 := structs.EvalDeleteRequest{
   789  		Evals: []string{eval.ID},
   790  	}
   791  	buf, err = structs.Encode(structs.EvalDeleteRequestType, req2)
   792  	if err != nil {
   793  		t.Fatalf("err: %v", err)
   794  	}
   795  
   796  	resp = fsm.Apply(makeLog(buf))
   797  	if resp != nil {
   798  		t.Fatalf("resp: %v", resp)
   799  	}
   800  
   801  	// Verify we are NOT registered
   802  	ws := memdb.NewWatchSet()
   803  	eval, err = fsm.State().EvalByID(ws, req.Evals[0].ID)
   804  	if err != nil {
   805  		t.Fatalf("err: %v", err)
   806  	}
   807  	if eval != nil {
   808  		t.Fatalf("eval found!")
   809  	}
   810  }
   811  
   812  func TestFSM_UpsertAllocs(t *testing.T) {
   813  	t.Parallel()
   814  	fsm := testFSM(t)
   815  
   816  	alloc := mock.Alloc()
   817  	fsm.State().UpsertJobSummary(1, mock.JobSummary(alloc.JobID))
   818  	req := structs.AllocUpdateRequest{
   819  		Alloc: []*structs.Allocation{alloc},
   820  	}
   821  	buf, err := structs.Encode(structs.AllocUpdateRequestType, req)
   822  	if err != nil {
   823  		t.Fatalf("err: %v", err)
   824  	}
   825  
   826  	resp := fsm.Apply(makeLog(buf))
   827  	if resp != nil {
   828  		t.Fatalf("resp: %v", resp)
   829  	}
   830  
   831  	// Verify we are registered
   832  	ws := memdb.NewWatchSet()
   833  	out, err := fsm.State().AllocByID(ws, alloc.ID)
   834  	if err != nil {
   835  		t.Fatalf("err: %v", err)
   836  	}
   837  	alloc.CreateIndex = out.CreateIndex
   838  	alloc.ModifyIndex = out.ModifyIndex
   839  	alloc.AllocModifyIndex = out.AllocModifyIndex
   840  	if !reflect.DeepEqual(alloc, out) {
   841  		t.Fatalf("bad: %#v %#v", alloc, out)
   842  	}
   843  
   844  	evictAlloc := new(structs.Allocation)
   845  	*evictAlloc = *alloc
   846  	evictAlloc.DesiredStatus = structs.AllocDesiredStatusEvict
   847  	req2 := structs.AllocUpdateRequest{
   848  		Alloc: []*structs.Allocation{evictAlloc},
   849  	}
   850  	buf, err = structs.Encode(structs.AllocUpdateRequestType, req2)
   851  	if err != nil {
   852  		t.Fatalf("err: %v", err)
   853  	}
   854  
   855  	resp = fsm.Apply(makeLog(buf))
   856  	if resp != nil {
   857  		t.Fatalf("resp: %v", resp)
   858  	}
   859  
   860  	// Verify we are evicted
   861  	out, err = fsm.State().AllocByID(ws, alloc.ID)
   862  	if err != nil {
   863  		t.Fatalf("err: %v", err)
   864  	}
   865  	if out.DesiredStatus != structs.AllocDesiredStatusEvict {
   866  		t.Fatalf("alloc found!")
   867  	}
   868  }
   869  
   870  func TestFSM_UpsertAllocs_SharedJob(t *testing.T) {
   871  	t.Parallel()
   872  	fsm := testFSM(t)
   873  
   874  	alloc := mock.Alloc()
   875  	fsm.State().UpsertJobSummary(1, mock.JobSummary(alloc.JobID))
   876  	job := alloc.Job
   877  	alloc.Job = nil
   878  	req := structs.AllocUpdateRequest{
   879  		Job:   job,
   880  		Alloc: []*structs.Allocation{alloc},
   881  	}
   882  	buf, err := structs.Encode(structs.AllocUpdateRequestType, req)
   883  	if err != nil {
   884  		t.Fatalf("err: %v", err)
   885  	}
   886  
   887  	resp := fsm.Apply(makeLog(buf))
   888  	if resp != nil {
   889  		t.Fatalf("resp: %v", resp)
   890  	}
   891  
   892  	// Verify we are registered
   893  	ws := memdb.NewWatchSet()
   894  	out, err := fsm.State().AllocByID(ws, alloc.ID)
   895  	if err != nil {
   896  		t.Fatalf("err: %v", err)
   897  	}
   898  	alloc.CreateIndex = out.CreateIndex
   899  	alloc.ModifyIndex = out.ModifyIndex
   900  	alloc.AllocModifyIndex = out.AllocModifyIndex
   901  
   902  	// Job should be re-attached
   903  	alloc.Job = job
   904  	if !reflect.DeepEqual(alloc, out) {
   905  		t.Fatalf("bad: %#v %#v", alloc, out)
   906  	}
   907  
   908  	// Ensure that the original job is used
   909  	evictAlloc := new(structs.Allocation)
   910  	*evictAlloc = *alloc
   911  	job = mock.Job()
   912  	job.Priority = 123
   913  
   914  	evictAlloc.Job = nil
   915  	evictAlloc.DesiredStatus = structs.AllocDesiredStatusEvict
   916  	req2 := structs.AllocUpdateRequest{
   917  		Job:   job,
   918  		Alloc: []*structs.Allocation{evictAlloc},
   919  	}
   920  	buf, err = structs.Encode(structs.AllocUpdateRequestType, req2)
   921  	if err != nil {
   922  		t.Fatalf("err: %v", err)
   923  	}
   924  
   925  	resp = fsm.Apply(makeLog(buf))
   926  	if resp != nil {
   927  		t.Fatalf("resp: %v", resp)
   928  	}
   929  
   930  	// Verify we are evicted
   931  	out, err = fsm.State().AllocByID(ws, alloc.ID)
   932  	if err != nil {
   933  		t.Fatalf("err: %v", err)
   934  	}
   935  	if out.DesiredStatus != structs.AllocDesiredStatusEvict {
   936  		t.Fatalf("alloc found!")
   937  	}
   938  	if out.Job == nil || out.Job.Priority == 123 {
   939  		t.Fatalf("bad job")
   940  	}
   941  }
   942  
   943  func TestFSM_UpsertAllocs_StrippedResources(t *testing.T) {
   944  	t.Parallel()
   945  	fsm := testFSM(t)
   946  
   947  	alloc := mock.Alloc()
   948  
   949  	// Need to remove mock dynamic port from alloc as it won't be computed
   950  	// in this test
   951  	alloc.TaskResources["web"].Networks[0].DynamicPorts[0].Value = 0
   952  
   953  	fsm.State().UpsertJobSummary(1, mock.JobSummary(alloc.JobID))
   954  	job := alloc.Job
   955  	origResources := alloc.Resources
   956  	alloc.Resources = nil
   957  	req := structs.AllocUpdateRequest{
   958  		Job:   job,
   959  		Alloc: []*structs.Allocation{alloc},
   960  	}
   961  	buf, err := structs.Encode(structs.AllocUpdateRequestType, req)
   962  	if err != nil {
   963  		t.Fatalf("err: %v", err)
   964  	}
   965  
   966  	resp := fsm.Apply(makeLog(buf))
   967  	if resp != nil {
   968  		t.Fatalf("resp: %v", resp)
   969  	}
   970  
   971  	// Verify we are registered
   972  	ws := memdb.NewWatchSet()
   973  	out, err := fsm.State().AllocByID(ws, alloc.ID)
   974  	if err != nil {
   975  		t.Fatalf("err: %v", err)
   976  	}
   977  	alloc.CreateIndex = out.CreateIndex
   978  	alloc.ModifyIndex = out.ModifyIndex
   979  	alloc.AllocModifyIndex = out.AllocModifyIndex
   980  
   981  	// Resources should be recomputed
   982  	origResources.DiskMB = alloc.Job.TaskGroups[0].EphemeralDisk.SizeMB
   983  	alloc.Resources = origResources
   984  	if !reflect.DeepEqual(alloc, out) {
   985  		t.Fatalf("not equal: % #v", pretty.Diff(alloc, out))
   986  	}
   987  }
   988  
   989  func TestFSM_UpdateAllocFromClient_Unblock(t *testing.T) {
   990  	t.Parallel()
   991  	fsm := testFSM(t)
   992  	fsm.blockedEvals.SetEnabled(true)
   993  	state := fsm.State()
   994  
   995  	node := mock.Node()
   996  	state.UpsertNode(1, node)
   997  
   998  	// Mark an eval as blocked.
   999  	eval := mock.Eval()
  1000  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
  1001  	fsm.blockedEvals.Block(eval)
  1002  
  1003  	bStats := fsm.blockedEvals.Stats()
  1004  	if bStats.TotalBlocked != 1 {
  1005  		t.Fatalf("bad: %#v", bStats)
  1006  	}
  1007  
  1008  	// Create a completed eval
  1009  	alloc := mock.Alloc()
  1010  	alloc.NodeID = node.ID
  1011  	alloc2 := mock.Alloc()
  1012  	alloc2.NodeID = node.ID
  1013  	state.UpsertJobSummary(8, mock.JobSummary(alloc.JobID))
  1014  	state.UpsertJobSummary(9, mock.JobSummary(alloc2.JobID))
  1015  	state.UpsertAllocs(10, []*structs.Allocation{alloc, alloc2})
  1016  
  1017  	clientAlloc := new(structs.Allocation)
  1018  	*clientAlloc = *alloc
  1019  	clientAlloc.ClientStatus = structs.AllocClientStatusComplete
  1020  	update2 := &structs.Allocation{
  1021  		ID:           alloc2.ID,
  1022  		ClientStatus: structs.AllocClientStatusRunning,
  1023  	}
  1024  
  1025  	req := structs.AllocUpdateRequest{
  1026  		Alloc: []*structs.Allocation{clientAlloc, update2},
  1027  	}
  1028  	buf, err := structs.Encode(structs.AllocClientUpdateRequestType, req)
  1029  	if err != nil {
  1030  		t.Fatalf("err: %v", err)
  1031  	}
  1032  
  1033  	resp := fsm.Apply(makeLog(buf))
  1034  	if resp != nil {
  1035  		t.Fatalf("resp: %v", resp)
  1036  	}
  1037  
  1038  	// Verify we are updated
  1039  	ws := memdb.NewWatchSet()
  1040  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1041  	if err != nil {
  1042  		t.Fatalf("err: %v", err)
  1043  	}
  1044  	clientAlloc.CreateIndex = out.CreateIndex
  1045  	clientAlloc.ModifyIndex = out.ModifyIndex
  1046  	if !reflect.DeepEqual(clientAlloc, out) {
  1047  		t.Fatalf("bad: %#v %#v", clientAlloc, out)
  1048  	}
  1049  
  1050  	out, err = fsm.State().AllocByID(ws, alloc2.ID)
  1051  	if err != nil {
  1052  		t.Fatalf("err: %v", err)
  1053  	}
  1054  	alloc2.CreateIndex = out.CreateIndex
  1055  	alloc2.ModifyIndex = out.ModifyIndex
  1056  	alloc2.ClientStatus = structs.AllocClientStatusRunning
  1057  	alloc2.TaskStates = nil
  1058  	if !reflect.DeepEqual(alloc2, out) {
  1059  		t.Fatalf("bad: %#v %#v", alloc2, out)
  1060  	}
  1061  
  1062  	// Verify the eval was unblocked.
  1063  	testutil.WaitForResult(func() (bool, error) {
  1064  		bStats = fsm.blockedEvals.Stats()
  1065  		if bStats.TotalBlocked != 0 {
  1066  			return false, fmt.Errorf("bad: %#v %#v", bStats, out)
  1067  		}
  1068  		return true, nil
  1069  	}, func(err error) {
  1070  		t.Fatalf("err: %s", err)
  1071  	})
  1072  }
  1073  
  1074  func TestFSM_UpdateAllocFromClient(t *testing.T) {
  1075  	t.Parallel()
  1076  	fsm := testFSM(t)
  1077  	state := fsm.State()
  1078  	require := require.New(t)
  1079  
  1080  	alloc := mock.Alloc()
  1081  	state.UpsertJobSummary(9, mock.JobSummary(alloc.JobID))
  1082  	state.UpsertAllocs(10, []*structs.Allocation{alloc})
  1083  
  1084  	clientAlloc := new(structs.Allocation)
  1085  	*clientAlloc = *alloc
  1086  	clientAlloc.ClientStatus = structs.AllocClientStatusFailed
  1087  
  1088  	eval := mock.Eval()
  1089  	eval.JobID = alloc.JobID
  1090  	eval.TriggeredBy = structs.EvalTriggerRetryFailedAlloc
  1091  	eval.Type = alloc.Job.Type
  1092  
  1093  	req := structs.AllocUpdateRequest{
  1094  		Alloc: []*structs.Allocation{clientAlloc},
  1095  		Evals: []*structs.Evaluation{eval},
  1096  	}
  1097  	buf, err := structs.Encode(structs.AllocClientUpdateRequestType, req)
  1098  	require.Nil(err)
  1099  
  1100  	resp := fsm.Apply(makeLog(buf))
  1101  	require.Nil(resp)
  1102  
  1103  	// Verify we are registered
  1104  	ws := memdb.NewWatchSet()
  1105  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1106  	require.Nil(err)
  1107  	clientAlloc.CreateIndex = out.CreateIndex
  1108  	clientAlloc.ModifyIndex = out.ModifyIndex
  1109  	require.Equal(clientAlloc, out)
  1110  
  1111  	// Verify eval was inserted
  1112  	ws = memdb.NewWatchSet()
  1113  	evals, err := fsm.State().EvalsByJob(ws, eval.Namespace, eval.JobID)
  1114  	require.Nil(err)
  1115  	require.Equal(1, len(evals))
  1116  	res := evals[0]
  1117  	eval.CreateIndex = res.CreateIndex
  1118  	eval.ModifyIndex = res.ModifyIndex
  1119  	require.Equal(eval, res)
  1120  }
  1121  
  1122  func TestFSM_UpsertVaultAccessor(t *testing.T) {
  1123  	t.Parallel()
  1124  	fsm := testFSM(t)
  1125  	fsm.blockedEvals.SetEnabled(true)
  1126  
  1127  	va := mock.VaultAccessor()
  1128  	va2 := mock.VaultAccessor()
  1129  	req := structs.VaultAccessorsRequest{
  1130  		Accessors: []*structs.VaultAccessor{va, va2},
  1131  	}
  1132  	buf, err := structs.Encode(structs.VaultAccessorRegisterRequestType, req)
  1133  	if err != nil {
  1134  		t.Fatalf("err: %v", err)
  1135  	}
  1136  
  1137  	resp := fsm.Apply(makeLog(buf))
  1138  	if resp != nil {
  1139  		t.Fatalf("resp: %v", resp)
  1140  	}
  1141  
  1142  	// Verify we are registered
  1143  	ws := memdb.NewWatchSet()
  1144  	out1, err := fsm.State().VaultAccessor(ws, va.Accessor)
  1145  	if err != nil {
  1146  		t.Fatalf("err: %v", err)
  1147  	}
  1148  	if out1 == nil {
  1149  		t.Fatalf("not found!")
  1150  	}
  1151  	if out1.CreateIndex != 1 {
  1152  		t.Fatalf("bad index: %d", out1.CreateIndex)
  1153  	}
  1154  	out2, err := fsm.State().VaultAccessor(ws, va2.Accessor)
  1155  	if err != nil {
  1156  		t.Fatalf("err: %v", err)
  1157  	}
  1158  	if out2 == nil {
  1159  		t.Fatalf("not found!")
  1160  	}
  1161  	if out1.CreateIndex != 1 {
  1162  		t.Fatalf("bad index: %d", out2.CreateIndex)
  1163  	}
  1164  
  1165  	tt := fsm.TimeTable()
  1166  	index := tt.NearestIndex(time.Now().UTC())
  1167  	if index != 1 {
  1168  		t.Fatalf("bad: %d", index)
  1169  	}
  1170  }
  1171  
  1172  func TestFSM_DeregisterVaultAccessor(t *testing.T) {
  1173  	t.Parallel()
  1174  	fsm := testFSM(t)
  1175  	fsm.blockedEvals.SetEnabled(true)
  1176  
  1177  	va := mock.VaultAccessor()
  1178  	va2 := mock.VaultAccessor()
  1179  	accessors := []*structs.VaultAccessor{va, va2}
  1180  
  1181  	// Insert the accessors
  1182  	if err := fsm.State().UpsertVaultAccessor(1000, accessors); err != nil {
  1183  		t.Fatalf("bad: %v", err)
  1184  	}
  1185  
  1186  	req := structs.VaultAccessorsRequest{
  1187  		Accessors: accessors,
  1188  	}
  1189  	buf, err := structs.Encode(structs.VaultAccessorDegisterRequestType, req)
  1190  	if err != nil {
  1191  		t.Fatalf("err: %v", err)
  1192  	}
  1193  
  1194  	resp := fsm.Apply(makeLog(buf))
  1195  	if resp != nil {
  1196  		t.Fatalf("resp: %v", resp)
  1197  	}
  1198  
  1199  	ws := memdb.NewWatchSet()
  1200  	out1, err := fsm.State().VaultAccessor(ws, va.Accessor)
  1201  	if err != nil {
  1202  		t.Fatalf("err: %v", err)
  1203  	}
  1204  	if out1 != nil {
  1205  		t.Fatalf("not deleted!")
  1206  	}
  1207  
  1208  	tt := fsm.TimeTable()
  1209  	index := tt.NearestIndex(time.Now().UTC())
  1210  	if index != 1 {
  1211  		t.Fatalf("bad: %d", index)
  1212  	}
  1213  }
  1214  
  1215  func TestFSM_ApplyPlanResults(t *testing.T) {
  1216  	t.Parallel()
  1217  	fsm := testFSM(t)
  1218  
  1219  	// Create the request and create a deployment
  1220  	alloc := mock.Alloc()
  1221  	job := alloc.Job
  1222  	alloc.Job = nil
  1223  
  1224  	d := mock.Deployment()
  1225  	d.JobID = job.ID
  1226  	d.JobModifyIndex = job.ModifyIndex
  1227  	d.JobVersion = job.Version
  1228  
  1229  	alloc.DeploymentID = d.ID
  1230  
  1231  	eval := mock.Eval()
  1232  	eval.JobID = job.ID
  1233  	fsm.State().UpsertEvals(1, []*structs.Evaluation{eval})
  1234  
  1235  	fsm.State().UpsertJobSummary(1, mock.JobSummary(alloc.JobID))
  1236  	req := structs.ApplyPlanResultsRequest{
  1237  		AllocUpdateRequest: structs.AllocUpdateRequest{
  1238  			Job:   job,
  1239  			Alloc: []*structs.Allocation{alloc},
  1240  		},
  1241  		Deployment: d,
  1242  		EvalID:     eval.ID,
  1243  	}
  1244  	buf, err := structs.Encode(structs.ApplyPlanResultsRequestType, req)
  1245  	if err != nil {
  1246  		t.Fatalf("err: %v", err)
  1247  	}
  1248  
  1249  	resp := fsm.Apply(makeLog(buf))
  1250  	if resp != nil {
  1251  		t.Fatalf("resp: %v", resp)
  1252  	}
  1253  
  1254  	// Verify the allocation is registered
  1255  	ws := memdb.NewWatchSet()
  1256  	assert := assert.New(t)
  1257  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1258  	assert.Nil(err)
  1259  	alloc.CreateIndex = out.CreateIndex
  1260  	alloc.ModifyIndex = out.ModifyIndex
  1261  	alloc.AllocModifyIndex = out.AllocModifyIndex
  1262  
  1263  	// Job should be re-attached
  1264  	alloc.Job = job
  1265  	assert.Equal(alloc, out)
  1266  
  1267  	dout, err := fsm.State().DeploymentByID(ws, d.ID)
  1268  	assert.Nil(err)
  1269  	tg, ok := dout.TaskGroups[alloc.TaskGroup]
  1270  	assert.True(ok)
  1271  	assert.NotNil(tg)
  1272  	assert.Equal(1, tg.PlacedAllocs)
  1273  
  1274  	// Ensure that the original job is used
  1275  	evictAlloc := alloc.Copy()
  1276  	job = mock.Job()
  1277  	job.Priority = 123
  1278  	eval = mock.Eval()
  1279  	eval.JobID = job.ID
  1280  
  1281  	fsm.State().UpsertEvals(2, []*structs.Evaluation{eval})
  1282  
  1283  	evictAlloc.Job = nil
  1284  	evictAlloc.DesiredStatus = structs.AllocDesiredStatusEvict
  1285  	req2 := structs.ApplyPlanResultsRequest{
  1286  		AllocUpdateRequest: structs.AllocUpdateRequest{
  1287  			Job:   job,
  1288  			Alloc: []*structs.Allocation{evictAlloc},
  1289  		},
  1290  		EvalID: eval.ID,
  1291  	}
  1292  	buf, err = structs.Encode(structs.ApplyPlanResultsRequestType, req2)
  1293  	assert.Nil(err)
  1294  
  1295  	log := makeLog(buf)
  1296  	//set the index to something other than 1
  1297  	log.Index = 25
  1298  	resp = fsm.Apply(log)
  1299  	assert.Nil(resp)
  1300  
  1301  	// Verify we are evicted
  1302  	out, err = fsm.State().AllocByID(ws, alloc.ID)
  1303  	assert.Nil(err)
  1304  	assert.Equal(structs.AllocDesiredStatusEvict, out.DesiredStatus)
  1305  	assert.NotNil(out.Job)
  1306  	assert.NotEqual(123, out.Job.Priority)
  1307  
  1308  	evalOut, err := fsm.State().EvalByID(ws, eval.ID)
  1309  	assert.Nil(err)
  1310  	assert.Equal(log.Index, evalOut.ModifyIndex)
  1311  
  1312  }
  1313  
  1314  func TestFSM_DeploymentStatusUpdate(t *testing.T) {
  1315  	t.Parallel()
  1316  	fsm := testFSM(t)
  1317  	fsm.evalBroker.SetEnabled(true)
  1318  	state := fsm.State()
  1319  
  1320  	// Upsert a deployment
  1321  	d := mock.Deployment()
  1322  	if err := state.UpsertDeployment(1, d); err != nil {
  1323  		t.Fatalf("bad: %v", err)
  1324  	}
  1325  
  1326  	// Create a request to update the deployment, create an eval and job
  1327  	e := mock.Eval()
  1328  	j := mock.Job()
  1329  	status, desc := structs.DeploymentStatusFailed, "foo"
  1330  	req := &structs.DeploymentStatusUpdateRequest{
  1331  		DeploymentUpdate: &structs.DeploymentStatusUpdate{
  1332  			DeploymentID:      d.ID,
  1333  			Status:            status,
  1334  			StatusDescription: desc,
  1335  		},
  1336  		Job:  j,
  1337  		Eval: e,
  1338  	}
  1339  	buf, err := structs.Encode(structs.DeploymentStatusUpdateRequestType, req)
  1340  	if err != nil {
  1341  		t.Fatalf("err: %v", err)
  1342  	}
  1343  	resp := fsm.Apply(makeLog(buf))
  1344  	if resp != nil {
  1345  		t.Fatalf("resp: %v", resp)
  1346  	}
  1347  
  1348  	// Check that the status was updated properly
  1349  	ws := memdb.NewWatchSet()
  1350  	dout, err := state.DeploymentByID(ws, d.ID)
  1351  	if err != nil {
  1352  		t.Fatalf("bad: %v", err)
  1353  	}
  1354  	if dout.Status != status || dout.StatusDescription != desc {
  1355  		t.Fatalf("bad: %#v", dout)
  1356  	}
  1357  
  1358  	// Check that the evaluation was created
  1359  	eout, _ := state.EvalByID(ws, e.ID)
  1360  	if err != nil {
  1361  		t.Fatalf("bad: %v", err)
  1362  	}
  1363  	if eout == nil {
  1364  		t.Fatalf("bad: %#v", eout)
  1365  	}
  1366  
  1367  	// Check that the job was created
  1368  	jout, _ := state.JobByID(ws, j.Namespace, j.ID)
  1369  	if err != nil {
  1370  		t.Fatalf("bad: %v", err)
  1371  	}
  1372  	if jout == nil {
  1373  		t.Fatalf("bad: %#v", jout)
  1374  	}
  1375  
  1376  	// Assert the eval was enqueued
  1377  	stats := fsm.evalBroker.Stats()
  1378  	if stats.TotalReady != 1 {
  1379  		t.Fatalf("bad: %#v %#v", stats, e)
  1380  	}
  1381  }
  1382  
  1383  func TestFSM_JobStabilityUpdate(t *testing.T) {
  1384  	t.Parallel()
  1385  	fsm := testFSM(t)
  1386  	fsm.evalBroker.SetEnabled(true)
  1387  	state := fsm.State()
  1388  
  1389  	// Upsert a deployment
  1390  	job := mock.Job()
  1391  	if err := state.UpsertJob(1, job); err != nil {
  1392  		t.Fatalf("bad: %v", err)
  1393  	}
  1394  
  1395  	// Create a request to update the job to stable
  1396  	req := &structs.JobStabilityRequest{
  1397  		JobID:      job.ID,
  1398  		JobVersion: job.Version,
  1399  		Stable:     true,
  1400  		WriteRequest: structs.WriteRequest{
  1401  			Namespace: job.Namespace,
  1402  		},
  1403  	}
  1404  	buf, err := structs.Encode(structs.JobStabilityRequestType, req)
  1405  	if err != nil {
  1406  		t.Fatalf("err: %v", err)
  1407  	}
  1408  	resp := fsm.Apply(makeLog(buf))
  1409  	if resp != nil {
  1410  		t.Fatalf("resp: %v", resp)
  1411  	}
  1412  
  1413  	// Check that the stability was updated properly
  1414  	ws := memdb.NewWatchSet()
  1415  	jout, _ := state.JobByIDAndVersion(ws, job.Namespace, job.ID, job.Version)
  1416  	if err != nil {
  1417  		t.Fatalf("bad: %v", err)
  1418  	}
  1419  	if jout == nil || !jout.Stable {
  1420  		t.Fatalf("bad: %#v", jout)
  1421  	}
  1422  }
  1423  
  1424  func TestFSM_DeploymentPromotion(t *testing.T) {
  1425  	t.Parallel()
  1426  	fsm := testFSM(t)
  1427  	fsm.evalBroker.SetEnabled(true)
  1428  	state := fsm.State()
  1429  
  1430  	// Create a job with two task groups
  1431  	j := mock.Job()
  1432  	tg1 := j.TaskGroups[0]
  1433  	tg2 := tg1.Copy()
  1434  	tg2.Name = "foo"
  1435  	j.TaskGroups = append(j.TaskGroups, tg2)
  1436  	if err := state.UpsertJob(1, j); err != nil {
  1437  		t.Fatalf("bad: %v", err)
  1438  	}
  1439  
  1440  	// Create a deployment
  1441  	d := mock.Deployment()
  1442  	d.JobID = j.ID
  1443  	d.TaskGroups = map[string]*structs.DeploymentState{
  1444  		"web": {
  1445  			DesiredTotal:    10,
  1446  			DesiredCanaries: 1,
  1447  		},
  1448  		"foo": {
  1449  			DesiredTotal:    10,
  1450  			DesiredCanaries: 1,
  1451  		},
  1452  	}
  1453  	if err := state.UpsertDeployment(2, d); err != nil {
  1454  		t.Fatalf("bad: %v", err)
  1455  	}
  1456  
  1457  	// Create a set of allocations
  1458  	c1 := mock.Alloc()
  1459  	c1.JobID = j.ID
  1460  	c1.DeploymentID = d.ID
  1461  	d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID)
  1462  	c1.DeploymentStatus = &structs.AllocDeploymentStatus{
  1463  		Healthy: helper.BoolToPtr(true),
  1464  	}
  1465  	c2 := mock.Alloc()
  1466  	c2.JobID = j.ID
  1467  	c2.DeploymentID = d.ID
  1468  	d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID)
  1469  	c2.TaskGroup = tg2.Name
  1470  	c2.DeploymentStatus = &structs.AllocDeploymentStatus{
  1471  		Healthy: helper.BoolToPtr(true),
  1472  	}
  1473  
  1474  	if err := state.UpsertAllocs(3, []*structs.Allocation{c1, c2}); err != nil {
  1475  		t.Fatalf("err: %v", err)
  1476  	}
  1477  
  1478  	// Create an eval
  1479  	e := mock.Eval()
  1480  
  1481  	// Promote the canaries
  1482  	req := &structs.ApplyDeploymentPromoteRequest{
  1483  		DeploymentPromoteRequest: structs.DeploymentPromoteRequest{
  1484  			DeploymentID: d.ID,
  1485  			All:          true,
  1486  		},
  1487  		Eval: e,
  1488  	}
  1489  	buf, err := structs.Encode(structs.DeploymentPromoteRequestType, req)
  1490  	if err != nil {
  1491  		t.Fatalf("err: %v", err)
  1492  	}
  1493  	resp := fsm.Apply(makeLog(buf))
  1494  	if resp != nil {
  1495  		t.Fatalf("resp: %v", resp)
  1496  	}
  1497  
  1498  	// Check that the status per task group was updated properly
  1499  	ws := memdb.NewWatchSet()
  1500  	dout, err := state.DeploymentByID(ws, d.ID)
  1501  	if err != nil {
  1502  		t.Fatalf("bad: %v", err)
  1503  	}
  1504  	if len(dout.TaskGroups) != 2 {
  1505  		t.Fatalf("bad: %#v", dout.TaskGroups)
  1506  	}
  1507  	for tg, state := range dout.TaskGroups {
  1508  		if !state.Promoted {
  1509  			t.Fatalf("bad: group %q not promoted %#v", tg, state)
  1510  		}
  1511  	}
  1512  
  1513  	// Check that the evaluation was created
  1514  	eout, _ := state.EvalByID(ws, e.ID)
  1515  	if err != nil {
  1516  		t.Fatalf("bad: %v", err)
  1517  	}
  1518  	if eout == nil {
  1519  		t.Fatalf("bad: %#v", eout)
  1520  	}
  1521  
  1522  	// Assert the eval was enqueued
  1523  	stats := fsm.evalBroker.Stats()
  1524  	if stats.TotalReady != 1 {
  1525  		t.Fatalf("bad: %#v %#v", stats, e)
  1526  	}
  1527  }
  1528  
  1529  func TestFSM_DeploymentAllocHealth(t *testing.T) {
  1530  	t.Parallel()
  1531  	fsm := testFSM(t)
  1532  	fsm.evalBroker.SetEnabled(true)
  1533  	state := fsm.State()
  1534  
  1535  	// Insert a deployment
  1536  	d := mock.Deployment()
  1537  	if err := state.UpsertDeployment(1, d); err != nil {
  1538  		t.Fatalf("bad: %v", err)
  1539  	}
  1540  
  1541  	// Insert two allocations
  1542  	a1 := mock.Alloc()
  1543  	a1.DeploymentID = d.ID
  1544  	a2 := mock.Alloc()
  1545  	a2.DeploymentID = d.ID
  1546  	if err := state.UpsertAllocs(2, []*structs.Allocation{a1, a2}); err != nil {
  1547  		t.Fatalf("bad: %v", err)
  1548  	}
  1549  
  1550  	// Create a job to roll back to
  1551  	j := mock.Job()
  1552  
  1553  	// Create an eval that should be upserted
  1554  	e := mock.Eval()
  1555  
  1556  	// Create a status update for the deployment
  1557  	status, desc := structs.DeploymentStatusFailed, "foo"
  1558  	u := &structs.DeploymentStatusUpdate{
  1559  		DeploymentID:      d.ID,
  1560  		Status:            status,
  1561  		StatusDescription: desc,
  1562  	}
  1563  
  1564  	// Set health against the deployment
  1565  	req := &structs.ApplyDeploymentAllocHealthRequest{
  1566  		DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{
  1567  			DeploymentID:           d.ID,
  1568  			HealthyAllocationIDs:   []string{a1.ID},
  1569  			UnhealthyAllocationIDs: []string{a2.ID},
  1570  		},
  1571  		Job:              j,
  1572  		Eval:             e,
  1573  		DeploymentUpdate: u,
  1574  	}
  1575  	buf, err := structs.Encode(structs.DeploymentAllocHealthRequestType, req)
  1576  	if err != nil {
  1577  		t.Fatalf("err: %v", err)
  1578  	}
  1579  	resp := fsm.Apply(makeLog(buf))
  1580  	if resp != nil {
  1581  		t.Fatalf("resp: %v", resp)
  1582  	}
  1583  
  1584  	// Check that the status was updated properly
  1585  	ws := memdb.NewWatchSet()
  1586  	dout, err := state.DeploymentByID(ws, d.ID)
  1587  	if err != nil {
  1588  		t.Fatalf("bad: %v", err)
  1589  	}
  1590  	if dout.Status != status || dout.StatusDescription != desc {
  1591  		t.Fatalf("bad: %#v", dout)
  1592  	}
  1593  
  1594  	// Check that the evaluation was created
  1595  	eout, _ := state.EvalByID(ws, e.ID)
  1596  	if err != nil {
  1597  		t.Fatalf("bad: %v", err)
  1598  	}
  1599  	if eout == nil {
  1600  		t.Fatalf("bad: %#v", eout)
  1601  	}
  1602  
  1603  	// Check that the job was created
  1604  	jout, _ := state.JobByID(ws, j.Namespace, j.ID)
  1605  	if err != nil {
  1606  		t.Fatalf("bad: %v", err)
  1607  	}
  1608  	if jout == nil {
  1609  		t.Fatalf("bad: %#v", jout)
  1610  	}
  1611  
  1612  	// Check the status of the allocs
  1613  	out1, err := state.AllocByID(ws, a1.ID)
  1614  	if err != nil {
  1615  		t.Fatalf("err: %v", err)
  1616  	}
  1617  	out2, err := state.AllocByID(ws, a2.ID)
  1618  	if err != nil {
  1619  		t.Fatalf("err: %v", err)
  1620  	}
  1621  
  1622  	if !out1.DeploymentStatus.IsHealthy() {
  1623  		t.Fatalf("bad: alloc %q not healthy", out1.ID)
  1624  	}
  1625  	if !out2.DeploymentStatus.IsUnhealthy() {
  1626  		t.Fatalf("bad: alloc %q not unhealthy", out2.ID)
  1627  	}
  1628  
  1629  	// Assert the eval was enqueued
  1630  	stats := fsm.evalBroker.Stats()
  1631  	if stats.TotalReady != 1 {
  1632  		t.Fatalf("bad: %#v %#v", stats, e)
  1633  	}
  1634  }
  1635  
  1636  func TestFSM_DeleteDeployment(t *testing.T) {
  1637  	t.Parallel()
  1638  	fsm := testFSM(t)
  1639  	state := fsm.State()
  1640  
  1641  	// Upsert a deployments
  1642  	d := mock.Deployment()
  1643  	if err := state.UpsertDeployment(1, d); err != nil {
  1644  		t.Fatalf("bad: %v", err)
  1645  	}
  1646  
  1647  	req := structs.DeploymentDeleteRequest{
  1648  		Deployments: []string{d.ID},
  1649  	}
  1650  	buf, err := structs.Encode(structs.DeploymentDeleteRequestType, req)
  1651  	if err != nil {
  1652  		t.Fatalf("err: %v", err)
  1653  	}
  1654  
  1655  	resp := fsm.Apply(makeLog(buf))
  1656  	if resp != nil {
  1657  		t.Fatalf("resp: %v", resp)
  1658  	}
  1659  
  1660  	// Verify we are NOT registered
  1661  	ws := memdb.NewWatchSet()
  1662  	deployment, err := state.DeploymentByID(ws, d.ID)
  1663  	if err != nil {
  1664  		t.Fatalf("err: %v", err)
  1665  	}
  1666  	if deployment != nil {
  1667  		t.Fatalf("deployment found!")
  1668  	}
  1669  }
  1670  
  1671  func TestFSM_UpsertACLPolicies(t *testing.T) {
  1672  	t.Parallel()
  1673  	fsm := testFSM(t)
  1674  
  1675  	policy := mock.ACLPolicy()
  1676  	req := structs.ACLPolicyUpsertRequest{
  1677  		Policies: []*structs.ACLPolicy{policy},
  1678  	}
  1679  	buf, err := structs.Encode(structs.ACLPolicyUpsertRequestType, req)
  1680  	if err != nil {
  1681  		t.Fatalf("err: %v", err)
  1682  	}
  1683  
  1684  	resp := fsm.Apply(makeLog(buf))
  1685  	if resp != nil {
  1686  		t.Fatalf("resp: %v", resp)
  1687  	}
  1688  
  1689  	// Verify we are registered
  1690  	ws := memdb.NewWatchSet()
  1691  	out, err := fsm.State().ACLPolicyByName(ws, policy.Name)
  1692  	assert.Nil(t, err)
  1693  	assert.NotNil(t, out)
  1694  }
  1695  
  1696  func TestFSM_DeleteACLPolicies(t *testing.T) {
  1697  	t.Parallel()
  1698  	fsm := testFSM(t)
  1699  
  1700  	policy := mock.ACLPolicy()
  1701  	err := fsm.State().UpsertACLPolicies(1000, []*structs.ACLPolicy{policy})
  1702  	assert.Nil(t, err)
  1703  
  1704  	req := structs.ACLPolicyDeleteRequest{
  1705  		Names: []string{policy.Name},
  1706  	}
  1707  	buf, err := structs.Encode(structs.ACLPolicyDeleteRequestType, req)
  1708  	if err != nil {
  1709  		t.Fatalf("err: %v", err)
  1710  	}
  1711  
  1712  	resp := fsm.Apply(makeLog(buf))
  1713  	if resp != nil {
  1714  		t.Fatalf("resp: %v", resp)
  1715  	}
  1716  
  1717  	// Verify we are NOT registered
  1718  	ws := memdb.NewWatchSet()
  1719  	out, err := fsm.State().ACLPolicyByName(ws, policy.Name)
  1720  	assert.Nil(t, err)
  1721  	assert.Nil(t, out)
  1722  }
  1723  
  1724  func TestFSM_BootstrapACLTokens(t *testing.T) {
  1725  	t.Parallel()
  1726  	fsm := testFSM(t)
  1727  
  1728  	token := mock.ACLToken()
  1729  	req := structs.ACLTokenBootstrapRequest{
  1730  		Token: token,
  1731  	}
  1732  	buf, err := structs.Encode(structs.ACLTokenBootstrapRequestType, req)
  1733  	if err != nil {
  1734  		t.Fatalf("err: %v", err)
  1735  	}
  1736  
  1737  	resp := fsm.Apply(makeLog(buf))
  1738  	if resp != nil {
  1739  		t.Fatalf("resp: %v", resp)
  1740  	}
  1741  
  1742  	// Verify we are registered
  1743  	out, err := fsm.State().ACLTokenByAccessorID(nil, token.AccessorID)
  1744  	assert.Nil(t, err)
  1745  	assert.NotNil(t, out)
  1746  
  1747  	// Test with reset
  1748  	token2 := mock.ACLToken()
  1749  	req = structs.ACLTokenBootstrapRequest{
  1750  		Token:      token2,
  1751  		ResetIndex: out.CreateIndex,
  1752  	}
  1753  	buf, err = structs.Encode(structs.ACLTokenBootstrapRequestType, req)
  1754  	if err != nil {
  1755  		t.Fatalf("err: %v", err)
  1756  	}
  1757  
  1758  	resp = fsm.Apply(makeLog(buf))
  1759  	if resp != nil {
  1760  		t.Fatalf("resp: %v", resp)
  1761  	}
  1762  
  1763  	// Verify we are registered
  1764  	out2, err := fsm.State().ACLTokenByAccessorID(nil, token2.AccessorID)
  1765  	assert.Nil(t, err)
  1766  	assert.NotNil(t, out2)
  1767  }
  1768  
  1769  func TestFSM_UpsertACLTokens(t *testing.T) {
  1770  	t.Parallel()
  1771  	fsm := testFSM(t)
  1772  
  1773  	token := mock.ACLToken()
  1774  	req := structs.ACLTokenUpsertRequest{
  1775  		Tokens: []*structs.ACLToken{token},
  1776  	}
  1777  	buf, err := structs.Encode(structs.ACLTokenUpsertRequestType, req)
  1778  	if err != nil {
  1779  		t.Fatalf("err: %v", err)
  1780  	}
  1781  
  1782  	resp := fsm.Apply(makeLog(buf))
  1783  	if resp != nil {
  1784  		t.Fatalf("resp: %v", resp)
  1785  	}
  1786  
  1787  	// Verify we are registered
  1788  	ws := memdb.NewWatchSet()
  1789  	out, err := fsm.State().ACLTokenByAccessorID(ws, token.AccessorID)
  1790  	assert.Nil(t, err)
  1791  	assert.NotNil(t, out)
  1792  }
  1793  
  1794  func TestFSM_DeleteACLTokens(t *testing.T) {
  1795  	t.Parallel()
  1796  	fsm := testFSM(t)
  1797  
  1798  	token := mock.ACLToken()
  1799  	err := fsm.State().UpsertACLTokens(1000, []*structs.ACLToken{token})
  1800  	assert.Nil(t, err)
  1801  
  1802  	req := structs.ACLTokenDeleteRequest{
  1803  		AccessorIDs: []string{token.AccessorID},
  1804  	}
  1805  	buf, err := structs.Encode(structs.ACLTokenDeleteRequestType, req)
  1806  	if err != nil {
  1807  		t.Fatalf("err: %v", err)
  1808  	}
  1809  
  1810  	resp := fsm.Apply(makeLog(buf))
  1811  	if resp != nil {
  1812  		t.Fatalf("resp: %v", resp)
  1813  	}
  1814  
  1815  	// Verify we are NOT registered
  1816  	ws := memdb.NewWatchSet()
  1817  	out, err := fsm.State().ACLTokenByAccessorID(ws, token.AccessorID)
  1818  	assert.Nil(t, err)
  1819  	assert.Nil(t, out)
  1820  }
  1821  
  1822  func testSnapshotRestore(t *testing.T, fsm *nomadFSM) *nomadFSM {
  1823  	// Snapshot
  1824  	snap, err := fsm.Snapshot()
  1825  	if err != nil {
  1826  		t.Fatalf("err: %v", err)
  1827  	}
  1828  	defer snap.Release()
  1829  
  1830  	// Persist
  1831  	buf := bytes.NewBuffer(nil)
  1832  	sink := &MockSink{buf, false}
  1833  	if err := snap.Persist(sink); err != nil {
  1834  		t.Fatalf("err: %v", err)
  1835  	}
  1836  
  1837  	// Try to restore on a new FSM
  1838  	fsm2 := testFSM(t)
  1839  	snap, err = fsm2.Snapshot()
  1840  	if err != nil {
  1841  		t.Fatalf("err: %v", err)
  1842  	}
  1843  	defer snap.Release()
  1844  
  1845  	abandonCh := fsm2.State().AbandonCh()
  1846  
  1847  	// Do a restore
  1848  	if err := fsm2.Restore(sink); err != nil {
  1849  		t.Fatalf("err: %v", err)
  1850  	}
  1851  
  1852  	select {
  1853  	case <-abandonCh:
  1854  	default:
  1855  		t.Fatalf("bad")
  1856  	}
  1857  
  1858  	return fsm2
  1859  }
  1860  
  1861  func TestFSM_SnapshotRestore_Nodes(t *testing.T) {
  1862  	t.Parallel()
  1863  	// Add some state
  1864  	fsm := testFSM(t)
  1865  	state := fsm.State()
  1866  	node1 := mock.Node()
  1867  	state.UpsertNode(1000, node1)
  1868  	node2 := mock.Node()
  1869  	state.UpsertNode(1001, node2)
  1870  
  1871  	// Verify the contents
  1872  	fsm2 := testSnapshotRestore(t, fsm)
  1873  	state2 := fsm2.State()
  1874  	ws := memdb.NewWatchSet()
  1875  	out1, _ := state2.NodeByID(ws, node1.ID)
  1876  	out2, _ := state2.NodeByID(ws, node2.ID)
  1877  	if !reflect.DeepEqual(node1, out1) {
  1878  		t.Fatalf("bad: \n%#v\n%#v", out1, node1)
  1879  	}
  1880  	if !reflect.DeepEqual(node2, out2) {
  1881  		t.Fatalf("bad: \n%#v\n%#v", out2, node2)
  1882  	}
  1883  }
  1884  
  1885  func TestFSM_SnapshotRestore_Jobs(t *testing.T) {
  1886  	t.Parallel()
  1887  	// Add some state
  1888  	fsm := testFSM(t)
  1889  	state := fsm.State()
  1890  	job1 := mock.Job()
  1891  	state.UpsertJob(1000, job1)
  1892  	job2 := mock.Job()
  1893  	state.UpsertJob(1001, job2)
  1894  
  1895  	// Verify the contents
  1896  	ws := memdb.NewWatchSet()
  1897  	fsm2 := testSnapshotRestore(t, fsm)
  1898  	state2 := fsm2.State()
  1899  	out1, _ := state2.JobByID(ws, job1.Namespace, job1.ID)
  1900  	out2, _ := state2.JobByID(ws, job2.Namespace, job2.ID)
  1901  	if !reflect.DeepEqual(job1, out1) {
  1902  		t.Fatalf("bad: \n%#v\n%#v", out1, job1)
  1903  	}
  1904  	if !reflect.DeepEqual(job2, out2) {
  1905  		t.Fatalf("bad: \n%#v\n%#v", out2, job2)
  1906  	}
  1907  }
  1908  
  1909  func TestFSM_SnapshotRestore_Evals(t *testing.T) {
  1910  	t.Parallel()
  1911  	// Add some state
  1912  	fsm := testFSM(t)
  1913  	state := fsm.State()
  1914  	eval1 := mock.Eval()
  1915  	state.UpsertEvals(1000, []*structs.Evaluation{eval1})
  1916  	eval2 := mock.Eval()
  1917  	state.UpsertEvals(1001, []*structs.Evaluation{eval2})
  1918  
  1919  	// Verify the contents
  1920  	fsm2 := testSnapshotRestore(t, fsm)
  1921  	state2 := fsm2.State()
  1922  	ws := memdb.NewWatchSet()
  1923  	out1, _ := state2.EvalByID(ws, eval1.ID)
  1924  	out2, _ := state2.EvalByID(ws, eval2.ID)
  1925  	if !reflect.DeepEqual(eval1, out1) {
  1926  		t.Fatalf("bad: \n%#v\n%#v", out1, eval1)
  1927  	}
  1928  	if !reflect.DeepEqual(eval2, out2) {
  1929  		t.Fatalf("bad: \n%#v\n%#v", out2, eval2)
  1930  	}
  1931  }
  1932  
  1933  func TestFSM_SnapshotRestore_Allocs(t *testing.T) {
  1934  	t.Parallel()
  1935  	// Add some state
  1936  	fsm := testFSM(t)
  1937  	state := fsm.State()
  1938  	alloc1 := mock.Alloc()
  1939  	alloc2 := mock.Alloc()
  1940  	state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID))
  1941  	state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
  1942  	state.UpsertAllocs(1000, []*structs.Allocation{alloc1})
  1943  	state.UpsertAllocs(1001, []*structs.Allocation{alloc2})
  1944  
  1945  	// Verify the contents
  1946  	fsm2 := testSnapshotRestore(t, fsm)
  1947  	state2 := fsm2.State()
  1948  	ws := memdb.NewWatchSet()
  1949  	out1, _ := state2.AllocByID(ws, alloc1.ID)
  1950  	out2, _ := state2.AllocByID(ws, alloc2.ID)
  1951  	if !reflect.DeepEqual(alloc1, out1) {
  1952  		t.Fatalf("bad: \n%#v\n%#v", out1, alloc1)
  1953  	}
  1954  	if !reflect.DeepEqual(alloc2, out2) {
  1955  		t.Fatalf("bad: \n%#v\n%#v", out2, alloc2)
  1956  	}
  1957  }
  1958  
  1959  func TestFSM_SnapshotRestore_Allocs_NoSharedResources(t *testing.T) {
  1960  	t.Parallel()
  1961  	// Add some state
  1962  	fsm := testFSM(t)
  1963  	state := fsm.State()
  1964  	alloc1 := mock.Alloc()
  1965  	alloc2 := mock.Alloc()
  1966  	alloc1.SharedResources = nil
  1967  	alloc2.SharedResources = nil
  1968  	state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID))
  1969  	state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
  1970  	state.UpsertAllocs(1000, []*structs.Allocation{alloc1})
  1971  	state.UpsertAllocs(1001, []*structs.Allocation{alloc2})
  1972  
  1973  	// Verify the contents
  1974  	fsm2 := testSnapshotRestore(t, fsm)
  1975  	state2 := fsm2.State()
  1976  	ws := memdb.NewWatchSet()
  1977  	out1, _ := state2.AllocByID(ws, alloc1.ID)
  1978  	out2, _ := state2.AllocByID(ws, alloc2.ID)
  1979  	alloc1.SharedResources = &structs.Resources{DiskMB: 150}
  1980  	alloc2.SharedResources = &structs.Resources{DiskMB: 150}
  1981  
  1982  	if !reflect.DeepEqual(alloc1, out1) {
  1983  		t.Fatalf("bad: \n%#v\n%#v", out1, alloc1)
  1984  	}
  1985  	if !reflect.DeepEqual(alloc2, out2) {
  1986  		t.Fatalf("bad: \n%#v\n%#v", out2, alloc2)
  1987  	}
  1988  }
  1989  
  1990  func TestFSM_SnapshotRestore_Indexes(t *testing.T) {
  1991  	t.Parallel()
  1992  	// Add some state
  1993  	fsm := testFSM(t)
  1994  	state := fsm.State()
  1995  	node1 := mock.Node()
  1996  	state.UpsertNode(1000, node1)
  1997  
  1998  	// Verify the contents
  1999  	fsm2 := testSnapshotRestore(t, fsm)
  2000  	state2 := fsm2.State()
  2001  
  2002  	index, err := state2.Index("nodes")
  2003  	if err != nil {
  2004  		t.Fatalf("err: %v", err)
  2005  	}
  2006  	if index != 1000 {
  2007  		t.Fatalf("bad: %d", index)
  2008  	}
  2009  }
  2010  
  2011  func TestFSM_SnapshotRestore_TimeTable(t *testing.T) {
  2012  	t.Parallel()
  2013  	// Add some state
  2014  	fsm := testFSM(t)
  2015  
  2016  	tt := fsm.TimeTable()
  2017  	start := time.Now().UTC()
  2018  	tt.Witness(1000, start)
  2019  	tt.Witness(2000, start.Add(10*time.Minute))
  2020  
  2021  	// Verify the contents
  2022  	fsm2 := testSnapshotRestore(t, fsm)
  2023  
  2024  	tt2 := fsm2.TimeTable()
  2025  	if tt2.NearestTime(1500) != start {
  2026  		t.Fatalf("bad")
  2027  	}
  2028  	if tt2.NearestIndex(start.Add(15*time.Minute)) != 2000 {
  2029  		t.Fatalf("bad")
  2030  	}
  2031  }
  2032  
  2033  func TestFSM_SnapshotRestore_PeriodicLaunches(t *testing.T) {
  2034  	t.Parallel()
  2035  	// Add some state
  2036  	fsm := testFSM(t)
  2037  	state := fsm.State()
  2038  	job1 := mock.Job()
  2039  	launch1 := &structs.PeriodicLaunch{
  2040  		ID:        job1.ID,
  2041  		Namespace: job1.Namespace,
  2042  		Launch:    time.Now(),
  2043  	}
  2044  	state.UpsertPeriodicLaunch(1000, launch1)
  2045  	job2 := mock.Job()
  2046  	launch2 := &structs.PeriodicLaunch{
  2047  		ID:        job2.ID,
  2048  		Namespace: job2.Namespace,
  2049  		Launch:    time.Now(),
  2050  	}
  2051  	state.UpsertPeriodicLaunch(1001, launch2)
  2052  
  2053  	// Verify the contents
  2054  	fsm2 := testSnapshotRestore(t, fsm)
  2055  	state2 := fsm2.State()
  2056  	ws := memdb.NewWatchSet()
  2057  	out1, _ := state2.PeriodicLaunchByID(ws, launch1.Namespace, launch1.ID)
  2058  	out2, _ := state2.PeriodicLaunchByID(ws, launch2.Namespace, launch2.ID)
  2059  
  2060  	if !cmp.Equal(launch1, out1) {
  2061  		t.Fatalf("bad: %v", cmp.Diff(launch1, out1))
  2062  	}
  2063  	if !cmp.Equal(launch2, out2) {
  2064  		t.Fatalf("bad: %v", cmp.Diff(launch2, out2))
  2065  	}
  2066  }
  2067  
  2068  func TestFSM_SnapshotRestore_JobSummary(t *testing.T) {
  2069  	t.Parallel()
  2070  	// Add some state
  2071  	fsm := testFSM(t)
  2072  	state := fsm.State()
  2073  
  2074  	job1 := mock.Job()
  2075  	state.UpsertJob(1000, job1)
  2076  	ws := memdb.NewWatchSet()
  2077  	js1, _ := state.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2078  
  2079  	job2 := mock.Job()
  2080  	state.UpsertJob(1001, job2)
  2081  	js2, _ := state.JobSummaryByID(ws, job2.Namespace, job2.ID)
  2082  
  2083  	// Verify the contents
  2084  	fsm2 := testSnapshotRestore(t, fsm)
  2085  	state2 := fsm2.State()
  2086  	out1, _ := state2.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2087  	out2, _ := state2.JobSummaryByID(ws, job2.Namespace, job2.ID)
  2088  	if !reflect.DeepEqual(js1, out1) {
  2089  		t.Fatalf("bad: \n%#v\n%#v", js1, out1)
  2090  	}
  2091  	if !reflect.DeepEqual(js2, out2) {
  2092  		t.Fatalf("bad: \n%#v\n%#v", js2, out2)
  2093  	}
  2094  }
  2095  
  2096  func TestFSM_SnapshotRestore_VaultAccessors(t *testing.T) {
  2097  	t.Parallel()
  2098  	// Add some state
  2099  	fsm := testFSM(t)
  2100  	state := fsm.State()
  2101  	a1 := mock.VaultAccessor()
  2102  	a2 := mock.VaultAccessor()
  2103  	state.UpsertVaultAccessor(1000, []*structs.VaultAccessor{a1, a2})
  2104  
  2105  	// Verify the contents
  2106  	fsm2 := testSnapshotRestore(t, fsm)
  2107  	state2 := fsm2.State()
  2108  	ws := memdb.NewWatchSet()
  2109  	out1, _ := state2.VaultAccessor(ws, a1.Accessor)
  2110  	out2, _ := state2.VaultAccessor(ws, a2.Accessor)
  2111  	if !reflect.DeepEqual(a1, out1) {
  2112  		t.Fatalf("bad: \n%#v\n%#v", out1, a1)
  2113  	}
  2114  	if !reflect.DeepEqual(a2, out2) {
  2115  		t.Fatalf("bad: \n%#v\n%#v", out2, a2)
  2116  	}
  2117  }
  2118  
  2119  func TestFSM_SnapshotRestore_JobVersions(t *testing.T) {
  2120  	t.Parallel()
  2121  	// Add some state
  2122  	fsm := testFSM(t)
  2123  	state := fsm.State()
  2124  	job1 := mock.Job()
  2125  	state.UpsertJob(1000, job1)
  2126  	job2 := mock.Job()
  2127  	job2.ID = job1.ID
  2128  	state.UpsertJob(1001, job2)
  2129  
  2130  	// Verify the contents
  2131  	ws := memdb.NewWatchSet()
  2132  	fsm2 := testSnapshotRestore(t, fsm)
  2133  	state2 := fsm2.State()
  2134  	out1, _ := state2.JobByIDAndVersion(ws, job1.Namespace, job1.ID, job1.Version)
  2135  	out2, _ := state2.JobByIDAndVersion(ws, job2.Namespace, job2.ID, job2.Version)
  2136  	if !reflect.DeepEqual(job1, out1) {
  2137  		t.Fatalf("bad: \n%#v\n%#v", out1, job1)
  2138  	}
  2139  	if !reflect.DeepEqual(job2, out2) {
  2140  		t.Fatalf("bad: \n%#v\n%#v", out2, job2)
  2141  	}
  2142  	if job2.Version != 1 {
  2143  		t.Fatalf("bad: \n%#v\n%#v", 1, job2)
  2144  	}
  2145  }
  2146  
  2147  func TestFSM_SnapshotRestore_Deployments(t *testing.T) {
  2148  	t.Parallel()
  2149  	// Add some state
  2150  	fsm := testFSM(t)
  2151  	state := fsm.State()
  2152  	d1 := mock.Deployment()
  2153  	d2 := mock.Deployment()
  2154  	state.UpsertDeployment(1000, d1)
  2155  	state.UpsertDeployment(1001, d2)
  2156  
  2157  	// Verify the contents
  2158  	fsm2 := testSnapshotRestore(t, fsm)
  2159  	state2 := fsm2.State()
  2160  	ws := memdb.NewWatchSet()
  2161  	out1, _ := state2.DeploymentByID(ws, d1.ID)
  2162  	out2, _ := state2.DeploymentByID(ws, d2.ID)
  2163  	if !reflect.DeepEqual(d1, out1) {
  2164  		t.Fatalf("bad: \n%#v\n%#v", out1, d1)
  2165  	}
  2166  	if !reflect.DeepEqual(d2, out2) {
  2167  		t.Fatalf("bad: \n%#v\n%#v", out2, d2)
  2168  	}
  2169  }
  2170  
  2171  func TestFSM_SnapshotRestore_ACLPolicy(t *testing.T) {
  2172  	t.Parallel()
  2173  	// Add some state
  2174  	fsm := testFSM(t)
  2175  	state := fsm.State()
  2176  	p1 := mock.ACLPolicy()
  2177  	p2 := mock.ACLPolicy()
  2178  	state.UpsertACLPolicies(1000, []*structs.ACLPolicy{p1, p2})
  2179  
  2180  	// Verify the contents
  2181  	fsm2 := testSnapshotRestore(t, fsm)
  2182  	state2 := fsm2.State()
  2183  	ws := memdb.NewWatchSet()
  2184  	out1, _ := state2.ACLPolicyByName(ws, p1.Name)
  2185  	out2, _ := state2.ACLPolicyByName(ws, p2.Name)
  2186  	assert.Equal(t, p1, out1)
  2187  	assert.Equal(t, p2, out2)
  2188  }
  2189  
  2190  func TestFSM_SnapshotRestore_ACLTokens(t *testing.T) {
  2191  	t.Parallel()
  2192  	// Add some state
  2193  	fsm := testFSM(t)
  2194  	state := fsm.State()
  2195  	tk1 := mock.ACLToken()
  2196  	tk2 := mock.ACLToken()
  2197  	state.UpsertACLTokens(1000, []*structs.ACLToken{tk1, tk2})
  2198  
  2199  	// Verify the contents
  2200  	fsm2 := testSnapshotRestore(t, fsm)
  2201  	state2 := fsm2.State()
  2202  	ws := memdb.NewWatchSet()
  2203  	out1, _ := state2.ACLTokenByAccessorID(ws, tk1.AccessorID)
  2204  	out2, _ := state2.ACLTokenByAccessorID(ws, tk2.AccessorID)
  2205  	assert.Equal(t, tk1, out1)
  2206  	assert.Equal(t, tk2, out2)
  2207  }
  2208  
  2209  func TestFSM_SnapshotRestore_AddMissingSummary(t *testing.T) {
  2210  	t.Parallel()
  2211  	// Add some state
  2212  	fsm := testFSM(t)
  2213  	state := fsm.State()
  2214  
  2215  	// make an allocation
  2216  	alloc := mock.Alloc()
  2217  	state.UpsertJob(1010, alloc.Job)
  2218  	state.UpsertAllocs(1011, []*structs.Allocation{alloc})
  2219  
  2220  	// Delete the summary
  2221  	state.DeleteJobSummary(1040, alloc.Namespace, alloc.Job.ID)
  2222  
  2223  	// Delete the index
  2224  	if err := state.RemoveIndex("job_summary"); err != nil {
  2225  		t.Fatalf("err: %v", err)
  2226  	}
  2227  
  2228  	fsm2 := testSnapshotRestore(t, fsm)
  2229  	state2 := fsm2.State()
  2230  	latestIndex, _ := state.LatestIndex()
  2231  
  2232  	ws := memdb.NewWatchSet()
  2233  	out, _ := state2.JobSummaryByID(ws, alloc.Namespace, alloc.Job.ID)
  2234  	expected := structs.JobSummary{
  2235  		JobID:     alloc.Job.ID,
  2236  		Namespace: alloc.Job.Namespace,
  2237  		Summary: map[string]structs.TaskGroupSummary{
  2238  			"web": {
  2239  				Starting: 1,
  2240  			},
  2241  		},
  2242  		CreateIndex: 1010,
  2243  		ModifyIndex: latestIndex,
  2244  	}
  2245  	if !reflect.DeepEqual(&expected, out) {
  2246  		t.Fatalf("expected: %#v, actual: %#v", &expected, out)
  2247  	}
  2248  }
  2249  
  2250  func TestFSM_ReconcileSummaries(t *testing.T) {
  2251  	t.Parallel()
  2252  	// Add some state
  2253  	fsm := testFSM(t)
  2254  	state := fsm.State()
  2255  
  2256  	// Add a node
  2257  	node := mock.Node()
  2258  	state.UpsertNode(800, node)
  2259  
  2260  	// Make a job so that none of the tasks can be placed
  2261  	job1 := mock.Job()
  2262  	job1.TaskGroups[0].Tasks[0].Resources.CPU = 5000
  2263  	state.UpsertJob(1000, job1)
  2264  
  2265  	// make a job which can make partial progress
  2266  	alloc := mock.Alloc()
  2267  	alloc.NodeID = node.ID
  2268  	state.UpsertJob(1010, alloc.Job)
  2269  	state.UpsertAllocs(1011, []*structs.Allocation{alloc})
  2270  
  2271  	// Delete the summaries
  2272  	state.DeleteJobSummary(1030, job1.Namespace, job1.ID)
  2273  	state.DeleteJobSummary(1040, alloc.Namespace, alloc.Job.ID)
  2274  
  2275  	req := structs.GenericRequest{}
  2276  	buf, err := structs.Encode(structs.ReconcileJobSummariesRequestType, req)
  2277  	if err != nil {
  2278  		t.Fatalf("err: %v", err)
  2279  	}
  2280  
  2281  	resp := fsm.Apply(makeLog(buf))
  2282  	if resp != nil {
  2283  		t.Fatalf("resp: %v", resp)
  2284  	}
  2285  
  2286  	ws := memdb.NewWatchSet()
  2287  	out1, _ := state.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2288  	expected := structs.JobSummary{
  2289  		JobID:     job1.ID,
  2290  		Namespace: job1.Namespace,
  2291  		Summary: map[string]structs.TaskGroupSummary{
  2292  			"web": {
  2293  				Queued: 10,
  2294  			},
  2295  		},
  2296  		CreateIndex: 1000,
  2297  		ModifyIndex: out1.ModifyIndex,
  2298  	}
  2299  	if !reflect.DeepEqual(&expected, out1) {
  2300  		t.Fatalf("expected: %#v, actual: %#v", &expected, out1)
  2301  	}
  2302  
  2303  	// This exercises the code path which adds the allocations made by the
  2304  	// planner and the number of unplaced allocations in the reconcile summaries
  2305  	// codepath
  2306  	out2, _ := state.JobSummaryByID(ws, alloc.Namespace, alloc.Job.ID)
  2307  	expected = structs.JobSummary{
  2308  		JobID:     alloc.Job.ID,
  2309  		Namespace: alloc.Job.Namespace,
  2310  		Summary: map[string]structs.TaskGroupSummary{
  2311  			"web": {
  2312  				Queued:   9,
  2313  				Starting: 1,
  2314  			},
  2315  		},
  2316  		CreateIndex: 1010,
  2317  		ModifyIndex: out2.ModifyIndex,
  2318  	}
  2319  	if !reflect.DeepEqual(&expected, out2) {
  2320  		t.Fatalf("Diff % #v", pretty.Diff(&expected, out2))
  2321  	}
  2322  }
  2323  
  2324  func TestFSM_Autopilot(t *testing.T) {
  2325  	t.Parallel()
  2326  	fsm := testFSM(t)
  2327  
  2328  	// Set the autopilot config using a request.
  2329  	req := structs.AutopilotSetConfigRequest{
  2330  		Datacenter: "dc1",
  2331  		Config: structs.AutopilotConfig{
  2332  			CleanupDeadServers:   true,
  2333  			LastContactThreshold: 10 * time.Second,
  2334  			MaxTrailingLogs:      300,
  2335  		},
  2336  	}
  2337  	buf, err := structs.Encode(structs.AutopilotRequestType, req)
  2338  	if err != nil {
  2339  		t.Fatalf("err: %v", err)
  2340  	}
  2341  	resp := fsm.Apply(makeLog(buf))
  2342  	if _, ok := resp.(error); ok {
  2343  		t.Fatalf("bad: %v", resp)
  2344  	}
  2345  
  2346  	// Verify key is set directly in the state store.
  2347  	_, config, err := fsm.state.AutopilotConfig()
  2348  	if err != nil {
  2349  		t.Fatalf("err: %v", err)
  2350  	}
  2351  	if config.CleanupDeadServers != req.Config.CleanupDeadServers {
  2352  		t.Fatalf("bad: %v", config.CleanupDeadServers)
  2353  	}
  2354  	if config.LastContactThreshold != req.Config.LastContactThreshold {
  2355  		t.Fatalf("bad: %v", config.LastContactThreshold)
  2356  	}
  2357  	if config.MaxTrailingLogs != req.Config.MaxTrailingLogs {
  2358  		t.Fatalf("bad: %v", config.MaxTrailingLogs)
  2359  	}
  2360  
  2361  	// Now use CAS and provide an old index
  2362  	req.CAS = true
  2363  	req.Config.CleanupDeadServers = false
  2364  	req.Config.ModifyIndex = config.ModifyIndex - 1
  2365  	buf, err = structs.Encode(structs.AutopilotRequestType, req)
  2366  	if err != nil {
  2367  		t.Fatalf("err: %v", err)
  2368  	}
  2369  	resp = fsm.Apply(makeLog(buf))
  2370  	if _, ok := resp.(error); ok {
  2371  		t.Fatalf("bad: %v", resp)
  2372  	}
  2373  
  2374  	_, config, err = fsm.state.AutopilotConfig()
  2375  	if err != nil {
  2376  		t.Fatalf("err: %v", err)
  2377  	}
  2378  	if !config.CleanupDeadServers {
  2379  		t.Fatalf("bad: %v", config.CleanupDeadServers)
  2380  	}
  2381  }