Validate Job .spec.ttlSecondsAfterFinished; clear it when feature disabled
1. If TTLAfterFinished feature is enabled, the value should be non-negative. 2. If TTLAfterFinished feature is disabled, the field value should not be kept.
This commit is contained in:
@@ -17,13 +17,16 @@ limitations under the License.
|
||||
package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func getValidManualSelector() *metav1.LabelSelector {
|
||||
@@ -64,7 +67,21 @@ func getValidPodTemplateSpecForGenerated(selector *metav1.LabelSelector) api.Pod
|
||||
}
|
||||
}
|
||||
|
||||
func featureToggle(feature utilfeature.Feature) []string {
|
||||
enabled := fmt.Sprintf("%s=%t", feature, true)
|
||||
disabled := fmt.Sprintf("%s=%t", feature, false)
|
||||
return []string{enabled, disabled}
|
||||
}
|
||||
|
||||
func TestValidateJob(t *testing.T) {
|
||||
ttlEnabled := utilfeature.DefaultFeatureGate.Enabled(features.TTLAfterFinished)
|
||||
defer func() {
|
||||
err := utilfeature.DefaultFeatureGate.Set(fmt.Sprintf("%s=%t", features.TTLAfterFinished, ttlEnabled))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to set feature gate for %s: %v", features.TTLAfterFinished, err)
|
||||
}
|
||||
}()
|
||||
|
||||
validManualSelector := getValidManualSelector()
|
||||
validPodTemplateSpecForManual := getValidPodTemplateSpecForManual(validManualSelector)
|
||||
validGeneratedSelector := getValidGeneratedSelector()
|
||||
@@ -214,15 +231,39 @@ func TestValidateJob(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for k, v := range errorCases {
|
||||
errs := ValidateJob(&v)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", k)
|
||||
for _, setFeature := range featureToggle(features.TTLAfterFinished) {
|
||||
// Set error cases based on if TTLAfterFinished feature is enabled or not
|
||||
if err := utilfeature.DefaultFeatureGate.Set(setFeature); err != nil {
|
||||
t.Fatalf("Failed to set feature gate for %s: %v", features.TTLAfterFinished, err)
|
||||
}
|
||||
ttlCase := "spec.ttlSecondsAfterFinished:must be greater than or equal to 0"
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.TTLAfterFinished) {
|
||||
errorCases[ttlCase] = batch.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myjob",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
UID: types.UID("1a2b3c"),
|
||||
},
|
||||
Spec: batch.JobSpec{
|
||||
TTLSecondsAfterFinished: &negative,
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGenerated,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
s := strings.Split(k, ":")
|
||||
err := errs[0]
|
||||
if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
|
||||
t.Errorf("unexpected error: %v, expected: %s", err, k)
|
||||
delete(errorCases, ttlCase)
|
||||
}
|
||||
|
||||
for k, v := range errorCases {
|
||||
errs := ValidateJob(&v)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", k)
|
||||
} else {
|
||||
s := strings.Split(k, ":")
|
||||
err := errs[0]
|
||||
if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
|
||||
t.Errorf("unexpected error: %v, expected: %s", err, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -584,6 +625,25 @@ func TestValidateCronJob(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.TTLAfterFinished) {
|
||||
errorCases["spec.jobTemplate.spec.ttlSecondsAfterFinished:must be greater than or equal to 0"] = batch.CronJob{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mycronjob",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
UID: types.UID("1a2b3c"),
|
||||
},
|
||||
Spec: batch.CronJobSpec{
|
||||
Schedule: "* * * * ?",
|
||||
ConcurrencyPolicy: batch.AllowConcurrent,
|
||||
JobTemplate: batch.JobTemplateSpec{
|
||||
Spec: batch.JobSpec{
|
||||
TTLSecondsAfterFinished: &negative,
|
||||
Template: validPodTemplateSpec,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range errorCases {
|
||||
errs := ValidateCronJob(&v)
|
||||
|
Reference in New Issue
Block a user