github.com/mattyr/nomad@v0.3.3-0.20160919021406-3485a065154a/api/jobs_test.go (about) 1 package api 2 3 import ( 4 "reflect" 5 "sort" 6 "strings" 7 "testing" 8 9 "github.com/hashicorp/nomad/testutil" 10 ) 11 12 func TestJobs_Register(t *testing.T) { 13 c, s := makeClient(t, nil, nil) 14 defer s.Stop() 15 jobs := c.Jobs() 16 17 // Listing jobs before registering returns nothing 18 resp, qm, err := jobs.List(nil) 19 if err != nil { 20 t.Fatalf("err: %s", err) 21 } 22 if qm.LastIndex != 0 { 23 t.Fatalf("bad index: %d", qm.LastIndex) 24 } 25 if n := len(resp); n != 0 { 26 t.Fatalf("expected 0 jobs, got: %d", n) 27 } 28 29 // Create a job and attempt to register it 30 job := testJob() 31 eval, wm, err := jobs.Register(job, nil) 32 if err != nil { 33 t.Fatalf("err: %s", err) 34 } 35 if eval == "" { 36 t.Fatalf("missing eval id") 37 } 38 assertWriteMeta(t, wm) 39 40 // Query the jobs back out again 41 resp, qm, err = jobs.List(nil) 42 if err != nil { 43 t.Fatalf("err: %s", err) 44 } 45 assertQueryMeta(t, qm) 46 47 // Check that we got the expected response 48 if len(resp) != 1 || resp[0].ID != job.ID { 49 t.Fatalf("bad: %#v", resp[0]) 50 } 51 } 52 53 func TestJobs_EnforceRegister(t *testing.T) { 54 c, s := makeClient(t, nil, nil) 55 defer s.Stop() 56 jobs := c.Jobs() 57 58 // Listing jobs before registering returns nothing 59 resp, qm, err := jobs.List(nil) 60 if err != nil { 61 t.Fatalf("err: %s", err) 62 } 63 if qm.LastIndex != 0 { 64 t.Fatalf("bad index: %d", qm.LastIndex) 65 } 66 if n := len(resp); n != 0 { 67 t.Fatalf("expected 0 jobs, got: %d", n) 68 } 69 70 // Create a job and attempt to register it with an incorrect index. 71 job := testJob() 72 eval, wm, err := jobs.EnforceRegister(job, 10, nil) 73 if err == nil || !strings.Contains(err.Error(), RegisterEnforceIndexErrPrefix) { 74 t.Fatalf("expected enforcement error: %v", err) 75 } 76 77 // Register 78 eval, wm, err = jobs.EnforceRegister(job, 0, nil) 79 if err != nil { 80 t.Fatalf("err: %s", err) 81 } 82 if eval == "" { 83 t.Fatalf("missing eval id") 84 } 85 assertWriteMeta(t, wm) 86 87 // Query the jobs back out again 88 resp, qm, err = jobs.List(nil) 89 if err != nil { 90 t.Fatalf("err: %s", err) 91 } 92 assertQueryMeta(t, qm) 93 94 // Check that we got the expected response 95 if len(resp) != 1 { 96 t.Fatalf("bad length: %d", len(resp)) 97 } 98 99 if resp[0].ID != job.ID { 100 t.Fatalf("bad: %#v", resp[0]) 101 } 102 curIndex := resp[0].JobModifyIndex 103 104 // Fail at incorrect index 105 eval, wm, err = jobs.EnforceRegister(job, 123456, nil) 106 if err == nil || !strings.Contains(err.Error(), RegisterEnforceIndexErrPrefix) { 107 t.Fatalf("expected enforcement error: %v", err) 108 } 109 110 // Works at correct index 111 eval, wm, err = jobs.EnforceRegister(job, curIndex, nil) 112 if err != nil { 113 t.Fatalf("err: %s", err) 114 } 115 if eval == "" { 116 t.Fatalf("missing eval id") 117 } 118 assertWriteMeta(t, wm) 119 } 120 121 func TestJobs_Info(t *testing.T) { 122 c, s := makeClient(t, nil, nil) 123 defer s.Stop() 124 jobs := c.Jobs() 125 126 // Trying to retrieve a job by ID before it exists 127 // returns an error 128 _, _, err := jobs.Info("job1", nil) 129 if err == nil || !strings.Contains(err.Error(), "not found") { 130 t.Fatalf("expected not found error, got: %#v", err) 131 } 132 133 // Register the job 134 job := testJob() 135 _, wm, err := jobs.Register(job, nil) 136 if err != nil { 137 t.Fatalf("err: %s", err) 138 } 139 assertWriteMeta(t, wm) 140 141 // Query the job again and ensure it exists 142 result, qm, err := jobs.Info("job1", nil) 143 if err != nil { 144 t.Fatalf("err: %s", err) 145 } 146 assertQueryMeta(t, qm) 147 148 // Check that the result is what we expect 149 if result == nil || result.ID != job.ID { 150 t.Fatalf("expect: %#v, got: %#v", job, result) 151 } 152 } 153 154 func TestJobs_PrefixList(t *testing.T) { 155 c, s := makeClient(t, nil, nil) 156 defer s.Stop() 157 jobs := c.Jobs() 158 159 // Listing when nothing exists returns empty 160 results, qm, err := jobs.PrefixList("dummy") 161 if err != nil { 162 t.Fatalf("err: %s", err) 163 } 164 if qm.LastIndex != 0 { 165 t.Fatalf("bad index: %d", qm.LastIndex) 166 } 167 if n := len(results); n != 0 { 168 t.Fatalf("expected 0 jobs, got: %d", n) 169 } 170 171 // Register the job 172 job := testJob() 173 _, wm, err := jobs.Register(job, nil) 174 if err != nil { 175 t.Fatalf("err: %s", err) 176 } 177 assertWriteMeta(t, wm) 178 179 // Query the job again and ensure it exists 180 // Listing when nothing exists returns empty 181 results, qm, err = jobs.PrefixList(job.ID[:1]) 182 if err != nil { 183 t.Fatalf("err: %s", err) 184 } 185 186 // Check if we have the right list 187 if len(results) != 1 || results[0].ID != job.ID { 188 t.Fatalf("bad: %#v", results) 189 } 190 } 191 192 func TestJobs_List(t *testing.T) { 193 c, s := makeClient(t, nil, nil) 194 defer s.Stop() 195 jobs := c.Jobs() 196 197 // Listing when nothing exists returns empty 198 results, qm, err := jobs.List(nil) 199 if err != nil { 200 t.Fatalf("err: %s", err) 201 } 202 if qm.LastIndex != 0 { 203 t.Fatalf("bad index: %d", qm.LastIndex) 204 } 205 if n := len(results); n != 0 { 206 t.Fatalf("expected 0 jobs, got: %d", n) 207 } 208 209 // Register the job 210 job := testJob() 211 _, wm, err := jobs.Register(job, nil) 212 if err != nil { 213 t.Fatalf("err: %s", err) 214 } 215 assertWriteMeta(t, wm) 216 217 // Query the job again and ensure it exists 218 // Listing when nothing exists returns empty 219 results, qm, err = jobs.List(nil) 220 if err != nil { 221 t.Fatalf("err: %s", err) 222 } 223 224 // Check if we have the right list 225 if len(results) != 1 || results[0].ID != job.ID { 226 t.Fatalf("bad: %#v", results) 227 } 228 } 229 230 func TestJobs_Allocations(t *testing.T) { 231 c, s := makeClient(t, nil, nil) 232 defer s.Stop() 233 jobs := c.Jobs() 234 235 // Looking up by a non-existent job returns nothing 236 allocs, qm, err := jobs.Allocations("job1", nil) 237 if err != nil { 238 t.Fatalf("err: %s", err) 239 } 240 if qm.LastIndex != 0 { 241 t.Fatalf("bad index: %d", qm.LastIndex) 242 } 243 if n := len(allocs); n != 0 { 244 t.Fatalf("expected 0 allocs, got: %d", n) 245 } 246 247 // TODO: do something here to create some allocations for 248 // an existing job, lookup again. 249 } 250 251 func TestJobs_Evaluations(t *testing.T) { 252 c, s := makeClient(t, nil, nil) 253 defer s.Stop() 254 jobs := c.Jobs() 255 256 // Looking up by a non-existent job ID returns nothing 257 evals, qm, err := jobs.Evaluations("job1", nil) 258 if err != nil { 259 t.Fatalf("err: %s", err) 260 } 261 if qm.LastIndex != 0 { 262 t.Fatalf("bad index: %d", qm.LastIndex) 263 } 264 if n := len(evals); n != 0 { 265 t.Fatalf("expected 0 evals, got: %d", n) 266 } 267 268 // Insert a job. This also creates an evaluation so we should 269 // be able to query that out after. 270 job := testJob() 271 evalID, wm, err := jobs.Register(job, nil) 272 if err != nil { 273 t.Fatalf("err: %s", err) 274 } 275 assertWriteMeta(t, wm) 276 277 // Look up the evaluations again. 278 evals, qm, err = jobs.Evaluations("job1", nil) 279 if err != nil { 280 t.Fatalf("err: %s", err) 281 } 282 assertQueryMeta(t, qm) 283 284 // Check that we got the evals back, evals are in order most recent to least recent 285 // so the last eval is the original registered eval 286 idx := len(evals) - 1 287 if n := len(evals); n == 0 || evals[idx].ID != evalID { 288 t.Fatalf("expected >= 1 eval (%s), got: %#v", evalID, evals[idx]) 289 } 290 } 291 292 func TestJobs_Deregister(t *testing.T) { 293 c, s := makeClient(t, nil, nil) 294 defer s.Stop() 295 jobs := c.Jobs() 296 297 // Register a new job 298 job := testJob() 299 _, wm, err := jobs.Register(job, nil) 300 if err != nil { 301 t.Fatalf("err: %s", err) 302 } 303 assertWriteMeta(t, wm) 304 305 // Attempting delete on non-existing job returns an error 306 if _, _, err = jobs.Deregister("nope", nil); err != nil { 307 t.Fatalf("unexpected error deregistering job: %v", err) 308 309 } 310 311 // Deleting an existing job works 312 evalID, wm3, err := jobs.Deregister("job1", nil) 313 if err != nil { 314 t.Fatalf("err: %s", err) 315 } 316 assertWriteMeta(t, wm3) 317 if evalID == "" { 318 t.Fatalf("missing eval ID") 319 } 320 321 // Check that the job is really gone 322 result, qm, err := jobs.List(nil) 323 if err != nil { 324 t.Fatalf("err: %s", err) 325 } 326 assertQueryMeta(t, qm) 327 if n := len(result); n != 0 { 328 t.Fatalf("expected 0 jobs, got: %d", n) 329 } 330 } 331 332 func TestJobs_ForceEvaluate(t *testing.T) { 333 c, s := makeClient(t, nil, nil) 334 defer s.Stop() 335 jobs := c.Jobs() 336 337 // Force-eval on a non-existent job fails 338 _, _, err := jobs.ForceEvaluate("job1", nil) 339 if err == nil || !strings.Contains(err.Error(), "not found") { 340 t.Fatalf("expected not found error, got: %#v", err) 341 } 342 343 // Create a new job 344 _, wm, err := jobs.Register(testJob(), nil) 345 if err != nil { 346 t.Fatalf("err: %s", err) 347 } 348 assertWriteMeta(t, wm) 349 350 // Try force-eval again 351 evalID, wm, err := jobs.ForceEvaluate("job1", nil) 352 if err != nil { 353 t.Fatalf("err: %s", err) 354 } 355 assertWriteMeta(t, wm) 356 357 // Retrieve the evals and see if we get a matching one 358 evals, qm, err := jobs.Evaluations("job1", nil) 359 if err != nil { 360 t.Fatalf("err: %s", err) 361 } 362 assertQueryMeta(t, qm) 363 for _, eval := range evals { 364 if eval.ID == evalID { 365 return 366 } 367 } 368 t.Fatalf("evaluation %q missing", evalID) 369 } 370 371 func TestJobs_PeriodicForce(t *testing.T) { 372 c, s := makeClient(t, nil, nil) 373 defer s.Stop() 374 jobs := c.Jobs() 375 376 // Force-eval on a non-existent job fails 377 _, _, err := jobs.PeriodicForce("job1", nil) 378 if err == nil || !strings.Contains(err.Error(), "not found") { 379 t.Fatalf("expected not found error, got: %#v", err) 380 } 381 382 // Create a new job 383 job := testPeriodicJob() 384 _, _, err = jobs.Register(job, nil) 385 if err != nil { 386 t.Fatalf("err: %s", err) 387 } 388 389 testutil.WaitForResult(func() (bool, error) { 390 out, _, err := jobs.Info(job.ID, nil) 391 if err != nil || out == nil || out.ID != job.ID { 392 return false, err 393 } 394 return true, nil 395 }, func(err error) { 396 t.Fatalf("err: %s", err) 397 }) 398 399 // Try force again 400 evalID, wm, err := jobs.PeriodicForce(job.ID, nil) 401 if err != nil { 402 t.Fatalf("err: %s", err) 403 } 404 assertWriteMeta(t, wm) 405 406 if evalID == "" { 407 t.Fatalf("empty evalID") 408 } 409 410 // Retrieve the eval 411 evals := c.Evaluations() 412 eval, qm, err := evals.Info(evalID, nil) 413 if err != nil { 414 t.Fatalf("err: %s", err) 415 } 416 assertQueryMeta(t, qm) 417 if eval.ID == evalID { 418 return 419 } 420 t.Fatalf("evaluation %q missing", evalID) 421 } 422 423 func TestJobs_Plan(t *testing.T) { 424 c, s := makeClient(t, nil, nil) 425 defer s.Stop() 426 jobs := c.Jobs() 427 428 // Create a job and attempt to register it 429 job := testJob() 430 eval, wm, err := jobs.Register(job, nil) 431 if err != nil { 432 t.Fatalf("err: %s", err) 433 } 434 if eval == "" { 435 t.Fatalf("missing eval id") 436 } 437 assertWriteMeta(t, wm) 438 439 // Check that passing a nil job fails 440 if _, _, err := jobs.Plan(nil, true, nil); err == nil { 441 t.Fatalf("expect an error when job isn't provided") 442 } 443 444 // Make a plan request 445 planResp, wm, err := jobs.Plan(job, true, nil) 446 if err != nil { 447 t.Fatalf("err: %s", err) 448 } 449 if planResp == nil { 450 t.Fatalf("nil response") 451 } 452 453 if planResp.JobModifyIndex == 0 { 454 t.Fatalf("bad JobModifyIndex value: %#v", planResp) 455 } 456 if planResp.Diff == nil { 457 t.Fatalf("got nil diff: %#v", planResp) 458 } 459 if planResp.Annotations == nil { 460 t.Fatalf("got nil annotations: %#v", planResp) 461 } 462 // Can make this assertion because there are no clients. 463 if len(planResp.CreatedEvals) == 0 { 464 t.Fatalf("got no CreatedEvals: %#v", planResp) 465 } 466 467 // Make a plan request w/o the diff 468 planResp, wm, err = jobs.Plan(job, false, nil) 469 if err != nil { 470 t.Fatalf("err: %s", err) 471 } 472 assertWriteMeta(t, wm) 473 474 if planResp == nil { 475 t.Fatalf("nil response") 476 } 477 478 if planResp.JobModifyIndex == 0 { 479 t.Fatalf("bad JobModifyIndex value: %d", planResp.JobModifyIndex) 480 } 481 if planResp.Diff != nil { 482 t.Fatalf("got non-nil diff: %#v", planResp) 483 } 484 if planResp.Annotations == nil { 485 t.Fatalf("got nil annotations: %#v", planResp) 486 } 487 // Can make this assertion because there are no clients. 488 if len(planResp.CreatedEvals) == 0 { 489 t.Fatalf("got no CreatedEvals: %#v", planResp) 490 } 491 } 492 493 func TestJobs_JobSummary(t *testing.T) { 494 c, s := makeClient(t, nil, nil) 495 defer s.Stop() 496 jobs := c.Jobs() 497 498 // Trying to retrieve a job summary before the job exists 499 // returns an error 500 _, _, err := jobs.Summary("job1", nil) 501 if err == nil || !strings.Contains(err.Error(), "not found") { 502 t.Fatalf("expected not found error, got: %#v", err) 503 } 504 505 // Register the job 506 job := testJob() 507 taskName := job.TaskGroups[0].Name 508 _, wm, err := jobs.Register(job, nil) 509 if err != nil { 510 t.Fatalf("err: %s", err) 511 } 512 assertWriteMeta(t, wm) 513 514 // Query the job summary again and ensure it exists 515 result, qm, err := jobs.Summary("job1", nil) 516 if err != nil { 517 t.Fatalf("err: %s", err) 518 } 519 assertQueryMeta(t, qm) 520 521 // Check that the result is what we expect 522 if job.ID != result.JobID { 523 t.Fatalf("err: expected job id of %s saw %s", job.ID, result.JobID) 524 } 525 if _, ok := result.Summary[taskName]; !ok { 526 t.Fatalf("err: unable to find %s key in job summary", taskName) 527 } 528 } 529 530 func TestJobs_NewBatchJob(t *testing.T) { 531 job := NewBatchJob("job1", "myjob", "region1", 5) 532 expect := &Job{ 533 Region: "region1", 534 ID: "job1", 535 Name: "myjob", 536 Type: JobTypeBatch, 537 Priority: 5, 538 } 539 if !reflect.DeepEqual(job, expect) { 540 t.Fatalf("expect: %#v, got: %#v", expect, job) 541 } 542 } 543 544 func TestJobs_NewServiceJob(t *testing.T) { 545 job := NewServiceJob("job1", "myjob", "region1", 5) 546 expect := &Job{ 547 Region: "region1", 548 ID: "job1", 549 Name: "myjob", 550 Type: JobTypeService, 551 Priority: 5, 552 } 553 if !reflect.DeepEqual(job, expect) { 554 t.Fatalf("expect: %#v, got: %#v", expect, job) 555 } 556 } 557 558 func TestJobs_SetMeta(t *testing.T) { 559 job := &Job{Meta: nil} 560 561 // Initializes a nil map 562 out := job.SetMeta("foo", "bar") 563 if job.Meta == nil { 564 t.Fatalf("should initialize metadata") 565 } 566 567 // Check that the job was returned 568 if job != out { 569 t.Fatalf("expect: %#v, got: %#v", job, out) 570 } 571 572 // Setting another pair is additive 573 job.SetMeta("baz", "zip") 574 expect := map[string]string{"foo": "bar", "baz": "zip"} 575 if !reflect.DeepEqual(job.Meta, expect) { 576 t.Fatalf("expect: %#v, got: %#v", expect, job.Meta) 577 } 578 } 579 580 func TestJobs_Constrain(t *testing.T) { 581 job := &Job{Constraints: nil} 582 583 // Create and add a constraint 584 out := job.Constrain(NewConstraint("kernel.name", "=", "darwin")) 585 if n := len(job.Constraints); n != 1 { 586 t.Fatalf("expected 1 constraint, got: %d", n) 587 } 588 589 // Check that the job was returned 590 if job != out { 591 t.Fatalf("expect: %#v, got: %#v", job, out) 592 } 593 594 // Adding another constraint preserves the original 595 job.Constrain(NewConstraint("memory.totalbytes", ">=", "128000000")) 596 expect := []*Constraint{ 597 &Constraint{ 598 LTarget: "kernel.name", 599 RTarget: "darwin", 600 Operand: "=", 601 }, 602 &Constraint{ 603 LTarget: "memory.totalbytes", 604 RTarget: "128000000", 605 Operand: ">=", 606 }, 607 } 608 if !reflect.DeepEqual(job.Constraints, expect) { 609 t.Fatalf("expect: %#v, got: %#v", expect, job.Constraints) 610 } 611 } 612 613 func TestJobs_Sort(t *testing.T) { 614 jobs := []*JobListStub{ 615 &JobListStub{ID: "job2"}, 616 &JobListStub{ID: "job0"}, 617 &JobListStub{ID: "job1"}, 618 } 619 sort.Sort(JobIDSort(jobs)) 620 621 expect := []*JobListStub{ 622 &JobListStub{ID: "job0"}, 623 &JobListStub{ID: "job1"}, 624 &JobListStub{ID: "job2"}, 625 } 626 if !reflect.DeepEqual(jobs, expect) { 627 t.Fatalf("\n\n%#v\n\n%#v", jobs, expect) 628 } 629 }