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  }