github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/eval_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  
    10  	memdb "github.com/hashicorp/go-memdb"
    11  	"github.com/hashicorp/net-rpc-msgpackrpc"
    12  	"github.com/hashicorp/nomad/acl"
    13  	"github.com/hashicorp/nomad/helper/uuid"
    14  	"github.com/hashicorp/nomad/nomad/mock"
    15  	"github.com/hashicorp/nomad/nomad/structs"
    16  	"github.com/hashicorp/nomad/scheduler"
    17  	"github.com/hashicorp/nomad/testutil"
    18  	"github.com/stretchr/testify/assert"
    19  )
    20  
    21  func TestEvalEndpoint_GetEval(t *testing.T) {
    22  	t.Parallel()
    23  	s1 := TestServer(t, nil)
    24  	defer s1.Shutdown()
    25  	codec := rpcClient(t, s1)
    26  	testutil.WaitForLeader(t, s1.RPC)
    27  
    28  	// Create the register request
    29  	eval1 := mock.Eval()
    30  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1})
    31  
    32  	// Lookup the eval
    33  	get := &structs.EvalSpecificRequest{
    34  		EvalID:       eval1.ID,
    35  		QueryOptions: structs.QueryOptions{Region: "global"},
    36  	}
    37  	var resp structs.SingleEvalResponse
    38  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil {
    39  		t.Fatalf("err: %v", err)
    40  	}
    41  	if resp.Index != 1000 {
    42  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
    43  	}
    44  
    45  	if !reflect.DeepEqual(eval1, resp.Eval) {
    46  		t.Fatalf("bad: %#v %#v", eval1, resp.Eval)
    47  	}
    48  
    49  	// Lookup non-existing node
    50  	get.EvalID = uuid.Generate()
    51  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil {
    52  		t.Fatalf("err: %v", err)
    53  	}
    54  	if resp.Index != 1000 {
    55  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
    56  	}
    57  	if resp.Eval != nil {
    58  		t.Fatalf("unexpected eval")
    59  	}
    60  }
    61  
    62  func TestEvalEndpoint_GetEval_ACL(t *testing.T) {
    63  	t.Parallel()
    64  	s1, root := TestACLServer(t, nil)
    65  	defer s1.Shutdown()
    66  	codec := rpcClient(t, s1)
    67  	testutil.WaitForLeader(t, s1.RPC)
    68  	assert := assert.New(t)
    69  
    70  	// Create the register request
    71  	eval1 := mock.Eval()
    72  	state := s1.fsm.State()
    73  	state.UpsertEvals(1000, []*structs.Evaluation{eval1})
    74  
    75  	// Create ACL tokens
    76  	validToken := mock.CreatePolicyAndToken(t, state, 1003, "test-valid",
    77  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}))
    78  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid",
    79  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs}))
    80  
    81  	get := &structs.EvalSpecificRequest{
    82  		EvalID:       eval1.ID,
    83  		QueryOptions: structs.QueryOptions{Region: "global"},
    84  	}
    85  
    86  	// Try with no token and expect permission denied
    87  	{
    88  		var resp structs.SingleEvalResponse
    89  		err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp)
    90  		assert.NotNil(err)
    91  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
    92  	}
    93  
    94  	// Try with an invalid token and expect permission denied
    95  	{
    96  		get.AuthToken = invalidToken.SecretID
    97  		var resp structs.SingleEvalResponse
    98  		err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp)
    99  		assert.NotNil(err)
   100  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
   101  	}
   102  
   103  	// Lookup the eval using a valid token
   104  	{
   105  		get.AuthToken = validToken.SecretID
   106  		var resp structs.SingleEvalResponse
   107  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp))
   108  		assert.Equal(uint64(1000), resp.Index, "Bad index: %d %d", resp.Index, 1000)
   109  		assert.Equal(eval1, resp.Eval)
   110  	}
   111  
   112  	// Lookup the eval using a root token
   113  	{
   114  		get.AuthToken = root.SecretID
   115  		var resp structs.SingleEvalResponse
   116  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp))
   117  		assert.Equal(uint64(1000), resp.Index, "Bad index: %d %d", resp.Index, 1000)
   118  		assert.Equal(eval1, resp.Eval)
   119  	}
   120  }
   121  
   122  func TestEvalEndpoint_GetEval_Blocking(t *testing.T) {
   123  	t.Parallel()
   124  	s1 := TestServer(t, nil)
   125  	defer s1.Shutdown()
   126  	state := s1.fsm.State()
   127  	codec := rpcClient(t, s1)
   128  	testutil.WaitForLeader(t, s1.RPC)
   129  
   130  	// Create the evals
   131  	eval1 := mock.Eval()
   132  	eval2 := mock.Eval()
   133  
   134  	// First create an unrelated eval
   135  	time.AfterFunc(100*time.Millisecond, func() {
   136  		err := state.UpsertEvals(100, []*structs.Evaluation{eval1})
   137  		if err != nil {
   138  			t.Fatalf("err: %v", err)
   139  		}
   140  	})
   141  
   142  	// Upsert the eval we are watching later
   143  	time.AfterFunc(200*time.Millisecond, func() {
   144  		err := state.UpsertEvals(200, []*structs.Evaluation{eval2})
   145  		if err != nil {
   146  			t.Fatalf("err: %v", err)
   147  		}
   148  	})
   149  
   150  	// Lookup the eval
   151  	req := &structs.EvalSpecificRequest{
   152  		EvalID: eval2.ID,
   153  		QueryOptions: structs.QueryOptions{
   154  			Region:        "global",
   155  			MinQueryIndex: 150,
   156  		},
   157  	}
   158  	var resp structs.SingleEvalResponse
   159  	start := time.Now()
   160  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", req, &resp); err != nil {
   161  		t.Fatalf("err: %v", err)
   162  	}
   163  
   164  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   165  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   166  	}
   167  	if resp.Index != 200 {
   168  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
   169  	}
   170  	if resp.Eval == nil || resp.Eval.ID != eval2.ID {
   171  		t.Fatalf("bad: %#v", resp.Eval)
   172  	}
   173  
   174  	// Eval delete triggers watches
   175  	time.AfterFunc(100*time.Millisecond, func() {
   176  		err := state.DeleteEval(300, []string{eval2.ID}, []string{})
   177  		if err != nil {
   178  			t.Fatalf("err: %v", err)
   179  		}
   180  	})
   181  
   182  	req.QueryOptions.MinQueryIndex = 250
   183  	var resp2 structs.SingleEvalResponse
   184  	start = time.Now()
   185  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", req, &resp2); err != nil {
   186  		t.Fatalf("err: %v", err)
   187  	}
   188  
   189  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   190  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   191  	}
   192  	if resp2.Index != 300 {
   193  		t.Fatalf("Bad index: %d %d", resp2.Index, 300)
   194  	}
   195  	if resp2.Eval != nil {
   196  		t.Fatalf("bad: %#v", resp2.Eval)
   197  	}
   198  }
   199  
   200  func TestEvalEndpoint_Dequeue(t *testing.T) {
   201  	t.Parallel()
   202  	s1 := TestServer(t, func(c *Config) {
   203  		c.NumSchedulers = 0 // Prevent automatic dequeue
   204  	})
   205  	defer s1.Shutdown()
   206  	codec := rpcClient(t, s1)
   207  	testutil.WaitForLeader(t, s1.RPC)
   208  
   209  	// Create the register request
   210  	eval1 := mock.Eval()
   211  	s1.evalBroker.Enqueue(eval1)
   212  
   213  	// Dequeue the eval
   214  	get := &structs.EvalDequeueRequest{
   215  		Schedulers:       defaultSched,
   216  		SchedulerVersion: scheduler.SchedulerVersion,
   217  		WriteRequest:     structs.WriteRequest{Region: "global"},
   218  	}
   219  	var resp structs.EvalDequeueResponse
   220  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp); err != nil {
   221  		t.Fatalf("err: %v", err)
   222  	}
   223  
   224  	if !reflect.DeepEqual(eval1, resp.Eval) {
   225  		t.Fatalf("bad: %v %v", eval1, resp.Eval)
   226  	}
   227  
   228  	// Ensure outstanding
   229  	token, ok := s1.evalBroker.Outstanding(eval1.ID)
   230  	if !ok {
   231  		t.Fatalf("should be outstanding")
   232  	}
   233  	if token != resp.Token {
   234  		t.Fatalf("bad token: %#v %#v", token, resp.Token)
   235  	}
   236  
   237  	if resp.WaitIndex != eval1.ModifyIndex {
   238  		t.Fatalf("bad wait index; got %d; want %d", resp.WaitIndex, eval1.ModifyIndex)
   239  	}
   240  }
   241  
   242  func TestEvalEndpoint_Dequeue_WaitIndex(t *testing.T) {
   243  	t.Parallel()
   244  	s1 := TestServer(t, func(c *Config) {
   245  		c.NumSchedulers = 0 // Prevent automatic dequeue
   246  	})
   247  	defer s1.Shutdown()
   248  	codec := rpcClient(t, s1)
   249  	testutil.WaitForLeader(t, s1.RPC)
   250  
   251  	// Create the register request
   252  	eval1 := mock.Eval()
   253  	eval2 := mock.Eval()
   254  	eval2.JobID = eval1.JobID
   255  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1})
   256  	s1.evalBroker.Enqueue(eval1)
   257  	s1.fsm.State().UpsertEvals(1001, []*structs.Evaluation{eval2})
   258  
   259  	// Dequeue the eval
   260  	get := &structs.EvalDequeueRequest{
   261  		Schedulers:       defaultSched,
   262  		SchedulerVersion: scheduler.SchedulerVersion,
   263  		WriteRequest:     structs.WriteRequest{Region: "global"},
   264  	}
   265  	var resp structs.EvalDequeueResponse
   266  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp); err != nil {
   267  		t.Fatalf("err: %v", err)
   268  	}
   269  
   270  	if !reflect.DeepEqual(eval1, resp.Eval) {
   271  		t.Fatalf("bad: %v %v", eval1, resp.Eval)
   272  	}
   273  
   274  	// Ensure outstanding
   275  	token, ok := s1.evalBroker.Outstanding(eval1.ID)
   276  	if !ok {
   277  		t.Fatalf("should be outstanding")
   278  	}
   279  	if token != resp.Token {
   280  		t.Fatalf("bad token: %#v %#v", token, resp.Token)
   281  	}
   282  
   283  	if resp.WaitIndex != 1001 {
   284  		t.Fatalf("bad wait index; got %d; want %d", resp.WaitIndex, 1001)
   285  	}
   286  }
   287  
   288  func TestEvalEndpoint_Dequeue_UpdateWaitIndex(t *testing.T) {
   289  	// test enqueuing an eval, updating a plan result for the same eval and de-queueing the eval
   290  	t.Parallel()
   291  	s1 := TestServer(t, func(c *Config) {
   292  		c.NumSchedulers = 0 // Prevent automatic dequeue
   293  	})
   294  	defer s1.Shutdown()
   295  	codec := rpcClient(t, s1)
   296  	testutil.WaitForLeader(t, s1.RPC)
   297  
   298  	alloc := mock.Alloc()
   299  	job := alloc.Job
   300  	alloc.Job = nil
   301  
   302  	state := s1.fsm.State()
   303  
   304  	if err := state.UpsertJob(999, job); err != nil {
   305  		t.Fatalf("err: %v", err)
   306  	}
   307  
   308  	eval := mock.Eval()
   309  	eval.JobID = job.ID
   310  
   311  	// Create an eval
   312  	if err := state.UpsertEvals(1, []*structs.Evaluation{eval}); err != nil {
   313  		t.Fatalf("err: %v", err)
   314  	}
   315  
   316  	s1.evalBroker.Enqueue(eval)
   317  
   318  	// Create a plan result and apply it with a later index
   319  	res := structs.ApplyPlanResultsRequest{
   320  		AllocUpdateRequest: structs.AllocUpdateRequest{
   321  			Alloc: []*structs.Allocation{alloc},
   322  			Job:   job,
   323  		},
   324  		EvalID: eval.ID,
   325  	}
   326  	assert := assert.New(t)
   327  	err := state.UpsertPlanResults(1000, &res)
   328  	assert.Nil(err)
   329  
   330  	// Dequeue the eval
   331  	get := &structs.EvalDequeueRequest{
   332  		Schedulers:       defaultSched,
   333  		SchedulerVersion: scheduler.SchedulerVersion,
   334  		WriteRequest:     structs.WriteRequest{Region: "global"},
   335  	}
   336  	var resp structs.EvalDequeueResponse
   337  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp); err != nil {
   338  		t.Fatalf("err: %v", err)
   339  	}
   340  
   341  	// Ensure outstanding
   342  	token, ok := s1.evalBroker.Outstanding(eval.ID)
   343  	if !ok {
   344  		t.Fatalf("should be outstanding")
   345  	}
   346  	if token != resp.Token {
   347  		t.Fatalf("bad token: %#v %#v", token, resp.Token)
   348  	}
   349  
   350  	if resp.WaitIndex != 1000 {
   351  		t.Fatalf("bad wait index; got %d; want %d", resp.WaitIndex, 1000)
   352  	}
   353  }
   354  
   355  func TestEvalEndpoint_Dequeue_Version_Mismatch(t *testing.T) {
   356  	t.Parallel()
   357  	s1 := TestServer(t, func(c *Config) {
   358  		c.NumSchedulers = 0 // Prevent automatic dequeue
   359  	})
   360  	defer s1.Shutdown()
   361  	codec := rpcClient(t, s1)
   362  	testutil.WaitForLeader(t, s1.RPC)
   363  
   364  	// Create the register request
   365  	eval1 := mock.Eval()
   366  	s1.evalBroker.Enqueue(eval1)
   367  
   368  	// Dequeue the eval
   369  	get := &structs.EvalDequeueRequest{
   370  		Schedulers:       defaultSched,
   371  		SchedulerVersion: 0,
   372  		WriteRequest:     structs.WriteRequest{Region: "global"},
   373  	}
   374  	var resp structs.EvalDequeueResponse
   375  	err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp)
   376  	if err == nil || !strings.Contains(err.Error(), "scheduler version is 0") {
   377  		t.Fatalf("err: %v", err)
   378  	}
   379  }
   380  
   381  func TestEvalEndpoint_Ack(t *testing.T) {
   382  	t.Parallel()
   383  	s1 := TestServer(t, nil)
   384  	defer s1.Shutdown()
   385  	codec := rpcClient(t, s1)
   386  
   387  	testutil.WaitForResult(func() (bool, error) {
   388  		return s1.evalBroker.Enabled(), nil
   389  	}, func(err error) {
   390  		t.Fatalf("should enable eval broker")
   391  	})
   392  
   393  	// Create the register request
   394  	eval1 := mock.Eval()
   395  	s1.evalBroker.Enqueue(eval1)
   396  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   397  	if err != nil {
   398  		t.Fatalf("err: %v", err)
   399  	}
   400  	if out == nil {
   401  		t.Fatalf("missing eval")
   402  	}
   403  
   404  	// Ack the eval
   405  	get := &structs.EvalAckRequest{
   406  		EvalID:       out.ID,
   407  		Token:        token,
   408  		WriteRequest: structs.WriteRequest{Region: "global"},
   409  	}
   410  	var resp structs.GenericResponse
   411  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Ack", get, &resp); err != nil {
   412  		t.Fatalf("err: %v", err)
   413  	}
   414  
   415  	// Ensure outstanding
   416  	if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok {
   417  		t.Fatalf("should not be outstanding")
   418  	}
   419  }
   420  
   421  func TestEvalEndpoint_Nack(t *testing.T) {
   422  	t.Parallel()
   423  	s1 := TestServer(t, func(c *Config) {
   424  		// Disable all of the schedulers so we can manually dequeue
   425  		// evals and check the queue status
   426  		c.NumSchedulers = 0
   427  	})
   428  	defer s1.Shutdown()
   429  	codec := rpcClient(t, s1)
   430  
   431  	testutil.WaitForResult(func() (bool, error) {
   432  		return s1.evalBroker.Enabled(), nil
   433  	}, func(err error) {
   434  		t.Fatalf("should enable eval broker")
   435  	})
   436  
   437  	// Create the register request
   438  	eval1 := mock.Eval()
   439  	s1.evalBroker.Enqueue(eval1)
   440  	out, token, _ := s1.evalBroker.Dequeue(defaultSched, time.Second)
   441  	if out == nil {
   442  		t.Fatalf("missing eval")
   443  	}
   444  
   445  	// Nack the eval
   446  	get := &structs.EvalAckRequest{
   447  		EvalID:       out.ID,
   448  		Token:        token,
   449  		WriteRequest: structs.WriteRequest{Region: "global"},
   450  	}
   451  	var resp structs.GenericResponse
   452  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Nack", get, &resp); err != nil {
   453  		t.Fatalf("err: %v", err)
   454  	}
   455  
   456  	// Ensure outstanding
   457  	if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok {
   458  		t.Fatalf("should not be outstanding")
   459  	}
   460  
   461  	// Should get it back
   462  	testutil.WaitForResult(func() (bool, error) {
   463  		out2, _, _ := s1.evalBroker.Dequeue(defaultSched, time.Second)
   464  		if out2 != out {
   465  			return false, fmt.Errorf("nack failed")
   466  		}
   467  
   468  		return true, nil
   469  	}, func(err error) {
   470  		t.Fatal(err)
   471  	})
   472  }
   473  
   474  func TestEvalEndpoint_Update(t *testing.T) {
   475  	t.Parallel()
   476  	s1 := TestServer(t, nil)
   477  	defer s1.Shutdown()
   478  	codec := rpcClient(t, s1)
   479  
   480  	testutil.WaitForResult(func() (bool, error) {
   481  		return s1.evalBroker.Enabled(), nil
   482  	}, func(err error) {
   483  		t.Fatalf("should enable eval broker")
   484  	})
   485  
   486  	// Create the register request
   487  	eval1 := mock.Eval()
   488  	s1.evalBroker.Enqueue(eval1)
   489  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   490  	if err != nil {
   491  		t.Fatalf("err: %v", err)
   492  	}
   493  	if out == nil {
   494  		t.Fatalf("missing eval")
   495  	}
   496  
   497  	// Update the eval
   498  	eval2 := eval1.Copy()
   499  	eval2.Status = structs.EvalStatusComplete
   500  
   501  	get := &structs.EvalUpdateRequest{
   502  		Evals:        []*structs.Evaluation{eval2},
   503  		EvalToken:    token,
   504  		WriteRequest: structs.WriteRequest{Region: "global"},
   505  	}
   506  	var resp structs.GenericResponse
   507  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Update", get, &resp); err != nil {
   508  		t.Fatalf("err: %v", err)
   509  	}
   510  
   511  	// Ensure updated
   512  	ws := memdb.NewWatchSet()
   513  	outE, err := s1.fsm.State().EvalByID(ws, eval2.ID)
   514  	if err != nil {
   515  		t.Fatalf("err: %v", err)
   516  	}
   517  	if outE.Status != structs.EvalStatusComplete {
   518  		t.Fatalf("Bad: %#v", out)
   519  	}
   520  }
   521  
   522  func TestEvalEndpoint_Create(t *testing.T) {
   523  	t.Parallel()
   524  	s1 := TestServer(t, func(c *Config) {
   525  		c.NumSchedulers = 0 // Prevent automatic dequeue
   526  	})
   527  	defer s1.Shutdown()
   528  	codec := rpcClient(t, s1)
   529  
   530  	testutil.WaitForResult(func() (bool, error) {
   531  		return s1.evalBroker.Enabled(), nil
   532  	}, func(err error) {
   533  		t.Fatalf("should enable eval broker")
   534  	})
   535  
   536  	// Create the register request
   537  	prev := mock.Eval()
   538  	s1.evalBroker.Enqueue(prev)
   539  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   540  	if err != nil {
   541  		t.Fatalf("err: %v", err)
   542  	}
   543  	if out == nil {
   544  		t.Fatalf("missing eval")
   545  	}
   546  
   547  	// Create the register request
   548  	eval1 := mock.Eval()
   549  	eval1.PreviousEval = prev.ID
   550  	get := &structs.EvalUpdateRequest{
   551  		Evals:        []*structs.Evaluation{eval1},
   552  		EvalToken:    token,
   553  		WriteRequest: structs.WriteRequest{Region: "global"},
   554  	}
   555  	var resp structs.GenericResponse
   556  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Create", get, &resp); err != nil {
   557  		t.Fatalf("err: %v", err)
   558  	}
   559  
   560  	// Ensure created
   561  	ws := memdb.NewWatchSet()
   562  	outE, err := s1.fsm.State().EvalByID(ws, eval1.ID)
   563  	if err != nil {
   564  		t.Fatalf("err: %v", err)
   565  	}
   566  
   567  	eval1.CreateIndex = resp.Index
   568  	eval1.ModifyIndex = resp.Index
   569  	if !reflect.DeepEqual(eval1, outE) {
   570  		t.Fatalf("Bad: %#v %#v", outE, eval1)
   571  	}
   572  }
   573  
   574  func TestEvalEndpoint_Reap(t *testing.T) {
   575  	t.Parallel()
   576  	s1 := TestServer(t, nil)
   577  	defer s1.Shutdown()
   578  	codec := rpcClient(t, s1)
   579  	testutil.WaitForLeader(t, s1.RPC)
   580  
   581  	// Create the register request
   582  	eval1 := mock.Eval()
   583  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1})
   584  
   585  	// Reap the eval
   586  	get := &structs.EvalDeleteRequest{
   587  		Evals:        []string{eval1.ID},
   588  		WriteRequest: structs.WriteRequest{Region: "global"},
   589  	}
   590  	var resp structs.GenericResponse
   591  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Reap", get, &resp); err != nil {
   592  		t.Fatalf("err: %v", err)
   593  	}
   594  	if resp.Index == 0 {
   595  		t.Fatalf("Bad index: %d", resp.Index)
   596  	}
   597  
   598  	// Ensure deleted
   599  	ws := memdb.NewWatchSet()
   600  	outE, err := s1.fsm.State().EvalByID(ws, eval1.ID)
   601  	if err != nil {
   602  		t.Fatalf("err: %v", err)
   603  	}
   604  	if outE != nil {
   605  		t.Fatalf("Bad: %#v", outE)
   606  	}
   607  }
   608  
   609  func TestEvalEndpoint_List(t *testing.T) {
   610  	t.Parallel()
   611  	s1 := TestServer(t, nil)
   612  	defer s1.Shutdown()
   613  	codec := rpcClient(t, s1)
   614  	testutil.WaitForLeader(t, s1.RPC)
   615  
   616  	// Create the register request
   617  	eval1 := mock.Eval()
   618  	eval1.ID = "aaaaaaaa-3350-4b4b-d185-0e1992ed43e9"
   619  	eval2 := mock.Eval()
   620  	eval2.ID = "aaaabbbb-3350-4b4b-d185-0e1992ed43e9"
   621  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1, eval2})
   622  
   623  	// Lookup the eval
   624  	get := &structs.EvalListRequest{
   625  		QueryOptions: structs.QueryOptions{
   626  			Region:    "global",
   627  			Namespace: structs.DefaultNamespace,
   628  		},
   629  	}
   630  	var resp structs.EvalListResponse
   631  	if err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp); err != nil {
   632  		t.Fatalf("err: %v", err)
   633  	}
   634  	if resp.Index != 1000 {
   635  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   636  	}
   637  
   638  	if len(resp.Evaluations) != 2 {
   639  		t.Fatalf("bad: %#v", resp.Evaluations)
   640  	}
   641  
   642  	// Lookup the eval by prefix
   643  	get = &structs.EvalListRequest{
   644  		QueryOptions: structs.QueryOptions{
   645  			Region:    "global",
   646  			Namespace: structs.DefaultNamespace,
   647  			Prefix:    "aaaabb",
   648  		},
   649  	}
   650  	var resp2 structs.EvalListResponse
   651  	if err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp2); err != nil {
   652  		t.Fatalf("err: %v", err)
   653  	}
   654  	if resp2.Index != 1000 {
   655  		t.Fatalf("Bad index: %d %d", resp2.Index, 1000)
   656  	}
   657  
   658  	if len(resp2.Evaluations) != 1 {
   659  		t.Fatalf("bad: %#v", resp2.Evaluations)
   660  	}
   661  
   662  }
   663  
   664  func TestEvalEndpoint_List_ACL(t *testing.T) {
   665  	t.Parallel()
   666  	s1, root := TestACLServer(t, nil)
   667  	defer s1.Shutdown()
   668  	codec := rpcClient(t, s1)
   669  	testutil.WaitForLeader(t, s1.RPC)
   670  	assert := assert.New(t)
   671  
   672  	// Create the register request
   673  	eval1 := mock.Eval()
   674  	eval1.ID = "aaaaaaaa-3350-4b4b-d185-0e1992ed43e9"
   675  	eval2 := mock.Eval()
   676  	eval2.ID = "aaaabbbb-3350-4b4b-d185-0e1992ed43e9"
   677  	state := s1.fsm.State()
   678  	assert.Nil(state.UpsertEvals(1000, []*structs.Evaluation{eval1, eval2}))
   679  
   680  	// Create ACL tokens
   681  	validToken := mock.CreatePolicyAndToken(t, state, 1003, "test-valid",
   682  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}))
   683  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid",
   684  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs}))
   685  
   686  	get := &structs.EvalListRequest{
   687  		QueryOptions: structs.QueryOptions{
   688  			Region:    "global",
   689  			Namespace: structs.DefaultNamespace,
   690  		},
   691  	}
   692  
   693  	// Try without a token and expect permission denied
   694  	{
   695  		var resp structs.EvalListResponse
   696  		err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp)
   697  		assert.NotNil(err)
   698  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
   699  	}
   700  
   701  	// Try with an invalid token and expect permission denied
   702  	{
   703  		get.AuthToken = invalidToken.SecretID
   704  		var resp structs.EvalListResponse
   705  		err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp)
   706  		assert.NotNil(err)
   707  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
   708  	}
   709  
   710  	// List evals with a valid token
   711  	{
   712  		get.AuthToken = validToken.SecretID
   713  		var resp structs.EvalListResponse
   714  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp))
   715  		assert.Equal(uint64(1000), resp.Index, "Bad index: %d %d", resp.Index, 1000)
   716  		assert.Lenf(resp.Evaluations, 2, "bad: %#v", resp.Evaluations)
   717  	}
   718  
   719  	// List evals with a root token
   720  	{
   721  		get.AuthToken = root.SecretID
   722  		var resp structs.EvalListResponse
   723  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp))
   724  		assert.Equal(uint64(1000), resp.Index, "Bad index: %d %d", resp.Index, 1000)
   725  		assert.Lenf(resp.Evaluations, 2, "bad: %#v", resp.Evaluations)
   726  	}
   727  }
   728  
   729  func TestEvalEndpoint_List_Blocking(t *testing.T) {
   730  	t.Parallel()
   731  	s1 := TestServer(t, nil)
   732  	defer s1.Shutdown()
   733  	state := s1.fsm.State()
   734  	codec := rpcClient(t, s1)
   735  	testutil.WaitForLeader(t, s1.RPC)
   736  
   737  	// Create the ieval
   738  	eval := mock.Eval()
   739  
   740  	// Upsert eval triggers watches
   741  	time.AfterFunc(100*time.Millisecond, func() {
   742  		if err := state.UpsertEvals(2, []*structs.Evaluation{eval}); err != nil {
   743  			t.Fatalf("err: %v", err)
   744  		}
   745  	})
   746  
   747  	req := &structs.EvalListRequest{
   748  		QueryOptions: structs.QueryOptions{
   749  			Region:        "global",
   750  			Namespace:     structs.DefaultNamespace,
   751  			MinQueryIndex: 1,
   752  		},
   753  	}
   754  	start := time.Now()
   755  	var resp structs.EvalListResponse
   756  	if err := msgpackrpc.CallWithCodec(codec, "Eval.List", req, &resp); err != nil {
   757  		t.Fatalf("err: %v", err)
   758  	}
   759  
   760  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   761  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   762  	}
   763  	if resp.Index != 2 {
   764  		t.Fatalf("Bad index: %d %d", resp.Index, 2)
   765  	}
   766  	if len(resp.Evaluations) != 1 || resp.Evaluations[0].ID != eval.ID {
   767  		t.Fatalf("bad: %#v", resp.Evaluations)
   768  	}
   769  
   770  	// Eval deletion triggers watches
   771  	time.AfterFunc(100*time.Millisecond, func() {
   772  		if err := state.DeleteEval(3, []string{eval.ID}, nil); err != nil {
   773  			t.Fatalf("err: %v", err)
   774  		}
   775  	})
   776  
   777  	req.MinQueryIndex = 2
   778  	start = time.Now()
   779  	var resp2 structs.EvalListResponse
   780  	if err := msgpackrpc.CallWithCodec(codec, "Eval.List", req, &resp2); err != nil {
   781  		t.Fatalf("err: %v", err)
   782  	}
   783  
   784  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   785  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   786  	}
   787  	if resp2.Index != 3 {
   788  		t.Fatalf("Bad index: %d %d", resp2.Index, 3)
   789  	}
   790  	if len(resp2.Evaluations) != 0 {
   791  		t.Fatalf("bad: %#v", resp2.Evaluations)
   792  	}
   793  }
   794  
   795  func TestEvalEndpoint_Allocations(t *testing.T) {
   796  	t.Parallel()
   797  	s1 := TestServer(t, nil)
   798  	defer s1.Shutdown()
   799  	codec := rpcClient(t, s1)
   800  	testutil.WaitForLeader(t, s1.RPC)
   801  
   802  	// Create the register request
   803  	alloc1 := mock.Alloc()
   804  	alloc2 := mock.Alloc()
   805  	alloc2.EvalID = alloc1.EvalID
   806  	state := s1.fsm.State()
   807  	state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID))
   808  	state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
   809  	err := state.UpsertAllocs(1000,
   810  		[]*structs.Allocation{alloc1, alloc2})
   811  	if err != nil {
   812  		t.Fatalf("err: %v", err)
   813  	}
   814  
   815  	// Lookup the eval
   816  	get := &structs.EvalSpecificRequest{
   817  		EvalID:       alloc1.EvalID,
   818  		QueryOptions: structs.QueryOptions{Region: "global"},
   819  	}
   820  	var resp structs.EvalAllocationsResponse
   821  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil {
   822  		t.Fatalf("err: %v", err)
   823  	}
   824  	if resp.Index != 1000 {
   825  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   826  	}
   827  
   828  	if len(resp.Allocations) != 2 {
   829  		t.Fatalf("bad: %#v", resp.Allocations)
   830  	}
   831  }
   832  
   833  func TestEvalEndpoint_Allocations_ACL(t *testing.T) {
   834  	t.Parallel()
   835  	s1, root := TestACLServer(t, nil)
   836  	defer s1.Shutdown()
   837  	codec := rpcClient(t, s1)
   838  	testutil.WaitForLeader(t, s1.RPC)
   839  	assert := assert.New(t)
   840  
   841  	// Create the register request
   842  	alloc1 := mock.Alloc()
   843  	alloc2 := mock.Alloc()
   844  	alloc2.EvalID = alloc1.EvalID
   845  	state := s1.fsm.State()
   846  	assert.Nil(state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID)))
   847  	assert.Nil(state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)))
   848  	assert.Nil(state.UpsertAllocs(1000, []*structs.Allocation{alloc1, alloc2}))
   849  
   850  	// Create ACL tokens
   851  	validToken := mock.CreatePolicyAndToken(t, state, 1003, "test-valid",
   852  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}))
   853  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid",
   854  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs}))
   855  
   856  	get := &structs.EvalSpecificRequest{
   857  		EvalID:       alloc1.EvalID,
   858  		QueryOptions: structs.QueryOptions{Region: "global"},
   859  	}
   860  
   861  	// Try with no token and expect permission denied
   862  	{
   863  		var resp structs.EvalAllocationsResponse
   864  		err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp)
   865  		assert.NotNil(err)
   866  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
   867  	}
   868  
   869  	// Try with an invalid token and expect permission denied
   870  	{
   871  		get.AuthToken = invalidToken.SecretID
   872  		var resp structs.EvalAllocationsResponse
   873  		err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp)
   874  		assert.NotNil(err)
   875  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
   876  	}
   877  
   878  	// Lookup the eval with a valid token
   879  	{
   880  		get.AuthToken = validToken.SecretID
   881  		var resp structs.EvalAllocationsResponse
   882  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp))
   883  		assert.Equal(uint64(1000), resp.Index, "Bad index: %d %d", resp.Index, 1000)
   884  		assert.Lenf(resp.Allocations, 2, "bad: %#v", resp.Allocations)
   885  	}
   886  
   887  	// Lookup the eval with a root token
   888  	{
   889  		get.AuthToken = root.SecretID
   890  		var resp structs.EvalAllocationsResponse
   891  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp))
   892  		assert.Equal(uint64(1000), resp.Index, "Bad index: %d %d", resp.Index, 1000)
   893  		assert.Lenf(resp.Allocations, 2, "bad: %#v", resp.Allocations)
   894  	}
   895  }
   896  
   897  func TestEvalEndpoint_Allocations_Blocking(t *testing.T) {
   898  	t.Parallel()
   899  	s1 := TestServer(t, nil)
   900  	defer s1.Shutdown()
   901  	state := s1.fsm.State()
   902  	codec := rpcClient(t, s1)
   903  	testutil.WaitForLeader(t, s1.RPC)
   904  
   905  	// Create the allocs
   906  	alloc1 := mock.Alloc()
   907  	alloc2 := mock.Alloc()
   908  
   909  	// Upsert an unrelated alloc first
   910  	time.AfterFunc(100*time.Millisecond, func() {
   911  		state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID))
   912  		err := state.UpsertAllocs(100, []*structs.Allocation{alloc1})
   913  		if err != nil {
   914  			t.Fatalf("err: %v", err)
   915  		}
   916  	})
   917  
   918  	// Upsert an alloc which will trigger the watch later
   919  	time.AfterFunc(200*time.Millisecond, func() {
   920  		state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID))
   921  		err := state.UpsertAllocs(200, []*structs.Allocation{alloc2})
   922  		if err != nil {
   923  			t.Fatalf("err: %v", err)
   924  		}
   925  	})
   926  
   927  	// Lookup the eval
   928  	get := &structs.EvalSpecificRequest{
   929  		EvalID: alloc2.EvalID,
   930  		QueryOptions: structs.QueryOptions{
   931  			Region:        "global",
   932  			MinQueryIndex: 150,
   933  		},
   934  	}
   935  	var resp structs.EvalAllocationsResponse
   936  	start := time.Now()
   937  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil {
   938  		t.Fatalf("err: %v", err)
   939  	}
   940  
   941  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   942  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   943  	}
   944  	if resp.Index != 200 {
   945  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
   946  	}
   947  	if len(resp.Allocations) != 1 || resp.Allocations[0].ID != alloc2.ID {
   948  		t.Fatalf("bad: %#v", resp.Allocations)
   949  	}
   950  }
   951  
   952  func TestEvalEndpoint_Reblock_Nonexistent(t *testing.T) {
   953  	t.Parallel()
   954  	s1 := TestServer(t, func(c *Config) {
   955  		c.NumSchedulers = 0 // Prevent automatic dequeue
   956  	})
   957  	defer s1.Shutdown()
   958  	codec := rpcClient(t, s1)
   959  
   960  	testutil.WaitForResult(func() (bool, error) {
   961  		return s1.evalBroker.Enabled(), nil
   962  	}, func(err error) {
   963  		t.Fatalf("should enable eval broker")
   964  	})
   965  
   966  	// Create the register request
   967  	eval1 := mock.Eval()
   968  	s1.evalBroker.Enqueue(eval1)
   969  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   970  	if err != nil {
   971  		t.Fatalf("err: %v", err)
   972  	}
   973  	if out == nil {
   974  		t.Fatalf("missing eval")
   975  	}
   976  
   977  	get := &structs.EvalUpdateRequest{
   978  		Evals:        []*structs.Evaluation{eval1},
   979  		EvalToken:    token,
   980  		WriteRequest: structs.WriteRequest{Region: "global"},
   981  	}
   982  	var resp structs.GenericResponse
   983  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Reblock", get, &resp); err == nil {
   984  		t.Fatalf("expect error since eval does not exist")
   985  	}
   986  }
   987  
   988  func TestEvalEndpoint_Reblock_NonBlocked(t *testing.T) {
   989  	t.Parallel()
   990  	s1 := TestServer(t, func(c *Config) {
   991  		c.NumSchedulers = 0 // Prevent automatic dequeue
   992  	})
   993  	defer s1.Shutdown()
   994  	codec := rpcClient(t, s1)
   995  
   996  	testutil.WaitForResult(func() (bool, error) {
   997  		return s1.evalBroker.Enabled(), nil
   998  	}, func(err error) {
   999  		t.Fatalf("should enable eval broker")
  1000  	})
  1001  
  1002  	// Create the eval
  1003  	eval1 := mock.Eval()
  1004  	s1.evalBroker.Enqueue(eval1)
  1005  
  1006  	// Insert it into the state store
  1007  	if err := s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}); err != nil {
  1008  		t.Fatal(err)
  1009  	}
  1010  
  1011  	out, token, err := s1.evalBroker.Dequeue(defaultSched, 2*time.Second)
  1012  	if err != nil {
  1013  		t.Fatalf("err: %v", err)
  1014  	}
  1015  	if out == nil {
  1016  		t.Fatalf("missing eval")
  1017  	}
  1018  
  1019  	get := &structs.EvalUpdateRequest{
  1020  		Evals:        []*structs.Evaluation{eval1},
  1021  		EvalToken:    token,
  1022  		WriteRequest: structs.WriteRequest{Region: "global"},
  1023  	}
  1024  	var resp structs.GenericResponse
  1025  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Reblock", get, &resp); err == nil {
  1026  		t.Fatalf("should error since eval was not in blocked state: %v", err)
  1027  	}
  1028  }
  1029  
  1030  func TestEvalEndpoint_Reblock(t *testing.T) {
  1031  	t.Parallel()
  1032  	s1 := TestServer(t, func(c *Config) {
  1033  		c.NumSchedulers = 0 // Prevent automatic dequeue
  1034  	})
  1035  	defer s1.Shutdown()
  1036  	codec := rpcClient(t, s1)
  1037  
  1038  	testutil.WaitForResult(func() (bool, error) {
  1039  		return s1.evalBroker.Enabled(), nil
  1040  	}, func(err error) {
  1041  		t.Fatalf("should enable eval broker")
  1042  	})
  1043  
  1044  	// Create the eval
  1045  	eval1 := mock.Eval()
  1046  	eval1.Status = structs.EvalStatusBlocked
  1047  	s1.evalBroker.Enqueue(eval1)
  1048  
  1049  	// Insert it into the state store
  1050  	if err := s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}); err != nil {
  1051  		t.Fatal(err)
  1052  	}
  1053  
  1054  	out, token, err := s1.evalBroker.Dequeue(defaultSched, 7*time.Second)
  1055  	if err != nil {
  1056  		t.Fatalf("err: %v", err)
  1057  	}
  1058  	if out == nil {
  1059  		t.Fatalf("bad: %v", out)
  1060  	}
  1061  
  1062  	get := &structs.EvalUpdateRequest{
  1063  		Evals:        []*structs.Evaluation{eval1},
  1064  		EvalToken:    token,
  1065  		WriteRequest: structs.WriteRequest{Region: "global"},
  1066  	}
  1067  	var resp structs.GenericResponse
  1068  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Reblock", get, &resp); err != nil {
  1069  		t.Fatalf("err: %v", err)
  1070  	}
  1071  
  1072  	// Check that it is blocked
  1073  	bStats := s1.blockedEvals.Stats()
  1074  	if bStats.TotalBlocked+bStats.TotalEscaped == 0 {
  1075  		t.Fatalf("ReblockEval didn't insert eval into the blocked eval tracker")
  1076  	}
  1077  }