2015-07-23 21:41:18 +00:00
|
|
|
package nomad
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
2015-10-27 21:36:32 +00:00
|
|
|
"time"
|
2015-07-23 21:41:18 +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 21:41:18 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
"github.com/hashicorp/nomad/testutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestJobEndpoint_Register(t *testing.T) {
|
2015-10-08 22:36:42 +00:00
|
|
|
s1 := testServer(t, func(c *Config) {
|
|
|
|
c.NumSchedulers = 0 // Prevent automatic dequeue
|
|
|
|
})
|
2015-07-23 21:41:18 +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
|
|
|
job := mock.Job()
|
2015-07-23 21:41:18 +00:00
|
|
|
req := &structs.JobRegisterRequest{
|
|
|
|
Job: job,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
2015-08-06 18:48:44 +00:00
|
|
|
var resp structs.JobRegisterResponse
|
2015-07-23 21:41:18 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Register", req, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for the node in the FSM
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:56:38 +00:00
|
|
|
out, err := state.JobByID(job.ID)
|
2015-07-23 21:41:18 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if out == nil {
|
|
|
|
t.Fatalf("expected job")
|
|
|
|
}
|
2015-08-06 18:48:44 +00:00
|
|
|
if out.CreateIndex != resp.JobModifyIndex {
|
2015-07-23 21:41:18 +00:00
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
2015-11-27 03:26:00 +00:00
|
|
|
serviceName := out.TaskGroups[0].Tasks[0].Services[0].Name
|
2015-12-01 06:13:02 +00:00
|
|
|
expectedServiceName := "web-frontend"
|
2015-11-30 10:27:26 +00:00
|
|
|
if serviceName != expectedServiceName {
|
|
|
|
t.Fatalf("Expected Service Name: %s, Actual: %s", expectedServiceName, serviceName)
|
2015-11-27 03:26:00 +00:00
|
|
|
}
|
2015-08-06 18:48:44 +00:00
|
|
|
|
|
|
|
// Lookup the evaluation
|
2015-09-07 03:56:38 +00:00
|
|
|
eval, err := state.EvalByID(resp.EvalID)
|
2015-08-06 18:48:44 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if eval == nil {
|
|
|
|
t.Fatalf("expected eval")
|
|
|
|
}
|
|
|
|
if eval.CreateIndex != resp.EvalCreateIndex {
|
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
|
|
|
|
|
|
|
if eval.Priority != job.Priority {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.Type != job.Type {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.TriggeredBy != structs.EvalTriggerJobRegister {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobID != job.ID {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobModifyIndex != resp.JobModifyIndex {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
2015-08-06 23:39:20 +00:00
|
|
|
if eval.Status != structs.EvalStatusPending {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
2015-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestJobEndpoint_Register_Existing(t *testing.T) {
|
2015-10-08 22:36:42 +00:00
|
|
|
s1 := testServer(t, func(c *Config) {
|
|
|
|
c.NumSchedulers = 0 // Prevent automatic dequeue
|
|
|
|
})
|
2015-07-23 21:41:18 +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
|
|
|
job := mock.Job()
|
2015-07-23 21:41:18 +00:00
|
|
|
req := &structs.JobRegisterRequest{
|
|
|
|
Job: job,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
2015-08-06 18:48:44 +00:00
|
|
|
var resp structs.JobRegisterResponse
|
2015-07-23 21:41:18 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Register", req, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the job definition
|
2015-08-11 21:27:14 +00:00
|
|
|
job2 := mock.Job()
|
2015-07-23 21:41:18 +00:00
|
|
|
job2.Priority = 100
|
2015-07-23 22:15:48 +00:00
|
|
|
job2.ID = job.ID
|
2015-07-23 21:41:18 +00:00
|
|
|
req.Job = job2
|
|
|
|
|
|
|
|
// Attempt update
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Register", req, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for the node in the FSM
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:56:38 +00:00
|
|
|
out, err := state.JobByID(job.ID)
|
2015-07-23 21:41:18 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if out == nil {
|
|
|
|
t.Fatalf("expected job")
|
|
|
|
}
|
2015-08-06 18:48:44 +00:00
|
|
|
if out.ModifyIndex != resp.JobModifyIndex {
|
2015-07-23 21:41:18 +00:00
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
|
|
|
if out.Priority != 100 {
|
|
|
|
t.Fatalf("expected update")
|
|
|
|
}
|
2015-08-06 18:48:44 +00:00
|
|
|
|
|
|
|
// Lookup the evaluation
|
2015-09-07 03:56:38 +00:00
|
|
|
eval, err := state.EvalByID(resp.EvalID)
|
2015-08-06 18:48:44 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if eval == nil {
|
|
|
|
t.Fatalf("expected eval")
|
|
|
|
}
|
|
|
|
if eval.CreateIndex != resp.EvalCreateIndex {
|
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
|
|
|
|
|
|
|
if eval.Priority != job2.Priority {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.Type != job2.Type {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.TriggeredBy != structs.EvalTriggerJobRegister {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobID != job2.ID {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobModifyIndex != resp.JobModifyIndex {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
2015-08-06 23:39:20 +00:00
|
|
|
if eval.Status != structs.EvalStatusPending {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
2015-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
2015-08-16 01:11:26 +00:00
|
|
|
func TestJobEndpoint_Evaluate(t *testing.T) {
|
2015-10-08 22:36:42 +00:00
|
|
|
s1 := testServer(t, func(c *Config) {
|
|
|
|
c.NumSchedulers = 0 // Prevent automatic dequeue
|
|
|
|
})
|
2015-08-16 01:11:26 +00:00
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
job := mock.Job()
|
|
|
|
req := &structs.JobRegisterRequest{
|
|
|
|
Job: job,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-16 01:11:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.JobRegisterResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Register", req, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force a re-evaluation
|
|
|
|
reEval := &structs.JobEvaluateRequest{
|
|
|
|
JobID: job.ID,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-16 01:11:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Evaluate", reEval, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the evaluation
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:56:38 +00:00
|
|
|
eval, err := state.EvalByID(resp.EvalID)
|
2015-08-16 01:11:26 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if eval == nil {
|
|
|
|
t.Fatalf("expected eval")
|
|
|
|
}
|
|
|
|
if eval.CreateIndex != resp.EvalCreateIndex {
|
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
|
|
|
|
|
|
|
if eval.Priority != job.Priority {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.Type != job.Type {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.TriggeredBy != structs.EvalTriggerJobRegister {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobID != job.ID {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobModifyIndex != resp.JobModifyIndex {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.Status != structs.EvalStatusPending {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-23 21:41:18 +00:00
|
|
|
func TestJobEndpoint_Deregister(t *testing.T) {
|
2015-10-08 22:36:42 +00:00
|
|
|
s1 := testServer(t, func(c *Config) {
|
|
|
|
c.NumSchedulers = 0 // Prevent automatic dequeue
|
|
|
|
})
|
2015-07-23 21:41:18 +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
|
|
|
job := mock.Job()
|
2015-07-23 21:41:18 +00:00
|
|
|
reg := &structs.JobRegisterRequest{
|
|
|
|
Job: job,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
2015-08-06 18:48:44 +00:00
|
|
|
var resp structs.JobRegisterResponse
|
2015-07-23 21:41:18 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Register", reg, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deregister
|
|
|
|
dereg := &structs.JobDeregisterRequest{
|
2015-07-23 22:15:48 +00:00
|
|
|
JobID: job.ID,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-23 21:41:18 +00:00
|
|
|
}
|
2015-08-06 21:17:18 +00:00
|
|
|
var resp2 structs.JobDeregisterResponse
|
2015-07-23 21:41:18 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Deregister", dereg, &resp2); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp2.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for the node in the FSM
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:56:38 +00:00
|
|
|
out, err := state.JobByID(job.ID)
|
2015-07-23 21:41:18 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if out != nil {
|
|
|
|
t.Fatalf("unexpected job")
|
|
|
|
}
|
2015-08-06 21:17:18 +00:00
|
|
|
|
|
|
|
// Lookup the evaluation
|
2015-09-07 03:56:38 +00:00
|
|
|
eval, err := state.EvalByID(resp2.EvalID)
|
2015-08-06 21:17:18 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if eval == nil {
|
|
|
|
t.Fatalf("expected eval")
|
|
|
|
}
|
|
|
|
if eval.CreateIndex != resp2.EvalCreateIndex {
|
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
|
|
|
|
|
|
|
if eval.Priority != structs.JobDefaultPriority {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.Type != structs.JobTypeService {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.TriggeredBy != structs.EvalTriggerJobDeregister {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobID != job.ID {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobModifyIndex != resp2.JobModifyIndex {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
2015-08-06 23:39:20 +00:00
|
|
|
if eval.Status != structs.EvalStatusPending {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
2015-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestJobEndpoint_GetJob(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
|
|
|
job := mock.Job()
|
2015-07-23 21:41:18 +00:00
|
|
|
reg := &structs.JobRegisterRequest{
|
|
|
|
Job: job,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
2015-08-06 18:48:44 +00:00
|
|
|
var resp structs.JobRegisterResponse
|
2015-07-23 21:41:18 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Register", reg, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-08-06 18:48:44 +00:00
|
|
|
job.CreateIndex = resp.JobModifyIndex
|
|
|
|
job.ModifyIndex = resp.JobModifyIndex
|
2015-07-23 21:41:18 +00:00
|
|
|
|
|
|
|
// Lookup the job
|
|
|
|
get := &structs.JobSpecificRequest{
|
2015-07-23 22:15:48 +00:00
|
|
|
JobID: job.ID,
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.SingleJobResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.GetJob", get, &resp2); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-08-06 18:48:44 +00:00
|
|
|
if resp2.Index != resp.JobModifyIndex {
|
2015-07-23 21:41:18 +00:00
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index)
|
|
|
|
}
|
|
|
|
|
2015-11-27 03:43:02 +00:00
|
|
|
// Make a copy of the origin job and change the service name so that we can
|
|
|
|
// do a deep equal with the response from the GET JOB Api
|
|
|
|
j := job
|
|
|
|
j.TaskGroups[0].Tasks[0].Services[0].Name = "web-frontend"
|
|
|
|
if !reflect.DeepEqual(j, resp2.Job) {
|
2015-07-23 21:41:18 +00:00
|
|
|
t.Fatalf("bad: %#v %#v", job, resp2.Job)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup non-existing job
|
2015-07-23 22:15:48 +00:00
|
|
|
get.JobID = "foobarbaz"
|
2015-07-23 21:41:18 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.GetJob", get, &resp2); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-08-06 18:48:44 +00:00
|
|
|
if resp2.Index != resp.JobModifyIndex {
|
2015-07-23 21:41:18 +00:00
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index)
|
|
|
|
}
|
|
|
|
if resp2.Job != nil {
|
|
|
|
t.Fatalf("unexpected job")
|
|
|
|
}
|
|
|
|
}
|
2015-09-06 19:18:45 +00:00
|
|
|
|
2015-10-30 02:00:02 +00:00
|
|
|
func TestJobEndpoint_GetJob_Blocking(t *testing.T) {
|
2015-10-29 22:01:29 +00:00
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
state := s1.fsm.State()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the jobs
|
|
|
|
job1 := mock.Job()
|
|
|
|
job2 := mock.Job()
|
|
|
|
|
|
|
|
// Upsert a job we are not interested in first.
|
|
|
|
time.AfterFunc(100*time.Millisecond, func() {
|
2015-10-30 02:00:02 +00:00
|
|
|
if err := state.UpsertJob(100, job1); err != nil {
|
2015-10-29 22:01:29 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// Upsert another job later which should trigger the watch.
|
|
|
|
time.AfterFunc(200*time.Millisecond, func() {
|
2015-10-30 02:00:02 +00:00
|
|
|
if err := state.UpsertJob(200, job2); err != nil {
|
2015-10-29 22:01:29 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
req := &structs.JobSpecificRequest{
|
|
|
|
JobID: job2.ID,
|
|
|
|
QueryOptions: structs.QueryOptions{
|
|
|
|
Region: "global",
|
2015-10-30 02:00:02 +00:00
|
|
|
MinQueryIndex: 50,
|
2015-10-29 22:01:29 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
start := time.Now()
|
|
|
|
var resp structs.SingleJobResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.GetJob", req, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-10-30 15:27:47 +00:00
|
|
|
if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
|
2015-10-29 22:01:29 +00:00
|
|
|
t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
|
|
|
|
}
|
2015-10-30 02:00:02 +00:00
|
|
|
if resp.Index != 200 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp.Index, 200)
|
2015-10-29 22:01:29 +00:00
|
|
|
}
|
|
|
|
if resp.Job == nil || resp.Job.ID != job2.ID {
|
|
|
|
t.Fatalf("bad: %#v", resp.Job)
|
|
|
|
}
|
2015-10-30 02:00:02 +00:00
|
|
|
|
|
|
|
// Job delete fires watches
|
|
|
|
time.AfterFunc(100*time.Millisecond, func() {
|
|
|
|
if err := state.DeleteJob(300, job2.ID); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
req.QueryOptions.MinQueryIndex = 250
|
|
|
|
start = time.Now()
|
|
|
|
|
|
|
|
var resp2 structs.SingleJobResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.GetJob", req, &resp2); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-10-30 15:27:47 +00:00
|
|
|
if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
|
2015-10-30 02:00:02 +00:00
|
|
|
t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
|
|
|
|
}
|
|
|
|
if resp2.Index != 300 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, 300)
|
|
|
|
}
|
|
|
|
if resp2.Job != nil {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Job)
|
|
|
|
}
|
2015-10-29 22:01:29 +00:00
|
|
|
}
|
|
|
|
|
2015-09-06 19:18:45 +00:00
|
|
|
func TestJobEndpoint_ListJobs(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
job := mock.Job()
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:47:42 +00:00
|
|
|
err := state.UpsertJob(1000, job)
|
2015-09-06 19:18:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the jobs
|
|
|
|
get := &structs.JobListRequest{
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-09-06 19:18:45 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.JobListResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.List", get, &resp2); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index != 1000 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, 1000)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp2.Jobs) != 1 {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Jobs)
|
|
|
|
}
|
|
|
|
if resp2.Jobs[0].ID != job.ID {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Jobs[0])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-30 02:00:02 +00:00
|
|
|
func TestJobEndpoint_ListJobs_Blocking(t *testing.T) {
|
2015-10-27 21:36:32 +00:00
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
2015-10-28 19:43:00 +00:00
|
|
|
state := s1.fsm.State()
|
2015-10-27 21:36:32 +00:00
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the job
|
|
|
|
job := mock.Job()
|
|
|
|
|
2015-10-28 19:43:00 +00:00
|
|
|
// Upsert job triggers watches
|
|
|
|
time.AfterFunc(100*time.Millisecond, func() {
|
2015-10-30 02:00:02 +00:00
|
|
|
if err := state.UpsertJob(100, job); err != nil {
|
2015-10-27 21:36:32 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-10-28 19:43:00 +00:00
|
|
|
})
|
2015-10-27 21:36:32 +00:00
|
|
|
|
2015-10-28 19:43:00 +00:00
|
|
|
req := &structs.JobListRequest{
|
2015-10-27 21:36:32 +00:00
|
|
|
QueryOptions: structs.QueryOptions{
|
|
|
|
Region: "global",
|
2015-10-30 02:00:02 +00:00
|
|
|
MinQueryIndex: 50,
|
2015-10-27 21:36:32 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
start := time.Now()
|
|
|
|
var resp structs.JobListResponse
|
2015-10-28 19:43:00 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.List", req, &resp); err != nil {
|
2015-10-27 21:36:32 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-10-30 15:27:47 +00:00
|
|
|
if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
|
2015-10-27 21:36:32 +00:00
|
|
|
t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
|
|
|
|
}
|
2015-10-30 02:00:02 +00:00
|
|
|
if resp.Index != 100 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp.Index, 100)
|
2015-10-27 21:36:32 +00:00
|
|
|
}
|
2015-10-28 19:43:00 +00:00
|
|
|
if len(resp.Jobs) != 1 || resp.Jobs[0].ID != job.ID {
|
2015-10-27 21:36:32 +00:00
|
|
|
t.Fatalf("bad: %#v", resp.Jobs)
|
|
|
|
}
|
2015-10-28 19:43:00 +00:00
|
|
|
|
|
|
|
// Job deletion triggers watches
|
|
|
|
time.AfterFunc(100*time.Millisecond, func() {
|
2015-10-30 02:00:02 +00:00
|
|
|
if err := state.DeleteJob(200, job.ID); err != nil {
|
2015-10-28 19:43:00 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2015-10-30 02:00:02 +00:00
|
|
|
req.MinQueryIndex = 150
|
2015-10-28 19:43:00 +00:00
|
|
|
start = time.Now()
|
|
|
|
var resp2 structs.JobListResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.List", req, &resp2); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-10-30 15:27:47 +00:00
|
|
|
if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
|
2015-10-29 01:35:48 +00:00
|
|
|
t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
|
2015-10-28 19:43:00 +00:00
|
|
|
}
|
2015-10-30 02:00:02 +00:00
|
|
|
if resp2.Index != 200 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, 200)
|
2015-10-28 19:43:00 +00:00
|
|
|
}
|
|
|
|
if len(resp2.Jobs) != 0 {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Jobs)
|
2015-10-27 21:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-06 19:18:45 +00:00
|
|
|
func TestJobEndpoint_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.JobID = alloc1.JobID
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:47:42 +00:00
|
|
|
err := state.UpsertAllocs(1000,
|
2015-09-06 19:18:45 +00:00
|
|
|
[]*structs.Allocation{alloc1, alloc2})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the jobs
|
|
|
|
get := &structs.JobSpecificRequest{
|
|
|
|
JobID: alloc1.JobID,
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-09-06 19:18:45 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.JobAllocationsResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Allocations", get, &resp2); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index != 1000 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, 1000)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp2.Allocations) != 2 {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Allocations)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-30 02:00:02 +00:00
|
|
|
func TestJobEndpoint_Allocations_Blocking(t *testing.T) {
|
2015-10-29 22:26:14 +00:00
|
|
|
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.JobID = "job1"
|
|
|
|
state := s1.fsm.State()
|
|
|
|
|
|
|
|
// First upsert an unrelated alloc
|
|
|
|
time.AfterFunc(100*time.Millisecond, func() {
|
2015-10-30 02:00:02 +00:00
|
|
|
err := state.UpsertAllocs(100, []*structs.Allocation{alloc1})
|
2015-10-29 22:26:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// Upsert an alloc for the job we are interested in later
|
|
|
|
time.AfterFunc(200*time.Millisecond, func() {
|
2015-10-30 02:00:02 +00:00
|
|
|
err := state.UpsertAllocs(200, []*structs.Allocation{alloc2})
|
2015-10-29 22:26:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// Lookup the jobs
|
|
|
|
get := &structs.JobSpecificRequest{
|
|
|
|
JobID: "job1",
|
|
|
|
QueryOptions: structs.QueryOptions{
|
|
|
|
Region: "global",
|
2015-10-30 02:00:02 +00:00
|
|
|
MinQueryIndex: 50,
|
2015-10-29 22:26:14 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
var resp structs.JobAllocationsResponse
|
|
|
|
start := time.Now()
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Allocations", get, &resp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-10-30 15:27:47 +00:00
|
|
|
if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
|
2015-10-29 22:26:14 +00:00
|
|
|
t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
|
|
|
|
}
|
2015-10-30 02:00:02 +00:00
|
|
|
if resp.Index != 200 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp.Index, 200)
|
2015-10-29 22:26:14 +00:00
|
|
|
}
|
|
|
|
if len(resp.Allocations) != 1 || resp.Allocations[0].JobID != "job1" {
|
|
|
|
t.Fatalf("bad: %#v", resp.Allocations)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-06 19:18:45 +00:00
|
|
|
func TestJobEndpoint_Evaluations(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()
|
|
|
|
eval2.JobID = eval1.JobID
|
|
|
|
state := s1.fsm.State()
|
|
|
|
err := state.UpsertEvals(1000,
|
|
|
|
[]*structs.Evaluation{eval1, eval2})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the jobs
|
|
|
|
get := &structs.JobSpecificRequest{
|
|
|
|
JobID: eval1.JobID,
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-09-06 19:18:45 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.JobEvaluationsResponse
|
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Job.Evaluations", get, &resp2); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index != 1000 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, 1000)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp2.Evaluations) != 2 {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Evaluations)
|
|
|
|
}
|
|
|
|
}
|