// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package apitests import ( "testing" "time" "github.com/hashicorp/nomad/api" "github.com/hashicorp/nomad/ci" "github.com/hashicorp/nomad/helper/pointer" "github.com/hashicorp/nomad/nomad/structs" "github.com/stretchr/testify/assert" ) // Verifies that reschedule policy is merged correctly func TestTaskGroup_Canonicalize_ReschedulePolicy(t *testing.T) { ci.Parallel(t) type testCase struct { desc string jobReschedulePolicy *api.ReschedulePolicy taskReschedulePolicy *api.ReschedulePolicy expected *api.ReschedulePolicy } testCases := []testCase{ { desc: "Default", jobReschedulePolicy: nil, taskReschedulePolicy: nil, expected: &api.ReschedulePolicy{ Attempts: pointer.Of(structs.DefaultBatchJobReschedulePolicy.Attempts), Interval: pointer.Of(structs.DefaultBatchJobReschedulePolicy.Interval), Delay: pointer.Of(structs.DefaultBatchJobReschedulePolicy.Delay), DelayFunction: pointer.Of(structs.DefaultBatchJobReschedulePolicy.DelayFunction), MaxDelay: pointer.Of(structs.DefaultBatchJobReschedulePolicy.MaxDelay), Unlimited: pointer.Of(structs.DefaultBatchJobReschedulePolicy.Unlimited), }, }, { desc: "Empty job reschedule policy", jobReschedulePolicy: &api.ReschedulePolicy{ Attempts: pointer.Of(0), Interval: pointer.Of(time.Duration(0)), Delay: pointer.Of(time.Duration(0)), MaxDelay: pointer.Of(time.Duration(0)), DelayFunction: pointer.Of(""), Unlimited: pointer.Of(false), }, taskReschedulePolicy: nil, expected: &api.ReschedulePolicy{ Attempts: pointer.Of(0), Interval: pointer.Of(time.Duration(0)), Delay: pointer.Of(time.Duration(0)), MaxDelay: pointer.Of(time.Duration(0)), DelayFunction: pointer.Of(""), Unlimited: pointer.Of(false), }, }, { desc: "Inherit from job", jobReschedulePolicy: &api.ReschedulePolicy{ Attempts: pointer.Of(1), Interval: pointer.Of(20 * time.Second), Delay: pointer.Of(20 * time.Second), MaxDelay: pointer.Of(10 * time.Minute), DelayFunction: pointer.Of("constant"), Unlimited: pointer.Of(false), }, taskReschedulePolicy: nil, expected: &api.ReschedulePolicy{ Attempts: pointer.Of(1), Interval: pointer.Of(20 * time.Second), Delay: pointer.Of(20 * time.Second), MaxDelay: pointer.Of(10 * time.Minute), DelayFunction: pointer.Of("constant"), Unlimited: pointer.Of(false), }, }, { desc: "Set in task", jobReschedulePolicy: nil, taskReschedulePolicy: &api.ReschedulePolicy{ Attempts: pointer.Of(5), Interval: pointer.Of(2 * time.Minute), Delay: pointer.Of(20 * time.Second), MaxDelay: pointer.Of(10 * time.Minute), DelayFunction: pointer.Of("constant"), Unlimited: pointer.Of(false), }, expected: &api.ReschedulePolicy{ Attempts: pointer.Of(5), Interval: pointer.Of(2 * time.Minute), Delay: pointer.Of(20 * time.Second), MaxDelay: pointer.Of(10 * time.Minute), DelayFunction: pointer.Of("constant"), Unlimited: pointer.Of(false), }, }, { desc: "Merge from job", jobReschedulePolicy: &api.ReschedulePolicy{ Attempts: pointer.Of(1), Delay: pointer.Of(20 * time.Second), MaxDelay: pointer.Of(10 * time.Minute), }, taskReschedulePolicy: &api.ReschedulePolicy{ Interval: pointer.Of(5 * time.Minute), DelayFunction: pointer.Of("constant"), Unlimited: pointer.Of(false), }, expected: &api.ReschedulePolicy{ Attempts: pointer.Of(1), Interval: pointer.Of(5 * time.Minute), Delay: pointer.Of(20 * time.Second), MaxDelay: pointer.Of(10 * time.Minute), DelayFunction: pointer.Of("constant"), Unlimited: pointer.Of(false), }, }, { desc: "Override from group", jobReschedulePolicy: &api.ReschedulePolicy{ Attempts: pointer.Of(1), MaxDelay: pointer.Of(10 * time.Second), }, taskReschedulePolicy: &api.ReschedulePolicy{ Attempts: pointer.Of(5), Delay: pointer.Of(20 * time.Second), MaxDelay: pointer.Of(20 * time.Minute), DelayFunction: pointer.Of("constant"), Unlimited: pointer.Of(false), }, expected: &api.ReschedulePolicy{ Attempts: pointer.Of(5), Interval: pointer.Of(structs.DefaultBatchJobReschedulePolicy.Interval), Delay: pointer.Of(20 * time.Second), MaxDelay: pointer.Of(20 * time.Minute), DelayFunction: pointer.Of("constant"), Unlimited: pointer.Of(false), }, }, { desc: "Attempts from job, default interval", jobReschedulePolicy: &api.ReschedulePolicy{ Attempts: pointer.Of(1), }, taskReschedulePolicy: nil, expected: &api.ReschedulePolicy{ Attempts: pointer.Of(1), Interval: pointer.Of(structs.DefaultBatchJobReschedulePolicy.Interval), Delay: pointer.Of(structs.DefaultBatchJobReschedulePolicy.Delay), DelayFunction: pointer.Of(structs.DefaultBatchJobReschedulePolicy.DelayFunction), MaxDelay: pointer.Of(structs.DefaultBatchJobReschedulePolicy.MaxDelay), Unlimited: pointer.Of(structs.DefaultBatchJobReschedulePolicy.Unlimited), }, }, } for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { job := &api.Job{ ID: pointer.Of("test"), Reschedule: tc.jobReschedulePolicy, Type: pointer.Of(api.JobTypeBatch), } job.Canonicalize() tg := &api.TaskGroup{ Name: pointer.Of("foo"), ReschedulePolicy: tc.taskReschedulePolicy, } tg.Canonicalize(job) assert.Equal(t, tc.expected, tg.ReschedulePolicy) }) } }