github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/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_Info(t *testing.T) { 54 c, s := makeClient(t, nil, nil) 55 defer s.Stop() 56 jobs := c.Jobs() 57 58 // Trying to retrieve a job by ID before it exists 59 // returns an error 60 _, _, err := jobs.Info("job1", nil) 61 if err == nil || !strings.Contains(err.Error(), "not found") { 62 t.Fatalf("expected not found error, got: %#v", err) 63 } 64 65 // Register the job 66 job := testJob() 67 _, wm, err := jobs.Register(job, nil) 68 if err != nil { 69 t.Fatalf("err: %s", err) 70 } 71 assertWriteMeta(t, wm) 72 73 // Query the job again and ensure it exists 74 result, qm, err := jobs.Info("job1", nil) 75 if err != nil { 76 t.Fatalf("err: %s", err) 77 } 78 assertQueryMeta(t, qm) 79 80 // Check that the result is what we expect 81 if result == nil || result.ID != job.ID { 82 t.Fatalf("expect: %#v, got: %#v", job, result) 83 } 84 } 85 86 func TestJobs_PrefixList(t *testing.T) { 87 c, s := makeClient(t, nil, nil) 88 defer s.Stop() 89 jobs := c.Jobs() 90 91 // Listing when nothing exists returns empty 92 results, qm, err := jobs.PrefixList("dummy") 93 if err != nil { 94 t.Fatalf("err: %s", err) 95 } 96 if qm.LastIndex != 0 { 97 t.Fatalf("bad index: %d", qm.LastIndex) 98 } 99 if n := len(results); n != 0 { 100 t.Fatalf("expected 0 jobs, got: %d", n) 101 } 102 103 // Register the job 104 job := testJob() 105 _, wm, err := jobs.Register(job, nil) 106 if err != nil { 107 t.Fatalf("err: %s", err) 108 } 109 assertWriteMeta(t, wm) 110 111 // Query the job again and ensure it exists 112 // Listing when nothing exists returns empty 113 results, qm, err = jobs.PrefixList(job.ID[:1]) 114 if err != nil { 115 t.Fatalf("err: %s", err) 116 } 117 118 // Check if we have the right list 119 if len(results) != 1 || results[0].ID != job.ID { 120 t.Fatalf("bad: %#v", results) 121 } 122 } 123 124 func TestJobs_List(t *testing.T) { 125 c, s := makeClient(t, nil, nil) 126 defer s.Stop() 127 jobs := c.Jobs() 128 129 // Listing when nothing exists returns empty 130 results, qm, err := jobs.List(nil) 131 if err != nil { 132 t.Fatalf("err: %s", err) 133 } 134 if qm.LastIndex != 0 { 135 t.Fatalf("bad index: %d", qm.LastIndex) 136 } 137 if n := len(results); n != 0 { 138 t.Fatalf("expected 0 jobs, got: %d", n) 139 } 140 141 // Register the job 142 job := testJob() 143 _, wm, err := jobs.Register(job, nil) 144 if err != nil { 145 t.Fatalf("err: %s", err) 146 } 147 assertWriteMeta(t, wm) 148 149 // Query the job again and ensure it exists 150 // Listing when nothing exists returns empty 151 results, qm, err = jobs.List(nil) 152 if err != nil { 153 t.Fatalf("err: %s", err) 154 } 155 156 // Check if we have the right list 157 if len(results) != 1 || results[0].ID != job.ID { 158 t.Fatalf("bad: %#v", results) 159 } 160 } 161 162 func TestJobs_Allocations(t *testing.T) { 163 c, s := makeClient(t, nil, nil) 164 defer s.Stop() 165 jobs := c.Jobs() 166 167 // Looking up by a non-existent job returns nothing 168 allocs, qm, err := jobs.Allocations("job1", nil) 169 if err != nil { 170 t.Fatalf("err: %s", err) 171 } 172 if qm.LastIndex != 0 { 173 t.Fatalf("bad index: %d", qm.LastIndex) 174 } 175 if n := len(allocs); n != 0 { 176 t.Fatalf("expected 0 allocs, got: %d", n) 177 } 178 179 // TODO: do something here to create some allocations for 180 // an existing job, lookup again. 181 } 182 183 func TestJobs_Evaluations(t *testing.T) { 184 c, s := makeClient(t, nil, nil) 185 defer s.Stop() 186 jobs := c.Jobs() 187 188 // Looking up by a non-existent job ID returns nothing 189 evals, qm, err := jobs.Evaluations("job1", nil) 190 if err != nil { 191 t.Fatalf("err: %s", err) 192 } 193 if qm.LastIndex != 0 { 194 t.Fatalf("bad index: %d", qm.LastIndex) 195 } 196 if n := len(evals); n != 0 { 197 t.Fatalf("expected 0 evals, got: %d", n) 198 } 199 200 // Insert a job. This also creates an evaluation so we should 201 // be able to query that out after. 202 job := testJob() 203 evalID, wm, err := jobs.Register(job, nil) 204 if err != nil { 205 t.Fatalf("err: %s", err) 206 } 207 assertWriteMeta(t, wm) 208 209 // Look up the evaluations again. 210 evals, qm, err = jobs.Evaluations("job1", nil) 211 if err != nil { 212 t.Fatalf("err: %s", err) 213 } 214 assertQueryMeta(t, qm) 215 216 // Check that we got the evals back 217 if n := len(evals); n == 0 || evals[0].ID != evalID { 218 t.Fatalf("expected 1 eval (%s), got: %#v", evalID, evals) 219 } 220 } 221 222 func TestJobs_Deregister(t *testing.T) { 223 c, s := makeClient(t, nil, nil) 224 defer s.Stop() 225 jobs := c.Jobs() 226 227 // Register a new job 228 job := testJob() 229 _, wm, err := jobs.Register(job, nil) 230 if err != nil { 231 t.Fatalf("err: %s", err) 232 } 233 assertWriteMeta(t, wm) 234 235 // Attempting delete on non-existing job returns an error 236 if _, _, err = jobs.Deregister("nope", nil); err != nil { 237 t.Fatalf("unexpected error deregistering job: %v", err) 238 239 } 240 241 // Deleting an existing job works 242 evalID, wm3, err := jobs.Deregister("job1", nil) 243 if err != nil { 244 t.Fatalf("err: %s", err) 245 } 246 assertWriteMeta(t, wm3) 247 if evalID == "" { 248 t.Fatalf("missing eval ID") 249 } 250 251 // Check that the job is really gone 252 result, qm, err := jobs.List(nil) 253 if err != nil { 254 t.Fatalf("err: %s", err) 255 } 256 assertQueryMeta(t, qm) 257 if n := len(result); n != 0 { 258 t.Fatalf("expected 0 jobs, got: %d", n) 259 } 260 } 261 262 func TestJobs_ForceEvaluate(t *testing.T) { 263 c, s := makeClient(t, nil, nil) 264 defer s.Stop() 265 jobs := c.Jobs() 266 267 // Force-eval on a non-existent job fails 268 _, _, err := jobs.ForceEvaluate("job1", nil) 269 if err == nil || !strings.Contains(err.Error(), "not found") { 270 t.Fatalf("expected not found error, got: %#v", err) 271 } 272 273 // Create a new job 274 _, wm, err := jobs.Register(testJob(), nil) 275 if err != nil { 276 t.Fatalf("err: %s", err) 277 } 278 assertWriteMeta(t, wm) 279 280 // Try force-eval again 281 evalID, wm, err := jobs.ForceEvaluate("job1", nil) 282 if err != nil { 283 t.Fatalf("err: %s", err) 284 } 285 assertWriteMeta(t, wm) 286 287 // Retrieve the evals and see if we get a matching one 288 evals, qm, err := jobs.Evaluations("job1", nil) 289 if err != nil { 290 t.Fatalf("err: %s", err) 291 } 292 assertQueryMeta(t, qm) 293 for _, eval := range evals { 294 if eval.ID == evalID { 295 return 296 } 297 } 298 t.Fatalf("evaluation %q missing", evalID) 299 } 300 301 func TestJobs_PeriodicForce(t *testing.T) { 302 c, s := makeClient(t, nil, nil) 303 defer s.Stop() 304 jobs := c.Jobs() 305 306 // Force-eval on a non-existent job fails 307 _, _, err := jobs.PeriodicForce("job1", nil) 308 if err == nil || !strings.Contains(err.Error(), "not found") { 309 t.Fatalf("expected not found error, got: %#v", err) 310 } 311 312 // Create a new job 313 job := testPeriodicJob() 314 _, _, err = jobs.Register(job, nil) 315 if err != nil { 316 t.Fatalf("err: %s", err) 317 } 318 319 testutil.WaitForResult(func() (bool, error) { 320 out, _, err := jobs.Info(job.ID, nil) 321 if err != nil || out == nil || out.ID != job.ID { 322 return false, err 323 } 324 return true, nil 325 }, func(err error) { 326 t.Fatalf("err: %s", err) 327 }) 328 329 // Try force again 330 evalID, wm, err := jobs.PeriodicForce(job.ID, nil) 331 if err != nil { 332 t.Fatalf("err: %s", err) 333 } 334 assertWriteMeta(t, wm) 335 336 if evalID == "" { 337 t.Fatalf("empty evalID") 338 } 339 340 // Retrieve the eval 341 evals := c.Evaluations() 342 eval, qm, err := evals.Info(evalID, nil) 343 if err != nil { 344 t.Fatalf("err: %s", err) 345 } 346 assertQueryMeta(t, qm) 347 if eval.ID == evalID { 348 return 349 } 350 t.Fatalf("evaluation %q missing", evalID) 351 } 352 353 func TestJobs_Plan(t *testing.T) { 354 c, s := makeClient(t, nil, nil) 355 defer s.Stop() 356 jobs := c.Jobs() 357 358 // Create a job and attempt to register it 359 job := testJob() 360 eval, wm, err := jobs.Register(job, nil) 361 if err != nil { 362 t.Fatalf("err: %s", err) 363 } 364 if eval == "" { 365 t.Fatalf("missing eval id") 366 } 367 assertWriteMeta(t, wm) 368 369 // Check that passing a nil job fails 370 if _, _, err := jobs.Plan(nil, true, nil); err == nil { 371 t.Fatalf("expect an error when job isn't provided") 372 } 373 374 // Make a plan request 375 planResp, wm, err := jobs.Plan(job, true, nil) 376 if err != nil { 377 t.Fatalf("err: %s", err) 378 } 379 if planResp == nil { 380 t.Fatalf("nil response") 381 } 382 383 if planResp.JobModifyIndex == 0 { 384 t.Fatalf("bad JobModifyIndex value: %#v", planResp) 385 } 386 if planResp.Diff == nil { 387 t.Fatalf("got nil diff: %#v", planResp) 388 } 389 if planResp.Annotations == nil { 390 t.Fatalf("got nil annotations: %#v", planResp) 391 } 392 // Can make this assertion because there are no clients. 393 if len(planResp.CreatedEvals) == 0 { 394 t.Fatalf("got no CreatedEvals: %#v", planResp) 395 } 396 397 // Make a plan request w/o the diff 398 planResp, wm, err = jobs.Plan(job, false, nil) 399 if err != nil { 400 t.Fatalf("err: %s", err) 401 } 402 assertWriteMeta(t, wm) 403 404 if planResp == nil { 405 t.Fatalf("nil response") 406 } 407 408 if planResp.JobModifyIndex == 0 { 409 t.Fatalf("bad JobModifyIndex value: %d", planResp.JobModifyIndex) 410 } 411 if planResp.Diff != nil { 412 t.Fatalf("got non-nil diff: %#v", planResp) 413 } 414 if planResp.Annotations == nil { 415 t.Fatalf("got nil annotations: %#v", planResp) 416 } 417 // Can make this assertion because there are no clients. 418 if len(planResp.CreatedEvals) == 0 { 419 t.Fatalf("got no CreatedEvals: %#v", planResp) 420 } 421 } 422 423 func TestJobs_NewBatchJob(t *testing.T) { 424 job := NewBatchJob("job1", "myjob", "region1", 5) 425 expect := &Job{ 426 Region: "region1", 427 ID: "job1", 428 Name: "myjob", 429 Type: JobTypeBatch, 430 Priority: 5, 431 } 432 if !reflect.DeepEqual(job, expect) { 433 t.Fatalf("expect: %#v, got: %#v", expect, job) 434 } 435 } 436 437 func TestJobs_NewServiceJob(t *testing.T) { 438 job := NewServiceJob("job1", "myjob", "region1", 5) 439 expect := &Job{ 440 Region: "region1", 441 ID: "job1", 442 Name: "myjob", 443 Type: JobTypeService, 444 Priority: 5, 445 } 446 if !reflect.DeepEqual(job, expect) { 447 t.Fatalf("expect: %#v, got: %#v", expect, job) 448 } 449 } 450 451 func TestJobs_SetMeta(t *testing.T) { 452 job := &Job{Meta: nil} 453 454 // Initializes a nil map 455 out := job.SetMeta("foo", "bar") 456 if job.Meta == nil { 457 t.Fatalf("should initialize metadata") 458 } 459 460 // Check that the job was returned 461 if job != out { 462 t.Fatalf("expect: %#v, got: %#v", job, out) 463 } 464 465 // Setting another pair is additive 466 job.SetMeta("baz", "zip") 467 expect := map[string]string{"foo": "bar", "baz": "zip"} 468 if !reflect.DeepEqual(job.Meta, expect) { 469 t.Fatalf("expect: %#v, got: %#v", expect, job.Meta) 470 } 471 } 472 473 func TestJobs_Constrain(t *testing.T) { 474 job := &Job{Constraints: nil} 475 476 // Create and add a constraint 477 out := job.Constrain(NewConstraint("kernel.name", "=", "darwin")) 478 if n := len(job.Constraints); n != 1 { 479 t.Fatalf("expected 1 constraint, got: %d", n) 480 } 481 482 // Check that the job was returned 483 if job != out { 484 t.Fatalf("expect: %#v, got: %#v", job, out) 485 } 486 487 // Adding another constraint preserves the original 488 job.Constrain(NewConstraint("memory.totalbytes", ">=", "128000000")) 489 expect := []*Constraint{ 490 &Constraint{ 491 LTarget: "kernel.name", 492 RTarget: "darwin", 493 Operand: "=", 494 }, 495 &Constraint{ 496 LTarget: "memory.totalbytes", 497 RTarget: "128000000", 498 Operand: ">=", 499 }, 500 } 501 if !reflect.DeepEqual(job.Constraints, expect) { 502 t.Fatalf("expect: %#v, got: %#v", expect, job.Constraints) 503 } 504 } 505 506 func TestJobs_Sort(t *testing.T) { 507 jobs := []*JobListStub{ 508 &JobListStub{ID: "job2"}, 509 &JobListStub{ID: "job0"}, 510 &JobListStub{ID: "job1"}, 511 } 512 sort.Sort(JobIDSort(jobs)) 513 514 expect := []*JobListStub{ 515 &JobListStub{ID: "job0"}, 516 &JobListStub{ID: "job1"}, 517 &JobListStub{ID: "job2"}, 518 } 519 if !reflect.DeepEqual(jobs, expect) { 520 t.Fatalf("\n\n%#v\n\n%#v", jobs, expect) 521 } 522 }