2015-07-23 23:00:19 +00:00
|
|
|
package nomad
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
2015-07-24 05:11:25 +00:00
|
|
|
"time"
|
2015-07-23 23:00:19 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/net-rpc-msgpackrpc"
|
2015-08-11 21:27:14 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
2015-07-23 23:00:19 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
"github.com/hashicorp/nomad/testutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestEvalEndpoint_GetEval(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
2015-08-11 21:27:14 +00:00
|
|
|
eval1 := mock.Eval()
|
2015-08-06 21:51:15 +00:00
|
|
|
s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1})
|
2015-07-23 23:00:19 +00:00
|
|
|
|
|
|
|
// Lookup the eval
|
|
|
|
get := &structs.EvalSpecificRequest{
|
|
|
|
EvalID: eval1.ID,
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-07-23 23:00:19 +00:00
|
|
|
}
|
|
|
|
var resp structs.SingleEvalResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index != 1000 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp.Index, 1000)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(eval1, resp.Eval) {
|
|
|
|
t.Fatalf("bad: %#v %#v", eval1, resp.Eval)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup non-existing node
|
2015-09-07 22:23:03 +00:00
|
|
|
get.EvalID = structs.GenerateUUID()
|
2015-07-23 23:00:19 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.GetEval", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index != 1000 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp.Index, 1000)
|
|
|
|
}
|
|
|
|
if resp.Eval != nil {
|
|
|
|
t.Fatalf("unexpected eval")
|
|
|
|
}
|
|
|
|
}
|
2015-07-24 04:58:51 +00:00
|
|
|
|
|
|
|
func TestEvalEndpoint_Dequeue(t *testing.T) {
|
2015-07-28 22:12:08 +00:00
|
|
|
s1 := testServer(t, func(c *Config) {
|
|
|
|
c.NumSchedulers = 0 // Prevent automatic dequeue
|
|
|
|
})
|
2015-07-24 04:58:51 +00:00
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
2015-08-11 21:27:14 +00:00
|
|
|
eval1 := mock.Eval()
|
2015-08-17 00:43:30 +00:00
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
err := s1.evalBroker.Enqueue(eval1)
|
|
|
|
return err == nil, err
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
})
|
2015-07-24 04:58:51 +00:00
|
|
|
|
|
|
|
// Dequeue the eval
|
|
|
|
get := &structs.EvalDequeueRequest{
|
|
|
|
Schedulers: defaultSched,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-24 04:58:51 +00:00
|
|
|
}
|
2015-08-12 22:25:31 +00:00
|
|
|
var resp structs.EvalDequeueResponse
|
2015-07-24 04:58:51 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.Dequeue", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(eval1, resp.Eval) {
|
2015-08-15 23:08:12 +00:00
|
|
|
t.Fatalf("bad: %v %v", eval1, resp.Eval)
|
2015-07-24 04:58:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure outstanding
|
2015-08-12 22:25:31 +00:00
|
|
|
token, ok := s1.evalBroker.Outstanding(eval1.ID)
|
|
|
|
if !ok {
|
2015-07-24 04:58:51 +00:00
|
|
|
t.Fatalf("should be outstanding")
|
|
|
|
}
|
2015-08-12 22:25:31 +00:00
|
|
|
if token != resp.Token {
|
|
|
|
t.Fatalf("bad token: %#v %#v", token, resp.Token)
|
|
|
|
}
|
2015-07-24 04:58:51 +00:00
|
|
|
}
|
2015-07-24 05:11:25 +00:00
|
|
|
|
|
|
|
func TestEvalEndpoint_Ack(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
2015-08-05 23:46:07 +00:00
|
|
|
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
return s1.evalBroker.Enabled(), nil
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("should enable eval broker")
|
|
|
|
})
|
2015-07-24 05:11:25 +00:00
|
|
|
|
|
|
|
// Create the register request
|
2015-08-11 21:27:14 +00:00
|
|
|
eval1 := mock.Eval()
|
2015-07-24 05:11:25 +00:00
|
|
|
s1.evalBroker.Enqueue(eval1)
|
2015-08-12 22:25:31 +00:00
|
|
|
out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
|
2015-08-05 00:13:32 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-07-24 05:11:25 +00:00
|
|
|
if out == nil {
|
|
|
|
t.Fatalf("missing eval")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ack the eval
|
2015-08-12 22:25:31 +00:00
|
|
|
get := &structs.EvalAckRequest{
|
2015-07-24 05:11:25 +00:00
|
|
|
EvalID: out.ID,
|
2015-08-12 22:25:31 +00:00
|
|
|
Token: token,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-24 05:11:25 +00:00
|
|
|
}
|
|
|
|
var resp structs.GenericResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.Ack", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure outstanding
|
2015-08-12 22:25:31 +00:00
|
|
|
if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok {
|
2015-07-24 05:11:25 +00:00
|
|
|
t.Fatalf("should not be outstanding")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEvalEndpoint_Nack(t *testing.T) {
|
2015-09-25 23:07:27 +00:00
|
|
|
s1 := testServer(t, func(c *Config) {
|
|
|
|
// Disable all of the schedulers so we can manually dequeue
|
|
|
|
// evals and check the queue status
|
|
|
|
c.NumSchedulers = 0
|
|
|
|
})
|
2015-07-24 05:11:25 +00:00
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
2015-08-05 23:46:07 +00:00
|
|
|
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
return s1.evalBroker.Enabled(), nil
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("should enable eval broker")
|
|
|
|
})
|
2015-07-24 05:11:25 +00:00
|
|
|
|
|
|
|
// Create the register request
|
2015-08-11 21:27:14 +00:00
|
|
|
eval1 := mock.Eval()
|
2015-07-24 05:11:25 +00:00
|
|
|
s1.evalBroker.Enqueue(eval1)
|
2015-08-12 22:25:31 +00:00
|
|
|
out, token, _ := s1.evalBroker.Dequeue(defaultSched, time.Second)
|
2015-07-24 05:11:25 +00:00
|
|
|
if out == nil {
|
|
|
|
t.Fatalf("missing eval")
|
|
|
|
}
|
|
|
|
|
2015-08-12 22:25:31 +00:00
|
|
|
// Nack the eval
|
|
|
|
get := &structs.EvalAckRequest{
|
2015-07-24 05:11:25 +00:00
|
|
|
EvalID: out.ID,
|
2015-08-12 22:25:31 +00:00
|
|
|
Token: token,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-24 05:11:25 +00:00
|
|
|
}
|
|
|
|
var resp structs.GenericResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.Nack", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure outstanding
|
2015-08-12 22:25:31 +00:00
|
|
|
if _, ok := s1.evalBroker.Outstanding(eval1.ID); ok {
|
2015-07-24 05:11:25 +00:00
|
|
|
t.Fatalf("should not be outstanding")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Should get it back
|
2015-08-12 22:25:31 +00:00
|
|
|
out2, _, _ := s1.evalBroker.Dequeue(defaultSched, time.Second)
|
2015-07-24 05:11:25 +00:00
|
|
|
if out2 != out {
|
|
|
|
t.Fatalf("nack failed")
|
|
|
|
}
|
|
|
|
}
|
2015-08-15 21:16:40 +00:00
|
|
|
|
|
|
|
func TestEvalEndpoint_Update(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
|
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
return s1.evalBroker.Enabled(), nil
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("should enable eval broker")
|
|
|
|
})
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
eval1 := mock.Eval()
|
|
|
|
s1.evalBroker.Enqueue(eval1)
|
|
|
|
out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if out == nil {
|
|
|
|
t.Fatalf("missing eval")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the eval
|
|
|
|
eval2 := eval1.Copy()
|
|
|
|
eval2.Status = structs.EvalStatusComplete
|
|
|
|
|
|
|
|
get := &structs.EvalUpdateRequest{
|
|
|
|
Evals: []*structs.Evaluation{eval2},
|
2015-08-15 21:22:21 +00:00
|
|
|
EvalToken: token,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-15 21:16:40 +00:00
|
|
|
}
|
|
|
|
var resp structs.GenericResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.Update", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure updated
|
2015-09-07 03:56:38 +00:00
|
|
|
outE, err := s1.fsm.State().EvalByID(eval2.ID)
|
2015-08-15 21:16:40 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if outE.Status != structs.EvalStatusComplete {
|
|
|
|
t.Fatalf("Bad: %#v", out)
|
|
|
|
}
|
|
|
|
}
|
2015-08-15 22:42:44 +00:00
|
|
|
|
2015-09-07 21:17:11 +00:00
|
|
|
func TestEvalEndpoint_Create(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
|
2015-09-07 21:21:38 +00:00
|
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
|
|
return s1.evalBroker.Enabled(), nil
|
|
|
|
}, func(err error) {
|
|
|
|
t.Fatalf("should enable eval broker")
|
|
|
|
})
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
prev := mock.Eval()
|
|
|
|
s1.evalBroker.Enqueue(prev)
|
|
|
|
out, token, err := s1.evalBroker.Dequeue(defaultSched, time.Second)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if out == nil {
|
|
|
|
t.Fatalf("missing eval")
|
|
|
|
}
|
|
|
|
|
2015-09-07 21:17:11 +00:00
|
|
|
// Create the register request
|
|
|
|
eval1 := mock.Eval()
|
2015-09-07 21:21:38 +00:00
|
|
|
eval1.PreviousEval = prev.ID
|
2015-09-07 21:17:11 +00:00
|
|
|
get := &structs.EvalUpdateRequest{
|
|
|
|
Evals: []*structs.Evaluation{eval1},
|
2015-09-07 21:21:38 +00:00
|
|
|
EvalToken: token,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-09-07 21:17:11 +00:00
|
|
|
}
|
|
|
|
var resp structs.GenericResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.Create", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure created
|
|
|
|
outE, err := s1.fsm.State().EvalByID(eval1.ID)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
eval1.CreateIndex = resp.Index
|
|
|
|
eval1.ModifyIndex = resp.Index
|
|
|
|
if !reflect.DeepEqual(eval1, outE) {
|
|
|
|
t.Fatalf("Bad: %#v %#v", outE, eval1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-15 22:42:44 +00:00
|
|
|
func TestEvalEndpoint_Reap(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
eval1 := mock.Eval()
|
|
|
|
s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1})
|
|
|
|
|
|
|
|
// Reap the eval
|
|
|
|
get := &structs.EvalDeleteRequest{
|
|
|
|
Evals: []string{eval1.ID},
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-15 22:42:44 +00:00
|
|
|
}
|
|
|
|
var resp structs.GenericResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.Reap", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index == 0 {
|
|
|
|
t.Fatalf("Bad index: %d", resp.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure deleted
|
2015-09-07 03:56:38 +00:00
|
|
|
outE, err := s1.fsm.State().EvalByID(eval1.ID)
|
2015-08-15 22:42:44 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if outE != nil {
|
|
|
|
t.Fatalf("Bad: %#v", outE)
|
|
|
|
}
|
|
|
|
}
|
2015-09-06 23:01:16 +00:00
|
|
|
|
|
|
|
func TestEvalEndpoint_List(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
eval1 := mock.Eval()
|
|
|
|
eval2 := mock.Eval()
|
|
|
|
s1.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1, eval2})
|
|
|
|
|
|
|
|
// Lookup the eval
|
|
|
|
get := &structs.EvalListRequest{
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-09-06 23:01:16 +00:00
|
|
|
}
|
|
|
|
var resp structs.EvalListResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.List", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index != 1000 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp.Index, 1000)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp.Evaluations) != 2 {
|
|
|
|
t.Fatalf("bad: %#v", resp.Evaluations)
|
|
|
|
}
|
|
|
|
}
|
2015-09-06 23:14:41 +00:00
|
|
|
|
|
|
|
func TestEvalEndpoint_Allocations(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
alloc1 := mock.Alloc()
|
|
|
|
alloc2 := mock.Alloc()
|
|
|
|
alloc2.EvalID = alloc1.EvalID
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:47:42 +00:00
|
|
|
err := state.UpsertAllocs(1000,
|
2015-09-06 23:14:41 +00:00
|
|
|
[]*structs.Allocation{alloc1, alloc2})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the eval
|
|
|
|
get := &structs.EvalSpecificRequest{
|
|
|
|
EvalID: alloc1.EvalID,
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-09-06 23:14:41 +00:00
|
|
|
}
|
|
|
|
var resp structs.EvalAllocationsResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index != 1000 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp.Index, 1000)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp.Allocations) != 2 {
|
|
|
|
t.Fatalf("bad: %#v", resp.Allocations)
|
|
|
|
}
|
|
|
|
}
|