github.com/jrxfive/nomad@v0.6.1-0.20170802162750-1fef470e89bf/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/nomad/mock"
    13  	"github.com/hashicorp/nomad/nomad/structs"
    14  	"github.com/hashicorp/nomad/scheduler"
    15  	"github.com/hashicorp/nomad/testutil"
    16  )
    17  
    18  func TestEvalEndpoint_GetEval(t *testing.T) {
    19  	t.Parallel()
    20  	s1 := testServer(t, nil)
    21  	defer s1.Shutdown()
    22  	codec := rpcClient(t, s1)
    23  	testutil.WaitForLeader(t, s1.RPC)
    24  
    25  	// Create the register request
    26  	eval1 := mock.Eval()
    27  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1})
    28  
    29  	// Lookup the eval
    30  	get := &structs.EvalSpecificRequest{
    31  		EvalID:       eval1.ID,
    32  		QueryOptions: structs.QueryOptions{Region: "global"},
    33  	}
    34  	var resp structs.SingleEvalResponse
    35  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil {
    36  		t.Fatalf("err: %v", err)
    37  	}
    38  	if resp.Index != 1000 {
    39  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
    40  	}
    41  
    42  	if !reflect.DeepEqual(eval1, resp.Eval) {
    43  		t.Fatalf("bad: %#v %#v", eval1, resp.Eval)
    44  	}
    45  
    46  	// Lookup non-existing node
    47  	get.EvalID = structs.GenerateUUID()
    48  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil {
    49  		t.Fatalf("err: %v", err)
    50  	}
    51  	if resp.Index != 1000 {
    52  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
    53  	}
    54  	if resp.Eval != nil {
    55  		t.Fatalf("unexpected eval")
    56  	}
    57  }
    58  
    59  func TestEvalEndpoint_GetEval_Blocking(t *testing.T) {
    60  	t.Parallel()
    61  	s1 := testServer(t, nil)
    62  	defer s1.Shutdown()
    63  	state := s1.fsm.State()
    64  	codec := rpcClient(t, s1)
    65  	testutil.WaitForLeader(t, s1.RPC)
    66  
    67  	// Create the evals
    68  	eval1 := mock.Eval()
    69  	eval2 := mock.Eval()
    70  
    71  	// First create an unrelated eval
    72  	time.AfterFunc(100*time.Millisecond, func() {
    73  		err := state.UpsertEvals(100, []*structs.Evaluation{eval1})
    74  		if err != nil {
    75  			t.Fatalf("err: %v", err)
    76  		}
    77  	})
    78  
    79  	// Upsert the eval we are watching later
    80  	time.AfterFunc(200*time.Millisecond, func() {
    81  		err := state.UpsertEvals(200, []*structs.Evaluation{eval2})
    82  		if err != nil {
    83  			t.Fatalf("err: %v", err)
    84  		}
    85  	})
    86  
    87  	// Lookup the eval
    88  	req := &structs.EvalSpecificRequest{
    89  		EvalID: eval2.ID,
    90  		QueryOptions: structs.QueryOptions{
    91  			Region:        "global",
    92  			MinQueryIndex: 150,
    93  		},
    94  	}
    95  	var resp structs.SingleEvalResponse
    96  	start := time.Now()
    97  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", req, &resp); err != nil {
    98  		t.Fatalf("err: %v", err)
    99  	}
   100  
   101  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   102  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   103  	}
   104  	if resp.Index != 200 {
   105  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
   106  	}
   107  	if resp.Eval == nil || resp.Eval.ID != eval2.ID {
   108  		t.Fatalf("bad: %#v", resp.Eval)
   109  	}
   110  
   111  	// Eval delete triggers watches
   112  	time.AfterFunc(100*time.Millisecond, func() {
   113  		err := state.DeleteEval(300, []string{eval2.ID}, []string{})
   114  		if err != nil {
   115  			t.Fatalf("err: %v", err)
   116  		}
   117  	})
   118  
   119  	req.QueryOptions.MinQueryIndex = 250
   120  	var resp2 structs.SingleEvalResponse
   121  	start = time.Now()
   122  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", req, &resp2); err != nil {
   123  		t.Fatalf("err: %v", err)
   124  	}
   125  
   126  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   127  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   128  	}
   129  	if resp2.Index != 300 {
   130  		t.Fatalf("Bad index: %d %d", resp2.Index, 300)
   131  	}
   132  	if resp2.Eval != nil {
   133  		t.Fatalf("bad: %#v", resp2.Eval)
   134  	}
   135  }
   136  
   137  func TestEvalEndpoint_Dequeue(t *testing.T) {
   138  	t.Parallel()
   139  	s1 := testServer(t, func(c *Config) {
   140  		c.NumSchedulers = 0 // Prevent automatic dequeue
   141  	})
   142  	defer s1.Shutdown()
   143  	codec := rpcClient(t, s1)
   144  	testutil.WaitForLeader(t, s1.RPC)
   145  
   146  	// Create the register request
   147  	eval1 := mock.Eval()
   148  	s1.evalBroker.Enqueue(eval1)
   149  
   150  	// Dequeue the eval
   151  	get := &structs.EvalDequeueRequest{
   152  		Schedulers:       defaultSched,
   153  		SchedulerVersion: scheduler.SchedulerVersion,
   154  		WriteRequest:     structs.WriteRequest{Region: "global"},
   155  	}
   156  	var resp structs.EvalDequeueResponse
   157  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp); err != nil {
   158  		t.Fatalf("err: %v", err)
   159  	}
   160  
   161  	if !reflect.DeepEqual(eval1, resp.Eval) {
   162  		t.Fatalf("bad: %v %v", eval1, resp.Eval)
   163  	}
   164  
   165  	// Ensure outstanding
   166  	token, ok := s1.evalBroker.Outstanding(eval1.ID)
   167  	if !ok {
   168  		t.Fatalf("should be outstanding")
   169  	}
   170  	if token != resp.Token {
   171  		t.Fatalf("bad token: %#v %#v", token, resp.Token)
   172  	}
   173  }
   174  
   175  func TestEvalEndpoint_Dequeue_Version_Mismatch(t *testing.T) {
   176  	t.Parallel()
   177  	s1 := testServer(t, func(c *Config) {
   178  		c.NumSchedulers = 0 // Prevent automatic dequeue
   179  	})
   180  	defer s1.Shutdown()
   181  	codec := rpcClient(t, s1)
   182  	testutil.WaitForLeader(t, s1.RPC)
   183  
   184  	// Create the register request
   185  	eval1 := mock.Eval()
   186  	s1.evalBroker.Enqueue(eval1)
   187  
   188  	// Dequeue the eval
   189  	get := &structs.EvalDequeueRequest{
   190  		Schedulers:       defaultSched,
   191  		SchedulerVersion: 0,
   192  		WriteRequest:     structs.WriteRequest{Region: "global"},
   193  	}
   194  	var resp structs.EvalDequeueResponse
   195  	err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp)
   196  	if err == nil || !strings.Contains(err.Error(), "scheduler version is 0") {
   197  		t.Fatalf("err: %v", err)
   198  	}
   199  }
   200  
   201  func TestEvalEndpoint_Ack(t *testing.T) {
   202  	t.Parallel()
   203  	s1 := testServer(t, nil)
   204  	defer s1.Shutdown()
   205  	codec := rpcClient(t, s1)
   206  
   207  	testutil.WaitForResult(func() (bool, error) {
   208  		return s1.evalBroker.Enabled(), nil
   209  	}, func(err error) {
   210  		t.Fatalf("should enable eval broker")
   211  	})
   212  
   213  	// Create the register request
   214  	eval1 := mock.Eval()
   215  	s1.evalBroker.Enqueue(eval1)
   216  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   217  	if err != nil {
   218  		t.Fatalf("err: %v", err)
   219  	}
   220  	if out == nil {
   221  		t.Fatalf("missing eval")
   222  	}
   223  
   224  	// Ack the eval
   225  	get := &structs.EvalAckRequest{
   226  		EvalID:       out.ID,
   227  		Token:        token,
   228  		WriteRequest: structs.WriteRequest{Region: "global"},
   229  	}
   230  	var resp structs.GenericResponse
   231  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Ack", get, &resp); err != nil {
   232  		t.Fatalf("err: %v", err)
   233  	}
   234  
   235  	// Ensure outstanding
   236  	if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok {
   237  		t.Fatalf("should not be outstanding")
   238  	}
   239  }
   240  
   241  func TestEvalEndpoint_Nack(t *testing.T) {
   242  	t.Parallel()
   243  	s1 := testServer(t, func(c *Config) {
   244  		// Disable all of the schedulers so we can manually dequeue
   245  		// evals and check the queue status
   246  		c.NumSchedulers = 0
   247  	})
   248  	defer s1.Shutdown()
   249  	codec := rpcClient(t, s1)
   250  
   251  	testutil.WaitForResult(func() (bool, error) {
   252  		return s1.evalBroker.Enabled(), nil
   253  	}, func(err error) {
   254  		t.Fatalf("should enable eval broker")
   255  	})
   256  
   257  	// Create the register request
   258  	eval1 := mock.Eval()
   259  	s1.evalBroker.Enqueue(eval1)
   260  	out, token, _ := s1.evalBroker.Dequeue(defaultSched, time.Second)
   261  	if out == nil {
   262  		t.Fatalf("missing eval")
   263  	}
   264  
   265  	// Nack the eval
   266  	get := &structs.EvalAckRequest{
   267  		EvalID:       out.ID,
   268  		Token:        token,
   269  		WriteRequest: structs.WriteRequest{Region: "global"},
   270  	}
   271  	var resp structs.GenericResponse
   272  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Nack", get, &resp); err != nil {
   273  		t.Fatalf("err: %v", err)
   274  	}
   275  
   276  	// Ensure outstanding
   277  	if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok {
   278  		t.Fatalf("should not be outstanding")
   279  	}
   280  
   281  	// Should get it back
   282  	testutil.WaitForResult(func() (bool, error) {
   283  		out2, _, _ := s1.evalBroker.Dequeue(defaultSched, time.Second)
   284  		if out2 != out {
   285  			return false, fmt.Errorf("nack failed")
   286  		}
   287  
   288  		return true, nil
   289  	}, func(err error) {
   290  		t.Fatal(err)
   291  	})
   292  }
   293  
   294  func TestEvalEndpoint_Update(t *testing.T) {
   295  	t.Parallel()
   296  	s1 := testServer(t, nil)
   297  	defer s1.Shutdown()
   298  	codec := rpcClient(t, s1)
   299  
   300  	testutil.WaitForResult(func() (bool, error) {
   301  		return s1.evalBroker.Enabled(), nil
   302  	}, func(err error) {
   303  		t.Fatalf("should enable eval broker")
   304  	})
   305  
   306  	// Create the register request
   307  	eval1 := mock.Eval()
   308  	s1.evalBroker.Enqueue(eval1)
   309  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   310  	if err != nil {
   311  		t.Fatalf("err: %v", err)
   312  	}
   313  	if out == nil {
   314  		t.Fatalf("missing eval")
   315  	}
   316  
   317  	// Update the eval
   318  	eval2 := eval1.Copy()
   319  	eval2.Status = structs.EvalStatusComplete
   320  
   321  	get := &structs.EvalUpdateRequest{
   322  		Evals:        []*structs.Evaluation{eval2},
   323  		EvalToken:    token,
   324  		WriteRequest: structs.WriteRequest{Region: "global"},
   325  	}
   326  	var resp structs.GenericResponse
   327  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Update", get, &resp); err != nil {
   328  		t.Fatalf("err: %v", err)
   329  	}
   330  
   331  	// Ensure updated
   332  	ws := memdb.NewWatchSet()
   333  	outE, err := s1.fsm.State().EvalByID(ws, eval2.ID)
   334  	if err != nil {
   335  		t.Fatalf("err: %v", err)
   336  	}
   337  	if outE.Status != structs.EvalStatusComplete {
   338  		t.Fatalf("Bad: %#v", out)
   339  	}
   340  }
   341  
   342  func TestEvalEndpoint_Create(t *testing.T) {
   343  	t.Parallel()
   344  	s1 := testServer(t, func(c *Config) {
   345  		c.NumSchedulers = 0 // Prevent automatic dequeue
   346  	})
   347  	defer s1.Shutdown()
   348  	codec := rpcClient(t, s1)
   349  
   350  	testutil.WaitForResult(func() (bool, error) {
   351  		return s1.evalBroker.Enabled(), nil
   352  	}, func(err error) {
   353  		t.Fatalf("should enable eval broker")
   354  	})
   355  
   356  	// Create the register request
   357  	prev := mock.Eval()
   358  	s1.evalBroker.Enqueue(prev)
   359  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   360  	if err != nil {
   361  		t.Fatalf("err: %v", err)
   362  	}
   363  	if out == nil {
   364  		t.Fatalf("missing eval")
   365  	}
   366  
   367  	// Create the register request
   368  	eval1 := mock.Eval()
   369  	eval1.PreviousEval = prev.ID
   370  	get := &structs.EvalUpdateRequest{
   371  		Evals:        []*structs.Evaluation{eval1},
   372  		EvalToken:    token,
   373  		WriteRequest: structs.WriteRequest{Region: "global"},
   374  	}
   375  	var resp structs.GenericResponse
   376  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Create", get, &resp); err != nil {
   377  		t.Fatalf("err: %v", err)
   378  	}
   379  
   380  	// Ensure created
   381  	ws := memdb.NewWatchSet()
   382  	outE, err := s1.fsm.State().EvalByID(ws, eval1.ID)
   383  	if err != nil {
   384  		t.Fatalf("err: %v", err)
   385  	}
   386  
   387  	eval1.CreateIndex = resp.Index
   388  	eval1.ModifyIndex = resp.Index
   389  	if !reflect.DeepEqual(eval1, outE) {
   390  		t.Fatalf("Bad: %#v %#v", outE, eval1)
   391  	}
   392  }
   393  
   394  func TestEvalEndpoint_Reap(t *testing.T) {
   395  	t.Parallel()
   396  	s1 := testServer(t, nil)
   397  	defer s1.Shutdown()
   398  	codec := rpcClient(t, s1)
   399  	testutil.WaitForLeader(t, s1.RPC)
   400  
   401  	// Create the register request
   402  	eval1 := mock.Eval()
   403  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1})
   404  
   405  	// Reap the eval
   406  	get := &structs.EvalDeleteRequest{
   407  		Evals:        []string{eval1.ID},
   408  		WriteRequest: structs.WriteRequest{Region: "global"},
   409  	}
   410  	var resp structs.GenericResponse
   411  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Reap", get, &resp); err != nil {
   412  		t.Fatalf("err: %v", err)
   413  	}
   414  	if resp.Index == 0 {
   415  		t.Fatalf("Bad index: %d", resp.Index)
   416  	}
   417  
   418  	// Ensure deleted
   419  	ws := memdb.NewWatchSet()
   420  	outE, err := s1.fsm.State().EvalByID(ws, eval1.ID)
   421  	if err != nil {
   422  		t.Fatalf("err: %v", err)
   423  	}
   424  	if outE != nil {
   425  		t.Fatalf("Bad: %#v", outE)
   426  	}
   427  }
   428  
   429  func TestEvalEndpoint_List(t *testing.T) {
   430  	t.Parallel()
   431  	s1 := testServer(t, nil)
   432  	defer s1.Shutdown()
   433  	codec := rpcClient(t, s1)
   434  	testutil.WaitForLeader(t, s1.RPC)
   435  
   436  	// Create the register request
   437  	eval1 := mock.Eval()
   438  	eval1.ID = "aaaaaaaa-3350-4b4b-d185-0e1992ed43e9"
   439  	eval2 := mock.Eval()
   440  	eval2.ID = "aaaabbbb-3350-4b4b-d185-0e1992ed43e9"
   441  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1, eval2})
   442  
   443  	// Lookup the eval
   444  	get := &structs.EvalListRequest{
   445  		QueryOptions: structs.QueryOptions{Region: "global"},
   446  	}
   447  	var resp structs.EvalListResponse
   448  	if err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp); err != nil {
   449  		t.Fatalf("err: %v", err)
   450  	}
   451  	if resp.Index != 1000 {
   452  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   453  	}
   454  
   455  	if len(resp.Evaluations) != 2 {
   456  		t.Fatalf("bad: %#v", resp.Evaluations)
   457  	}
   458  
   459  	// Lookup the eval by prefix
   460  	get = &structs.EvalListRequest{
   461  		QueryOptions: structs.QueryOptions{Region: "global", Prefix: "aaaabb"},
   462  	}
   463  	var resp2 structs.EvalListResponse
   464  	if err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp2); err != nil {
   465  		t.Fatalf("err: %v", err)
   466  	}
   467  	if resp2.Index != 1000 {
   468  		t.Fatalf("Bad index: %d %d", resp2.Index, 1000)
   469  	}
   470  
   471  	if len(resp2.Evaluations) != 1 {
   472  		t.Fatalf("bad: %#v", resp2.Evaluations)
   473  	}
   474  
   475  }
   476  
   477  func TestEvalEndpoint_List_Blocking(t *testing.T) {
   478  	t.Parallel()
   479  	s1 := testServer(t, nil)
   480  	defer s1.Shutdown()
   481  	state := s1.fsm.State()
   482  	codec := rpcClient(t, s1)
   483  	testutil.WaitForLeader(t, s1.RPC)
   484  
   485  	// Create the ieval
   486  	eval := mock.Eval()
   487  
   488  	// Upsert eval triggers watches
   489  	time.AfterFunc(100*time.Millisecond, func() {
   490  		if err := state.UpsertEvals(2, []*structs.Evaluation{eval}); err != nil {
   491  			t.Fatalf("err: %v", err)
   492  		}
   493  	})
   494  
   495  	req := &structs.EvalListRequest{
   496  		QueryOptions: structs.QueryOptions{
   497  			Region:        "global",
   498  			MinQueryIndex: 1,
   499  		},
   500  	}
   501  	start := time.Now()
   502  	var resp structs.EvalListResponse
   503  	if err := msgpackrpc.CallWithCodec(codec, "Eval.List", req, &resp); err != nil {
   504  		t.Fatalf("err: %v", err)
   505  	}
   506  
   507  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   508  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   509  	}
   510  	if resp.Index != 2 {
   511  		t.Fatalf("Bad index: %d %d", resp.Index, 2)
   512  	}
   513  	if len(resp.Evaluations) != 1 || resp.Evaluations[0].ID != eval.ID {
   514  		t.Fatalf("bad: %#v", resp.Evaluations)
   515  	}
   516  
   517  	// Eval deletion triggers watches
   518  	time.AfterFunc(100*time.Millisecond, func() {
   519  		if err := state.DeleteEval(3, []string{eval.ID}, nil); err != nil {
   520  			t.Fatalf("err: %v", err)
   521  		}
   522  	})
   523  
   524  	req.MinQueryIndex = 2
   525  	start = time.Now()
   526  	var resp2 structs.EvalListResponse
   527  	if err := msgpackrpc.CallWithCodec(codec, "Eval.List", req, &resp2); err != nil {
   528  		t.Fatalf("err: %v", err)
   529  	}
   530  
   531  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   532  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   533  	}
   534  	if resp2.Index != 3 {
   535  		t.Fatalf("Bad index: %d %d", resp2.Index, 3)
   536  	}
   537  	if len(resp2.Evaluations) != 0 {
   538  		t.Fatalf("bad: %#v", resp2.Evaluations)
   539  	}
   540  }
   541  
   542  func TestEvalEndpoint_Allocations(t *testing.T) {
   543  	t.Parallel()
   544  	s1 := testServer(t, nil)
   545  	defer s1.Shutdown()
   546  	codec := rpcClient(t, s1)
   547  	testutil.WaitForLeader(t, s1.RPC)
   548  
   549  	// Create the register request
   550  	alloc1 := mock.Alloc()
   551  	alloc2 := mock.Alloc()
   552  	alloc2.EvalID = alloc1.EvalID
   553  	state := s1.fsm.State()
   554  	state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID))
   555  	state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
   556  	err := state.UpsertAllocs(1000,
   557  		[]*structs.Allocation{alloc1, alloc2})
   558  	if err != nil {
   559  		t.Fatalf("err: %v", err)
   560  	}
   561  
   562  	// Lookup the eval
   563  	get := &structs.EvalSpecificRequest{
   564  		EvalID:       alloc1.EvalID,
   565  		QueryOptions: structs.QueryOptions{Region: "global"},
   566  	}
   567  	var resp structs.EvalAllocationsResponse
   568  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil {
   569  		t.Fatalf("err: %v", err)
   570  	}
   571  	if resp.Index != 1000 {
   572  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   573  	}
   574  
   575  	if len(resp.Allocations) != 2 {
   576  		t.Fatalf("bad: %#v", resp.Allocations)
   577  	}
   578  }
   579  
   580  func TestEvalEndpoint_Allocations_Blocking(t *testing.T) {
   581  	t.Parallel()
   582  	s1 := testServer(t, nil)
   583  	defer s1.Shutdown()
   584  	state := s1.fsm.State()
   585  	codec := rpcClient(t, s1)
   586  	testutil.WaitForLeader(t, s1.RPC)
   587  
   588  	// Create the allocs
   589  	alloc1 := mock.Alloc()
   590  	alloc2 := mock.Alloc()
   591  
   592  	// Upsert an unrelated alloc first
   593  	time.AfterFunc(100*time.Millisecond, func() {
   594  		state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID))
   595  		err := state.UpsertAllocs(100, []*structs.Allocation{alloc1})
   596  		if err != nil {
   597  			t.Fatalf("err: %v", err)
   598  		}
   599  	})
   600  
   601  	// Upsert an alloc which will trigger the watch later
   602  	time.AfterFunc(200*time.Millisecond, func() {
   603  		state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID))
   604  		err := state.UpsertAllocs(200, []*structs.Allocation{alloc2})
   605  		if err != nil {
   606  			t.Fatalf("err: %v", err)
   607  		}
   608  	})
   609  
   610  	// Lookup the eval
   611  	get := &structs.EvalSpecificRequest{
   612  		EvalID: alloc2.EvalID,
   613  		QueryOptions: structs.QueryOptions{
   614  			Region:        "global",
   615  			MinQueryIndex: 150,
   616  		},
   617  	}
   618  	var resp structs.EvalAllocationsResponse
   619  	start := time.Now()
   620  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil {
   621  		t.Fatalf("err: %v", err)
   622  	}
   623  
   624  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   625  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   626  	}
   627  	if resp.Index != 200 {
   628  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
   629  	}
   630  	if len(resp.Allocations) != 1 || resp.Allocations[0].ID != alloc2.ID {
   631  		t.Fatalf("bad: %#v", resp.Allocations)
   632  	}
   633  }
   634  
   635  func TestEvalEndpoint_Reblock_NonExistent(t *testing.T) {
   636  	t.Parallel()
   637  	s1 := testServer(t, func(c *Config) {
   638  		c.NumSchedulers = 0 // Prevent automatic dequeue
   639  	})
   640  	defer s1.Shutdown()
   641  	codec := rpcClient(t, s1)
   642  
   643  	testutil.WaitForResult(func() (bool, error) {
   644  		return s1.evalBroker.Enabled(), nil
   645  	}, func(err error) {
   646  		t.Fatalf("should enable eval broker")
   647  	})
   648  
   649  	// Create the register request
   650  	eval1 := mock.Eval()
   651  	s1.evalBroker.Enqueue(eval1)
   652  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   653  	if err != nil {
   654  		t.Fatalf("err: %v", err)
   655  	}
   656  	if out == nil {
   657  		t.Fatalf("missing eval")
   658  	}
   659  
   660  	get := &structs.EvalUpdateRequest{
   661  		Evals:        []*structs.Evaluation{eval1},
   662  		EvalToken:    token,
   663  		WriteRequest: structs.WriteRequest{Region: "global"},
   664  	}
   665  	var resp structs.GenericResponse
   666  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Reblock", get, &resp); err == nil {
   667  		t.Fatalf("expect error since eval does not exist")
   668  	}
   669  }
   670  
   671  func TestEvalEndpoint_Reblock_NonBlocked(t *testing.T) {
   672  	t.Parallel()
   673  	s1 := testServer(t, func(c *Config) {
   674  		c.NumSchedulers = 0 // Prevent automatic dequeue
   675  	})
   676  	defer s1.Shutdown()
   677  	codec := rpcClient(t, s1)
   678  
   679  	testutil.WaitForResult(func() (bool, error) {
   680  		return s1.evalBroker.Enabled(), nil
   681  	}, func(err error) {
   682  		t.Fatalf("should enable eval broker")
   683  	})
   684  
   685  	// Create the eval
   686  	eval1 := mock.Eval()
   687  	s1.evalBroker.Enqueue(eval1)
   688  
   689  	// Insert it into the state store
   690  	if err := s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}); err != nil {
   691  		t.Fatal(err)
   692  	}
   693  
   694  	out, token, err := s1.evalBroker.Dequeue(defaultSched, 2*time.Second)
   695  	if err != nil {
   696  		t.Fatalf("err: %v", err)
   697  	}
   698  	if out == nil {
   699  		t.Fatalf("missing eval")
   700  	}
   701  
   702  	get := &structs.EvalUpdateRequest{
   703  		Evals:        []*structs.Evaluation{eval1},
   704  		EvalToken:    token,
   705  		WriteRequest: structs.WriteRequest{Region: "global"},
   706  	}
   707  	var resp structs.GenericResponse
   708  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Reblock", get, &resp); err == nil {
   709  		t.Fatalf("should error since eval was not in blocked state: %v", err)
   710  	}
   711  }
   712  
   713  func TestEvalEndpoint_Reblock(t *testing.T) {
   714  	t.Parallel()
   715  	s1 := testServer(t, func(c *Config) {
   716  		c.NumSchedulers = 0 // Prevent automatic dequeue
   717  	})
   718  	defer s1.Shutdown()
   719  	codec := rpcClient(t, s1)
   720  
   721  	testutil.WaitForResult(func() (bool, error) {
   722  		return s1.evalBroker.Enabled(), nil
   723  	}, func(err error) {
   724  		t.Fatalf("should enable eval broker")
   725  	})
   726  
   727  	// Create the eval
   728  	eval1 := mock.Eval()
   729  	eval1.Status = structs.EvalStatusBlocked
   730  	s1.evalBroker.Enqueue(eval1)
   731  
   732  	// Insert it into the state store
   733  	if err := s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}); err != nil {
   734  		t.Fatal(err)
   735  	}
   736  
   737  	out, token, err := s1.evalBroker.Dequeue(defaultSched, 7*time.Second)
   738  	if err != nil {
   739  		t.Fatalf("err: %v", err)
   740  	}
   741  	if out == nil {
   742  		t.Fatalf("bad: %v", out)
   743  	}
   744  
   745  	get := &structs.EvalUpdateRequest{
   746  		Evals:        []*structs.Evaluation{eval1},
   747  		EvalToken:    token,
   748  		WriteRequest: structs.WriteRequest{Region: "global"},
   749  	}
   750  	var resp structs.GenericResponse
   751  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Reblock", get, &resp); err != nil {
   752  		t.Fatalf("err: %v", err)
   753  	}
   754  
   755  	// Check that it is blocked
   756  	bStats := s1.blockedEvals.Stats()
   757  	if bStats.TotalBlocked+bStats.TotalEscaped == 0 {
   758  		t.Fatalf("ReblockEval didn't insert eval into the blocked eval tracker")
   759  	}
   760  }