github.com/mongey/nomad@v0.5.2/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 alloc1 := mock.Alloc() 400 args := structs.JobRegisterRequest{ 401 Job: alloc1.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 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc1}) 412 if err != nil { 413 t.Fatalf("err: %v", err) 414 } 415 416 // Make the HTTP request 417 req, err := http.NewRequest("GET", "/v1/job/"+alloc1.Job.ID+"/allocations?all=true", nil) 418 if err != nil { 419 t.Fatalf("err: %v", err) 420 } 421 respW := httptest.NewRecorder() 422 423 // Make the request 424 obj, err := s.Server.JobSpecificRequest(respW, req) 425 if err != nil { 426 t.Fatalf("err: %v", err) 427 } 428 429 // Check the response 430 allocs := obj.([]*structs.AllocListStub) 431 if len(allocs) != 1 && allocs[0].ID != alloc1.ID { 432 t.Fatalf("bad: %v", allocs) 433 } 434 435 // Check for the index 436 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 437 t.Fatalf("missing index") 438 } 439 if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { 440 t.Fatalf("missing known leader") 441 } 442 if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { 443 t.Fatalf("missing last contact") 444 } 445 }) 446 } 447 448 func TestHTTP_PeriodicForce(t *testing.T) { 449 httpTest(t, nil, func(s *TestServer) { 450 // Create and register a periodic job. 451 job := mock.PeriodicJob() 452 args := structs.JobRegisterRequest{ 453 Job: job, 454 WriteRequest: structs.WriteRequest{Region: "global"}, 455 } 456 var resp structs.JobRegisterResponse 457 if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil { 458 t.Fatalf("err: %v", err) 459 } 460 461 // Make the HTTP request 462 req, err := http.NewRequest("POST", "/v1/job/"+job.ID+"/periodic/force", nil) 463 if err != nil { 464 t.Fatalf("err: %v", err) 465 } 466 respW := httptest.NewRecorder() 467 468 // Make the request 469 obj, err := s.Server.JobSpecificRequest(respW, req) 470 if err != nil { 471 t.Fatalf("err: %v", err) 472 } 473 474 // Check for the index 475 if respW.HeaderMap.Get("X-Nomad-Index") == "" { 476 t.Fatalf("missing index") 477 } 478 479 // Check the response 480 r := obj.(structs.PeriodicForceResponse) 481 if r.EvalID == "" { 482 t.Fatalf("bad: %#v", r) 483 } 484 }) 485 } 486 487 func TestHTTP_JobPlan(t *testing.T) { 488 httpTest(t, nil, func(s *TestServer) { 489 // Create the job 490 job := mock.Job() 491 args := structs.JobPlanRequest{ 492 Job: job, 493 Diff: true, 494 WriteRequest: structs.WriteRequest{Region: "global"}, 495 } 496 buf := encodeReq(args) 497 498 // Make the HTTP request 499 req, err := http.NewRequest("PUT", "/v1/job/"+job.ID+"/plan", buf) 500 if err != nil { 501 t.Fatalf("err: %v", err) 502 } 503 respW := httptest.NewRecorder() 504 505 // Make the request 506 obj, err := s.Server.JobSpecificRequest(respW, req) 507 if err != nil { 508 t.Fatalf("err: %v", err) 509 } 510 511 // Check the response 512 plan := obj.(structs.JobPlanResponse) 513 if plan.Annotations == nil { 514 t.Fatalf("bad: %v", plan) 515 } 516 517 if plan.Diff == nil { 518 t.Fatalf("bad: %v", plan) 519 } 520 }) 521 }