github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/nomad/job_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/hashicorp/net-rpc-msgpackrpc" 8 "github.com/hashicorp/nomad/nomad/mock" 9 "github.com/hashicorp/nomad/nomad/structs" 10 "github.com/hashicorp/nomad/testutil" 11 ) 12 13 func TestJobEndpoint_Register(t *testing.T) { 14 s1 := testServer(t, func(c *Config) { 15 c.NumSchedulers = 0 // Prevent automatic dequeue 16 }) 17 defer s1.Shutdown() 18 codec := rpcClient(t, s1) 19 testutil.WaitForLeader(t, s1.RPC) 20 21 // Create the register request 22 job := mock.Job() 23 req := &structs.JobRegisterRequest{ 24 Job: job, 25 WriteRequest: structs.WriteRequest{Region: "global"}, 26 } 27 28 // Fetch the response 29 var resp structs.JobRegisterResponse 30 if err := msgpackrpc.CallWithCodec(codec, "Job.Register", req, &resp); err != nil { 31 t.Fatalf("err: %v", err) 32 } 33 if resp.Index == 0 { 34 t.Fatalf("bad index: %d", resp.Index) 35 } 36 37 // Check for the node in the FSM 38 state := s1.fsm.State() 39 out, err := state.JobByID(job.ID) 40 if err != nil { 41 t.Fatalf("err: %v", err) 42 } 43 if out == nil { 44 t.Fatalf("expected job") 45 } 46 if out.CreateIndex != resp.JobModifyIndex { 47 t.Fatalf("index mis-match") 48 } 49 50 // Lookup the evaluation 51 eval, err := state.EvalByID(resp.EvalID) 52 if err != nil { 53 t.Fatalf("err: %v", err) 54 } 55 if eval == nil { 56 t.Fatalf("expected eval") 57 } 58 if eval.CreateIndex != resp.EvalCreateIndex { 59 t.Fatalf("index mis-match") 60 } 61 62 if eval.Priority != job.Priority { 63 t.Fatalf("bad: %#v", eval) 64 } 65 if eval.Type != job.Type { 66 t.Fatalf("bad: %#v", eval) 67 } 68 if eval.TriggeredBy != structs.EvalTriggerJobRegister { 69 t.Fatalf("bad: %#v", eval) 70 } 71 if eval.JobID != job.ID { 72 t.Fatalf("bad: %#v", eval) 73 } 74 if eval.JobModifyIndex != resp.JobModifyIndex { 75 t.Fatalf("bad: %#v", eval) 76 } 77 if eval.Status != structs.EvalStatusPending { 78 t.Fatalf("bad: %#v", eval) 79 } 80 } 81 82 func TestJobEndpoint_Register_Existing(t *testing.T) { 83 s1 := testServer(t, func(c *Config) { 84 c.NumSchedulers = 0 // Prevent automatic dequeue 85 }) 86 defer s1.Shutdown() 87 codec := rpcClient(t, s1) 88 testutil.WaitForLeader(t, s1.RPC) 89 90 // Create the register request 91 job := mock.Job() 92 req := &structs.JobRegisterRequest{ 93 Job: job, 94 WriteRequest: structs.WriteRequest{Region: "global"}, 95 } 96 97 // Fetch the response 98 var resp structs.JobRegisterResponse 99 if err := msgpackrpc.CallWithCodec(codec, "Job.Register", req, &resp); err != nil { 100 t.Fatalf("err: %v", err) 101 } 102 if resp.Index == 0 { 103 t.Fatalf("bad index: %d", resp.Index) 104 } 105 106 // Update the job definition 107 job2 := mock.Job() 108 job2.Priority = 100 109 job2.ID = job.ID 110 req.Job = job2 111 112 // Attempt update 113 if err := msgpackrpc.CallWithCodec(codec, "Job.Register", req, &resp); err != nil { 114 t.Fatalf("err: %v", err) 115 } 116 if resp.Index == 0 { 117 t.Fatalf("bad index: %d", resp.Index) 118 } 119 120 // Check for the node in the FSM 121 state := s1.fsm.State() 122 out, err := state.JobByID(job.ID) 123 if err != nil { 124 t.Fatalf("err: %v", err) 125 } 126 if out == nil { 127 t.Fatalf("expected job") 128 } 129 if out.ModifyIndex != resp.JobModifyIndex { 130 t.Fatalf("index mis-match") 131 } 132 if out.Priority != 100 { 133 t.Fatalf("expected update") 134 } 135 136 // Lookup the evaluation 137 eval, err := state.EvalByID(resp.EvalID) 138 if err != nil { 139 t.Fatalf("err: %v", err) 140 } 141 if eval == nil { 142 t.Fatalf("expected eval") 143 } 144 if eval.CreateIndex != resp.EvalCreateIndex { 145 t.Fatalf("index mis-match") 146 } 147 148 if eval.Priority != job2.Priority { 149 t.Fatalf("bad: %#v", eval) 150 } 151 if eval.Type != job2.Type { 152 t.Fatalf("bad: %#v", eval) 153 } 154 if eval.TriggeredBy != structs.EvalTriggerJobRegister { 155 t.Fatalf("bad: %#v", eval) 156 } 157 if eval.JobID != job2.ID { 158 t.Fatalf("bad: %#v", eval) 159 } 160 if eval.JobModifyIndex != resp.JobModifyIndex { 161 t.Fatalf("bad: %#v", eval) 162 } 163 if eval.Status != structs.EvalStatusPending { 164 t.Fatalf("bad: %#v", eval) 165 } 166 } 167 168 func TestJobEndpoint_Evaluate(t *testing.T) { 169 s1 := testServer(t, func(c *Config) { 170 c.NumSchedulers = 0 // Prevent automatic dequeue 171 }) 172 defer s1.Shutdown() 173 codec := rpcClient(t, s1) 174 testutil.WaitForLeader(t, s1.RPC) 175 176 // Create the register request 177 job := mock.Job() 178 req := &structs.JobRegisterRequest{ 179 Job: job, 180 WriteRequest: structs.WriteRequest{Region: "global"}, 181 } 182 183 // Fetch the response 184 var resp structs.JobRegisterResponse 185 if err := msgpackrpc.CallWithCodec(codec, "Job.Register", req, &resp); err != nil { 186 t.Fatalf("err: %v", err) 187 } 188 if resp.Index == 0 { 189 t.Fatalf("bad index: %d", resp.Index) 190 } 191 192 // Force a re-evaluation 193 reEval := &structs.JobEvaluateRequest{ 194 JobID: job.ID, 195 WriteRequest: structs.WriteRequest{Region: "global"}, 196 } 197 198 // Fetch the response 199 if err := msgpackrpc.CallWithCodec(codec, "Job.Evaluate", reEval, &resp); err != nil { 200 t.Fatalf("err: %v", err) 201 } 202 if resp.Index == 0 { 203 t.Fatalf("bad index: %d", resp.Index) 204 } 205 206 // Lookup the evaluation 207 state := s1.fsm.State() 208 eval, err := state.EvalByID(resp.EvalID) 209 if err != nil { 210 t.Fatalf("err: %v", err) 211 } 212 if eval == nil { 213 t.Fatalf("expected eval") 214 } 215 if eval.CreateIndex != resp.EvalCreateIndex { 216 t.Fatalf("index mis-match") 217 } 218 219 if eval.Priority != job.Priority { 220 t.Fatalf("bad: %#v", eval) 221 } 222 if eval.Type != job.Type { 223 t.Fatalf("bad: %#v", eval) 224 } 225 if eval.TriggeredBy != structs.EvalTriggerJobRegister { 226 t.Fatalf("bad: %#v", eval) 227 } 228 if eval.JobID != job.ID { 229 t.Fatalf("bad: %#v", eval) 230 } 231 if eval.JobModifyIndex != resp.JobModifyIndex { 232 t.Fatalf("bad: %#v", eval) 233 } 234 if eval.Status != structs.EvalStatusPending { 235 t.Fatalf("bad: %#v", eval) 236 } 237 } 238 239 func TestJobEndpoint_Deregister(t *testing.T) { 240 s1 := testServer(t, func(c *Config) { 241 c.NumSchedulers = 0 // Prevent automatic dequeue 242 }) 243 defer s1.Shutdown() 244 codec := rpcClient(t, s1) 245 testutil.WaitForLeader(t, s1.RPC) 246 247 // Create the register request 248 job := mock.Job() 249 reg := &structs.JobRegisterRequest{ 250 Job: job, 251 WriteRequest: structs.WriteRequest{Region: "global"}, 252 } 253 254 // Fetch the response 255 var resp structs.JobRegisterResponse 256 if err := msgpackrpc.CallWithCodec(codec, "Job.Register", reg, &resp); err != nil { 257 t.Fatalf("err: %v", err) 258 } 259 260 // Deregister 261 dereg := &structs.JobDeregisterRequest{ 262 JobID: job.ID, 263 WriteRequest: structs.WriteRequest{Region: "global"}, 264 } 265 var resp2 structs.JobDeregisterResponse 266 if err := msgpackrpc.CallWithCodec(codec, "Job.Deregister", dereg, &resp2); err != nil { 267 t.Fatalf("err: %v", err) 268 } 269 if resp2.Index == 0 { 270 t.Fatalf("bad index: %d", resp2.Index) 271 } 272 273 // Check for the node in the FSM 274 state := s1.fsm.State() 275 out, err := state.JobByID(job.ID) 276 if err != nil { 277 t.Fatalf("err: %v", err) 278 } 279 if out != nil { 280 t.Fatalf("unexpected job") 281 } 282 283 // Lookup the evaluation 284 eval, err := state.EvalByID(resp2.EvalID) 285 if err != nil { 286 t.Fatalf("err: %v", err) 287 } 288 if eval == nil { 289 t.Fatalf("expected eval") 290 } 291 if eval.CreateIndex != resp2.EvalCreateIndex { 292 t.Fatalf("index mis-match") 293 } 294 295 if eval.Priority != structs.JobDefaultPriority { 296 t.Fatalf("bad: %#v", eval) 297 } 298 if eval.Type != structs.JobTypeService { 299 t.Fatalf("bad: %#v", eval) 300 } 301 if eval.TriggeredBy != structs.EvalTriggerJobDeregister { 302 t.Fatalf("bad: %#v", eval) 303 } 304 if eval.JobID != job.ID { 305 t.Fatalf("bad: %#v", eval) 306 } 307 if eval.JobModifyIndex != resp2.JobModifyIndex { 308 t.Fatalf("bad: %#v", eval) 309 } 310 if eval.Status != structs.EvalStatusPending { 311 t.Fatalf("bad: %#v", eval) 312 } 313 } 314 315 func TestJobEndpoint_GetJob(t *testing.T) { 316 s1 := testServer(t, nil) 317 defer s1.Shutdown() 318 codec := rpcClient(t, s1) 319 testutil.WaitForLeader(t, s1.RPC) 320 321 // Create the register request 322 job := mock.Job() 323 reg := &structs.JobRegisterRequest{ 324 Job: job, 325 WriteRequest: structs.WriteRequest{Region: "global"}, 326 } 327 328 // Fetch the response 329 var resp structs.JobRegisterResponse 330 if err := msgpackrpc.CallWithCodec(codec, "Job.Register", reg, &resp); err != nil { 331 t.Fatalf("err: %v", err) 332 } 333 job.CreateIndex = resp.JobModifyIndex 334 job.ModifyIndex = resp.JobModifyIndex 335 336 // Lookup the job 337 get := &structs.JobSpecificRequest{ 338 JobID: job.ID, 339 QueryOptions: structs.QueryOptions{Region: "global"}, 340 } 341 var resp2 structs.SingleJobResponse 342 if err := msgpackrpc.CallWithCodec(codec, "Job.GetJob", get, &resp2); err != nil { 343 t.Fatalf("err: %v", err) 344 } 345 if resp2.Index != resp.JobModifyIndex { 346 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 347 } 348 349 if !reflect.DeepEqual(job, resp2.Job) { 350 t.Fatalf("bad: %#v %#v", job, resp2.Job) 351 } 352 353 // Lookup non-existing job 354 get.JobID = "foobarbaz" 355 if err := msgpackrpc.CallWithCodec(codec, "Job.GetJob", get, &resp2); err != nil { 356 t.Fatalf("err: %v", err) 357 } 358 if resp2.Index != resp.JobModifyIndex { 359 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 360 } 361 if resp2.Job != nil { 362 t.Fatalf("unexpected job") 363 } 364 } 365 366 func TestJobEndpoint_ListJobs(t *testing.T) { 367 s1 := testServer(t, nil) 368 defer s1.Shutdown() 369 codec := rpcClient(t, s1) 370 testutil.WaitForLeader(t, s1.RPC) 371 372 // Create the register request 373 job := mock.Job() 374 state := s1.fsm.State() 375 err := state.UpsertJob(1000, job) 376 if err != nil { 377 t.Fatalf("err: %v", err) 378 } 379 380 // Lookup the jobs 381 get := &structs.JobListRequest{ 382 QueryOptions: structs.QueryOptions{Region: "global"}, 383 } 384 var resp2 structs.JobListResponse 385 if err := msgpackrpc.CallWithCodec(codec, "Job.List", get, &resp2); err != nil { 386 t.Fatalf("err: %v", err) 387 } 388 if resp2.Index != 1000 { 389 t.Fatalf("Bad index: %d %d", resp2.Index, 1000) 390 } 391 392 if len(resp2.Jobs) != 1 { 393 t.Fatalf("bad: %#v", resp2.Jobs) 394 } 395 if resp2.Jobs[0].ID != job.ID { 396 t.Fatalf("bad: %#v", resp2.Jobs[0]) 397 } 398 } 399 400 func TestJobEndpoint_Allocations(t *testing.T) { 401 s1 := testServer(t, nil) 402 defer s1.Shutdown() 403 codec := rpcClient(t, s1) 404 testutil.WaitForLeader(t, s1.RPC) 405 406 // Create the register request 407 alloc1 := mock.Alloc() 408 alloc2 := mock.Alloc() 409 alloc2.JobID = alloc1.JobID 410 state := s1.fsm.State() 411 err := state.UpsertAllocs(1000, 412 []*structs.Allocation{alloc1, alloc2}) 413 if err != nil { 414 t.Fatalf("err: %v", err) 415 } 416 417 // Lookup the jobs 418 get := &structs.JobSpecificRequest{ 419 JobID: alloc1.JobID, 420 QueryOptions: structs.QueryOptions{Region: "global"}, 421 } 422 var resp2 structs.JobAllocationsResponse 423 if err := msgpackrpc.CallWithCodec(codec, "Job.Allocations", get, &resp2); err != nil { 424 t.Fatalf("err: %v", err) 425 } 426 if resp2.Index != 1000 { 427 t.Fatalf("Bad index: %d %d", resp2.Index, 1000) 428 } 429 430 if len(resp2.Allocations) != 2 { 431 t.Fatalf("bad: %#v", resp2.Allocations) 432 } 433 } 434 435 func TestJobEndpoint_Evaluations(t *testing.T) { 436 s1 := testServer(t, nil) 437 defer s1.Shutdown() 438 codec := rpcClient(t, s1) 439 testutil.WaitForLeader(t, s1.RPC) 440 441 // Create the register request 442 eval1 := mock.Eval() 443 eval2 := mock.Eval() 444 eval2.JobID = eval1.JobID 445 state := s1.fsm.State() 446 err := state.UpsertEvals(1000, 447 []*structs.Evaluation{eval1, eval2}) 448 if err != nil { 449 t.Fatalf("err: %v", err) 450 } 451 452 // Lookup the jobs 453 get := &structs.JobSpecificRequest{ 454 JobID: eval1.JobID, 455 QueryOptions: structs.QueryOptions{Region: "global"}, 456 } 457 var resp2 structs.JobEvaluationsResponse 458 if err := msgpackrpc.CallWithCodec(codec, "Job.Evaluations", get, &resp2); err != nil { 459 t.Fatalf("err: %v", err) 460 } 461 if resp2.Index != 1000 { 462 t.Fatalf("Bad index: %d %d", resp2.Index, 1000) 463 } 464 465 if len(resp2.Evaluations) != 2 { 466 t.Fatalf("bad: %#v", resp2.Evaluations) 467 } 468 }