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  }