Fix validation test for ReplicationController

I discovered this by changing the validation in a way that SHOULD fail
(by allowing something it should not).  But it didn't.  A different
error happens which totally masks the non-failure I expected.  New test
is much more explicit about what failures are expected.

This does not focus on adding test coverage, just making sure the test
is not terrible.
This commit is contained in:
Tim Hockin 2024-12-01 10:21:07 -08:00
parent 133d5d612e
commit 46ac2af06a
No known key found for this signature in database

View File

@ -16606,435 +16606,267 @@ func TestValidateReplicationControllerStatusUpdate(t *testing.T) {
} }
func TestValidateReplicationControllerUpdate(t *testing.T) { // Helper function for RC tests.
validSelector := map[string]string{"a": "b"} func mkValidReplicationController(tweaks ...func(rc *core.ReplicationController)) core.ReplicationController {
validPodTemplate := core.PodTemplate{ rc := core.ReplicationController{
Template: core.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: validSelector,
},
Spec: podtest.MakePodSpec(),
},
}
readWriteVolumePodTemplate := core.PodTemplate{
Template: core.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: validSelector,
},
Spec: podtest.MakePodSpec(
podtest.SetVolumes(core.Volume{Name: "gcepd", VolumeSource: core.VolumeSource{GCEPersistentDisk: &core.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}),
),
},
}
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
invalidPodTemplate := core.PodTemplate{
Template: core.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: invalidSelector,
},
Spec: podtest.MakePodSpec(),
},
}
type rcUpdateTest struct {
old core.ReplicationController
update core.ReplicationController
}
successCases := []rcUpdateTest{{
old: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
update: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: 3,
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
}, {
old: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
update: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: 1,
Selector: validSelector,
Template: &readWriteVolumePodTemplate.Template,
},
},
},
}
for _, successCase := range successCases {
successCase.old.ObjectMeta.ResourceVersion = "1"
successCase.update.ObjectMeta.ResourceVersion = "1"
if errs := ValidateReplicationControllerUpdate(&successCase.update, &successCase.old, PodValidationOptions{}); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := map[string]rcUpdateTest{
"more than one read/write": {
old: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
update: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: 2,
Selector: validSelector,
Template: &readWriteVolumePodTemplate.Template,
},
},
},
"invalid selector": {
old: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
update: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: 2,
Selector: invalidSelector,
Template: &validPodTemplate.Template,
},
},
},
"invalid pod": {
old: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
update: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: 2,
Selector: validSelector,
Template: &invalidPodTemplate.Template,
},
},
},
"negative replicas": {
old: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
update: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: -1,
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
},
}
for testName, errorCase := range errorCases {
if errs := ValidateReplicationControllerUpdate(&errorCase.update, &errorCase.old, PodValidationOptions{}); len(errs) == 0 {
t.Errorf("expected failure: %s", testName)
}
}
}
func TestValidateReplicationController(t *testing.T) {
validSelector := map[string]string{"a": "b"}
validPodTemplate := core.PodTemplate{
Template: core.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: validSelector,
},
Spec: podtest.MakePodSpec(),
},
}
readWriteVolumePodTemplate := core.PodTemplate{
Template: core.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: validSelector,
},
Spec: podtest.MakePodSpec(
podtest.SetVolumes(core.Volume{Name: "gcepd", VolumeSource: core.VolumeSource{GCEPersistentDisk: &core.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}),
),
},
}
hostnetPodTemplate := core.PodTemplate{
Template: core.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: validSelector,
},
Spec: podtest.MakePodSpec(
podtest.SetSecurityContext(&core.PodSecurityContext{
HostNetwork: true,
}),
podtest.SetContainers(podtest.MakeContainer("abc", podtest.SetContainerPorts(
core.ContainerPort{
ContainerPort: 12345,
Protocol: core.ProtocolTCP,
}))),
),
},
}
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
invalidPodTemplate := core.PodTemplate{
Template: core.PodTemplateSpec{
Spec: podtest.MakePodSpec(),
ObjectMeta: metav1.ObjectMeta{
Labels: invalidSelector,
},
},
}
successCases := []core.ReplicationController{{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
}, {
ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
}, {
ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{ Spec: core.ReplicationControllerSpec{
Replicas: 1, Replicas: 1,
Selector: validSelector, Selector: map[string]string{"a": "b"},
Template: &readWriteVolumePodTemplate.Template, Template: &core.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"a": "b"},
},
Spec: podtest.MakePodSpec(),
},
}, },
}
for _, tweak := range tweaks {
tweak(&rc)
}
return rc
}
func TestValidateReplicationControllerUpdate(t *testing.T) {
successCases := []struct {
old core.ReplicationController
update core.ReplicationController
}{{
old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
update: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Replicas = 0
}),
}, { }, {
ObjectMeta: metav1.ObjectMeta{Name: "hostnet", Namespace: metav1.NamespaceDefault}, old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
Spec: core.ReplicationControllerSpec{ update: mkValidReplicationController(func(rc *core.ReplicationController) {
Replicas: 1, rc.Spec.Replicas = 3
Selector: validSelector, }),
Template: &hostnetPodTemplate.Template, }, {
}, old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
update: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Replicas = 2
rc.Spec.Template.Spec = podtest.MakePodSpec(
podtest.SetVolumes(
core.Volume{
Name: "gcepd",
VolumeSource: core.VolumeSource{
GCEPersistentDisk: &core.GCEPersistentDiskVolumeSource{
PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false,
},
},
}))
}),
}} }}
for _, successCase := range successCases { for _, tc := range successCases {
if errs := ValidateReplicationController(&successCase, PodValidationOptions{}); len(errs) != 0 { tc.old.ObjectMeta.ResourceVersion = "1"
tc.update.ObjectMeta.ResourceVersion = "1"
if errs := ValidateReplicationControllerUpdate(&tc.update, &tc.old, PodValidationOptions{}); len(errs) != 0 {
t.Errorf("expected success: %v", errs) t.Errorf("expected success: %v", errs)
} }
} }
errorCases := map[string]struct { errorCases := map[string]struct {
rc core.ReplicationController old core.ReplicationController
expectedOrigin []string update core.ReplicationController
expectedErrs field.ErrorList
}{ }{
"zero-length ID": { "unmatched selector": {
rc: core.ReplicationController{ old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault}, update: mkValidReplicationController(func(rc *core.ReplicationController) {
Spec: core.ReplicationControllerSpec{ rc.Spec.Selector["another"] = "value"
Selector: validSelector, }),
Template: &validPodTemplate.Template, expectedErrs: field.ErrorList{
}, field.Invalid(field.NewPath("spec.template.metadata.labels"), nil, "does not match template"),
}, },
}, },
"missing-namespace": { "invalid selector": {
rc: core.ReplicationController{ old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
ObjectMeta: metav1.ObjectMeta{Name: "abc-123"}, update: mkValidReplicationController(func(rc *core.ReplicationController) {
Spec: core.ReplicationControllerSpec{ invalid := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
Selector: validSelector, rc.Spec.Template.Labels = invalid
Template: &validPodTemplate.Template, rc.Spec.Selector = invalid
}, }),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("spec.template.labels"), nil, "").WithOrigin("labelKey"),
}, },
}, },
"empty selector": { "invalid pod": {
rc: core.ReplicationController{ old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, update: mkValidReplicationController(func(rc *core.ReplicationController) {
Spec: core.ReplicationControllerSpec{ rc.Spec.Template = nil
Template: &validPodTemplate.Template, }),
}, expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec.template"), ""),
}, },
}, },
"selector_doesnt_match": { "negative replicas": {
rc: core.ReplicationController{ old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, update: mkValidReplicationController(func(rc *core.ReplicationController) {
Spec: core.ReplicationControllerSpec{ rc.Spec.Replicas = -1
Selector: map[string]string{"foo": "bar"}, }),
Template: &validPodTemplate.Template, expectedErrs: field.ErrorList{
}, field.Invalid(field.NewPath("spec.replicas"), nil, "").WithOrigin("minimum"),
},
},
"invalid manifest": {
rc: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
},
},
},
"read-write persistent disk with > 1 pod": {
rc: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc"},
Spec: core.ReplicationControllerSpec{
Replicas: 2,
Selector: validSelector,
Template: &readWriteVolumePodTemplate.Template,
},
},
},
"negative_replicas": {
rc: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: -1,
Selector: validSelector,
},
},
expectedOrigin: []string{
"minimum",
},
},
"invalid_label": {
rc: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Name: "abc-123",
Namespace: metav1.NamespaceDefault,
Labels: map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
},
},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
},
"invalid_label 2": {
rc: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Name: "abc-123",
Namespace: metav1.NamespaceDefault,
Labels: map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
},
},
Spec: core.ReplicationControllerSpec{
Template: &invalidPodTemplate.Template,
},
},
},
"invalid_annotation": {
rc: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Name: "abc-123",
Namespace: metav1.NamespaceDefault,
Annotations: map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
},
},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
},
},
},
"invalid restart policy 1": {
rc: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Name: "abc-123",
Namespace: metav1.NamespaceDefault,
},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &core.PodTemplateSpec{
Spec: podtest.MakePodSpec(podtest.SetRestartPolicy(core.RestartPolicyOnFailure)),
ObjectMeta: metav1.ObjectMeta{
Labels: validSelector,
},
},
},
},
},
"invalid restart policy 2": {
rc: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Name: "abc-123",
Namespace: metav1.NamespaceDefault,
},
Spec: core.ReplicationControllerSpec{
Selector: validSelector,
Template: &core.PodTemplateSpec{
Spec: podtest.MakePodSpec(podtest.SetRestartPolicy(core.RestartPolicyNever)),
ObjectMeta: metav1.ObjectMeta{
Labels: validSelector,
},
},
},
},
},
"template may not contain ephemeral containers": {
rc: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: 1,
Selector: validSelector,
Template: &core.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: validSelector,
},
Spec: podtest.MakePodSpec(
podtest.SetEphemeralContainers(core.EphemeralContainer{EphemeralContainerCommon: core.EphemeralContainerCommon{Name: "debug", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}),
),
},
},
}, },
}, },
} }
for k, v := range errorCases { for k, tc := range errorCases {
errs := ValidateReplicationController(&v.rc, PodValidationOptions{}) t.Run(k, func(t *testing.T) {
if len(errs) == 0 { tc.old.ObjectMeta.ResourceVersion = "1"
t.Errorf("expected failure for %s", k) tc.update.ObjectMeta.ResourceVersion = "1"
errs := ValidateReplicationControllerUpdate(&tc.update, &tc.old, PodValidationOptions{})
matcher := fldtest.ErrorMatcher{}.ByType().ByField().ByOrigin().ByDetailSubstring()
matcher.Test(t, tc.expectedErrs, errs)
})
}
}
func TestValidateReplicationController(t *testing.T) {
successCases := []core.ReplicationController{
mkValidReplicationController(func(rc *core.ReplicationController) {}),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Name = "abc-123" }),
mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Replicas = 2
rc.Spec.Template.Spec = podtest.MakePodSpec(
podtest.SetVolumes(
core.Volume{
Name: "gcepd",
VolumeSource: core.VolumeSource{
GCEPersistentDisk: &core.GCEPersistentDiskVolumeSource{
PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false,
},
},
}))
}),
mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Template.Spec = podtest.MakePodSpec(
podtest.SetSecurityContext(&core.PodSecurityContext{HostNetwork: true}),
podtest.SetContainers(podtest.MakeContainer("abc",
podtest.SetContainerPorts(core.ContainerPort{
ContainerPort: 12345, Protocol: core.ProtocolTCP,
}))),
)
}),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = 0 }),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = 1 }),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = 100 }),
}
for _, tc := range successCases {
if errs := ValidateReplicationController(&tc, PodValidationOptions{}); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
} }
}
expectedOrigins := sets.NewString(v.expectedOrigin...) errorCases := map[string]struct {
input core.ReplicationController
for i := range errs { expectedErrs field.ErrorList
field := errs[i].Field }{
if !strings.HasPrefix(field, "spec.template.") && "missing name": {
field != "metadata.name" && input: mkValidReplicationController(func(rc *core.ReplicationController) { rc.Name = "" }),
field != "metadata.namespace" && expectedErrs: field.ErrorList{
field != "spec.selector" && field.Required(field.NewPath("metadata.name"), ""),
field != "spec.template" && },
field != "GCEPersistentDisk.ReadOnly" && },
field != "spec.replicas" && "missing namespace": {
field != "spec.template.labels" && input: mkValidReplicationController(func(rc *core.ReplicationController) { rc.Namespace = "" }),
field != "metadata.annotations" && expectedErrs: field.ErrorList{
field != "metadata.labels" && field.Required(field.NewPath("metadata.namespace"), ""),
field != "status.replicas" { },
t.Errorf("%s: missing prefix for: %v", k, errs[i]) },
} "empty selector": {
input: mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Selector = nil }),
if len(v.expectedOrigin) > 0 && errs[i].Origin != "" { expectedErrs: field.ErrorList{
if !expectedOrigins.Has(errs[i].Origin) { field.Required(field.NewPath("spec.selector"), ""),
t.Errorf("%s: unexpected origin for: %v, expected one of %v", k, errs[i].Origin, v.expectedOrigin) },
},
"selector doesnt match": {
input: mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Selector = map[string]string{"foo": "bar"} }),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("spec.template.metadata.labels"), nil, "does not match template"),
},
},
"invalid manifest": {
input: mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Template = nil }),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec.template"), ""),
},
},
"negative replicas": {
input: mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = -1 }),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("spec.replicas"), nil, "").WithOrigin("minimum"),
},
},
"invalid label": {
input: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Labels = map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
} }
expectedOrigins.Delete(errs[i].Origin) }),
} expectedErrs: field.ErrorList{
} field.Invalid(field.NewPath("metadata.labels"), nil, "").WithOrigin("labelKey"),
if len(expectedOrigins) > 0 { },
t.Errorf("%s: missing errors with origin: %v", k, expectedOrigins.List()) },
} "invalid label 2": {
input: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Template.Labels = map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
}
}),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("spec.template.metadata.labels"), nil, "does not match template"),
field.Invalid(field.NewPath("spec.template.labels"), nil, "").WithOrigin("labelKey"),
},
},
"invalid annotation": {
input: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Annotations = map[string]string{
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
}
}),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("metadata.annotations"), nil, "name part must consist of"),
},
},
"invalid restart policy 1": {
input: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Template.Spec.RestartPolicy = core.RestartPolicyOnFailure
}),
expectedErrs: field.ErrorList{
field.NotSupported[core.RestartPolicy](field.NewPath("spec.template.spec.restartPolicy"), nil, nil),
},
},
"invalid restart policy 2": {
input: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Template.Spec.RestartPolicy = core.RestartPolicyNever
}),
expectedErrs: field.ErrorList{
field.NotSupported[core.RestartPolicy](field.NewPath("spec.template.spec.restartPolicy"), nil, nil),
},
},
"template may not contain ephemeral containers": {
input: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Template.Spec = podtest.MakePodSpec(
podtest.SetEphemeralContainers(
core.EphemeralContainer{
EphemeralContainerCommon: core.EphemeralContainerCommon{
Name: "debug",
Image: "image",
ImagePullPolicy: "IfNotPresent",
TerminationMessagePolicy: "File",
},
}))
}),
expectedErrs: field.ErrorList{
field.Forbidden(field.NewPath("spec.template.spec.ephemeralContainers"), "not allowed in pod template"),
},
},
}
for k, tc := range errorCases {
t.Run(k, func(t *testing.T) {
errs := ValidateReplicationController(&tc.input, PodValidationOptions{})
matcher := fldtest.ErrorMatcher{}.ByType().ByField().ByOrigin().ByDetailSubstring()
matcher.Test(t, tc.expectedErrs, errs)
})
} }
} }