github.com/emate/nomad@v0.8.2-wo-binpacking/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  				Delay:         helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.Delay),
   290  				DelayFunction: helper.StringToPtr(structs.DefaultBatchJobReschedulePolicy.DelayFunction),
   291  				MaxDelay:      helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.MaxDelay),
   292  				Unlimited:     helper.BoolToPtr(structs.DefaultBatchJobReschedulePolicy.Unlimited),
   293  			},
   294  		},
   295  		{
   296  			desc: "Empty job reschedule policy",
   297  			jobReschedulePolicy: &ReschedulePolicy{
   298  				Attempts:      helper.IntToPtr(0),
   299  				Interval:      helper.TimeToPtr(0),
   300  				Delay:         helper.TimeToPtr(0),
   301  				MaxDelay:      helper.TimeToPtr(0),
   302  				DelayFunction: helper.StringToPtr(""),
   303  				Unlimited:     helper.BoolToPtr(false),
   304  			},
   305  			taskReschedulePolicy: nil,
   306  			expected: &ReschedulePolicy{
   307  				Attempts:      helper.IntToPtr(0),
   308  				Interval:      helper.TimeToPtr(0),
   309  				Delay:         helper.TimeToPtr(0),
   310  				MaxDelay:      helper.TimeToPtr(0),
   311  				DelayFunction: helper.StringToPtr(""),
   312  				Unlimited:     helper.BoolToPtr(false),
   313  			},
   314  		},
   315  		{
   316  			desc: "Inherit from job",
   317  			jobReschedulePolicy: &ReschedulePolicy{
   318  				Attempts:      helper.IntToPtr(1),
   319  				Interval:      helper.TimeToPtr(20 * time.Second),
   320  				Delay:         helper.TimeToPtr(20 * time.Second),
   321  				MaxDelay:      helper.TimeToPtr(10 * time.Minute),
   322  				DelayFunction: helper.StringToPtr("constant"),
   323  				Unlimited:     helper.BoolToPtr(false),
   324  			},
   325  			taskReschedulePolicy: nil,
   326  			expected: &ReschedulePolicy{
   327  				Attempts:      helper.IntToPtr(1),
   328  				Interval:      helper.TimeToPtr(20 * time.Second),
   329  				Delay:         helper.TimeToPtr(20 * time.Second),
   330  				MaxDelay:      helper.TimeToPtr(10 * time.Minute),
   331  				DelayFunction: helper.StringToPtr("constant"),
   332  				Unlimited:     helper.BoolToPtr(false),
   333  			},
   334  		},
   335  		{
   336  			desc:                "Set in task",
   337  			jobReschedulePolicy: nil,
   338  			taskReschedulePolicy: &ReschedulePolicy{
   339  				Attempts:      helper.IntToPtr(5),
   340  				Interval:      helper.TimeToPtr(2 * time.Minute),
   341  				Delay:         helper.TimeToPtr(20 * time.Second),
   342  				MaxDelay:      helper.TimeToPtr(10 * time.Minute),
   343  				DelayFunction: helper.StringToPtr("constant"),
   344  				Unlimited:     helper.BoolToPtr(false),
   345  			},
   346  			expected: &ReschedulePolicy{
   347  				Attempts:      helper.IntToPtr(5),
   348  				Interval:      helper.TimeToPtr(2 * time.Minute),
   349  				Delay:         helper.TimeToPtr(20 * time.Second),
   350  				MaxDelay:      helper.TimeToPtr(10 * time.Minute),
   351  				DelayFunction: helper.StringToPtr("constant"),
   352  				Unlimited:     helper.BoolToPtr(false),
   353  			},
   354  		},
   355  		{
   356  			desc: "Merge from job",
   357  			jobReschedulePolicy: &ReschedulePolicy{
   358  				Attempts: helper.IntToPtr(1),
   359  				Delay:    helper.TimeToPtr(20 * time.Second),
   360  				MaxDelay: helper.TimeToPtr(10 * time.Minute),
   361  			},
   362  			taskReschedulePolicy: &ReschedulePolicy{
   363  				Interval:      helper.TimeToPtr(5 * time.Minute),
   364  				DelayFunction: helper.StringToPtr("constant"),
   365  				Unlimited:     helper.BoolToPtr(false),
   366  			},
   367  			expected: &ReschedulePolicy{
   368  				Attempts:      helper.IntToPtr(1),
   369  				Interval:      helper.TimeToPtr(5 * time.Minute),
   370  				Delay:         helper.TimeToPtr(20 * time.Second),
   371  				MaxDelay:      helper.TimeToPtr(10 * time.Minute),
   372  				DelayFunction: helper.StringToPtr("constant"),
   373  				Unlimited:     helper.BoolToPtr(false),
   374  			},
   375  		},
   376  		{
   377  			desc: "Override from group",
   378  			jobReschedulePolicy: &ReschedulePolicy{
   379  				Attempts: helper.IntToPtr(1),
   380  				MaxDelay: helper.TimeToPtr(10 * time.Second),
   381  			},
   382  			taskReschedulePolicy: &ReschedulePolicy{
   383  				Attempts:      helper.IntToPtr(5),
   384  				Delay:         helper.TimeToPtr(20 * time.Second),
   385  				MaxDelay:      helper.TimeToPtr(20 * time.Minute),
   386  				DelayFunction: helper.StringToPtr("constant"),
   387  				Unlimited:     helper.BoolToPtr(false),
   388  			},
   389  			expected: &ReschedulePolicy{
   390  				Attempts:      helper.IntToPtr(5),
   391  				Interval:      helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.Interval),
   392  				Delay:         helper.TimeToPtr(20 * time.Second),
   393  				MaxDelay:      helper.TimeToPtr(20 * time.Minute),
   394  				DelayFunction: helper.StringToPtr("constant"),
   395  				Unlimited:     helper.BoolToPtr(false),
   396  			},
   397  		},
   398  		{
   399  			desc: "Attempts from job, default interval",
   400  			jobReschedulePolicy: &ReschedulePolicy{
   401  				Attempts: helper.IntToPtr(1),
   402  			},
   403  			taskReschedulePolicy: nil,
   404  			expected: &ReschedulePolicy{
   405  				Attempts:      helper.IntToPtr(1),
   406  				Interval:      helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.Interval),
   407  				Delay:         helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.Delay),
   408  				DelayFunction: helper.StringToPtr(structs.DefaultBatchJobReschedulePolicy.DelayFunction),
   409  				MaxDelay:      helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.MaxDelay),
   410  				Unlimited:     helper.BoolToPtr(structs.DefaultBatchJobReschedulePolicy.Unlimited),
   411  			},
   412  		},
   413  	}
   414  
   415  	for _, tc := range testCases {
   416  		t.Run(tc.desc, func(t *testing.T) {
   417  			job := &Job{
   418  				ID:         helper.StringToPtr("test"),
   419  				Reschedule: tc.jobReschedulePolicy,
   420  				Type:       helper.StringToPtr(JobTypeBatch),
   421  			}
   422  			job.Canonicalize()
   423  			tg := &TaskGroup{
   424  				Name:             helper.StringToPtr("foo"),
   425  				ReschedulePolicy: tc.taskReschedulePolicy,
   426  			}
   427  			tg.Canonicalize(job)
   428  			assert.Equal(t, tc.expected, tg.ReschedulePolicy)
   429  		})
   430  	}
   431  }
   432  
   433  // Verifies that migrate strategy is merged correctly
   434  func TestTaskGroup_Canonicalize_MigrateStrategy(t *testing.T) {
   435  	type testCase struct {
   436  		desc        string
   437  		jobType     string
   438  		jobMigrate  *MigrateStrategy
   439  		taskMigrate *MigrateStrategy
   440  		expected    *MigrateStrategy
   441  	}
   442  
   443  	testCases := []testCase{
   444  		{
   445  			desc:        "Default batch",
   446  			jobType:     "batch",
   447  			jobMigrate:  nil,
   448  			taskMigrate: nil,
   449  			expected:    nil,
   450  		},
   451  		{
   452  			desc:        "Default service",
   453  			jobType:     "service",
   454  			jobMigrate:  nil,
   455  			taskMigrate: nil,
   456  			expected: &MigrateStrategy{
   457  				MaxParallel:     helper.IntToPtr(1),
   458  				HealthCheck:     helper.StringToPtr("checks"),
   459  				MinHealthyTime:  helper.TimeToPtr(10 * time.Second),
   460  				HealthyDeadline: helper.TimeToPtr(5 * time.Minute),
   461  			},
   462  		},
   463  		{
   464  			desc:    "Empty job migrate strategy",
   465  			jobType: "service",
   466  			jobMigrate: &MigrateStrategy{
   467  				MaxParallel:     helper.IntToPtr(0),
   468  				HealthCheck:     helper.StringToPtr(""),
   469  				MinHealthyTime:  helper.TimeToPtr(0),
   470  				HealthyDeadline: helper.TimeToPtr(0),
   471  			},
   472  			taskMigrate: nil,
   473  			expected: &MigrateStrategy{
   474  				MaxParallel:     helper.IntToPtr(0),
   475  				HealthCheck:     helper.StringToPtr(""),
   476  				MinHealthyTime:  helper.TimeToPtr(0),
   477  				HealthyDeadline: helper.TimeToPtr(0),
   478  			},
   479  		},
   480  		{
   481  			desc:    "Inherit from job",
   482  			jobType: "service",
   483  			jobMigrate: &MigrateStrategy{
   484  				MaxParallel:     helper.IntToPtr(3),
   485  				HealthCheck:     helper.StringToPtr("checks"),
   486  				MinHealthyTime:  helper.TimeToPtr(2),
   487  				HealthyDeadline: helper.TimeToPtr(2),
   488  			},
   489  			taskMigrate: nil,
   490  			expected: &MigrateStrategy{
   491  				MaxParallel:     helper.IntToPtr(3),
   492  				HealthCheck:     helper.StringToPtr("checks"),
   493  				MinHealthyTime:  helper.TimeToPtr(2),
   494  				HealthyDeadline: helper.TimeToPtr(2),
   495  			},
   496  		},
   497  		{
   498  			desc:       "Set in task",
   499  			jobType:    "service",
   500  			jobMigrate: nil,
   501  			taskMigrate: &MigrateStrategy{
   502  				MaxParallel:     helper.IntToPtr(3),
   503  				HealthCheck:     helper.StringToPtr("checks"),
   504  				MinHealthyTime:  helper.TimeToPtr(2),
   505  				HealthyDeadline: helper.TimeToPtr(2),
   506  			},
   507  			expected: &MigrateStrategy{
   508  				MaxParallel:     helper.IntToPtr(3),
   509  				HealthCheck:     helper.StringToPtr("checks"),
   510  				MinHealthyTime:  helper.TimeToPtr(2),
   511  				HealthyDeadline: helper.TimeToPtr(2),
   512  			},
   513  		},
   514  		{
   515  			desc:    "Merge from job",
   516  			jobType: "service",
   517  			jobMigrate: &MigrateStrategy{
   518  				MaxParallel: helper.IntToPtr(11),
   519  			},
   520  			taskMigrate: &MigrateStrategy{
   521  				HealthCheck:     helper.StringToPtr("checks"),
   522  				MinHealthyTime:  helper.TimeToPtr(2),
   523  				HealthyDeadline: helper.TimeToPtr(2),
   524  			},
   525  			expected: &MigrateStrategy{
   526  				MaxParallel:     helper.IntToPtr(11),
   527  				HealthCheck:     helper.StringToPtr("checks"),
   528  				MinHealthyTime:  helper.TimeToPtr(2),
   529  				HealthyDeadline: helper.TimeToPtr(2),
   530  			},
   531  		},
   532  		{
   533  			desc:    "Override from group",
   534  			jobType: "service",
   535  			jobMigrate: &MigrateStrategy{
   536  				MaxParallel: helper.IntToPtr(11),
   537  			},
   538  			taskMigrate: &MigrateStrategy{
   539  				MaxParallel:     helper.IntToPtr(5),
   540  				HealthCheck:     helper.StringToPtr("checks"),
   541  				MinHealthyTime:  helper.TimeToPtr(2),
   542  				HealthyDeadline: helper.TimeToPtr(2),
   543  			},
   544  			expected: &MigrateStrategy{
   545  				MaxParallel:     helper.IntToPtr(5),
   546  				HealthCheck:     helper.StringToPtr("checks"),
   547  				MinHealthyTime:  helper.TimeToPtr(2),
   548  				HealthyDeadline: helper.TimeToPtr(2),
   549  			},
   550  		},
   551  		{
   552  			desc:    "Parallel from job, defaulting",
   553  			jobType: "service",
   554  			jobMigrate: &MigrateStrategy{
   555  				MaxParallel: helper.IntToPtr(5),
   556  			},
   557  			taskMigrate: nil,
   558  			expected: &MigrateStrategy{
   559  				MaxParallel:     helper.IntToPtr(5),
   560  				HealthCheck:     helper.StringToPtr("checks"),
   561  				MinHealthyTime:  helper.TimeToPtr(10 * time.Second),
   562  				HealthyDeadline: helper.TimeToPtr(5 * time.Minute),
   563  			},
   564  		},
   565  	}
   566  
   567  	for _, tc := range testCases {
   568  		t.Run(tc.desc, func(t *testing.T) {
   569  			job := &Job{
   570  				ID:      helper.StringToPtr("test"),
   571  				Migrate: tc.jobMigrate,
   572  				Type:    helper.StringToPtr(tc.jobType),
   573  			}
   574  			job.Canonicalize()
   575  			tg := &TaskGroup{
   576  				Name:    helper.StringToPtr("foo"),
   577  				Migrate: tc.taskMigrate,
   578  			}
   579  			tg.Canonicalize(job)
   580  			assert.Equal(t, tc.expected, tg.Migrate)
   581  		})
   582  	}
   583  }
   584  
   585  // TestService_CheckRestart asserts Service.CheckRestart settings are properly
   586  // inherited by Checks.
   587  func TestService_CheckRestart(t *testing.T) {
   588  	job := &Job{Name: helper.StringToPtr("job")}
   589  	tg := &TaskGroup{Name: helper.StringToPtr("group")}
   590  	task := &Task{Name: "task"}
   591  	service := &Service{
   592  		CheckRestart: &CheckRestart{
   593  			Limit:          11,
   594  			Grace:          helper.TimeToPtr(11 * time.Second),
   595  			IgnoreWarnings: true,
   596  		},
   597  		Checks: []ServiceCheck{
   598  			{
   599  				Name: "all-set",
   600  				CheckRestart: &CheckRestart{
   601  					Limit:          22,
   602  					Grace:          helper.TimeToPtr(22 * time.Second),
   603  					IgnoreWarnings: true,
   604  				},
   605  			},
   606  			{
   607  				Name: "some-set",
   608  				CheckRestart: &CheckRestart{
   609  					Limit: 33,
   610  					Grace: helper.TimeToPtr(33 * time.Second),
   611  				},
   612  			},
   613  			{
   614  				Name: "unset",
   615  			},
   616  		},
   617  	}
   618  
   619  	service.Canonicalize(task, tg, job)
   620  	assert.Equal(t, service.Checks[0].CheckRestart.Limit, 22)
   621  	assert.Equal(t, *service.Checks[0].CheckRestart.Grace, 22*time.Second)
   622  	assert.True(t, service.Checks[0].CheckRestart.IgnoreWarnings)
   623  
   624  	assert.Equal(t, service.Checks[1].CheckRestart.Limit, 33)
   625  	assert.Equal(t, *service.Checks[1].CheckRestart.Grace, 33*time.Second)
   626  	assert.True(t, service.Checks[1].CheckRestart.IgnoreWarnings)
   627  
   628  	assert.Equal(t, service.Checks[2].CheckRestart.Limit, 11)
   629  	assert.Equal(t, *service.Checks[2].CheckRestart.Grace, 11*time.Second)
   630  	assert.True(t, service.Checks[2].CheckRestart.IgnoreWarnings)
   631  }