validation

This commit is contained in:
AxeZhan 2023-08-18 13:35:57 +08:00
parent 9327f3a173
commit fa01dfdb0a
2 changed files with 113 additions and 33 deletions

View File

@ -2886,52 +2886,52 @@ func validatePodResourceClaimSource(claimSource core.ClaimSource, fldPath *field
return allErrs return allErrs
} }
func validateLivenessProbe(probe *core.Probe, fldPath *field.Path) field.ErrorList { func validateLivenessProbe(probe *core.Probe, gracePeriod int64, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if probe == nil { if probe == nil {
return allErrs return allErrs
} }
allErrs = append(allErrs, validateProbe(probe, fldPath)...) allErrs = append(allErrs, validateProbe(probe, gracePeriod, fldPath)...)
if probe.SuccessThreshold != 1 { if probe.SuccessThreshold != 1 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("successThreshold"), probe.SuccessThreshold, "must be 1")) allErrs = append(allErrs, field.Invalid(fldPath.Child("successThreshold"), probe.SuccessThreshold, "must be 1"))
} }
return allErrs return allErrs
} }
func validateReadinessProbe(probe *core.Probe, fldPath *field.Path) field.ErrorList { func validateReadinessProbe(probe *core.Probe, gracePeriod int64, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if probe == nil { if probe == nil {
return allErrs return allErrs
} }
allErrs = append(allErrs, validateProbe(probe, fldPath)...) allErrs = append(allErrs, validateProbe(probe, gracePeriod, fldPath)...)
if probe.TerminationGracePeriodSeconds != nil { if probe.TerminationGracePeriodSeconds != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("terminationGracePeriodSeconds"), probe.TerminationGracePeriodSeconds, "must not be set for readinessProbes")) allErrs = append(allErrs, field.Invalid(fldPath.Child("terminationGracePeriodSeconds"), probe.TerminationGracePeriodSeconds, "must not be set for readinessProbes"))
} }
return allErrs return allErrs
} }
func validateStartupProbe(probe *core.Probe, fldPath *field.Path) field.ErrorList { func validateStartupProbe(probe *core.Probe, gracePeriod int64, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if probe == nil { if probe == nil {
return allErrs return allErrs
} }
allErrs = append(allErrs, validateProbe(probe, fldPath)...) allErrs = append(allErrs, validateProbe(probe, gracePeriod, fldPath)...)
if probe.SuccessThreshold != 1 { if probe.SuccessThreshold != 1 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("successThreshold"), probe.SuccessThreshold, "must be 1")) allErrs = append(allErrs, field.Invalid(fldPath.Child("successThreshold"), probe.SuccessThreshold, "must be 1"))
} }
return allErrs return allErrs
} }
func validateProbe(probe *core.Probe, fldPath *field.Path) field.ErrorList { func validateProbe(probe *core.Probe, gracePeriod int64, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if probe == nil { if probe == nil {
return allErrs return allErrs
} }
allErrs = append(allErrs, validateHandler(handlerFromProbe(&probe.ProbeHandler), fldPath)...) allErrs = append(allErrs, validateHandler(handlerFromProbe(&probe.ProbeHandler), gracePeriod, fldPath)...)
allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.InitialDelaySeconds), fldPath.Child("initialDelaySeconds"))...) allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.InitialDelaySeconds), fldPath.Child("initialDelaySeconds"))...)
allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.TimeoutSeconds), fldPath.Child("timeoutSeconds"))...) allErrs = append(allErrs, ValidateNonnegativeField(int64(probe.TimeoutSeconds), fldPath.Child("timeoutSeconds"))...)
@ -2966,6 +2966,7 @@ type commonHandler struct {
HTTPGet *core.HTTPGetAction HTTPGet *core.HTTPGetAction
TCPSocket *core.TCPSocketAction TCPSocket *core.TCPSocketAction
GRPC *core.GRPCAction GRPC *core.GRPCAction
Sleep *core.SleepAction
} }
func handlerFromProbe(ph *core.ProbeHandler) commonHandler { func handlerFromProbe(ph *core.ProbeHandler) commonHandler {
@ -2982,9 +2983,19 @@ func handlerFromLifecycle(lh *core.LifecycleHandler) commonHandler {
Exec: lh.Exec, Exec: lh.Exec,
HTTPGet: lh.HTTPGet, HTTPGet: lh.HTTPGet,
TCPSocket: lh.TCPSocket, TCPSocket: lh.TCPSocket,
Sleep: lh.Sleep,
} }
} }
func validateSleepAction(sleep *core.SleepAction, gracePeriod int64, fldPath *field.Path) field.ErrorList {
allErrors := field.ErrorList{}
if sleep.Seconds <= 0 || sleep.Seconds > gracePeriod {
invalidStr := fmt.Sprintf("must be greater than 0 and less than terminationGracePeriodSeconds (%d)", gracePeriod)
allErrors = append(allErrors, field.Invalid(fldPath, sleep.Seconds, invalidStr))
}
return allErrors
}
func validateClientIPAffinityConfig(config *core.SessionAffinityConfig, fldPath *field.Path) field.ErrorList { func validateClientIPAffinityConfig(config *core.SessionAffinityConfig, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if config == nil { if config == nil {
@ -3093,7 +3104,7 @@ func validateTCPSocketAction(tcp *core.TCPSocketAction, fldPath *field.Path) fie
func validateGRPCAction(grpc *core.GRPCAction, fldPath *field.Path) field.ErrorList { func validateGRPCAction(grpc *core.GRPCAction, fldPath *field.Path) field.ErrorList {
return ValidatePortNumOrName(intstr.FromInt32(grpc.Port), fldPath.Child("port")) return ValidatePortNumOrName(intstr.FromInt32(grpc.Port), fldPath.Child("port"))
} }
func validateHandler(handler commonHandler, fldPath *field.Path) field.ErrorList { func validateHandler(handler commonHandler, gracePeriod int64, fldPath *field.Path) field.ErrorList {
numHandlers := 0 numHandlers := 0
allErrors := field.ErrorList{} allErrors := field.ErrorList{}
if handler.Exec != nil { if handler.Exec != nil {
@ -3128,19 +3139,27 @@ func validateHandler(handler commonHandler, fldPath *field.Path) field.ErrorList
allErrors = append(allErrors, validateGRPCAction(handler.GRPC, fldPath.Child("grpc"))...) allErrors = append(allErrors, validateGRPCAction(handler.GRPC, fldPath.Child("grpc"))...)
} }
} }
if handler.Sleep != nil {
if numHandlers > 0 {
allErrors = append(allErrors, field.Forbidden(fldPath.Child("sleep"), "may not specify more than 1 handler type"))
} else {
numHandlers++
allErrors = append(allErrors, validateSleepAction(handler.Sleep, gracePeriod, fldPath.Child("sleep"))...)
}
}
if numHandlers == 0 { if numHandlers == 0 {
allErrors = append(allErrors, field.Required(fldPath, "must specify a handler type")) allErrors = append(allErrors, field.Required(fldPath, "must specify a handler type"))
} }
return allErrors return allErrors
} }
func validateLifecycle(lifecycle *core.Lifecycle, fldPath *field.Path) field.ErrorList { func validateLifecycle(lifecycle *core.Lifecycle, gracePeriod int64, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if lifecycle.PostStart != nil { if lifecycle.PostStart != nil {
allErrs = append(allErrs, validateHandler(handlerFromLifecycle(lifecycle.PostStart), fldPath.Child("postStart"))...) allErrs = append(allErrs, validateHandler(handlerFromLifecycle(lifecycle.PostStart), gracePeriod, fldPath.Child("postStart"))...)
} }
if lifecycle.PreStop != nil { if lifecycle.PreStop != nil {
allErrs = append(allErrs, validateHandler(handlerFromLifecycle(lifecycle.PreStop), fldPath.Child("preStop"))...) allErrs = append(allErrs, validateHandler(handlerFromLifecycle(lifecycle.PreStop), gracePeriod, fldPath.Child("preStop"))...)
} }
return allErrs return allErrs
} }
@ -3282,7 +3301,7 @@ func validateFieldAllowList(value interface{}, allowedFields map[string]bool, er
} }
// validateInitContainers is called by pod spec and template validation to validate the list of init containers // validateInitContainers is called by pod spec and template validation to validate the list of init containers
func validateInitContainers(containers []core.Container, regularContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.String, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList { func validateInitContainers(containers []core.Container, regularContainers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.String, gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
var allErrs field.ErrorList var allErrs field.ErrorList
allNames := sets.String{} allNames := sets.String{}
@ -3316,11 +3335,11 @@ func validateInitContainers(containers []core.Container, regularContainers []cor
switch { switch {
case restartAlways: case restartAlways:
if ctr.Lifecycle != nil { if ctr.Lifecycle != nil {
allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, idxPath.Child("lifecycle"))...) allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, gracePeriod, idxPath.Child("lifecycle"))...)
} }
allErrs = append(allErrs, validateLivenessProbe(ctr.LivenessProbe, idxPath.Child("livenessProbe"))...) allErrs = append(allErrs, validateLivenessProbe(ctr.LivenessProbe, gracePeriod, idxPath.Child("livenessProbe"))...)
allErrs = append(allErrs, validateReadinessProbe(ctr.ReadinessProbe, idxPath.Child("readinessProbe"))...) allErrs = append(allErrs, validateReadinessProbe(ctr.ReadinessProbe, gracePeriod, idxPath.Child("readinessProbe"))...)
allErrs = append(allErrs, validateStartupProbe(ctr.StartupProbe, idxPath.Child("startupProbe"))...) allErrs = append(allErrs, validateStartupProbe(ctr.StartupProbe, gracePeriod, idxPath.Child("startupProbe"))...)
default: default:
// These fields are disallowed for init containers. // These fields are disallowed for init containers.
@ -3420,7 +3439,7 @@ func validateHostUsers(spec *core.PodSpec, fldPath *field.Path) field.ErrorList
} }
// validateContainers is called by pod spec and template validation to validate the list of regular containers. // validateContainers is called by pod spec and template validation to validate the list of regular containers.
func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.String, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList { func validateContainers(containers []core.Container, volumes map[string]core.VolumeSource, podClaimNames sets.String, gracePeriod int64, fldPath *field.Path, opts PodValidationOptions, podRestartPolicy *core.RestartPolicy) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if len(containers) == 0 { if len(containers) == 0 {
@ -3448,11 +3467,11 @@ func validateContainers(containers []core.Container, volumes map[string]core.Vol
// Regular init container and ephemeral container validation will return // Regular init container and ephemeral container validation will return
// field.Forbidden() for these paths. // field.Forbidden() for these paths.
if ctr.Lifecycle != nil { if ctr.Lifecycle != nil {
allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, path.Child("lifecycle"))...) allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, gracePeriod, path.Child("lifecycle"))...)
} }
allErrs = append(allErrs, validateLivenessProbe(ctr.LivenessProbe, path.Child("livenessProbe"))...) allErrs = append(allErrs, validateLivenessProbe(ctr.LivenessProbe, gracePeriod, path.Child("livenessProbe"))...)
allErrs = append(allErrs, validateReadinessProbe(ctr.ReadinessProbe, path.Child("readinessProbe"))...) allErrs = append(allErrs, validateReadinessProbe(ctr.ReadinessProbe, gracePeriod, path.Child("readinessProbe"))...)
allErrs = append(allErrs, validateStartupProbe(ctr.StartupProbe, path.Child("startupProbe"))...) allErrs = append(allErrs, validateStartupProbe(ctr.StartupProbe, gracePeriod, path.Child("startupProbe"))...)
// These fields are disallowed for regular containers // These fields are disallowed for regular containers
if ctr.RestartPolicy != nil { if ctr.RestartPolicy != nil {
@ -3974,12 +3993,18 @@ func validateHostIPs(pod *core.Pod) field.ErrorList {
func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
var gracePeriod int64
if spec.TerminationGracePeriodSeconds != nil {
// this could happen in tests
gracePeriod = *spec.TerminationGracePeriodSeconds
}
vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"), opts) vols, vErrs := ValidateVolumes(spec.Volumes, podMeta, fldPath.Child("volumes"), opts)
allErrs = append(allErrs, vErrs...) allErrs = append(allErrs, vErrs...)
podClaimNames := gatherPodResourceClaimNames(spec.ResourceClaims) podClaimNames := gatherPodResourceClaimNames(spec.ResourceClaims)
allErrs = append(allErrs, validatePodResourceClaims(podMeta, spec.ResourceClaims, fldPath.Child("resourceClaims"))...) allErrs = append(allErrs, validatePodResourceClaims(podMeta, spec.ResourceClaims, fldPath.Child("resourceClaims"))...)
allErrs = append(allErrs, validateContainers(spec.Containers, vols, podClaimNames, fldPath.Child("containers"), opts, &spec.RestartPolicy)...) allErrs = append(allErrs, validateContainers(spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("containers"), opts, &spec.RestartPolicy)...)
allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, podClaimNames, fldPath.Child("initContainers"), opts, &spec.RestartPolicy)...) allErrs = append(allErrs, validateInitContainers(spec.InitContainers, spec.Containers, vols, podClaimNames, gracePeriod, fldPath.Child("initContainers"), opts, &spec.RestartPolicy)...)
allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, podClaimNames, fldPath.Child("ephemeralContainers"), opts, &spec.RestartPolicy)...) allErrs = append(allErrs, validateEphemeralContainers(spec.EphemeralContainers, spec.Containers, spec.InitContainers, vols, podClaimNames, fldPath.Child("ephemeralContainers"), opts, &spec.RestartPolicy)...)
allErrs = append(allErrs, validatePodHostNetworkDeps(spec, fldPath, opts)...) allErrs = append(allErrs, validatePodHostNetworkDeps(spec, fldPath, opts)...)
allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...) allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy, fldPath.Child("restartPolicy"))...)

