Move fielderrors into validation

This commit is contained in:
Tim Hockin
2015-11-03 13:17:51 -08:00
parent 3fbf0cb810
commit 0ff66da346
42 changed files with 711 additions and 717 deletions

View File

@@ -29,15 +29,14 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/capabilities"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/fielderrors"
errors "k8s.io/kubernetes/pkg/util/fielderrors"
"k8s.io/kubernetes/pkg/util/intstr"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/validation"
)
func expectPrefix(t *testing.T, prefix string, errs fielderrors.ValidationErrorList) {
func expectPrefix(t *testing.T, prefix string, errs validation.ValidationErrorList) {
for i := range errs {
if f, p := errs[i].(*errors.ValidationError).Field, prefix; !strings.HasPrefix(f, p) {
if f, p := errs[i].(*validation.ValidationError).Field, prefix; !strings.HasPrefix(f, p) {
t.Errorf("expected prefix '%s' for field '%s' (%v)", p, f, errs[i])
}
}
@@ -151,7 +150,7 @@ func TestValidateLabels(t *testing.T) {
if len(errs) != 1 {
t.Errorf("case[%d] expected failure", i)
} else {
detail := errs[0].(*errors.ValidationError).Detail
detail := errs[0].(*validation.ValidationError).Detail
if detail != qualifiedNameErrorMsg {
t.Errorf("error detail %s should be equal %s", detail, qualifiedNameErrorMsg)
}
@@ -169,7 +168,7 @@ func TestValidateLabels(t *testing.T) {
if len(errs) != 1 {
t.Errorf("case[%d] expected failure", i)
} else {
detail := errs[0].(*errors.ValidationError).Detail
detail := errs[0].(*validation.ValidationError).Detail
if detail != labelValueErrorMsg {
t.Errorf("error detail %s should be equal %s", detail, labelValueErrorMsg)
}
@@ -216,7 +215,7 @@ func TestValidateAnnotations(t *testing.T) {
if len(errs) != 1 {
t.Errorf("case[%d] expected failure", i)
}
detail := errs[0].(*errors.ValidationError).Detail
detail := errs[0].(*validation.ValidationError).Detail
if detail != qualifiedNameErrorMsg {
t.Errorf("error detail %s should be equal %s", detail, qualifiedNameErrorMsg)
}
@@ -537,30 +536,30 @@ func TestValidateVolumes(t *testing.T) {
slashInName := api.VolumeSource{Flocker: &api.FlockerVolumeSource{DatasetName: "foo/bar"}}
errorCases := map[string]struct {
V []api.Volume
T errors.ValidationErrorType
T validation.ValidationErrorType
F string
D string
}{
"zero-length name": {[]api.Volume{{Name: "", VolumeSource: emptyVS}}, errors.ValidationErrorTypeRequired, "[0].name", ""},
"name > 63 characters": {[]api.Volume{{Name: strings.Repeat("a", 64), VolumeSource: emptyVS}}, errors.ValidationErrorTypeInvalid, "[0].name", "must be a DNS label (at most 63 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?): e.g. \"my-name\""},
"name not a DNS label": {[]api.Volume{{Name: "a.b.c", VolumeSource: emptyVS}}, errors.ValidationErrorTypeInvalid, "[0].name", "must be a DNS label (at most 63 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?): e.g. \"my-name\""},
"name not unique": {[]api.Volume{{Name: "abc", VolumeSource: emptyVS}, {Name: "abc", VolumeSource: emptyVS}}, errors.ValidationErrorTypeDuplicate, "[1].name", ""},
"empty portal": {[]api.Volume{{Name: "badportal", VolumeSource: emptyPortal}}, errors.ValidationErrorTypeRequired, "[0].source.iscsi.targetPortal", ""},
"empty iqn": {[]api.Volume{{Name: "badiqn", VolumeSource: emptyIQN}}, errors.ValidationErrorTypeRequired, "[0].source.iscsi.iqn", ""},
"empty hosts": {[]api.Volume{{Name: "badhost", VolumeSource: emptyHosts}}, errors.ValidationErrorTypeRequired, "[0].source.glusterfs.endpoints", ""},
"empty path": {[]api.Volume{{Name: "badpath", VolumeSource: emptyPath}}, errors.ValidationErrorTypeRequired, "[0].source.glusterfs.path", ""},
"empty datasetName": {[]api.Volume{{Name: "badname", VolumeSource: emptyName}}, errors.ValidationErrorTypeRequired, "[0].source.flocker.datasetName", ""},
"empty mon": {[]api.Volume{{Name: "badmon", VolumeSource: emptyMon}}, errors.ValidationErrorTypeRequired, "[0].source.rbd.monitors", ""},
"empty image": {[]api.Volume{{Name: "badimage", VolumeSource: emptyImage}}, errors.ValidationErrorTypeRequired, "[0].source.rbd.image", ""},
"empty cephfs mon": {[]api.Volume{{Name: "badmon", VolumeSource: emptyCephFSMon}}, errors.ValidationErrorTypeRequired, "[0].source.cephfs.monitors", ""},
"empty metatada path": {[]api.Volume{{Name: "emptyname", VolumeSource: emptyPathName}}, errors.ValidationErrorTypeRequired, "[0].source.downwardApi.path", ""},
"absolute path": {[]api.Volume{{Name: "absolutepath", VolumeSource: absolutePathName}}, errors.ValidationErrorTypeForbidden, "[0].source.downwardApi.path", ""},
"dot dot path": {[]api.Volume{{Name: "dotdotpath", VolumeSource: dotDotInPath}}, errors.ValidationErrorTypeInvalid, "[0].source.downwardApi.path", "must not contain \"..\"."},
"dot dot file name": {[]api.Volume{{Name: "dotdotfilename", VolumeSource: dotDotPathName}}, errors.ValidationErrorTypeInvalid, "[0].source.downwardApi.path", "must not start with \"..\"."},
"dot dot first level dirent": {[]api.Volume{{Name: "dotdotdirfilename", VolumeSource: dotDotFirstLevelDirent}}, errors.ValidationErrorTypeInvalid, "[0].source.downwardApi.path", "must not start with \"..\"."},
"empty wwn": {[]api.Volume{{Name: "badimage", VolumeSource: zeroWWN}}, errors.ValidationErrorTypeRequired, "[0].source.fc.targetWWNs", ""},
"empty lun": {[]api.Volume{{Name: "badimage", VolumeSource: emptyLun}}, errors.ValidationErrorTypeRequired, "[0].source.fc.lun", ""},
"slash in datasetName": {[]api.Volume{{Name: "slashinname", VolumeSource: slashInName}}, errors.ValidationErrorTypeInvalid, "[0].source.flocker.datasetName", "must not contain '/'"},
"zero-length name": {[]api.Volume{{Name: "", VolumeSource: emptyVS}}, validation.ValidationErrorTypeRequired, "[0].name", ""},
"name > 63 characters": {[]api.Volume{{Name: strings.Repeat("a", 64), VolumeSource: emptyVS}}, validation.ValidationErrorTypeInvalid, "[0].name", "must be a DNS label (at most 63 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?): e.g. \"my-name\""},
"name not a DNS label": {[]api.Volume{{Name: "a.b.c", VolumeSource: emptyVS}}, validation.ValidationErrorTypeInvalid, "[0].name", "must be a DNS label (at most 63 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?): e.g. \"my-name\""},
"name not unique": {[]api.Volume{{Name: "abc", VolumeSource: emptyVS}, {Name: "abc", VolumeSource: emptyVS}}, validation.ValidationErrorTypeDuplicate, "[1].name", ""},
"empty portal": {[]api.Volume{{Name: "badportal", VolumeSource: emptyPortal}}, validation.ValidationErrorTypeRequired, "[0].source.iscsi.targetPortal", ""},
"empty iqn": {[]api.Volume{{Name: "badiqn", VolumeSource: emptyIQN}}, validation.ValidationErrorTypeRequired, "[0].source.iscsi.iqn", ""},
"empty hosts": {[]api.Volume{{Name: "badhost", VolumeSource: emptyHosts}}, validation.ValidationErrorTypeRequired, "[0].source.glusterfs.endpoints", ""},
"empty path": {[]api.Volume{{Name: "badpath", VolumeSource: emptyPath}}, validation.ValidationErrorTypeRequired, "[0].source.glusterfs.path", ""},
"empty datasetName": {[]api.Volume{{Name: "badname", VolumeSource: emptyName}}, validation.ValidationErrorTypeRequired, "[0].source.flocker.datasetName", ""},
"empty mon": {[]api.Volume{{Name: "badmon", VolumeSource: emptyMon}}, validation.ValidationErrorTypeRequired, "[0].source.rbd.monitors", ""},
"empty image": {[]api.Volume{{Name: "badimage", VolumeSource: emptyImage}}, validation.ValidationErrorTypeRequired, "[0].source.rbd.image", ""},
"empty cephfs mon": {[]api.Volume{{Name: "badmon", VolumeSource: emptyCephFSMon}}, validation.ValidationErrorTypeRequired, "[0].source.cephfs.monitors", ""},
"empty metatada path": {[]api.Volume{{Name: "emptyname", VolumeSource: emptyPathName}}, validation.ValidationErrorTypeRequired, "[0].source.downwardApi.path", ""},
"absolute path": {[]api.Volume{{Name: "absolutepath", VolumeSource: absolutePathName}}, validation.ValidationErrorTypeForbidden, "[0].source.downwardApi.path", ""},
"dot dot path": {[]api.Volume{{Name: "dotdotpath", VolumeSource: dotDotInPath}}, validation.ValidationErrorTypeInvalid, "[0].source.downwardApi.path", "must not contain \"..\"."},
"dot dot file name": {[]api.Volume{{Name: "dotdotfilename", VolumeSource: dotDotPathName}}, validation.ValidationErrorTypeInvalid, "[0].source.downwardApi.path", "must not start with \"..\"."},
"dot dot first level dirent": {[]api.Volume{{Name: "dotdotdirfilename", VolumeSource: dotDotFirstLevelDirent}}, validation.ValidationErrorTypeInvalid, "[0].source.downwardApi.path", "must not start with \"..\"."},
"empty wwn": {[]api.Volume{{Name: "badimage", VolumeSource: zeroWWN}}, validation.ValidationErrorTypeRequired, "[0].source.fc.targetWWNs", ""},
"empty lun": {[]api.Volume{{Name: "badimage", VolumeSource: emptyLun}}, validation.ValidationErrorTypeRequired, "[0].source.fc.lun", ""},
"slash in datasetName": {[]api.Volume{{Name: "slashinname", VolumeSource: slashInName}}, validation.ValidationErrorTypeInvalid, "[0].source.flocker.datasetName", "must not contain '/'"},
}
for k, v := range errorCases {
_, errs := validateVolumes(v.V)
@@ -569,13 +568,13 @@ func TestValidateVolumes(t *testing.T) {
continue
}
for i := range errs {
if errs[i].(*errors.ValidationError).Type != v.T {
if errs[i].(*validation.ValidationError).Type != v.T {
t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
}
if errs[i].(*errors.ValidationError).Field != v.F {
if errs[i].(*validation.ValidationError).Field != v.F {
t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
}
detail := errs[i].(*errors.ValidationError).Detail
detail := errs[i].(*validation.ValidationError).Detail
if detail != v.D {
t.Errorf("%s: expected error detail \"%s\", got \"%s\"", k, v.D, detail)
}
@@ -604,23 +603,23 @@ func TestValidatePorts(t *testing.T) {
errorCases := map[string]struct {
P []api.ContainerPort
T errors.ValidationErrorType
T validation.ValidationErrorType
F string
D string
}{
"name > 15 characters": {[]api.ContainerPort{{Name: strings.Repeat("a", 16), ContainerPort: 80, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].name", PortNameErrorMsg},
"name not a IANA svc name ": {[]api.ContainerPort{{Name: "a.b.c", ContainerPort: 80, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].name", PortNameErrorMsg},
"name not a IANA svc name (i.e. a number)": {[]api.ContainerPort{{Name: "80", ContainerPort: 80, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].name", PortNameErrorMsg},
"name > 15 characters": {[]api.ContainerPort{{Name: strings.Repeat("a", 16), ContainerPort: 80, Protocol: "TCP"}}, validation.ValidationErrorTypeInvalid, "[0].name", PortNameErrorMsg},
"name not a IANA svc name ": {[]api.ContainerPort{{Name: "a.b.c", ContainerPort: 80, Protocol: "TCP"}}, validation.ValidationErrorTypeInvalid, "[0].name", PortNameErrorMsg},
"name not a IANA svc name (i.e. a number)": {[]api.ContainerPort{{Name: "80", ContainerPort: 80, Protocol: "TCP"}}, validation.ValidationErrorTypeInvalid, "[0].name", PortNameErrorMsg},
"name not unique": {[]api.ContainerPort{
{Name: "abc", ContainerPort: 80, Protocol: "TCP"},
{Name: "abc", ContainerPort: 81, Protocol: "TCP"},
}, errors.ValidationErrorTypeDuplicate, "[1].name", ""},
"zero container port": {[]api.ContainerPort{{ContainerPort: 0, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].containerPort", PortRangeErrorMsg},
"invalid container port": {[]api.ContainerPort{{ContainerPort: 65536, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].containerPort", PortRangeErrorMsg},
"invalid host port": {[]api.ContainerPort{{ContainerPort: 80, HostPort: 65536, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].hostPort", PortRangeErrorMsg},
"invalid protocol case": {[]api.ContainerPort{{ContainerPort: 80, Protocol: "tcp"}}, errors.ValidationErrorTypeNotSupported, "[0].protocol", "supported values: TCP, UDP"},
"invalid protocol": {[]api.ContainerPort{{ContainerPort: 80, Protocol: "ICMP"}}, errors.ValidationErrorTypeNotSupported, "[0].protocol", "supported values: TCP, UDP"},
"protocol required": {[]api.ContainerPort{{Name: "abc", ContainerPort: 80}}, errors.ValidationErrorTypeRequired, "[0].protocol", ""},
}, validation.ValidationErrorTypeDuplicate, "[1].name", ""},
"zero container port": {[]api.ContainerPort{{ContainerPort: 0, Protocol: "TCP"}}, validation.ValidationErrorTypeInvalid, "[0].containerPort", PortRangeErrorMsg},
"invalid container port": {[]api.ContainerPort{{ContainerPort: 65536, Protocol: "TCP"}}, validation.ValidationErrorTypeInvalid, "[0].containerPort", PortRangeErrorMsg},
"invalid host port": {[]api.ContainerPort{{ContainerPort: 80, HostPort: 65536, Protocol: "TCP"}}, validation.ValidationErrorTypeInvalid, "[0].hostPort", PortRangeErrorMsg},
"invalid protocol case": {[]api.ContainerPort{{ContainerPort: 80, Protocol: "tcp"}}, validation.ValidationErrorTypeNotSupported, "[0].protocol", "supported values: TCP, UDP"},
"invalid protocol": {[]api.ContainerPort{{ContainerPort: 80, Protocol: "ICMP"}}, validation.ValidationErrorTypeNotSupported, "[0].protocol", "supported values: TCP, UDP"},
"protocol required": {[]api.ContainerPort{{Name: "abc", ContainerPort: 80}}, validation.ValidationErrorTypeRequired, "[0].protocol", ""},
}
for k, v := range errorCases {
errs := validatePorts(v.P)
@@ -628,13 +627,13 @@ func TestValidatePorts(t *testing.T) {
t.Errorf("expected failure for %s", k)
}
for i := range errs {
if errs[i].(*errors.ValidationError).Type != v.T {
if errs[i].(*validation.ValidationError).Type != v.T {
t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
}
if errs[i].(*errors.ValidationError).Field != v.F {
if errs[i].(*validation.ValidationError).Field != v.F {
t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
}
detail := errs[i].(*errors.ValidationError).Detail
detail := errs[i].(*validation.ValidationError).Detail
if detail != v.D {
t.Errorf("%s: expected error detail either empty or %s, got %s", k, v.D, detail)
}
@@ -773,7 +772,7 @@ func TestValidateEnv(t *testing.T) {
t.Errorf("expected failure for %s", tc.name)
} else {
for i := range errs {
str := errs[i].(*errors.ValidationError).Error()
str := errs[i].(*validation.ValidationError).Error()
if str != "" && str != tc.expectedError {
t.Errorf("%s: expected error detail either empty or %s, got %s", tc.name, tc.expectedError, str)
}
@@ -2561,7 +2560,7 @@ func TestValidateReplicationController(t *testing.T) {
t.Errorf("expected failure for %s", k)
}
for i := range errs {
field := errs[i].(*errors.ValidationError).Field
field := errs[i].(*validation.ValidationError).Field
if !strings.HasPrefix(field, "spec.template.") &&
field != "metadata.name" &&
field != "metadata.namespace" &&
@@ -2677,7 +2676,7 @@ func TestValidateNode(t *testing.T) {
t.Errorf("expected failure for %s", k)
}
for i := range errs {
field := errs[i].(*errors.ValidationError).Field
field := errs[i].(*validation.ValidationError).Field
expectedFields := map[string]bool{
"metadata.name": true,
"metadata.labels": true,
@@ -3009,7 +3008,7 @@ func TestValidateResourceNames(t *testing.T) {
} else if len(err) == 0 && !item.success {
t.Errorf("expected failure for input %q", item.input)
for i := range err {
detail := err[i].(*errors.ValidationError).Detail
detail := err[i].(*validation.ValidationError).Detail
if detail != "" && detail != qualifiedNameErrorMsg {
t.Errorf("%d: expected error detail either empty or %s, got %s", k, qualifiedNameErrorMsg, detail)
}
@@ -3225,7 +3224,7 @@ func TestValidateLimitRange(t *testing.T) {
t.Errorf("expected failure for %s", k)
}
for i := range errs {
detail := errs[i].(*errors.ValidationError).Detail
detail := errs[i].(*validation.ValidationError).Detail
if detail != v.D {
t.Errorf("%s: expected error detail either empty or %s, got %s", k, v.D, detail)
}
@@ -3330,8 +3329,8 @@ func TestValidateResourceQuota(t *testing.T) {
t.Errorf("expected failure for %s", k)
}
for i := range errs {
field := errs[i].(*errors.ValidationError).Field
detail := errs[i].(*errors.ValidationError).Detail
field := errs[i].(*validation.ValidationError).Field
detail := errs[i].(*validation.ValidationError).Detail
if field != "metadata.name" && field != "metadata.namespace" && !api.IsStandardResourceName(field) {
t.Errorf("%s: missing prefix for: %v", k, field)
}
@@ -3765,7 +3764,7 @@ func TestValidateEndpoints(t *testing.T) {
errorCases := map[string]struct {
endpoints api.Endpoints
errorType fielderrors.ValidationErrorType
errorType validation.ValidationErrorType
errorDetail string
}{
"missing namespace": {
@@ -3938,7 +3937,7 @@ func TestValidateEndpoints(t *testing.T) {
}
for k, v := range errorCases {
if errs := ValidateEndpoints(&v.endpoints); len(errs) == 0 || errs[0].(*errors.ValidationError).Type != v.errorType || !strings.Contains(errs[0].(*errors.ValidationError).Detail, v.errorDetail) {
if errs := ValidateEndpoints(&v.endpoints); len(errs) == 0 || errs[0].(*validation.ValidationError).Type != v.errorType || !strings.Contains(errs[0].(*validation.ValidationError).Detail, v.errorDetail) {
t.Errorf("Expected error type %s with detail %s for %s, got %v", v.errorType, v.errorDetail, k, errs)
}
}
@@ -4003,7 +4002,7 @@ func TestValidateSecurityContext(t *testing.T) {
errorCases := map[string]struct {
sc *api.SecurityContext
errorType fielderrors.ValidationErrorType
errorType validation.ValidationErrorType
errorDetail string
}{
"request privileged when capabilities forbids": {
@@ -4018,7 +4017,7 @@ func TestValidateSecurityContext(t *testing.T) {
},
}
for k, v := range errorCases {
if errs := ValidateSecurityContext(v.sc); len(errs) == 0 || errs[0].(*errors.ValidationError).Type != v.errorType || errs[0].(*errors.ValidationError).Detail != v.errorDetail {
if errs := ValidateSecurityContext(v.sc); len(errs) == 0 || errs[0].(*validation.ValidationError).Type != v.errorType || errs[0].(*validation.ValidationError).Detail != v.errorDetail {
t.Errorf("Expected error type %s with detail %s for %s, got %v", v.errorType, v.errorDetail, k, errs)
}
}