github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/nomad/eval_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/hashicorp/net-rpc-msgpackrpc"
     9  	"github.com/hashicorp/nomad/nomad/mock"
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  	"github.com/hashicorp/nomad/testutil"
    12  )
    13  
    14  func TestEvalEndpoint_GetEval(t *testing.T) {
    15  	s1 := testServer(t, nil)
    16  	defer s1.Shutdown()
    17  	codec := rpcClient(t, s1)
    18  	testutil.WaitForLeader(t, s1.RPC)
    19  
    20  	// Create the register request
    21  	eval1 := mock.Eval()
    22  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1})
    23  
    24  	// Lookup the eval
    25  	get := &structs.EvalSpecificRequest{
    26  		EvalID:       eval1.ID,
    27  		QueryOptions: structs.QueryOptions{Region: "global"},
    28  	}
    29  	var resp structs.SingleEvalResponse
    30  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil {
    31  		t.Fatalf("err: %v", err)
    32  	}
    33  	if resp.Index != 1000 {
    34  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
    35  	}
    36  
    37  	if !reflect.DeepEqual(eval1, resp.Eval) {
    38  		t.Fatalf("bad: %#v %#v", eval1, resp.Eval)
    39  	}
    40  
    41  	// Lookup non-existing node
    42  	get.EvalID = structs.GenerateUUID()
    43  	if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil {
    44  		t.Fatalf("err: %v", err)
    45  	}
    46  	if resp.Index != 1000 {
    47  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
    48  	}
    49  	if resp.Eval != nil {
    50  		t.Fatalf("unexpected eval")
    51  	}
    52  }
    53  
    54  func TestEvalEndpoint_Dequeue(t *testing.T) {
    55  	s1 := testServer(t, func(c *Config) {
    56  		c.NumSchedulers = 0 // Prevent automatic dequeue
    57  	})
    58  	defer s1.Shutdown()
    59  	codec := rpcClient(t, s1)
    60  	testutil.WaitForLeader(t, s1.RPC)
    61  
    62  	// Create the register request
    63  	eval1 := mock.Eval()
    64  	testutil.WaitForResult(func() (bool, error) {
    65  		err := s1.evalBroker.Enqueue(eval1)
    66  		return err == nil, err
    67  	}, func(err error) {
    68  		t.Fatalf("err: %v", err)
    69  	})
    70  
    71  	// Dequeue the eval
    72  	get := &structs.EvalDequeueRequest{
    73  		Schedulers:   defaultSched,
    74  		WriteRequest: structs.WriteRequest{Region: "global"},
    75  	}
    76  	var resp structs.EvalDequeueResponse
    77  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp); err != nil {
    78  		t.Fatalf("err: %v", err)
    79  	}
    80  
    81  	if !reflect.DeepEqual(eval1, resp.Eval) {
    82  		t.Fatalf("bad: %v %v", eval1, resp.Eval)
    83  	}
    84  
    85  	// Ensure outstanding
    86  	token, ok := s1.evalBroker.Outstanding(eval1.ID)
    87  	if !ok {
    88  		t.Fatalf("should be outstanding")
    89  	}
    90  	if token != resp.Token {
    91  		t.Fatalf("bad token: %#v %#v", token, resp.Token)
    92  	}
    93  }
    94  
    95  func TestEvalEndpoint_Ack(t *testing.T) {
    96  	s1 := testServer(t, nil)
    97  	defer s1.Shutdown()
    98  	codec := rpcClient(t, s1)
    99  
   100  	testutil.WaitForResult(func() (bool, error) {
   101  		return s1.evalBroker.Enabled(), nil
   102  	}, func(err error) {
   103  		t.Fatalf("should enable eval broker")
   104  	})
   105  
   106  	// Create the register request
   107  	eval1 := mock.Eval()
   108  	s1.evalBroker.Enqueue(eval1)
   109  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   110  	if err != nil {
   111  		t.Fatalf("err: %v", err)
   112  	}
   113  	if out == nil {
   114  		t.Fatalf("missing eval")
   115  	}
   116  
   117  	// Ack the eval
   118  	get := &structs.EvalAckRequest{
   119  		EvalID:       out.ID,
   120  		Token:        token,
   121  		WriteRequest: structs.WriteRequest{Region: "global"},
   122  	}
   123  	var resp structs.GenericResponse
   124  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Ack", get, &resp); err != nil {
   125  		t.Fatalf("err: %v", err)
   126  	}
   127  
   128  	// Ensure outstanding
   129  	if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok {
   130  		t.Fatalf("should not be outstanding")
   131  	}
   132  }
   133  
   134  func TestEvalEndpoint_Nack(t *testing.T) {
   135  	s1 := testServer(t, func(c *Config) {
   136  		// Disable all of the schedulers so we can manually dequeue
   137  		// evals and check the queue status
   138  		c.NumSchedulers = 0
   139  	})
   140  	defer s1.Shutdown()
   141  	codec := rpcClient(t, s1)
   142  
   143  	testutil.WaitForResult(func() (bool, error) {
   144  		return s1.evalBroker.Enabled(), nil
   145  	}, func(err error) {
   146  		t.Fatalf("should enable eval broker")
   147  	})
   148  
   149  	// Create the register request
   150  	eval1 := mock.Eval()
   151  	s1.evalBroker.Enqueue(eval1)
   152  	out, token, _ := s1.evalBroker.Dequeue(defaultSched, time.Second)
   153  	if out == nil {
   154  		t.Fatalf("missing eval")
   155  	}
   156  
   157  	// Nack the eval
   158  	get := &structs.EvalAckRequest{
   159  		EvalID:       out.ID,
   160  		Token:        token,
   161  		WriteRequest: structs.WriteRequest{Region: "global"},
   162  	}
   163  	var resp structs.GenericResponse
   164  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Nack", get, &resp); err != nil {
   165  		t.Fatalf("err: %v", err)
   166  	}
   167  
   168  	// Ensure outstanding
   169  	if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok {
   170  		t.Fatalf("should not be outstanding")
   171  	}
   172  
   173  	// Should get it back
   174  	out2, _, _ := s1.evalBroker.Dequeue(defaultSched, time.Second)
   175  	if out2 != out {
   176  		t.Fatalf("nack failed")
   177  	}
   178  }
   179  
   180  func TestEvalEndpoint_Update(t *testing.T) {
   181  	s1 := testServer(t, nil)
   182  	defer s1.Shutdown()
   183  	codec := rpcClient(t, s1)
   184  
   185  	testutil.WaitForResult(func() (bool, error) {
   186  		return s1.evalBroker.Enabled(), nil
   187  	}, func(err error) {
   188  		t.Fatalf("should enable eval broker")
   189  	})
   190  
   191  	// Create the register request
   192  	eval1 := mock.Eval()
   193  	s1.evalBroker.Enqueue(eval1)
   194  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   195  	if err != nil {
   196  		t.Fatalf("err: %v", err)
   197  	}
   198  	if out == nil {
   199  		t.Fatalf("missing eval")
   200  	}
   201  
   202  	// Update the eval
   203  	eval2 := eval1.Copy()
   204  	eval2.Status = structs.EvalStatusComplete
   205  
   206  	get := &structs.EvalUpdateRequest{
   207  		Evals:        []*structs.Evaluation{eval2},
   208  		EvalToken:    token,
   209  		WriteRequest: structs.WriteRequest{Region: "global"},
   210  	}
   211  	var resp structs.GenericResponse
   212  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Update", get, &resp); err != nil {
   213  		t.Fatalf("err: %v", err)
   214  	}
   215  
   216  	// Ensure updated
   217  	outE, err := s1.fsm.State().EvalByID(eval2.ID)
   218  	if err != nil {
   219  		t.Fatalf("err: %v", err)
   220  	}
   221  	if outE.Status != structs.EvalStatusComplete {
   222  		t.Fatalf("Bad: %#v", out)
   223  	}
   224  }
   225  
   226  func TestEvalEndpoint_Create(t *testing.T) {
   227  	s1 := testServer(t, func(c *Config) {
   228  		c.NumSchedulers = 0 // Prevent automatic dequeue
   229  	})
   230  	defer s1.Shutdown()
   231  	codec := rpcClient(t, s1)
   232  
   233  	testutil.WaitForResult(func() (bool, error) {
   234  		return s1.evalBroker.Enabled(), nil
   235  	}, func(err error) {
   236  		t.Fatalf("should enable eval broker")
   237  	})
   238  
   239  	// Create the register request
   240  	prev := mock.Eval()
   241  	s1.evalBroker.Enqueue(prev)
   242  	out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
   243  	if err != nil {
   244  		t.Fatalf("err: %v", err)
   245  	}
   246  	if out == nil {
   247  		t.Fatalf("missing eval")
   248  	}
   249  
   250  	// Create the register request
   251  	eval1 := mock.Eval()
   252  	eval1.PreviousEval = prev.ID
   253  	get := &structs.EvalUpdateRequest{
   254  		Evals:        []*structs.Evaluation{eval1},
   255  		EvalToken:    token,
   256  		WriteRequest: structs.WriteRequest{Region: "global"},
   257  	}
   258  	var resp structs.GenericResponse
   259  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Create", get, &resp); err != nil {
   260  		t.Fatalf("err: %v", err)
   261  	}
   262  
   263  	// Ensure created
   264  	outE, err := s1.fsm.State().EvalByID(eval1.ID)
   265  	if err != nil {
   266  		t.Fatalf("err: %v", err)
   267  	}
   268  
   269  	eval1.CreateIndex = resp.Index
   270  	eval1.ModifyIndex = resp.Index
   271  	if !reflect.DeepEqual(eval1, outE) {
   272  		t.Fatalf("Bad: %#v %#v", outE, eval1)
   273  	}
   274  }
   275  
   276  func TestEvalEndpoint_Reap(t *testing.T) {
   277  	s1 := testServer(t, nil)
   278  	defer s1.Shutdown()
   279  	codec := rpcClient(t, s1)
   280  	testutil.WaitForLeader(t, s1.RPC)
   281  
   282  	// Create the register request
   283  	eval1 := mock.Eval()
   284  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1})
   285  
   286  	// Reap the eval
   287  	get := &structs.EvalDeleteRequest{
   288  		Evals:        []string{eval1.ID},
   289  		WriteRequest: structs.WriteRequest{Region: "global"},
   290  	}
   291  	var resp structs.GenericResponse
   292  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Reap", get, &resp); err != nil {
   293  		t.Fatalf("err: %v", err)
   294  	}
   295  	if resp.Index == 0 {
   296  		t.Fatalf("Bad index: %d", resp.Index)
   297  	}
   298  
   299  	// Ensure deleted
   300  	outE, err := s1.fsm.State().EvalByID(eval1.ID)
   301  	if err != nil {
   302  		t.Fatalf("err: %v", err)
   303  	}
   304  	if outE != nil {
   305  		t.Fatalf("Bad: %#v", outE)
   306  	}
   307  }
   308  
   309  func TestEvalEndpoint_List(t *testing.T) {
   310  	s1 := testServer(t, nil)
   311  	defer s1.Shutdown()
   312  	codec := rpcClient(t, s1)
   313  	testutil.WaitForLeader(t, s1.RPC)
   314  
   315  	// Create the register request
   316  	eval1 := mock.Eval()
   317  	eval2 := mock.Eval()
   318  	s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1, eval2})
   319  
   320  	// Lookup the eval
   321  	get := &structs.EvalListRequest{
   322  		QueryOptions: structs.QueryOptions{Region: "global"},
   323  	}
   324  	var resp structs.EvalListResponse
   325  	if err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp); err != nil {
   326  		t.Fatalf("err: %v", err)
   327  	}
   328  	if resp.Index != 1000 {
   329  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   330  	}
   331  
   332  	if len(resp.Evaluations) != 2 {
   333  		t.Fatalf("bad: %#v", resp.Evaluations)
   334  	}
   335  }
   336  
   337  func TestEvalEndpoint_Allocations(t *testing.T) {
   338  	s1 := testServer(t, nil)
   339  	defer s1.Shutdown()
   340  	codec := rpcClient(t, s1)
   341  	testutil.WaitForLeader(t, s1.RPC)
   342  
   343  	// Create the register request
   344  	alloc1 := mock.Alloc()
   345  	alloc2 := mock.Alloc()
   346  	alloc2.EvalID = alloc1.EvalID
   347  	state := s1.fsm.State()
   348  	err := state.UpsertAllocs(1000,
   349  		[]*structs.Allocation{alloc1, alloc2})
   350  	if err != nil {
   351  		t.Fatalf("err: %v", err)
   352  	}
   353  
   354  	// Lookup the eval
   355  	get := &structs.EvalSpecificRequest{
   356  		EvalID:       alloc1.EvalID,
   357  		QueryOptions: structs.QueryOptions{Region: "global"},
   358  	}
   359  	var resp structs.EvalAllocationsResponse
   360  	if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil {
   361  		t.Fatalf("err: %v", err)
   362  	}
   363  	if resp.Index != 1000 {
   364  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   365  	}
   366  
   367  	if len(resp.Allocations) != 2 {
   368  		t.Fatalf("bad: %#v", resp.Allocations)
   369  	}
   370  }