github.com/mattyr/nomad@v0.3.3-0.20160919021406-3485a065154a/command/agent/job_endpoint_test.go (about) 1 package agent 2 3 import ( 4 "net/http" 5 "net/http/httptest" 6 "testing" 7 8 "github.com/hashicorp/nomad/nomad/mock" 9 "github.com/hashicorp/nomad/nomad/structs" 10 ) 11 12 func TestHTTP_JobsList(t *testing.T) { 13 httpTest(t, nil, func(s *TestServer) { 14 for i := 0; i < 3; i++ { 15 // Create the job 16 job := mock.Job() 17 args := structs.JobRegisterRequest{ 18 Job: job, 19 WriteRequest: structs.WriteRequest{Region: "global"}, 20 } 21 var resp structs.JobRegisterResponse 22 if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil { 23 t.Fatalf("err: %v", err) 24 } 25 } 26 27 // Make the HTTP request 28 req, err := http.NewRequest("GET", "/v1/jobs", nil) 29 if err != nil { 30 t.Fatalf("err: %v", err) 31 } 32 respW := httptest.NewRecorder() 33 34 // Make the request 35 obj, err := s.Server.JobsRequest(respW, req) 36 if err != nil { 37 t.Fatalf("err: %v", err) 38 } 39 40 // Check for the index 41 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 42 t.Fatalf("missing index") 43 } 44 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 45 t.Fatalf("missing known leader") 46 } 47 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 48 t.Fatalf("missing last contact") 49 } 50 51 // Check the job 52 j := obj.([]*structs.JobListStub) 53 if len(j) != 3 { 54 t.Fatalf("bad: %#v", j) 55 } 56 }) 57 } 58 59 func TestHTTP_PrefixJobsList(t *testing.T) { 60 ids := []string{ 61 "aaaaaaaa-e8f7-fd38-c855-ab94ceb89706", 62 "aabbbbbb-e8f7-fd38-c855-ab94ceb89706", 63 "aabbcccc-e8f7-fd38-c855-ab94ceb89706", 64 } 65 httpTest(t, nil, func(s *TestServer) { 66 for i := 0; i < 3; i++ { 67 // Create the job 68 job := mock.Job() 69 job.ID = ids[i] 70 job.TaskGroups[0].Count = 1 71 args := structs.JobRegisterRequest{ 72 Job: job, 73 WriteRequest: structs.WriteRequest{Region: "global"}, 74 } 75 var resp structs.JobRegisterResponse 76 if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil { 77 t.Fatalf("err: %v", err) 78 } 79 } 80 81 // Make the HTTP request 82 req, err := http.NewRequest("GET", "/v1/jobs?prefix=aabb", nil) 83 if err != nil { 84 t.Fatalf("err: %v", err) 85 } 86 respW := httptest.NewRecorder() 87 88 // Make the request 89 obj, err := s.Server.JobsRequest(respW, req) 90 if err != nil { 91 t.Fatalf("err: %v", err) 92 } 93 94 // Check for the index 95 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 96 t.Fatalf("missing index") 97 } 98 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 99 t.Fatalf("missing known leader") 100 } 101 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 102 t.Fatalf("missing last contact") 103 } 104 105 // Check the job 106 j := obj.([]*structs.JobListStub) 107 if len(j) != 2 { 108 t.Fatalf("bad: %#v", j) 109 } 110 }) 111 } 112 113 func TestHTTP_JobsRegister(t *testing.T) { 114 httpTest(t, nil, func(s *TestServer) { 115 // Create the job 116 job := mock.Job() 117 args := structs.JobRegisterRequest{ 118 Job: job, 119 WriteRequest: structs.WriteRequest{Region: "global"}, 120 } 121 buf := encodeReq(args) 122 123 // Make the HTTP request 124 req, err := http.NewRequest("PUT", "/v1/jobs", buf) 125 if err != nil { 126 t.Fatalf("err: %v", err) 127 } 128 respW := httptest.NewRecorder() 129 130 // Make the request 131 obj, err := s.Server.JobsRequest(respW, req) 132 if err != nil { 133 t.Fatalf("err: %v", err) 134 } 135 136 // Check the response 137 dereg := obj.(structs.JobRegisterResponse) 138 if dereg.EvalID == "" { 139 t.Fatalf("bad: %v", dereg) 140 } 141 142 // Check for the index 143 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 144 t.Fatalf("missing index") 145 } 146 147 // Check the job is registered 148 getReq := structs.JobSpecificRequest{ 149 JobID: job.ID, 150 QueryOptions: structs.QueryOptions{Region: "global"}, 151 } 152 var getResp structs.SingleJobResponse 153 if err := s.Agent.RPC("Job.GetJob", &getReq, &getResp); err != nil { 154 t.Fatalf("err: %v", err) 155 } 156 157 if getResp.Job == nil { 158 t.Fatalf("job does not exist") 159 } 160 }) 161 } 162 163 func TestHTTP_JobQuery(t *testing.T) { 164 httpTest(t, nil, func(s *TestServer) { 165 // Create the job 166 job := mock.Job() 167 args := structs.JobRegisterRequest{ 168 Job: job, 169 WriteRequest: structs.WriteRequest{Region: "global"}, 170 } 171 var resp structs.JobRegisterResponse 172 if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil { 173 t.Fatalf("err: %v", err) 174 } 175 176 // Make the HTTP request 177 req, err := http.NewRequest("GET", "/v1/job/"+job.ID, nil) 178 if err != nil { 179 t.Fatalf("err: %v", err) 180 } 181 respW := httptest.NewRecorder() 182 183 // Make the request 184 obj, err := s.Server.JobSpecificRequest(respW, req) 185 if err != nil { 186 t.Fatalf("err: %v", err) 187 } 188 189 // Check for the index 190 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 191 t.Fatalf("missing index") 192 } 193 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 194 t.Fatalf("missing known leader") 195 } 196 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 197 t.Fatalf("missing last contact") 198 } 199 200 // Check the job 201 j := obj.(*structs.Job) 202 if j.ID != job.ID { 203 t.Fatalf("bad: %#v", j) 204 } 205 }) 206 } 207 208 func TestHTTP_JobUpdate(t *testing.T) { 209 httpTest(t, nil, func(s *TestServer) { 210 // Create the job 211 job := mock.Job() 212 args := structs.JobRegisterRequest{ 213 Job: job, 214 WriteRequest: structs.WriteRequest{Region: "global"}, 215 } 216 buf := encodeReq(args) 217 218 // Make the HTTP request 219 req, err := http.NewRequest("PUT", "/v1/job/"+job.ID, buf) 220 if err != nil { 221 t.Fatalf("err: %v", err) 222 } 223 respW := httptest.NewRecorder() 224 225 // Make the request 226 obj, err := s.Server.JobSpecificRequest(respW, req) 227 if err != nil { 228 t.Fatalf("err: %v", err) 229 } 230 231 // Check the response 232 dereg := obj.(structs.JobRegisterResponse) 233 if dereg.EvalID == "" { 234 t.Fatalf("bad: %v", dereg) 235 } 236 237 // Check for the index 238 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 239 t.Fatalf("missing index") 240 } 241 242 // Check the job is registered 243 getReq := structs.JobSpecificRequest{ 244 JobID: job.ID, 245 QueryOptions: structs.QueryOptions{Region: "global"}, 246 } 247 var getResp structs.SingleJobResponse 248 if err := s.Agent.RPC("Job.GetJob", &getReq, &getResp); err != nil { 249 t.Fatalf("err: %v", err) 250 } 251 252 if getResp.Job == nil { 253 t.Fatalf("job does not exist") 254 } 255 }) 256 } 257 258 func TestHTTP_JobDelete(t *testing.T) { 259 httpTest(t, nil, func(s *TestServer) { 260 // Create the job 261 job := mock.Job() 262 args := structs.JobRegisterRequest{ 263 Job: job, 264 WriteRequest: structs.WriteRequest{Region: "global"}, 265 } 266 var resp structs.JobRegisterResponse 267 if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil { 268 t.Fatalf("err: %v", err) 269 } 270 271 // Make the HTTP request 272 req, err := http.NewRequest("DELETE", "/v1/job/"+job.ID, nil) 273 if err != nil { 274 t.Fatalf("err: %v", err) 275 } 276 respW := httptest.NewRecorder() 277 278 // Make the request 279 obj, err := s.Server.JobSpecificRequest(respW, req) 280 if err != nil { 281 t.Fatalf("err: %v", err) 282 } 283 284 // Check the response 285 dereg := obj.(structs.JobDeregisterResponse) 286 if dereg.EvalID == "" { 287 t.Fatalf("bad: %v", dereg) 288 } 289 290 // Check for the index 291 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 292 t.Fatalf("missing index") 293 } 294 295 // Check the job is gone 296 getReq := structs.JobSpecificRequest{ 297 JobID: job.ID, 298 QueryOptions: structs.QueryOptions{Region: "global"}, 299 } 300 var getResp structs.SingleJobResponse 301 if err := s.Agent.RPC("Job.GetJob", &getReq, &getResp); err != nil { 302 t.Fatalf("err: %v", err) 303 } 304 if getResp.Job != nil { 305 t.Fatalf("job still exists") 306 } 307 }) 308 } 309 310 func TestHTTP_JobForceEvaluate(t *testing.T) { 311 httpTest(t, nil, func(s *TestServer) { 312 // Create the job 313 job := mock.Job() 314 args := structs.JobRegisterRequest{ 315 Job: job, 316 WriteRequest: structs.WriteRequest{Region: "global"}, 317 } 318 var resp structs.JobRegisterResponse 319 if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil { 320 t.Fatalf("err: %v", err) 321 } 322 323 // Make the HTTP request 324 req, err := http.NewRequest("POST", "/v1/job/"+job.ID+"/evaluate", nil) 325 if err != nil { 326 t.Fatalf("err: %v", err) 327 } 328 respW := httptest.NewRecorder() 329 330 // Make the request 331 obj, err := s.Server.JobSpecificRequest(respW, req) 332 if err != nil { 333 t.Fatalf("err: %v", err) 334 } 335 336 // Check the response 337 reg := obj.(structs.JobRegisterResponse) 338 if reg.EvalID == "" { 339 t.Fatalf("bad: %v", reg) 340 } 341 342 // Check for the index 343 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 344 t.Fatalf("missing index") 345 } 346 }) 347 } 348 349 func TestHTTP_JobEvaluations(t *testing.T) { 350 httpTest(t, nil, func(s *TestServer) { 351 // Create the job 352 job := mock.Job() 353 args := structs.JobRegisterRequest{ 354 Job: job, 355 WriteRequest: structs.WriteRequest{Region: "global"}, 356 } 357 var resp structs.JobRegisterResponse 358 if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil { 359 t.Fatalf("err: %v", err) 360 } 361 362 // Make the HTTP request 363 req, err := http.NewRequest("GET", "/v1/job/"+job.ID+"/evaluations", nil) 364 if err != nil { 365 t.Fatalf("err: %v", err) 366 } 367 respW := httptest.NewRecorder() 368 369 // Make the request 370 obj, err := s.Server.JobSpecificRequest(respW, req) 371 if err != nil { 372 t.Fatalf("err: %v", err) 373 } 374 375 // Check the response 376 evals := obj.([]*structs.Evaluation) 377 // Can be multiple evals, use the last one, since they are in order 378 idx := len(evals) - 1 379 if len(evals) < 0 || evals[idx].ID != resp.EvalID { 380 t.Fatalf("bad: %v", evals) 381 } 382 383 // Check for the index 384 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 385 t.Fatalf("missing index") 386 } 387 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 388 t.Fatalf("missing known leader") 389 } 390 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 391 t.Fatalf("missing last contact") 392 } 393 }) 394 } 395 396 func TestHTTP_JobAllocations(t *testing.T) { 397 httpTest(t, nil, func(s *TestServer) { 398 // Create the job 399 job := mock.Job() 400 args := structs.JobRegisterRequest{ 401 Job: job, 402 WriteRequest: structs.WriteRequest{Region: "global"}, 403 } 404 var resp structs.JobRegisterResponse 405 if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil { 406 t.Fatalf("err: %v", err) 407 } 408 409 // Directly manipulate the state 410 state := s.Agent.server.State() 411 alloc1 := mock.Alloc() 412 alloc1.JobID = job.ID 413 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc1}) 414 if err != nil { 415 t.Fatalf("err: %v", err) 416 } 417 418 // Make the HTTP request 419 req, err := http.NewRequest("GET", "/v1/job/"+job.ID+"/allocations", nil) 420 if err != nil { 421 t.Fatalf("err: %v", err) 422 } 423 respW := httptest.NewRecorder() 424 425 // Make the request 426 obj, err := s.Server.JobSpecificRequest(respW, req) 427 if err != nil { 428 t.Fatalf("err: %v", err) 429 } 430 431 // Check the response 432 allocs := obj.([]*structs.AllocListStub) 433 if len(allocs) != 1 && allocs[0].ID != alloc1.ID { 434 t.Fatalf("bad: %v", allocs) 435 } 436 437 // Check for the index 438 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 439 t.Fatalf("missing index") 440 } 441 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 442 t.Fatalf("missing known leader") 443 } 444 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 445 t.Fatalf("missing last contact") 446 } 447 }) 448 } 449 450 func TestHTTP_PeriodicForce(t *testing.T) { 451 httpTest(t, nil, func(s *TestServer) { 452 // Create and register a periodic job. 453 job := mock.PeriodicJob() 454 args := structs.JobRegisterRequest{ 455 Job: job, 456 WriteRequest: structs.WriteRequest{Region: "global"}, 457 } 458 var resp structs.JobRegisterResponse 459 if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil { 460 t.Fatalf("err: %v", err) 461 } 462 463 // Make the HTTP request 464 req, err := http.NewRequest("POST", "/v1/job/"+job.ID+"/periodic/force", nil) 465 if err != nil { 466 t.Fatalf("err: %v", err) 467 } 468 respW := httptest.NewRecorder() 469 470 // Make the request 471 obj, err := s.Server.JobSpecificRequest(respW, req) 472 if err != nil { 473 t.Fatalf("err: %v", err) 474 } 475 476 // Check for the index 477 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 478 t.Fatalf("missing index") 479 } 480 481 // Check the response 482 r := obj.(structs.PeriodicForceResponse) 483 if r.EvalID == "" { 484 t.Fatalf("bad: %#v", r) 485 } 486 }) 487 } 488 489 func TestHTTP_JobPlan(t *testing.T) { 490 httpTest(t, nil, func(s *TestServer) { 491 // Create the job 492 job := mock.Job() 493 args := structs.JobPlanRequest{ 494 Job: job, 495 Diff: true, 496 WriteRequest: structs.WriteRequest{Region: "global"}, 497 } 498 buf := encodeReq(args) 499 500 // Make the HTTP request 501 req, err := http.NewRequest("PUT", "/v1/job/"+job.ID+"/plan", buf) 502 if err != nil { 503 t.Fatalf("err: %v", err) 504 } 505 respW := httptest.NewRecorder() 506 507 // Make the request 508 obj, err := s.Server.JobSpecificRequest(respW, req) 509 if err != nil { 510 t.Fatalf("err: %v", err) 511 } 512 513 // Check the response 514 plan := obj.(structs.JobPlanResponse) 515 if plan.Annotations == nil { 516 t.Fatalf("bad: %v", plan) 517 } 518 519 if plan.Diff == nil { 520 t.Fatalf("bad: %v", plan) 521 } 522 }) 523 }