github.com/hspak/nomad@v0.7.2-0.20180309000617-bc4ae22a39a5/api/tasks_test.go (about)

     1  package api
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/hashicorp/nomad/helper"
     9  	"github.com/hashicorp/nomad/nomad/structs"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func TestTaskGroup_NewTaskGroup(t *testing.T) {
    14  	t.Parallel()
    15  	grp := NewTaskGroup("grp1", 2)
    16  	expect := &TaskGroup{
    17  		Name:  helper.StringToPtr("grp1"),
    18  		Count: helper.IntToPtr(2),
    19  	}
    20  	if !reflect.DeepEqual(grp, expect) {
    21  		t.Fatalf("expect: %#v, got: %#v", expect, grp)
    22  	}
    23  }
    24  
    25  func TestTaskGroup_Constrain(t *testing.T) {
    26  	t.Parallel()
    27  	grp := NewTaskGroup("grp1", 1)
    28  
    29  	// Add a constraint to the group
    30  	out := grp.Constrain(NewConstraint("kernel.name", "=", "darwin"))
    31  	if n := len(grp.Constraints); n != 1 {
    32  		t.Fatalf("expected 1 constraint, got: %d", n)
    33  	}
    34  
    35  	// Check that the group was returned
    36  	if out != grp {
    37  		t.Fatalf("expected: %#v, got: %#v", grp, out)
    38  	}
    39  
    40  	// Add a second constraint
    41  	grp.Constrain(NewConstraint("memory.totalbytes", ">=", "128000000"))
    42  	expect := []*Constraint{
    43  		{
    44  			LTarget: "kernel.name",
    45  			RTarget: "darwin",
    46  			Operand: "=",
    47  		},
    48  		{
    49  			LTarget: "memory.totalbytes",
    50  			RTarget: "128000000",
    51  			Operand: ">=",
    52  		},
    53  	}
    54  	if !reflect.DeepEqual(grp.Constraints, expect) {
    55  		t.Fatalf("expect: %#v, got: %#v", expect, grp.Constraints)
    56  	}
    57  }
    58  
    59  func TestTaskGroup_SetMeta(t *testing.T) {
    60  	t.Parallel()
    61  	grp := NewTaskGroup("grp1", 1)
    62  
    63  	// Initializes an empty map
    64  	out := grp.SetMeta("foo", "bar")
    65  	if grp.Meta == nil {
    66  		t.Fatalf("should be initialized")
    67  	}
    68  
    69  	// Check that we returned the group
    70  	if out != grp {
    71  		t.Fatalf("expect: %#v, got: %#v", grp, out)
    72  	}
    73  
    74  	// Add a second meta k/v
    75  	grp.SetMeta("baz", "zip")
    76  	expect := map[string]string{"foo": "bar", "baz": "zip"}
    77  	if !reflect.DeepEqual(grp.Meta, expect) {
    78  		t.Fatalf("expect: %#v, got: %#v", expect, grp.Meta)
    79  	}
    80  }
    81  
    82  func TestTaskGroup_AddTask(t *testing.T) {
    83  	t.Parallel()
    84  	grp := NewTaskGroup("grp1", 1)
    85  
    86  	// Add the task to the task group
    87  	out := grp.AddTask(NewTask("task1", "java"))
    88  	if n := len(grp.Tasks); n != 1 {
    89  		t.Fatalf("expected 1 task, got: %d", n)
    90  	}
    91  
    92  	// Check that we returned the group
    93  	if out != grp {
    94  		t.Fatalf("expect: %#v, got: %#v", grp, out)
    95  	}
    96  
    97  	// Add a second task
    98  	grp.AddTask(NewTask("task2", "exec"))
    99  	expect := []*Task{
   100  		{
   101  			Name:   "task1",
   102  			Driver: "java",
   103  		},
   104  		{
   105  			Name:   "task2",
   106  			Driver: "exec",
   107  		},
   108  	}
   109  	if !reflect.DeepEqual(grp.Tasks, expect) {
   110  		t.Fatalf("expect: %#v, got: %#v", expect, grp.Tasks)
   111  	}
   112  }
   113  
   114  func TestTask_NewTask(t *testing.T) {
   115  	t.Parallel()
   116  	task := NewTask("task1", "exec")
   117  	expect := &Task{
   118  		Name:   "task1",
   119  		Driver: "exec",
   120  	}
   121  	if !reflect.DeepEqual(task, expect) {
   122  		t.Fatalf("expect: %#v, got: %#v", expect, task)
   123  	}
   124  }
   125  
   126  func TestTask_SetConfig(t *testing.T) {
   127  	t.Parallel()
   128  	task := NewTask("task1", "exec")
   129  
   130  	// Initializes an empty map
   131  	out := task.SetConfig("foo", "bar")
   132  	if task.Config == nil {
   133  		t.Fatalf("should be initialized")
   134  	}
   135  
   136  	// Check that we returned the task
   137  	if out != task {
   138  		t.Fatalf("expect: %#v, got: %#v", task, out)
   139  	}
   140  
   141  	// Set another config value
   142  	task.SetConfig("baz", "zip")
   143  	expect := map[string]interface{}{"foo": "bar", "baz": "zip"}
   144  	if !reflect.DeepEqual(task.Config, expect) {
   145  		t.Fatalf("expect: %#v, got: %#v", expect, task.Config)
   146  	}
   147  }
   148  
   149  func TestTask_SetMeta(t *testing.T) {
   150  	t.Parallel()
   151  	task := NewTask("task1", "exec")
   152  
   153  	// Initializes an empty map
   154  	out := task.SetMeta("foo", "bar")
   155  	if task.Meta == nil {
   156  		t.Fatalf("should be initialized")
   157  	}
   158  
   159  	// Check that we returned the task
   160  	if out != task {
   161  		t.Fatalf("expect: %#v, got: %#v", task, out)
   162  	}
   163  
   164  	// Set another meta k/v
   165  	task.SetMeta("baz", "zip")
   166  	expect := map[string]string{"foo": "bar", "baz": "zip"}
   167  	if !reflect.DeepEqual(task.Meta, expect) {
   168  		t.Fatalf("expect: %#v, got: %#v", expect, task.Meta)
   169  	}
   170  }
   171  
   172  func TestTask_Require(t *testing.T) {
   173  	t.Parallel()
   174  	task := NewTask("task1", "exec")
   175  
   176  	// Create some require resources
   177  	resources := &Resources{
   178  		CPU:      helper.IntToPtr(1250),
   179  		MemoryMB: helper.IntToPtr(128),
   180  		DiskMB:   helper.IntToPtr(2048),
   181  		IOPS:     helper.IntToPtr(500),
   182  		Networks: []*NetworkResource{
   183  			{
   184  				CIDR:          "0.0.0.0/0",
   185  				MBits:         helper.IntToPtr(100),
   186  				ReservedPorts: []Port{{"", 80}, {"", 443}},
   187  			},
   188  		},
   189  	}
   190  	out := task.Require(resources)
   191  	if !reflect.DeepEqual(task.Resources, resources) {
   192  		t.Fatalf("expect: %#v, got: %#v", resources, task.Resources)
   193  	}
   194  
   195  	// Check that we returned the task
   196  	if out != task {
   197  		t.Fatalf("expect: %#v, got: %#v", task, out)
   198  	}
   199  }
   200  
   201  func TestTask_Constrain(t *testing.T) {
   202  	t.Parallel()
   203  	task := NewTask("task1", "exec")
   204  
   205  	// Add a constraint to the task
   206  	out := task.Constrain(NewConstraint("kernel.name", "=", "darwin"))
   207  	if n := len(task.Constraints); n != 1 {
   208  		t.Fatalf("expected 1 constraint, got: %d", n)
   209  	}
   210  
   211  	// Check that the task was returned
   212  	if out != task {
   213  		t.Fatalf("expected: %#v, got: %#v", task, out)
   214  	}
   215  
   216  	// Add a second constraint
   217  	task.Constrain(NewConstraint("memory.totalbytes", ">=", "128000000"))
   218  	expect := []*Constraint{
   219  		{
   220  			LTarget: "kernel.name",
   221  			RTarget: "darwin",
   222  			Operand: "=",
   223  		},
   224  		{
   225  			LTarget: "memory.totalbytes",
   226  			RTarget: "128000000",
   227  			Operand: ">=",
   228  		},
   229  	}
   230  	if !reflect.DeepEqual(task.Constraints, expect) {
   231  		t.Fatalf("expect: %#v, got: %#v", expect, task.Constraints)
   232  	}
   233  }
   234  
   235  func TestTask_Artifact(t *testing.T) {
   236  	t.Parallel()
   237  	a := TaskArtifact{
   238  		GetterSource: helper.StringToPtr("http://localhost/foo.txt"),
   239  		GetterMode:   helper.StringToPtr("file"),
   240  	}
   241  	a.Canonicalize()
   242  	if *a.GetterMode != "file" {
   243  		t.Errorf("expected file but found %q", *a.GetterMode)
   244  	}
   245  	if *a.RelativeDest != "local/foo.txt" {
   246  		t.Errorf("expected local/foo.txt but found %q", *a.RelativeDest)
   247  	}
   248  }
   249  
   250  // Ensures no regression on https://github.com/hashicorp/nomad/issues/3132
   251  func TestTaskGroup_Canonicalize_Update(t *testing.T) {
   252  	job := &Job{
   253  		ID: helper.StringToPtr("test"),
   254  		Update: &UpdateStrategy{
   255  			AutoRevert:      helper.BoolToPtr(false),
   256  			Canary:          helper.IntToPtr(0),
   257  			HealthCheck:     helper.StringToPtr(""),
   258  			HealthyDeadline: helper.TimeToPtr(0),
   259  			MaxParallel:     helper.IntToPtr(0),
   260  			MinHealthyTime:  helper.TimeToPtr(0),
   261  			Stagger:         helper.TimeToPtr(0),
   262  		},
   263  	}
   264  	job.Canonicalize()
   265  	tg := &TaskGroup{
   266  		Name: helper.StringToPtr("foo"),
   267  	}
   268  	tg.Canonicalize(job)
   269  	assert.Nil(t, tg.Update)
   270  }
   271  
   272  // Verifies that reschedule policy is merged correctly
   273  func TestTaskGroup_Canonicalize_ReschedulePolicy(t *testing.T) {
   274  	type testCase struct {
   275  		desc                 string
   276  		jobReschedulePolicy  *ReschedulePolicy
   277  		taskReschedulePolicy *ReschedulePolicy
   278  		expected             *ReschedulePolicy
   279  	}
   280  
   281  	testCases := []testCase{
   282  		{
   283  			desc:                 "Default",
   284  			jobReschedulePolicy:  nil,
   285  			taskReschedulePolicy: nil,
   286  			expected: &ReschedulePolicy{
   287  				Attempts: helper.IntToPtr(structs.DefaultBatchJobReschedulePolicy.Attempts),
   288  				Interval: helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.Interval),
   289  			},
   290  		},
   291  		{
   292  			desc: "Empty job reschedule policy",
   293  			jobReschedulePolicy: &ReschedulePolicy{
   294  				Attempts: helper.IntToPtr(0),
   295  				Interval: helper.TimeToPtr(0),
   296  			},
   297  			taskReschedulePolicy: nil,
   298  			expected: &ReschedulePolicy{
   299  				Attempts: helper.IntToPtr(0),
   300  				Interval: helper.TimeToPtr(0),
   301  			},
   302  		},
   303  		{
   304  			desc: "Inherit from job",
   305  			jobReschedulePolicy: &ReschedulePolicy{
   306  				Attempts: helper.IntToPtr(1),
   307  				Interval: helper.TimeToPtr(20 * time.Second),
   308  			},
   309  			taskReschedulePolicy: nil,
   310  			expected: &ReschedulePolicy{
   311  				Attempts: helper.IntToPtr(1),
   312  				Interval: helper.TimeToPtr(20 * time.Second),
   313  			},
   314  		},
   315  		{
   316  			desc:                "Set in task",
   317  			jobReschedulePolicy: nil,
   318  			taskReschedulePolicy: &ReschedulePolicy{
   319  				Attempts: helper.IntToPtr(5),
   320  				Interval: helper.TimeToPtr(2 * time.Minute),
   321  			},
   322  			expected: &ReschedulePolicy{
   323  				Attempts: helper.IntToPtr(5),
   324  				Interval: helper.TimeToPtr(2 * time.Minute),
   325  			},
   326  		},
   327  		{
   328  			desc: "Merge from job",
   329  			jobReschedulePolicy: &ReschedulePolicy{
   330  				Attempts: helper.IntToPtr(1),
   331  			},
   332  			taskReschedulePolicy: &ReschedulePolicy{
   333  				Interval: helper.TimeToPtr(5 * time.Minute),
   334  			},
   335  			expected: &ReschedulePolicy{
   336  				Attempts: helper.IntToPtr(1),
   337  				Interval: helper.TimeToPtr(5 * time.Minute),
   338  			},
   339  		},
   340  		{
   341  			desc: "Override from group",
   342  			jobReschedulePolicy: &ReschedulePolicy{
   343  				Attempts: helper.IntToPtr(1),
   344  			},
   345  			taskReschedulePolicy: &ReschedulePolicy{
   346  				Attempts: helper.IntToPtr(5),
   347  			},
   348  			expected: &ReschedulePolicy{
   349  				Attempts: helper.IntToPtr(5),
   350  				Interval: helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.Interval),
   351  			},
   352  		},
   353  		{
   354  			desc: "Attempts from job, default interval",
   355  			jobReschedulePolicy: &ReschedulePolicy{
   356  				Attempts: helper.IntToPtr(1),
   357  			},
   358  			taskReschedulePolicy: nil,
   359  			expected: &ReschedulePolicy{
   360  				Attempts: helper.IntToPtr(1),
   361  				Interval: helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.Interval),
   362  			},
   363  		},
   364  	}
   365  
   366  	for _, tc := range testCases {
   367  		t.Run(tc.desc, func(t *testing.T) {
   368  			job := &Job{
   369  				ID:         helper.StringToPtr("test"),
   370  				Reschedule: tc.jobReschedulePolicy,
   371  				Type:       helper.StringToPtr(JobTypeBatch),
   372  			}
   373  			job.Canonicalize()
   374  			tg := &TaskGroup{
   375  				Name:             helper.StringToPtr("foo"),
   376  				ReschedulePolicy: tc.taskReschedulePolicy,
   377  			}
   378  			tg.Canonicalize(job)
   379  			assert.Equal(t, tc.expected, tg.ReschedulePolicy)
   380  		})
   381  	}
   382  }
   383  
   384  // TestService_CheckRestart asserts Service.CheckRestart settings are properly
   385  // inherited by Checks.
   386  func TestService_CheckRestart(t *testing.T) {
   387  	job := &Job{Name: helper.StringToPtr("job")}
   388  	tg := &TaskGroup{Name: helper.StringToPtr("group")}
   389  	task := &Task{Name: "task"}
   390  	service := &Service{
   391  		CheckRestart: &CheckRestart{
   392  			Limit:          11,
   393  			Grace:          helper.TimeToPtr(11 * time.Second),
   394  			IgnoreWarnings: true,
   395  		},
   396  		Checks: []ServiceCheck{
   397  			{
   398  				Name: "all-set",
   399  				CheckRestart: &CheckRestart{
   400  					Limit:          22,
   401  					Grace:          helper.TimeToPtr(22 * time.Second),
   402  					IgnoreWarnings: true,
   403  				},
   404  			},
   405  			{
   406  				Name: "some-set",
   407  				CheckRestart: &CheckRestart{
   408  					Limit: 33,
   409  					Grace: helper.TimeToPtr(33 * time.Second),
   410  				},
   411  			},
   412  			{
   413  				Name: "unset",
   414  			},
   415  		},
   416  	}
   417  
   418  	service.Canonicalize(task, tg, job)
   419  	assert.Equal(t, service.Checks[0].CheckRestart.Limit, 22)
   420  	assert.Equal(t, *service.Checks[0].CheckRestart.Grace, 22*time.Second)
   421  	assert.True(t, service.Checks[0].CheckRestart.IgnoreWarnings)
   422  
   423  	assert.Equal(t, service.Checks[1].CheckRestart.Limit, 33)
   424  	assert.Equal(t, *service.Checks[1].CheckRestart.Grace, 33*time.Second)
   425  	assert.True(t, service.Checks[1].CheckRestart.IgnoreWarnings)
   426  
   427  	assert.Equal(t, service.Checks[2].CheckRestart.Limit, 11)
   428  	assert.Equal(t, *service.Checks[2].CheckRestart.Grace, 11*time.Second)
   429  	assert.True(t, service.Checks[2].CheckRestart.IgnoreWarnings)
   430  }