View File

@ -52,6 +52,7 @@ const (
dnsLabelErrMsg = "a lowercase RFC 1123 label must consist of" dnsLabelErrMsg = "a lowercase RFC 1123 label must consist of"
dnsSubdomainLabelErrMsg = "a lowercase RFC 1123 subdomain" dnsSubdomainLabelErrMsg = "a lowercase RFC 1123 subdomain"
envVarNameErrMsg = "a valid environment variable name must consist of" envVarNameErrMsg = "a valid environment variable name must consist of"
defaultGracePeriod = int64(30)
) )
var ( var (
@ -6616,7 +6617,7 @@ func TestValidateProbe(t *testing.T) {
} }
for _, p := range successCases { for _, p := range successCases {
if errs := validateProbe(p, field.NewPath("field")); len(errs) != 0 { if errs := validateProbe(p, defaultGracePeriod, field.NewPath("field")); len(errs) != 0 {
t.Errorf("expected success: %v", errs) t.Errorf("expected success: %v", errs)
} }
} }
@ -6628,7 +6629,7 @@ func TestValidateProbe(t *testing.T) {
errorCases = append(errorCases, probe) errorCases = append(errorCases, probe)
} }
for _, p := range errorCases { for _, p := range errorCases {
if errs := validateProbe(p, field.NewPath("field")); len(errs) == 0 { if errs := validateProbe(p, defaultGracePeriod, field.NewPath("field")); len(errs) == 0 {
t.Errorf("expected failure for %v", p) t.Errorf("expected failure for %v", p)
} }
} }
@ -6734,7 +6735,7 @@ func Test_validateProbe(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got := validateProbe(tt.args.probe, tt.args.fldPath) got := validateProbe(tt.args.probe, defaultGracePeriod, tt.args.fldPath)
if len(got) != len(tt.want) { if len(got) != len(tt.want) {
t.Errorf("validateProbe() = %v, want %v", got, tt.want) t.Errorf("validateProbe() = %v, want %v", got, tt.want)
return return
@ -6759,7 +6760,7 @@ func TestValidateHandler(t *testing.T) {
{HTTPGet: &core.HTTPGetAction{Path: "/", Port: intstr.FromString("port"), Host: "", Scheme: "HTTP", HTTPHeaders: []core.HTTPHeader{{Name: "X-Forwarded-For", Value: "1.2.3.4"}, {Name: "X-Forwarded-For", Value: "5.6.7.8"}}}}, {HTTPGet: &core.HTTPGetAction{Path: "/", Port: intstr.FromString("port"), Host: "", Scheme: "HTTP", HTTPHeaders: []core.HTTPHeader{{Name: "X-Forwarded-For", Value: "1.2.3.4"}, {Name: "X-Forwarded-For", Value: "5.6.7.8"}}}},
} }
for _, h := range successCases { for _, h := range successCases {
if errs := validateHandler(handlerFromProbe(&h), field.NewPath("field")); len(errs) != 0 { if errs := validateHandler(handlerFromProbe(&h), defaultGracePeriod, field.NewPath("field")); len(errs) != 0 {
t.Errorf("expected success: %v", errs) t.Errorf("expected success: %v", errs)
} }
} }
@ -6774,7 +6775,7 @@ func TestValidateHandler(t *testing.T) {
{HTTPGet: &core.HTTPGetAction{Path: "/", Port: intstr.FromString("port"), Host: "", Scheme: "HTTP", HTTPHeaders: []core.HTTPHeader{{Name: "X_Forwarded_For", Value: "foo.example.com"}}}}, {HTTPGet: &core.HTTPGetAction{Path: "/", Port: intstr.FromString("port"), Host: "", Scheme: "HTTP", HTTPHeaders: []core.HTTPHeader{{Name: "X_Forwarded_For", Value: "foo.example.com"}}}},
} }
for _, h := range errorCases { for _, h := range errorCases {
if errs := validateHandler(handlerFromProbe(&h), field.NewPath("field")); len(errs) == 0 { if errs := validateHandler(handlerFromProbe(&h), defaultGracePeriod, field.NewPath("field")); len(errs) == 0 {
t.Errorf("expected failure for %#v", h) t.Errorf("expected failure for %#v", h)
} }
} }
@ -7694,7 +7695,7 @@ func TestValidateContainers(t *testing.T) {
var PodRestartPolicy core.RestartPolicy var PodRestartPolicy core.RestartPolicy
PodRestartPolicy = "Always" PodRestartPolicy = "Always"
if errs := validateContainers(successCase, volumeDevices, nil, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 { if errs := validateContainers(successCase, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 {
t.Errorf("expected success: %v", errs) t.Errorf("expected success: %v", errs)
} }
@ -8308,7 +8309,7 @@ func TestValidateContainers(t *testing.T) {
for _, tc := range errorCases { for _, tc := range errorCases {
t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) { t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
errs := validateContainers(tc.containers, volumeDevices, nil, field.NewPath("containers"), PodValidationOptions{}, &PodRestartPolicy) errs := validateContainers(tc.containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("containers"), PodValidationOptions{}, &PodRestartPolicy)
if len(errs) == 0 { if len(errs) == 0 {
t.Fatal("expected error but received none") t.Fatal("expected error but received none")
} }
@ -8398,7 +8399,7 @@ func TestValidateInitContainers(t *testing.T) {
} }
var PodRestartPolicy core.RestartPolicy var PodRestartPolicy core.RestartPolicy
PodRestartPolicy = "Never" PodRestartPolicy = "Never"
if errs := validateInitContainers(successCase, containers, volumeDevices, nil, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 { if errs := validateInitContainers(successCase, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 {
t.Errorf("expected success: %v", errs) t.Errorf("expected success: %v", errs)
} }
@ -8777,7 +8778,7 @@ func TestValidateInitContainers(t *testing.T) {
for _, tc := range errorCases { for _, tc := range errorCases {
t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) { t.Run(tc.title+"__@L"+tc.line, func(t *testing.T) {
errs := validateInitContainers(tc.initContainers, containers, volumeDevices, nil, field.NewPath("initContainers"), PodValidationOptions{}, &PodRestartPolicy) errs := validateInitContainers(tc.initContainers, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("initContainers"), PodValidationOptions{}, &PodRestartPolicy)
if len(errs) == 0 { if len(errs) == 0 {
t.Fatal("expected error but received none") t.Fatal("expected error but received none")
} }
@ -23702,3 +23703,57 @@ func TestValidateLoadBalancerStatus(t *testing.T) {
}) })
} }
} }
func TestValidateSleepAction(t *testing.T) {
fldPath := field.NewPath("root")
getInvalidStr := func(gracePeriod int64) string {
return fmt.Sprintf("must be greater than 0 and less than terminationGracePeriodSeconds (%d)", gracePeriod)
}
testCases := []struct {
name string
action *core.SleepAction
gracePeriod int64
expectErr field.ErrorList
}{
{
name: "valid setting",
action: &core.SleepAction{
Seconds: 5,
},
gracePeriod: 30,
},
{
name: "negative seconds",
action: &core.SleepAction{
Seconds: -1,
},
gracePeriod: 30,
expectErr: field.ErrorList{field.Invalid(fldPath, -1, getInvalidStr(30))},
},
{
name: "longer than gracePeriod",
action: &core.SleepAction{
Seconds: 5,
},
gracePeriod: 3,
expectErr: field.ErrorList{field.Invalid(fldPath, 5, getInvalidStr(3))},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
errs := validateSleepAction(tc.action, tc.gracePeriod, fldPath)
if len(tc.expectErr) > 0 && len(errs) == 0 {
t.Errorf("Unexpected success")
} else if len(tc.expectErr) == 0 && len(errs) != 0 {
t.Errorf("Unexpected error(s): %v", errs)
} else if len(tc.expectErr) > 0 {
if tc.expectErr[0].Error() != errs[0].Error() {
t.Errorf("Unexpected error(s): %v", errs)
}
}
})
}
}