Clean up brace whitespace in **/validation_test.go

This was making my eyes bleed as I read over code.

I used the following in vim.  I made them up on the fly, but they seemed
to pass manual inspection.

:g/},\n\s*{$/s//}, {/
:w
:g/{$\n\s*{$/s//{{/
:w
:g/^\(\s*\)},\n\1},$/s//}},/
:w
:g/^\(\s*\)},$\n\1}$/s//}}/
:w
This commit is contained in:
Tim Hockin
2023-05-02 00:36:15 -07:00
parent 19830bf51b
commit d55b67b349
27 changed files with 18026 additions and 22083 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -28,96 +28,84 @@ func TestValidateServerStorageVersion(t *testing.T) {
cases := []struct {
ssv apiserverinternal.ServerStorageVersion
expectedErr string
}{
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "-fea",
EncodingVersion: "v1alpha1",
DecodableVersions: []string{"v1alpha1", "v1"},
},
expectedErr: "apiServerID: Invalid value",
}{{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "-fea",
EncodingVersion: "v1alpha1",
DecodableVersions: []string{"v1alpha1", "v1"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1alpha1",
DecodableVersions: []string{"v1beta1", "v1"},
},
expectedErr: "decodableVersions must include encodingVersion",
expectedErr: "apiServerID: Invalid value",
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1alpha1",
DecodableVersions: []string{"v1beta1", "v1"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1alpha1",
DecodableVersions: []string{"v1alpha1", "v1", "-fea"},
},
expectedErr: "decodableVersions[2]: Invalid value",
expectedErr: "decodableVersions must include encodingVersion",
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1alpha1",
DecodableVersions: []string{"v1alpha1", "v1", "-fea"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1alpha1",
DecodableVersions: []string{"v1alpha1", "v1"},
},
expectedErr: "",
expectedErr: "decodableVersions[2]: Invalid value",
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1alpha1",
DecodableVersions: []string{"v1alpha1", "v1"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "mygroup.com/v2",
DecodableVersions: []string{"v1alpha1", "v1", "mygroup.com/v2"},
},
expectedErr: "",
expectedErr: "",
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "mygroup.com/v2",
DecodableVersions: []string{"v1alpha1", "v1", "mygroup.com/v2"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "mygroup.com/v2",
DecodableVersions: []string{"mygroup.com/v2", "/v3"},
},
expectedErr: `[].decodableVersions[1]: Invalid value: "/v3": group part: must be non-empty`,
expectedErr: "",
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "mygroup.com/v2",
DecodableVersions: []string{"mygroup.com/v2", "/v3"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "mygroup.com/v2",
DecodableVersions: []string{"mygroup.com/v2", "mygroup.com/"},
},
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/": version part: must be non-empty`,
expectedErr: `[].decodableVersions[1]: Invalid value: "/v3": group part: must be non-empty`,
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "mygroup.com/v2",
DecodableVersions: []string{"mygroup.com/v2", "mygroup.com/"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "/v3",
DecodableVersions: []string{"mygroup.com/v2", "/v3"},
},
expectedErr: `[].encodingVersion: Invalid value: "/v3": group part: must be non-empty`,
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/": version part: must be non-empty`,
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "/v3",
DecodableVersions: []string{"mygroup.com/v2", "/v3"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1",
DecodableVersions: []string{"v1", "mygroup_com/v2"},
},
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup_com/v2": group part: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')`,
expectedErr: `[].encodingVersion: Invalid value: "/v3": group part: must be non-empty`,
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1",
DecodableVersions: []string{"v1", "mygroup_com/v2"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1",
DecodableVersions: []string{"v1", "mygroup.com/v2_"},
},
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/v2_": version part: a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?')`,
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup_com/v2": group part: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')`,
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1",
DecodableVersions: []string{"v1", "mygroup.com/v2_"},
},
{
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1",
DecodableVersions: []string{"v1", "mygroup.com/v2/myresource"},
},
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/v2/myresource": an apiVersion is a DNS-1035 label, which must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?') with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyVersion')`,
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/v2_": version part: a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?')`,
}, {
ssv: apiserverinternal.ServerStorageVersion{
APIServerID: "fea",
EncodingVersion: "v1",
DecodableVersions: []string{"v1", "mygroup.com/v2/myresource"},
},
}
expectedErr: `[].decodableVersions[1]: Invalid value: "mygroup.com/v2/myresource": an apiVersion is a DNS-1035 label, which must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?') with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyVersion')`,
}}
for _, tc := range cases {
err := validateServerStorageVersion(tc.ssv, field.NewPath("")).ToAggregate()
@@ -142,91 +130,70 @@ func TestValidateCommonVersion(t *testing.T) {
cases := []struct {
status apiserverinternal.StorageVersionStatus
expectedErr string
}{
{
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{},
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
expectedErr: "should be nil if servers do not agree on the same encoding version, or if there is no server reporting the supported versions yet",
}{{
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{},
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
{
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{
{
APIServerID: "1",
EncodingVersion: "v1alpha1",
},
{
APIServerID: "2",
EncodingVersion: "v1",
},
},
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
expectedErr: "should be nil if servers do not agree on the same encoding version, or if there is no server reporting the supported versions yet",
expectedErr: "should be nil if servers do not agree on the same encoding version, or if there is no server reporting the supported versions yet",
}, {
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1",
EncodingVersion: "v1alpha1",
}, {
APIServerID: "2",
EncodingVersion: "v1",
}},
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
{
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{
{
APIServerID: "1",
EncodingVersion: "v1alpha1",
},
{
APIServerID: "2",
EncodingVersion: "v1alpha1",
},
},
CommonEncodingVersion: nil,
},
expectedErr: "Invalid value: \"null\": the common encoding version is v1alpha1",
expectedErr: "should be nil if servers do not agree on the same encoding version, or if there is no server reporting the supported versions yet",
}, {
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1",
EncodingVersion: "v1alpha1",
}, {
APIServerID: "2",
EncodingVersion: "v1alpha1",
}},
CommonEncodingVersion: nil,
},
{
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{
{
APIServerID: "1",
EncodingVersion: "v1alpha1",
},
{
APIServerID: "2",
EncodingVersion: "v1alpha1",
},
},
CommonEncodingVersion: func() *string { a := "v1"; return &a }(),
},
expectedErr: "Invalid value: \"v1\": the actual common encoding version is v1alpha1",
expectedErr: "Invalid value: \"null\": the common encoding version is v1alpha1",
}, {
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1",
EncodingVersion: "v1alpha1",
}, {
APIServerID: "2",
EncodingVersion: "v1alpha1",
}},
CommonEncodingVersion: func() *string { a := "v1"; return &a }(),
},
{
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{
{
APIServerID: "1",
EncodingVersion: "v1alpha1",
},
{
APIServerID: "2",
EncodingVersion: "v1alpha1",
},
},
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
expectedErr: "",
expectedErr: "Invalid value: \"v1\": the actual common encoding version is v1alpha1",
}, {
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1",
EncodingVersion: "v1alpha1",
}, {
APIServerID: "2",
EncodingVersion: "v1alpha1",
}},
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
{
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{
{
APIServerID: "1",
EncodingVersion: "v1alpha1",
},
},
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
expectedErr: "",
expectedErr: "",
}, {
status: apiserverinternal.StorageVersionStatus{
StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1",
EncodingVersion: "v1alpha1",
}},
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
}
expectedErr: "",
}}
for _, tc := range cases {
err := validateCommonVersion(tc.status, field.NewPath(""))
if err == nil && len(tc.expectedErr) == 0 {
@@ -250,78 +217,58 @@ func TestValidateStorageVersionCondition(t *testing.T) {
cases := []struct {
conditions []apiserverinternal.StorageVersionCondition
expectedErr string
}{
{
conditions: []apiserverinternal.StorageVersionCondition{
{
Type: "-fea",
Status: "True",
Reason: "unknown",
Message: "unknown",
},
},
expectedErr: "type: Invalid value",
},
{
conditions: []apiserverinternal.StorageVersionCondition{
{
Type: "fea",
Status: "-True",
Reason: "unknown",
Message: "unknown",
},
},
expectedErr: "status: Invalid value",
},
{
conditions: []apiserverinternal.StorageVersionCondition{
{
Type: "fea",
Status: "True",
Message: "unknown",
},
},
expectedErr: "Required value: reason cannot be empty",
},
{
conditions: []apiserverinternal.StorageVersionCondition{
{
Type: "fea",
Status: "True",
Reason: "unknown",
},
},
expectedErr: "Required value: message cannot be empty",
},
{
conditions: []apiserverinternal.StorageVersionCondition{
{
Type: "fea",
Status: "True",
Reason: "unknown",
Message: "unknown",
},
{
Type: "fea",
Status: "True",
Reason: "unknown",
Message: "unknown",
},
},
expectedErr: `"fea": the type of the condition is not unique, it also appears in conditions[0]`,
},
{
conditions: []apiserverinternal.StorageVersionCondition{
{
Type: "fea",
Status: "True",
Reason: "unknown",
Message: "unknown",
},
},
expectedErr: "",
},
}
}{{
conditions: []apiserverinternal.StorageVersionCondition{{
Type: "-fea",
Status: "True",
Reason: "unknown",
Message: "unknown",
}},
expectedErr: "type: Invalid value",
}, {
conditions: []apiserverinternal.StorageVersionCondition{{
Type: "fea",
Status: "-True",
Reason: "unknown",
Message: "unknown",
}},
expectedErr: "status: Invalid value",
}, {
conditions: []apiserverinternal.StorageVersionCondition{{
Type: "fea",
Status: "True",
Message: "unknown",
}},
expectedErr: "Required value: reason cannot be empty",
}, {
conditions: []apiserverinternal.StorageVersionCondition{{
Type: "fea",
Status: "True",
Reason: "unknown",
}},
expectedErr: "Required value: message cannot be empty",
}, {
conditions: []apiserverinternal.StorageVersionCondition{{
Type: "fea",
Status: "True",
Reason: "unknown",
Message: "unknown",
}, {
Type: "fea",
Status: "True",
Reason: "unknown",
Message: "unknown",
}},
expectedErr: `"fea": the type of the condition is not unique, it also appears in conditions[0]`,
}, {
conditions: []apiserverinternal.StorageVersionCondition{{
Type: "fea",
Status: "True",
Reason: "unknown",
Message: "unknown",
}},
expectedErr: "",
}}
for _, tc := range cases {
err := validateStorageVersionCondition(tc.conditions, field.NewPath("")).ToAggregate()
if err == nil && len(tc.expectedErr) == 0 {
@@ -345,40 +292,31 @@ func TestValidateStorageVersionName(t *testing.T) {
cases := []struct {
name string
expectedErr string
}{
{
name: "",
expectedErr: `name must be in the form of <group>.<resource>`,
},
{
name: "pods",
expectedErr: `name must be in the form of <group>.<resource>`,
},
{
name: "core.pods",
expectedErr: "",
},
{
name: "authentication.k8s.io.tokenreviews",
expectedErr: "",
},
{
name: strings.Repeat("x", 253) + ".tokenreviews",
expectedErr: "",
},
{
name: strings.Repeat("x", 254) + ".tokenreviews",
expectedErr: `the group segment must be no more than 253 characters`,
},
{
name: "authentication.k8s.io." + strings.Repeat("x", 63),
expectedErr: "",
},
{
name: "authentication.k8s.io." + strings.Repeat("x", 64),
expectedErr: `the resource segment must be no more than 63 characters`,
},
}
}{{
name: "",
expectedErr: `name must be in the form of <group>.<resource>`,
}, {
name: "pods",
expectedErr: `name must be in the form of <group>.<resource>`,
}, {
name: "core.pods",
expectedErr: "",
}, {
name: "authentication.k8s.io.tokenreviews",
expectedErr: "",
}, {
name: strings.Repeat("x", 253) + ".tokenreviews",
expectedErr: "",
}, {
name: strings.Repeat("x", 254) + ".tokenreviews",
expectedErr: `the group segment must be no more than 253 characters`,
}, {
name: "authentication.k8s.io." + strings.Repeat("x", 63),
expectedErr: "",
}, {
name: "authentication.k8s.io." + strings.Repeat("x", 64),
expectedErr: `the resource segment must be no more than 63 characters`,
}}
for _, tc := range cases {
errs := ValidateStorageVersionName(tc.name, false)
if errs == nil && len(tc.expectedErr) == 0 {

File diff suppressed because it is too large Load Diff

View File

@@ -40,29 +40,25 @@ func TestValidateSARSpec(t *testing.T) {
name string
obj authorizationapi.SubjectAccessReviewSpec
msg string
}{
{
name: "neither request",
obj: authorizationapi.SubjectAccessReviewSpec{User: "me"},
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
}{{
name: "neither request",
obj: authorizationapi.SubjectAccessReviewSpec{User: "me"},
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
}, {
name: "both requests",
obj: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
User: "me",
},
{
name: "both requests",
obj: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
User: "me",
},
msg: "cannot be specified in combination with resourceAttributes",
msg: "cannot be specified in combination with resourceAttributes",
}, {
name: "no subject",
obj: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
},
{
name: "no subject",
obj: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
},
msg: `spec.user: Invalid value: "": at least one of user or group must be specified`,
},
}
msg: `spec.user: Invalid value: "": at least one of user or group must be specified`,
}}
for _, c := range errorCases {
errs := ValidateSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
@@ -102,21 +98,18 @@ func TestValidateSelfSAR(t *testing.T) {
name string
obj authorizationapi.SelfSubjectAccessReviewSpec
msg string
}{
{
name: "neither request",
obj: authorizationapi.SelfSubjectAccessReviewSpec{},
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
}{{
name: "neither request",
obj: authorizationapi.SelfSubjectAccessReviewSpec{},
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
}, {
name: "both requests",
obj: authorizationapi.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
},
{
name: "both requests",
obj: authorizationapi.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
},
msg: "cannot be specified in combination with resourceAttributes",
},
}
msg: "cannot be specified in combination with resourceAttributes",
}}
for _, c := range errorCases {
errs := ValidateSelfSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
@@ -136,14 +129,12 @@ func TestValidateSelfSAR(t *testing.T) {
}
func TestValidateLocalSAR(t *testing.T) {
successCases := []authorizationapi.LocalSubjectAccessReview{
{
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "user",
},
successCases := []authorizationapi.LocalSubjectAccessReview{{
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "user",
},
}
}}
for _, successCase := range successCases {
if errs := ValidateLocalSubjectAccessReview(&successCase); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
@@ -154,41 +145,37 @@ func TestValidateLocalSAR(t *testing.T) {
name string
obj *authorizationapi.LocalSubjectAccessReview
msg string
}{
{
name: "name",
obj: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: metav1.ObjectMeta{Name: "a"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "user",
},
}{{
name: "name",
obj: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: metav1.ObjectMeta{Name: "a"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "user",
},
msg: "must be empty except for namespace",
},
{
name: "namespace conflict",
obj: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "user",
},
msg: "must be empty except for namespace",
}, {
name: "namespace conflict",
obj: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "user",
},
msg: "must match metadata.namespace",
},
{
name: "nonresource",
obj: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
Spec: authorizationapi.SubjectAccessReviewSpec{
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
User: "user",
},
msg: "must match metadata.namespace",
}, {
name: "nonresource",
obj: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
Spec: authorizationapi.SubjectAccessReviewSpec{
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
User: "user",
},
msg: "disallowed on this kind of request",
},
}
msg: "disallowed on this kind of request",
}}
for _, c := range errorCases {
errs := ValidateLocalSubjectAccessReview(c.obj)

File diff suppressed because it is too large Load Diff

View File

@@ -112,49 +112,39 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
}},
}, {
Action: batch.PodFailurePolicyActionFailJob,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.PodConditionType("CustomConditionType"),
Status: api.ConditionFalse,
}},
}, {
Action: batch.PodFailurePolicyActionCount,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("abc"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
{
Action: batch.PodFailurePolicyActionFailJob,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.PodConditionType("CustomConditionType"),
Status: api.ConditionFalse,
},
},
}, {
Action: batch.PodFailurePolicyActionIgnore,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("def"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{4},
},
{
Action: batch.PodFailurePolicyActionCount,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("abc"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
}, {
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpNotIn,
Values: []int32{5, 6, 7},
},
{
Action: batch.PodFailurePolicyActionIgnore,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("def"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{4},
},
},
{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpNotIn,
Values: []int32{5, 6, 7},
},
},
},
}},
},
},
},
@@ -314,11 +304,9 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionFailJob,
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionFailJob,
}},
},
},
},
@@ -331,15 +319,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{11, 11},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{11, 11},
},
},
}},
},
},
},
@@ -352,21 +338,19 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: func() (values []int32) {
tooManyValues := make([]int32, maxPodFailurePolicyOnExitCodesValues+1)
for i := range tooManyValues {
tooManyValues[i] = int32(i)
}
return tooManyValues
}(),
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: func() (values []int32) {
tooManyValues := make([]int32, maxPodFailurePolicyOnExitCodesValues+1)
for i := range tooManyValues {
tooManyValues[i] = int32(i)
}
return tooManyValues
}(),
},
},
}},
},
},
},
@@ -404,21 +388,19 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionFailJob,
OnPodConditions: func() []batch.PodFailurePolicyOnPodConditionsPattern {
tooManyPatterns := make([]batch.PodFailurePolicyOnPodConditionsPattern, maxPodFailurePolicyOnPodConditionsPatterns+1)
for i := range tooManyPatterns {
tooManyPatterns[i] = batch.PodFailurePolicyOnPodConditionsPattern{
Type: api.PodConditionType(fmt.Sprintf("CustomType_%d", i)),
Status: api.ConditionTrue,
}
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionFailJob,
OnPodConditions: func() []batch.PodFailurePolicyOnPodConditionsPattern {
tooManyPatterns := make([]batch.PodFailurePolicyOnPodConditionsPattern, maxPodFailurePolicyOnPodConditionsPatterns+1)
for i := range tooManyPatterns {
tooManyPatterns[i] = batch.PodFailurePolicyOnPodConditionsPattern{
Type: api.PodConditionType(fmt.Sprintf("CustomType_%d", i)),
Status: api.ConditionTrue,
}
return tooManyPatterns
}(),
},
},
}
return tooManyPatterns
}(),
}},
},
},
},
@@ -431,15 +413,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{12, 13, 13, 13},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{12, 13, 13, 13},
},
},
}},
},
},
},
@@ -452,15 +432,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{19, 11},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{19, 11},
},
},
}},
},
},
},
@@ -473,15 +451,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{},
},
},
}},
},
},
},
@@ -494,15 +470,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: "",
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
Rules: []batch.PodFailurePolicyRule{{
Action: "",
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
},
}},
},
},
},
@@ -515,15 +489,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: "",
Values: []int32{1, 2, 3},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: "",
Values: []int32{1, 2, 3},
},
},
}},
},
},
},
@@ -536,22 +508,18 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("abc"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("abc"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
},
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
}},
}},
},
},
},
@@ -564,15 +532,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 0, 2},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 0, 2},
},
},
}},
},
},
},
@@ -585,24 +551,21 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("abc"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("abc"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
{
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("xyz"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{5, 6, 7},
},
}, {
Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("xyz"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{5, 6, 7},
},
},
}},
},
},
},
@@ -615,16 +578,14 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: "UnknownAction",
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("abc"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
Rules: []batch.PodFailurePolicyRule{{
Action: "UnknownAction",
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("abc"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{1, 2, 3},
},
},
}},
},
},
},
@@ -637,15 +598,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: "UnknownOperator",
Values: []int32{1, 2, 3},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
Operator: "UnknownOperator",
Values: []int32{1, 2, 3},
},
},
}},
},
},
},
@@ -658,16 +617,12 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.DisruptionTarget,
},
},
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.DisruptionTarget,
}},
}},
},
},
},
@@ -680,17 +635,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.DisruptionTarget,
Status: "UnknownStatus",
},
},
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.DisruptionTarget,
Status: "UnknownStatus",
}},
}},
},
},
},
@@ -703,16 +654,12 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Status: api.ConditionTrue,
},
},
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Status: api.ConditionTrue,
}},
}},
},
},
},
@@ -725,17 +672,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.PodConditionType("Invalid Condition Type"),
Status: api.ConditionTrue,
},
},
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.PodConditionType("Invalid Condition Type"),
Status: api.ConditionTrue,
}},
}},
},
},
},
@@ -1116,17 +1059,13 @@ func TestValidateJobUpdate(t *testing.T) {
validNodeAffinity := &api.Affinity{
NodeAffinity: &api.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
NodeSelectorTerms: []api.NodeSelectorTerm{
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: "foo",
Operator: api.NodeSelectorOpIn,
Values: []string{"bar", "value2"},
},
},
},
},
NodeSelectorTerms: []api.NodeSelectorTerm{{
MatchExpressions: []api.NodeSelectorRequirement{{
Key: "foo",
Operator: api.NodeSelectorOpIn,
Values: []string{"bar", "value2"},
}},
}},
},
},
}
@@ -1134,17 +1073,13 @@ func TestValidateJobUpdate(t *testing.T) {
validPodTemplateWithAffinity.Spec.Affinity = &api.Affinity{
NodeAffinity: &api.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
NodeSelectorTerms: []api.NodeSelectorTerm{
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: "foo",
Operator: api.NodeSelectorOpIn,
Values: []string{"bar", "value"},
},
},
},
},
NodeSelectorTerms: []api.NodeSelectorTerm{{
MatchExpressions: []api.NodeSelectorRequirement{{
Key: "foo",
Operator: api.NodeSelectorOpIn,
Values: []string{"bar", "value"},
}},
}},
},
},
}
@@ -1242,17 +1177,13 @@ func TestValidateJobUpdate(t *testing.T) {
},
update: func(job *batch.Job) {
job.Spec.PodFailurePolicy = &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
},
},
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
}},
}},
}
},
err: &field.Error{
@@ -1267,29 +1198,23 @@ func TestValidateJobUpdate(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
},
},
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
}},
}},
},
},
},
update: func(job *batch.Job) {
job.Spec.PodFailurePolicy.Rules = append(job.Spec.PodFailurePolicy.Rules, batch.PodFailurePolicyRule{
Action: batch.PodFailurePolicyActionCount,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
},
},
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
}},
})
},
err: &field.Error{
@@ -1304,17 +1229,13 @@ func TestValidateJobUpdate(t *testing.T) {
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{
{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
},
},
},
},
Rules: []batch.PodFailurePolicyRule{{
Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
}},
}},
},
},
},

File diff suppressed because it is too large Load Diff

View File

@@ -31,56 +31,51 @@ func TestValidateResourceRequirements(t *testing.T) {
successCase := []struct {
name string
requirements v1.ResourceRequirements
}{
{
name: "Resources with Requests equal to Limits",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
},
Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
},
}{{
name: "Resources with Requests equal to Limits",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
},
Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
},
},
{
name: "Resources with only Limits",
requirements: v1.ResourceRequirements{
Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("10"),
},
}, {
name: "Resources with only Limits",
requirements: v1.ResourceRequirements{
Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("10"),
},
},
{
name: "Resources with only Requests",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("10"),
},
}, {
name: "Resources with only Requests",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("10"),
},
},
{
name: "Resources with Requests Less Than Limits",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
v1.ResourceName("my.org/resource"): resource.MustParse("9"),
},
Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("9"),
},
}, {
name: "Resources with Requests Less Than Limits",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
v1.ResourceName("my.org/resource"): resource.MustParse("9"),
},
Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("9"),
},
},
}
}}
for _, tc := range successCase {
t.Run(tc.name, func(t *testing.T) {
if errs := ValidateResourceRequirements(&tc.requirements, field.NewPath("resources")); len(errs) != 0 {
@@ -94,41 +89,37 @@ func TestValidateResourceRequirements(t *testing.T) {
requirements v1.ResourceRequirements
skipLimitValueCheck bool
skipRequestValueCheck bool
}{
{
name: "Resources with Requests Larger Than Limits",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("10m"),
},
Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
v1.ResourceName("my.org/resource"): resource.MustParse("9m"),
},
}{{
name: "Resources with Requests Larger Than Limits",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("10m"),
},
Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
v1.ResourceName("my.org/resource"): resource.MustParse("9m"),
},
},
{
name: "Invalid Resources with Requests",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("my.org"): resource.MustParse("10m"),
},
}, {
name: "Invalid Resources with Requests",
requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("my.org"): resource.MustParse("10m"),
},
skipRequestValueCheck: true,
},
{
name: "Invalid Resources with Limits",
requirements: v1.ResourceRequirements{
Limits: v1.ResourceList{
v1.ResourceName("my.org"): resource.MustParse("9m"),
},
skipRequestValueCheck: true,
}, {
name: "Invalid Resources with Limits",
requirements: v1.ResourceRequirements{
Limits: v1.ResourceList{
v1.ResourceName("my.org"): resource.MustParse("9m"),
},
skipLimitValueCheck: true,
},
}
skipLimitValueCheck: true,
}}
for _, tc := range errorCase {
t.Run(tc.name, func(t *testing.T) {
errs := ValidateResourceRequirements(&tc.requirements, field.NewPath("resources"))
@@ -168,28 +159,22 @@ func TestValidateContainerResourceName(t *testing.T) {
successCase := []struct {
name string
ResourceName string
}{
{
name: "CPU resource",
ResourceName: "cpu",
},
{
name: "Memory resource",
ResourceName: "memory",
},
{
name: "Hugepages resource",
ResourceName: "hugepages-2Mi",
},
{
name: "Namespaced resource",
ResourceName: "kubernetes.io/resource-foo",
},
{
name: "Extended Resource",
ResourceName: "my.org/resource-bar",
},
}
}{{
name: "CPU resource",
ResourceName: "cpu",
}, {
name: "Memory resource",
ResourceName: "memory",
}, {
name: "Hugepages resource",
ResourceName: "hugepages-2Mi",
}, {
name: "Namespaced resource",
ResourceName: "kubernetes.io/resource-foo",
}, {
name: "Extended Resource",
ResourceName: "my.org/resource-bar",
}}
for _, tc := range successCase {
t.Run(tc.name, func(t *testing.T) {
if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) != 0 {
@@ -201,20 +186,16 @@ func TestValidateContainerResourceName(t *testing.T) {
errorCase := []struct {
name string
ResourceName string
}{
{
name: "Invalid standard resource",
ResourceName: "cpu-core",
},
{
name: "Invalid namespaced resource",
ResourceName: "kubernetes.io/",
},
{
name: "Invalid extended resource",
ResourceName: "my.org-foo-resource",
},
}
}{{
name: "Invalid standard resource",
ResourceName: "cpu-core",
}, {
name: "Invalid namespaced resource",
ResourceName: "kubernetes.io/",
}, {
name: "Invalid extended resource",
ResourceName: "my.org-foo-resource",
}}
for _, tc := range errorCase {
t.Run(tc.name, func(t *testing.T) {
if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) == 0 {
@@ -239,45 +220,38 @@ func TestValidatePodLogOptions(t *testing.T) {
successCase := []struct {
name string
podLogOptions v1.PodLogOptions
}{
{
name: "Empty PodLogOptions",
podLogOptions: v1.PodLogOptions{},
}{{
name: "Empty PodLogOptions",
podLogOptions: v1.PodLogOptions{},
}, {
name: "PodLogOptions with TailLines",
podLogOptions: v1.PodLogOptions{
TailLines: &positiveLine,
},
{
name: "PodLogOptions with TailLines",
podLogOptions: v1.PodLogOptions{
TailLines: &positiveLine,
},
}, {
name: "PodLogOptions with LimitBytes",
podLogOptions: v1.PodLogOptions{
LimitBytes: &limitBytesGreaterThan1,
},
{
name: "PodLogOptions with LimitBytes",
podLogOptions: v1.PodLogOptions{
LimitBytes: &limitBytesGreaterThan1,
},
}, {
name: "PodLogOptions with only sinceSeconds",
podLogOptions: v1.PodLogOptions{
SinceSeconds: &sinceSecondsGreaterThan1,
},
{
name: "PodLogOptions with only sinceSeconds",
podLogOptions: v1.PodLogOptions{
SinceSeconds: &sinceSecondsGreaterThan1,
},
}, {
name: "PodLogOptions with LimitBytes with TailLines",
podLogOptions: v1.PodLogOptions{
LimitBytes: &limitBytesGreaterThan1,
TailLines: &positiveLine,
},
{
name: "PodLogOptions with LimitBytes with TailLines",
podLogOptions: v1.PodLogOptions{
LimitBytes: &limitBytesGreaterThan1,
TailLines: &positiveLine,
},
}, {
name: "PodLogOptions with LimitBytes with TailLines with SinceSeconds",
podLogOptions: v1.PodLogOptions{
LimitBytes: &limitBytesGreaterThan1,
TailLines: &positiveLine,
SinceSeconds: &sinceSecondsGreaterThan1,
},
{
name: "PodLogOptions with LimitBytes with TailLines with SinceSeconds",
podLogOptions: v1.PodLogOptions{
LimitBytes: &limitBytesGreaterThan1,
TailLines: &positiveLine,
SinceSeconds: &sinceSecondsGreaterThan1,
},
},
}
}}
for _, tc := range successCase {
t.Run(tc.name, func(t *testing.T) {
if errs := ValidatePodLogOptions(&tc.podLogOptions); len(errs) != 0 {
@@ -289,40 +263,36 @@ func TestValidatePodLogOptions(t *testing.T) {
errorCase := []struct {
name string
podLogOptions v1.PodLogOptions
}{
{
name: "Invalid podLogOptions with Negative TailLines",
podLogOptions: v1.PodLogOptions{
TailLines: &negativeLine,
LimitBytes: &limitBytesGreaterThan1,
SinceSeconds: &sinceSecondsGreaterThan1,
},
}{{
name: "Invalid podLogOptions with Negative TailLines",
podLogOptions: v1.PodLogOptions{
TailLines: &negativeLine,
LimitBytes: &limitBytesGreaterThan1,
SinceSeconds: &sinceSecondsGreaterThan1,
},
{
name: "Invalid podLogOptions with zero or negative LimitBytes",
podLogOptions: v1.PodLogOptions{
TailLines: &positiveLine,
LimitBytes: &limitBytesLessThan1,
SinceSeconds: &sinceSecondsGreaterThan1,
},
}, {
name: "Invalid podLogOptions with zero or negative LimitBytes",
podLogOptions: v1.PodLogOptions{
TailLines: &positiveLine,
LimitBytes: &limitBytesLessThan1,
SinceSeconds: &sinceSecondsGreaterThan1,
},
{
name: "Invalid podLogOptions with zero or negative SinceSeconds",
podLogOptions: v1.PodLogOptions{
TailLines: &negativeLine,
LimitBytes: &limitBytesGreaterThan1,
SinceSeconds: &sinceSecondsLessThan1,
},
}, {
name: "Invalid podLogOptions with both SinceSeconds and SinceTime set",
podLogOptions: v1.PodLogOptions{
TailLines: &negativeLine,
LimitBytes: &limitBytesGreaterThan1,
SinceSeconds: &sinceSecondsGreaterThan1,
SinceTime: &timestamp,
},
}, {
name: "Invalid podLogOptions with zero or negative SinceSeconds",
podLogOptions: v1.PodLogOptions{
TailLines: &negativeLine,
LimitBytes: &limitBytesGreaterThan1,
SinceSeconds: &sinceSecondsLessThan1,
},
}
}, {
name: "Invalid podLogOptions with both SinceSeconds and SinceTime set",
podLogOptions: v1.PodLogOptions{
TailLines: &negativeLine,
LimitBytes: &limitBytesGreaterThan1,
SinceSeconds: &sinceSecondsGreaterThan1,
SinceTime: &timestamp,
},
}}
for _, tc := range errorCase {
t.Run(tc.name, func(t *testing.T) {
if errs := ValidatePodLogOptions(&tc.podLogOptions); len(errs) == 0 {
@@ -338,54 +308,37 @@ func TestAccumulateUniqueHostPorts(t *testing.T) {
containers []v1.Container
accumulator *sets.String
fldPath *field.Path
}{
{
name: "HostPort is not allocated while containers use the same port with different protocol",
containers: []v1.Container{
{
Ports: []v1.ContainerPort{
{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
},
},
},
{
Ports: []v1.ContainerPort{
{
HostPort: 8080,
Protocol: v1.ProtocolTCP,
},
},
},
},
accumulator: &sets.String{},
fldPath: field.NewPath("spec", "containers"),
},
{
name: "HostPort is not allocated while containers use different ports",
containers: []v1.Container{
{
Ports: []v1.ContainerPort{
{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
},
},
},
{
Ports: []v1.ContainerPort{
{
HostPort: 8081,
Protocol: v1.ProtocolUDP,
},
},
},
},
accumulator: &sets.String{},
fldPath: field.NewPath("spec", "containers"),
},
}
}{{
name: "HostPort is not allocated while containers use the same port with different protocol",
containers: []v1.Container{{
Ports: []v1.ContainerPort{{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
}},
}, {
Ports: []v1.ContainerPort{{
HostPort: 8080,
Protocol: v1.ProtocolTCP,
}},
}},
accumulator: &sets.String{},
fldPath: field.NewPath("spec", "containers"),
}, {
name: "HostPort is not allocated while containers use different ports",
containers: []v1.Container{{
Ports: []v1.ContainerPort{{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
}},
}, {
Ports: []v1.ContainerPort{{
HostPort: 8081,
Protocol: v1.ProtocolUDP,
}},
}},
accumulator: &sets.String{},
fldPath: field.NewPath("spec", "containers"),
}}
for _, tc := range successCase {
t.Run(tc.name, func(t *testing.T) {
if errs := AccumulateUniqueHostPorts(tc.containers, tc.accumulator, tc.fldPath); len(errs) != 0 {
@@ -398,54 +351,37 @@ func TestAccumulateUniqueHostPorts(t *testing.T) {
containers []v1.Container
accumulator *sets.String
fldPath *field.Path
}{
{
name: "HostPort is already allocated while containers use the same port with UDP",
containers: []v1.Container{
{
Ports: []v1.ContainerPort{
{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
},
},
},
{
Ports: []v1.ContainerPort{
{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
},
},
},
},
accumulator: &sets.String{},
fldPath: field.NewPath("spec", "containers"),
},
{
name: "HostPort is already allocated",
containers: []v1.Container{
{
Ports: []v1.ContainerPort{
{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
},
},
},
{
Ports: []v1.ContainerPort{
{
HostPort: 8081,
Protocol: v1.ProtocolUDP,
},
},
},
},
accumulator: &sets.String{"8080/UDP": sets.Empty{}},
fldPath: field.NewPath("spec", "containers"),
},
}
}{{
name: "HostPort is already allocated while containers use the same port with UDP",
containers: []v1.Container{{
Ports: []v1.ContainerPort{{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
}},
}, {
Ports: []v1.ContainerPort{{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
}},
}},
accumulator: &sets.String{},
fldPath: field.NewPath("spec", "containers"),
}, {
name: "HostPort is already allocated",
containers: []v1.Container{{
Ports: []v1.ContainerPort{{
HostPort: 8080,
Protocol: v1.ProtocolUDP,
}},
}, {
Ports: []v1.ContainerPort{{
HostPort: 8081,
Protocol: v1.ProtocolUDP,
}},
}},
accumulator: &sets.String{"8080/UDP": sets.Empty{}},
fldPath: field.NewPath("spec", "containers"),
}}
for _, tc := range errorCase {
t.Run(tc.name, func(t *testing.T) {
if errs := AccumulateUniqueHostPorts(tc.containers, tc.accumulator, tc.fldPath); len(errs) == 0 {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -477,22 +477,18 @@ func TestValidateIngress(t *testing.T) {
},
Spec: networking.IngressSpec{
DefaultBackend: &defaultBackend,
Rules: []networking.IngressRule{
{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/foo",
PathType: &pathTypeImplementationSpecific,
Backend: defaultBackend,
},
},
},
Rules: []networking.IngressRule{{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{{
Path: "/foo",
PathType: &pathTypeImplementationSpecific,
Backend: defaultBackend,
}},
},
},
},
}},
},
Status: networking.IngressStatus{
LoadBalancer: networking.IngressLoadBalancerStatus{
@@ -595,20 +591,18 @@ func TestValidateIngress(t *testing.T) {
tweakIngress: func(ing *networking.Ingress) {
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/foo",
PathType: &pathTypeImplementationSpecific,
Backend: networking.IngressBackend{
Service: serviceBackend,
Resource: &api.TypedLocalObjectReference{
APIGroup: utilpointer.String("example.com"),
Kind: "foo",
Name: "bar",
},
Paths: []networking.HTTPIngressPath{{
Path: "/foo",
PathType: &pathTypeImplementationSpecific,
Backend: networking.IngressBackend{
Service: serviceBackend,
Resource: &api.TypedLocalObjectReference{
APIGroup: utilpointer.String("example.com"),
Kind: "foo",
Name: "bar",
},
},
},
}},
},
}
},
@@ -620,20 +614,18 @@ func TestValidateIngress(t *testing.T) {
tweakIngress: func(ing *networking.Ingress) {
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/foo",
PathType: &pathTypeImplementationSpecific,
Backend: networking.IngressBackend{
Service: serviceBackend,
Resource: &api.TypedLocalObjectReference{
APIGroup: utilpointer.String("example.com"),
Kind: "foo",
Name: "bar",
},
Paths: []networking.HTTPIngressPath{{
Path: "/foo",
PathType: &pathTypeImplementationSpecific,
Backend: networking.IngressBackend{
Service: serviceBackend,
Resource: &api.TypedLocalObjectReference{
APIGroup: utilpointer.String("example.com"),
Kind: "foo",
Name: "bar",
},
},
},
}},
},
}
},
@@ -790,15 +782,13 @@ func TestValidateIngressRuleValue(t *testing.T) {
t.Run(name, func(t *testing.T) {
irv := &networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: testCase.path,
PathType: &testCase.pathType,
Backend: networking.IngressBackend{
Service: &serviceBackend,
},
Paths: []networking.HTTPIngressPath{{
Path: testCase.path,
PathType: &testCase.pathType,
Backend: networking.IngressBackend{
Service: &serviceBackend,
},
},
}},
},
}
errs := validateIngressRuleValue(irv, field.NewPath("testing"), IngressValidationOptions{})
@@ -1638,22 +1628,18 @@ func TestValidateIngressTLS(t *testing.T) {
},
Spec: networking.IngressSpec{
DefaultBackend: &defaultBackend,
Rules: []networking.IngressRule{
{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/foo",
PathType: &pathTypeImplementationSpecific,
Backend: defaultBackend,
},
},
},
Rules: []networking.IngressRule{{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{{
Path: "/foo",
PathType: &pathTypeImplementationSpecific,
Backend: defaultBackend,
}},
},
},
},
}},
},
Status: networking.IngressStatus{
LoadBalancer: networking.IngressLoadBalancerStatus{
@@ -1670,11 +1656,9 @@ func TestValidateIngressTLS(t *testing.T) {
wildcardHost := "foo.*.bar.com"
badWildcardTLS := newValid()
badWildcardTLS.Spec.Rules[0].Host = "*.foo.bar.com"
badWildcardTLS.Spec.TLS = []networking.IngressTLS{
{
Hosts: []string{wildcardHost},
},
}
badWildcardTLS.Spec.TLS = []networking.IngressTLS{{
Hosts: []string{wildcardHost},
}}
badWildcardTLSErr := fmt.Sprintf("spec.tls[0].hosts[0]: Invalid value: '%v'", wildcardHost)
errorCases[badWildcardTLSErr] = badWildcardTLS
@@ -1696,11 +1680,9 @@ func TestValidateIngressTLS(t *testing.T) {
wildHost := "*.bar.com"
goodWildcardTLS := newValid()
goodWildcardTLS.Spec.Rules[0].Host = "*.bar.com"
goodWildcardTLS.Spec.TLS = []networking.IngressTLS{
{
Hosts: []string{wildHost},
},
}
goodWildcardTLS.Spec.TLS = []networking.IngressTLS{{
Hosts: []string{wildHost},
}}
validCases[fmt.Sprintf("spec.tls[0].hosts: Valid value: '%v'", wildHost)] = goodWildcardTLS
for k, v := range validCases {
errs := validateIngress(&v, IngressValidationOptions{})
@@ -1731,21 +1713,17 @@ func TestValidateEmptyIngressTLS(t *testing.T) {
Namespace: metav1.NamespaceDefault,
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
PathType: &pathTypeImplementationSpecific,
Backend: defaultBackend,
},
},
},
Rules: []networking.IngressRule{{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{{
PathType: &pathTypeImplementationSpecific,
Backend: defaultBackend,
}},
},
},
},
}},
},
}
}
@@ -1757,11 +1735,9 @@ func TestValidateEmptyIngressTLS(t *testing.T) {
}
validCases[fmt.Sprintf("spec.tls[0]: Valid value: %v", goodEmptyTLS.Spec.TLS[0])] = goodEmptyTLS
goodEmptyHosts := newValid()
goodEmptyHosts.Spec.TLS = []networking.IngressTLS{
{
Hosts: []string{},
},
}
goodEmptyHosts.Spec.TLS = []networking.IngressTLS{{
Hosts: []string{},
}}
validCases[fmt.Sprintf("spec.tls[0]: Valid value: %v", goodEmptyHosts.Spec.TLS[0])] = goodEmptyHosts
for k, v := range validCases {
errs := validateIngress(&v, IngressValidationOptions{})
@@ -1791,21 +1767,17 @@ func TestValidateIngressStatusUpdate(t *testing.T) {
},
Spec: networking.IngressSpec{
DefaultBackend: &defaultBackend,
Rules: []networking.IngressRule{
{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/foo",
Backend: defaultBackend,
},
},
},
Rules: []networking.IngressRule{{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{{
Path: "/foo",
Backend: defaultBackend,
}},
},
},
},
}},
},
Status: networking.IngressStatus{
LoadBalancer: networking.IngressLoadBalancerStatus{
@@ -1867,17 +1839,13 @@ func TestValidateIngressStatusUpdate(t *testing.T) {
func makeNodeSelector(key string, op api.NodeSelectorOperator, values []string) *api.NodeSelector {
return &api.NodeSelector{
NodeSelectorTerms: []api.NodeSelectorTerm{
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: key,
Operator: op,
Values: values,
},
},
},
},
NodeSelectorTerms: []api.NodeSelectorTerm{{
MatchExpressions: []api.NodeSelectorRequirement{{
Key: key,
Operator: op,
Values: values,
}},
}},
}
}
@@ -1901,59 +1869,49 @@ func TestValidateClusterCIDR(t *testing.T) {
name string
cc *networking.ClusterCIDR
expectErr bool
}{
{
name: "valid SingleStack IPv4 ClusterCIDR",
cc: makeClusterCIDR(8, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
},
{
name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits = maxPerNodeHostBits",
cc: makeClusterCIDR(16, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
},
{
name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits > minPerNodeHostBits",
cc: makeClusterCIDR(4, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
},
{
name: "valid SingleStack IPv6 ClusterCIDR",
cc: makeClusterCIDR(8, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
},
{
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits = maxPerNodeHostBit",
cc: makeClusterCIDR(64, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
},
{
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits > minPerNodeHostBit",
cc: makeClusterCIDR(4, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
},
{
name: "valid SingleStack IPv6 ClusterCIDR perNodeHostBits=100",
cc: makeClusterCIDR(100, "", "fd00:1:1::/16", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
},
{
name: "valid DualStack ClusterCIDR",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
},
{
name: "valid DualStack ClusterCIDR, no NodeSelector",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", nil),
expectErr: false,
},
}{{
name: "valid SingleStack IPv4 ClusterCIDR",
cc: makeClusterCIDR(8, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
}, {
name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits = maxPerNodeHostBits",
cc: makeClusterCIDR(16, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
}, {
name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits > minPerNodeHostBits",
cc: makeClusterCIDR(4, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
}, {
name: "valid SingleStack IPv6 ClusterCIDR",
cc: makeClusterCIDR(8, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
}, {
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits = maxPerNodeHostBit",
cc: makeClusterCIDR(64, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
}, {
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits > minPerNodeHostBit",
cc: makeClusterCIDR(4, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
}, {
name: "valid SingleStack IPv6 ClusterCIDR perNodeHostBits=100",
cc: makeClusterCIDR(100, "", "fd00:1:1::/16", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
}, {
name: "valid DualStack ClusterCIDR",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
}, {
name: "valid DualStack ClusterCIDR, no NodeSelector",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", nil),
expectErr: false,
},
// Failure cases.
{
name: "invalid ClusterCIDR, no IPv4 or IPv6 CIDR",
cc: makeClusterCIDR(8, "", "", nil),
expectErr: true,
},
{
}, {
name: "invalid ClusterCIDR, invalid nodeSelector",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("NoUppercaseOrSpecialCharsLike=Equals", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
@@ -1963,13 +1921,11 @@ func TestValidateClusterCIDR(t *testing.T) {
name: "invalid SingleStack IPv4 ClusterCIDR, invalid spec.IPv4",
cc: makeClusterCIDR(8, "test", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
}, {
name: "invalid Singlestack IPv4 ClusterCIDR, perNodeHostBits > maxPerNodeHostBits",
cc: makeClusterCIDR(100, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
}, {
name: "invalid SingleStack IPv4 ClusterCIDR, perNodeHostBits < minPerNodeHostBits",
cc: makeClusterCIDR(2, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
@@ -1979,18 +1935,15 @@ func TestValidateClusterCIDR(t *testing.T) {
name: "invalid SingleStack IPv6 ClusterCIDR, invalid spec.IPv6",
cc: makeClusterCIDR(8, "", "testv6", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
}, {
name: "invalid SingleStack IPv6 ClusterCIDR, valid IPv4 CIDR in spec.IPv6",
cc: makeClusterCIDR(8, "", "10.2.0.0/16", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
}, {
name: "invalid SingleStack IPv6 ClusterCIDR, invalid perNodeHostBits > maxPerNodeHostBits",
cc: makeClusterCIDR(12, "", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
}, {
name: "invalid SingleStack IPv6 ClusterCIDR, invalid perNodeHostBits < minPerNodeHostBits",
cc: makeClusterCIDR(3, "", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
@@ -2000,18 +1953,15 @@ func TestValidateClusterCIDR(t *testing.T) {
name: "invalid DualStack ClusterCIDR, valid spec.IPv4, invalid spec.IPv6",
cc: makeClusterCIDR(8, "10.1.0.0/16", "testv6", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
}, {
name: "invalid DualStack ClusterCIDR, valid spec.IPv6, invalid spec.IPv4",
cc: makeClusterCIDR(8, "testv4", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
}, {
name: "invalid DualStack ClusterCIDR, invalid perNodeHostBits > maxPerNodeHostBits",
cc: makeClusterCIDR(24, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
}, {
name: "invalid DualStack ClusterCIDR, valid IPv6 CIDR in spec.IPv4",
cc: makeClusterCIDR(8, "fd00::/120", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
@@ -2038,33 +1988,27 @@ func TestValidateClusterConfigUpdate(t *testing.T) {
name string
cc *networking.ClusterCIDR
expectErr bool
}{
{
name: "Successful update, no changes to ClusterCIDR.Spec",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
},
{
name: "Failed update, update spec.PerNodeHostBits",
cc: makeClusterCIDR(12, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
name: "Failed update, update spec.IPv4",
cc: makeClusterCIDR(8, "10.2.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
name: "Failed update, update spec.IPv6",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:2:/112", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
},
{
name: "Failed update, update spec.NodeSelector",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar2"})),
expectErr: true,
},
}
}{{
name: "Successful update, no changes to ClusterCIDR.Spec",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false,
}, {
name: "Failed update, update spec.PerNodeHostBits",
cc: makeClusterCIDR(12, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
}, {
name: "Failed update, update spec.IPv4",
cc: makeClusterCIDR(8, "10.2.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
}, {
name: "Failed update, update spec.IPv6",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:2:/112", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true,
}, {
name: "Failed update, update spec.NodeSelector",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar2"})),
expectErr: true,
}}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
err := ValidateClusterCIDRUpdate(testCase.cc, oldCCC)
@@ -2244,15 +2188,14 @@ func TestValidateIPAddressUpdate(t *testing.T) {
name string
new func(svc *networking.IPAddress) *networking.IPAddress
expectErr bool
}{
{
name: "Successful update, no changes",
new: func(old *networking.IPAddress) *networking.IPAddress {
out := old.DeepCopy()
return out
},
expectErr: false,
}{{
name: "Successful update, no changes",
new: func(old *networking.IPAddress) *networking.IPAddress {
out := old.DeepCopy()
return out
},
expectErr: false,
},
{
name: "Failed update, update spec.ParentRef",
@@ -2267,8 +2210,7 @@ func TestValidateIPAddressUpdate(t *testing.T) {
return out
}, expectErr: true,
},
{
}, {
name: "Failed update, delete spec.ParentRef",
new: func(svc *networking.IPAddress) *networking.IPAddress {
out := svc.DeepCopy()

View File

@@ -134,17 +134,15 @@ func TestValidateOverhead(t *testing.T) {
successCase := []struct {
Name string
overhead *node.Overhead
}{
{
Name: "Overhead with valid cpu and memory resources",
overhead: &node.Overhead{
PodFixed: core.ResourceList{
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
},
}{{
Name: "Overhead with valid cpu and memory resources",
overhead: &node.Overhead{
PodFixed: core.ResourceList{
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
},
},
}
}}
for _, tc := range successCase {
rc := &node.RuntimeClass{
@@ -160,16 +158,14 @@ func TestValidateOverhead(t *testing.T) {
errorCase := []struct {
Name string
overhead *node.Overhead
}{
{
Name: "Invalid Resources",
overhead: &node.Overhead{
PodFixed: core.ResourceList{
core.ResourceName("my.org"): resource.MustParse("10m"),
},
}{{
Name: "Invalid Resources",
overhead: &node.Overhead{
PodFixed: core.ResourceList{
core.ResourceName("my.org"): resource.MustParse("10m"),
},
},
}
}}
for _, tc := range errorCase {
rc := &node.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},

View File

@@ -107,40 +107,35 @@ func TestValidateUnhealthyPodEvictionPolicyDisruptionBudgetSpec(t *testing.T) {
name string
pdbSpec policy.PodDisruptionBudgetSpec
expectErr bool
}{
{
name: "valid nil UnhealthyPodEvictionPolicy",
pdbSpec: policy.PodDisruptionBudgetSpec{
MinAvailable: &c1,
UnhealthyPodEvictionPolicy: nil,
},
expectErr: false,
}{{
name: "valid nil UnhealthyPodEvictionPolicy",
pdbSpec: policy.PodDisruptionBudgetSpec{
MinAvailable: &c1,
UnhealthyPodEvictionPolicy: nil,
},
{
name: "valid UnhealthyPodEvictionPolicy",
pdbSpec: policy.PodDisruptionBudgetSpec{
MinAvailable: &c1,
UnhealthyPodEvictionPolicy: &alwaysAllowPolicy,
},
expectErr: false,
expectErr: false,
}, {
name: "valid UnhealthyPodEvictionPolicy",
pdbSpec: policy.PodDisruptionBudgetSpec{
MinAvailable: &c1,
UnhealthyPodEvictionPolicy: &alwaysAllowPolicy,
},
{
name: "empty UnhealthyPodEvictionPolicy",
pdbSpec: policy.PodDisruptionBudgetSpec{
MinAvailable: &c1,
UnhealthyPodEvictionPolicy: new(policy.UnhealthyPodEvictionPolicyType),
},
expectErr: true,
expectErr: false,
}, {
name: "empty UnhealthyPodEvictionPolicy",
pdbSpec: policy.PodDisruptionBudgetSpec{
MinAvailable: &c1,
UnhealthyPodEvictionPolicy: new(policy.UnhealthyPodEvictionPolicyType),
},
{
name: "invalid UnhealthyPodEvictionPolicy",
pdbSpec: policy.PodDisruptionBudgetSpec{
MinAvailable: &c1,
UnhealthyPodEvictionPolicy: &invalidPolicy,
},
expectErr: true,
expectErr: true,
}, {
name: "invalid UnhealthyPodEvictionPolicy",
pdbSpec: policy.PodDisruptionBudgetSpec{
MinAvailable: &c1,
UnhealthyPodEvictionPolicy: &invalidPolicy,
},
}
expectErr: true,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@@ -162,128 +157,112 @@ func TestValidatePodDisruptionBudgetStatus(t *testing.T) {
name string
pdbStatus policy.PodDisruptionBudgetStatus
expectErrForVersion map[schema.GroupVersion]bool
}{
{
name: "DisruptionsAllowed: 10",
pdbStatus: policy.PodDisruptionBudgetStatus{
DisruptionsAllowed: 10,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
}{{
name: "DisruptionsAllowed: 10",
pdbStatus: policy.PodDisruptionBudgetStatus{
DisruptionsAllowed: 10,
},
{
name: "CurrentHealthy: 5",
pdbStatus: policy.PodDisruptionBudgetStatus{
CurrentHealthy: 5,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
{
name: "DesiredHealthy: 3",
pdbStatus: policy.PodDisruptionBudgetStatus{
DesiredHealthy: 3,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
}, {
name: "CurrentHealthy: 5",
pdbStatus: policy.PodDisruptionBudgetStatus{
CurrentHealthy: 5,
},
{
name: "ExpectedPods: 2",
pdbStatus: policy.PodDisruptionBudgetStatus{
ExpectedPods: 2,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
{
name: "DisruptionsAllowed: -10",
pdbStatus: policy.PodDisruptionBudgetStatus{
DisruptionsAllowed: -10,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
}, {
name: "DesiredHealthy: 3",
pdbStatus: policy.PodDisruptionBudgetStatus{
DesiredHealthy: 3,
},
{
name: "CurrentHealthy: -5",
pdbStatus: policy.PodDisruptionBudgetStatus{
CurrentHealthy: -5,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
{
name: "DesiredHealthy: -3",
pdbStatus: policy.PodDisruptionBudgetStatus{
DesiredHealthy: -3,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
}, {
name: "ExpectedPods: 2",
pdbStatus: policy.PodDisruptionBudgetStatus{
ExpectedPods: 2,
},
{
name: "ExpectedPods: -2",
pdbStatus: policy.PodDisruptionBudgetStatus{
ExpectedPods: -2,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
{
name: "Conditions valid",
pdbStatus: policy.PodDisruptionBudgetStatus{
Conditions: []metav1.Condition{
{
Type: policyv1beta1.DisruptionAllowedCondition,
Status: metav1.ConditionTrue,
LastTransitionTime: metav1.Time{
Time: time.Now().Add(-5 * time.Minute),
},
Reason: policyv1beta1.SufficientPodsReason,
Message: "message",
ObservedGeneration: 3,
},
}, {
name: "DisruptionsAllowed: -10",
pdbStatus: policy.PodDisruptionBudgetStatus{
DisruptionsAllowed: -10,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
}, {
name: "CurrentHealthy: -5",
pdbStatus: policy.PodDisruptionBudgetStatus{
CurrentHealthy: -5,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
}, {
name: "DesiredHealthy: -3",
pdbStatus: policy.PodDisruptionBudgetStatus{
DesiredHealthy: -3,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
}, {
name: "ExpectedPods: -2",
pdbStatus: policy.PodDisruptionBudgetStatus{
ExpectedPods: -2,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
}, {
name: "Conditions valid",
pdbStatus: policy.PodDisruptionBudgetStatus{
Conditions: []metav1.Condition{{
Type: policyv1beta1.DisruptionAllowedCondition,
Status: metav1.ConditionTrue,
LastTransitionTime: metav1.Time{
Time: time.Now().Add(-5 * time.Minute),
},
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
Reason: policyv1beta1.SufficientPodsReason,
Message: "message",
ObservedGeneration: 3,
}},
},
{
name: "Conditions not valid",
pdbStatus: policy.PodDisruptionBudgetStatus{
Conditions: []metav1.Condition{
{
Type: policyv1beta1.DisruptionAllowedCondition,
Status: metav1.ConditionTrue,
},
{
Type: policyv1beta1.DisruptionAllowedCondition,
Status: metav1.ConditionFalse,
},
},
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectErrors,
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectNoErrors,
policyv1beta1.SchemeGroupVersion: expectNoErrors,
},
}
}, {
name: "Conditions not valid",
pdbStatus: policy.PodDisruptionBudgetStatus{
Conditions: []metav1.Condition{{
Type: policyv1beta1.DisruptionAllowedCondition,
Status: metav1.ConditionTrue,
}, {
Type: policyv1beta1.DisruptionAllowedCondition,
Status: metav1.ConditionFalse,
}},
},
expectErrForVersion: map[schema.GroupVersion]bool{
policy.SchemeGroupVersion: expectErrors,
policyv1beta1.SchemeGroupVersion: expectErrors,
},
}}
for _, tc := range testCases {
for apiVersion, expectErrors := range tc.expectErrForVersion {
@@ -1165,23 +1144,19 @@ func TestAllowEphemeralVolumeType(t *testing.T) {
description string
hasGenericVolume bool
psp func() *policy.PodSecurityPolicy
}{
{
description: "PodSecurityPolicySpec Without GenericVolume",
hasGenericVolume: false,
psp: pspWithoutGenericVolume,
},
{
description: "PodSecurityPolicySpec With GenericVolume",
hasGenericVolume: true,
psp: pspWithGenericVolume,
},
{
description: "is nil",
hasGenericVolume: false,
psp: pspNil,
},
}
}{{
description: "PodSecurityPolicySpec Without GenericVolume",
hasGenericVolume: false,
psp: pspWithoutGenericVolume,
}, {
description: "PodSecurityPolicySpec With GenericVolume",
hasGenericVolume: true,
psp: pspWithGenericVolume,
}, {
description: "is nil",
hasGenericVolume: false,
psp: pspNil,
}}
for _, oldPSPInfo := range pspInfo {
for _, newPSPInfo := range pspInfo {

View File

@@ -402,12 +402,10 @@ func TestValidateRoleNonResourceURL(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Name: "default",
},
Rules: []rbac.PolicyRule{
{
Verbs: []string{"get"},
NonResourceURLs: []string{"/*"},
},
},
Rules: []rbac.PolicyRule{{
Verbs: []string{"get"},
NonResourceURLs: []string{"/*"},
}},
},
wantErr: false,
}.test(t)
@@ -420,13 +418,11 @@ func TestValidateRoleNamespacedNonResourceURL(t *testing.T) {
Namespace: "default",
Name: "default",
},
Rules: []rbac.PolicyRule{
{
// non-resource URLs are invalid for namespaced rules
Verbs: []string{"get"},
NonResourceURLs: []string{"/*"},
},
},
Rules: []rbac.PolicyRule{{
// non-resource URLs are invalid for namespaced rules
Verbs: []string{"get"},
NonResourceURLs: []string{"/*"},
}},
},
wantErr: true,
errType: field.ErrorTypeInvalid,
@@ -440,12 +436,10 @@ func TestValidateRoleNonResourceURLNoVerbs(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Name: "default",
},
Rules: []rbac.PolicyRule{
{
Verbs: []string{},
NonResourceURLs: []string{"/*"},
},
},
Rules: []rbac.PolicyRule{{
Verbs: []string{},
NonResourceURLs: []string{"/*"},
}},
},
wantErr: true,
errType: field.ErrorTypeRequired,
@@ -460,14 +454,12 @@ func TestValidateRoleMixedNonResourceAndResource(t *testing.T) {
Name: "default",
Namespace: "default",
},
Rules: []rbac.PolicyRule{
{
Verbs: []string{"get"},
NonResourceURLs: []string{"/*"},
APIGroups: []string{"v1"},
Resources: []string{"pods"},
},
},
Rules: []rbac.PolicyRule{{
Verbs: []string{"get"},
NonResourceURLs: []string{"/*"},
APIGroups: []string{"v1"},
Resources: []string{"pods"},
}},
},
wantErr: true,
errType: field.ErrorTypeInvalid,
@@ -482,13 +474,11 @@ func TestValidateRoleValidResource(t *testing.T) {
Name: "default",
Namespace: "default",
},
Rules: []rbac.PolicyRule{
{
Verbs: []string{"get"},
APIGroups: []string{"v1"},
Resources: []string{"pods"},
},
},
Rules: []rbac.PolicyRule{{
Verbs: []string{"get"},
APIGroups: []string{"v1"},
Resources: []string{"pods"},
}},
},
wantErr: false,
}.test(t)
@@ -501,12 +491,10 @@ func TestValidateRoleNoAPIGroup(t *testing.T) {
Name: "default",
Namespace: "default",
},
Rules: []rbac.PolicyRule{
{
Verbs: []string{"get"},
Resources: []string{"pods"},
},
},
Rules: []rbac.PolicyRule{{
Verbs: []string{"get"},
Resources: []string{"pods"},
}},
},
wantErr: true,
errType: field.ErrorTypeRequired,
@@ -521,12 +509,10 @@ func TestValidateRoleNoResources(t *testing.T) {
Name: "default",
Namespace: "default",
},
Rules: []rbac.PolicyRule{
{
Verbs: []string{"get"},
APIGroups: []string{"v1"},
},
},
Rules: []rbac.PolicyRule{{
Verbs: []string{"get"},
APIGroups: []string{"v1"},
}},
},
wantErr: true,
errType: field.ErrorTypeRequired,

File diff suppressed because it is too large Load Diff

View File

@@ -86,502 +86,442 @@ func TestValidateKubeletConfiguration(t *testing.T) {
name string
configure func(config *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration
errMsg string
}{
{
name: "Success",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf
},
}{{
name: "Success",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf
},
{
name: "invalid NodeLeaseDurationSeconds",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.NodeLeaseDurationSeconds = 0
return conf
},
errMsg: "invalid configuration: nodeLeaseDurationSeconds must be greater than 0",
}, {
name: "invalid NodeLeaseDurationSeconds",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.NodeLeaseDurationSeconds = 0
return conf
},
{
name: "specify EnforceNodeAllocatable without enabling CgroupsPerQOS",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.CgroupsPerQOS = false
conf.EnforceNodeAllocatable = []string{"pods"}
return conf
},
errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) is not supported unless cgroupsPerQOS (--cgroups-per-qos) is set to true",
errMsg: "invalid configuration: nodeLeaseDurationSeconds must be greater than 0",
}, {
name: "specify EnforceNodeAllocatable without enabling CgroupsPerQOS",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.CgroupsPerQOS = false
conf.EnforceNodeAllocatable = []string{"pods"}
return conf
},
{
name: "specify SystemCgroups without CgroupRoot",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.SystemCgroups = "/"
conf.CgroupRoot = ""
return conf
},
errMsg: "invalid configuration: systemCgroups (--system-cgroups) was specified and cgroupRoot (--cgroup-root) was not specified",
errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) is not supported unless cgroupsPerQOS (--cgroups-per-qos) is set to true",
}, {
name: "specify SystemCgroups without CgroupRoot",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.SystemCgroups = "/"
conf.CgroupRoot = ""
return conf
},
{
name: "invalid EventBurst",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EventBurst = -1
return conf
},
errMsg: "invalid configuration: eventBurst (--event-burst) -1 must not be a negative number",
errMsg: "invalid configuration: systemCgroups (--system-cgroups) was specified and cgroupRoot (--cgroup-root) was not specified",
}, {
name: "invalid EventBurst",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EventBurst = -1
return conf
},
{
name: "invalid EventRecordQPS",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EventRecordQPS = -1
return conf
},
errMsg: "invalid configuration: eventRecordQPS (--event-qps) -1 must not be a negative number",
errMsg: "invalid configuration: eventBurst (--event-burst) -1 must not be a negative number",
}, {
name: "invalid EventRecordQPS",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EventRecordQPS = -1
return conf
},
{
name: "invalid HealthzPort",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.HealthzPort = 65536
return conf
},
errMsg: "invalid configuration: healthzPort (--healthz-port) 65536 must be between 1 and 65535, inclusive",
errMsg: "invalid configuration: eventRecordQPS (--event-qps) -1 must not be a negative number",
}, {
name: "invalid HealthzPort",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.HealthzPort = 65536
return conf
},
{
name: "specify CPUCFSQuotaPeriod without enabling CPUCFSQuotaPeriod",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": false}
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 200 * time.Millisecond}
return conf
},
errMsg: "invalid configuration: cpuCFSQuotaPeriod (--cpu-cfs-quota-period) {200ms} requires feature gate CustomCPUCFSQuotaPeriod",
errMsg: "invalid configuration: healthzPort (--healthz-port) 65536 must be between 1 and 65535, inclusive",
}, {
name: "specify CPUCFSQuotaPeriod without enabling CPUCFSQuotaPeriod",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": false}
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 200 * time.Millisecond}
return conf
},
{
name: "invalid CPUCFSQuotaPeriod",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": true}
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 2 * time.Second}
return conf
},
errMsg: "invalid configuration: cpuCFSQuotaPeriod (--cpu-cfs-quota-period) {2s} must be between 1ms and 1sec, inclusive",
errMsg: "invalid configuration: cpuCFSQuotaPeriod (--cpu-cfs-quota-period) {200ms} requires feature gate CustomCPUCFSQuotaPeriod",
}, {
name: "invalid CPUCFSQuotaPeriod",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": true}
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 2 * time.Second}
return conf
},
{
name: "invalid ImageGCHighThresholdPercent",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCHighThresholdPercent = 101
return conf
},
errMsg: "invalid configuration: imageGCHighThresholdPercent (--image-gc-high-threshold) 101 must be between 0 and 100, inclusive",
errMsg: "invalid configuration: cpuCFSQuotaPeriod (--cpu-cfs-quota-period) {2s} must be between 1ms and 1sec, inclusive",
}, {
name: "invalid ImageGCHighThresholdPercent",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCHighThresholdPercent = 101
return conf
},
{
name: "invalid ImageGCLowThresholdPercent",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCLowThresholdPercent = -1
return conf
},
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) -1 must be between 0 and 100, inclusive",
errMsg: "invalid configuration: imageGCHighThresholdPercent (--image-gc-high-threshold) 101 must be between 0 and 100, inclusive",
}, {
name: "invalid ImageGCLowThresholdPercent",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCLowThresholdPercent = -1
return conf
},
{
name: "ImageGCLowThresholdPercent is equal to ImageGCHighThresholdPercent",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCHighThresholdPercent = 0
conf.ImageGCLowThresholdPercent = 0
return conf
},
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) 0 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) -1 must be between 0 and 100, inclusive",
}, {
name: "ImageGCLowThresholdPercent is equal to ImageGCHighThresholdPercent",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCHighThresholdPercent = 0
conf.ImageGCLowThresholdPercent = 0
return conf
},
{
name: "ImageGCLowThresholdPercent is greater than ImageGCHighThresholdPercent",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCHighThresholdPercent = 0
conf.ImageGCLowThresholdPercent = 1
return conf
},
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) 1 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) 0 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
}, {
name: "ImageGCLowThresholdPercent is greater than ImageGCHighThresholdPercent",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCHighThresholdPercent = 0
conf.ImageGCLowThresholdPercent = 1
return conf
},
{
name: "invalid IPTablesDropBit",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.IPTablesDropBit = 32
return conf
},
errMsg: "invalid configuration: iptablesDropBit (--iptables-drop-bit) 32 must be between 0 and 31, inclusive",
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) 1 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
}, {
name: "invalid IPTablesDropBit",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.IPTablesDropBit = 32
return conf
},
{
name: "invalid IPTablesMasqueradeBit",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.IPTablesMasqueradeBit = 32
return conf
},
errMsg: "invalid configuration: iptablesMasqueradeBit (--iptables-masquerade-bit) 32 must be between 0 and 31, inclusive",
errMsg: "invalid configuration: iptablesDropBit (--iptables-drop-bit) 32 must be between 0 and 31, inclusive",
}, {
name: "invalid IPTablesMasqueradeBit",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.IPTablesMasqueradeBit = 32
return conf
},
{
name: "invalid KubeAPIBurst",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.KubeAPIBurst = -1
return conf
},
errMsg: "invalid configuration: kubeAPIBurst (--kube-api-burst) -1 must not be a negative number",
errMsg: "invalid configuration: iptablesMasqueradeBit (--iptables-masquerade-bit) 32 must be between 0 and 31, inclusive",
}, {
name: "invalid KubeAPIBurst",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.KubeAPIBurst = -1
return conf
},
{
name: "invalid KubeAPIQPS",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.KubeAPIQPS = -1
return conf
},
errMsg: "invalid configuration: kubeAPIQPS (--kube-api-qps) -1 must not be a negative number",
errMsg: "invalid configuration: kubeAPIBurst (--kube-api-burst) -1 must not be a negative number",
}, {
name: "invalid KubeAPIQPS",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.KubeAPIQPS = -1
return conf
},
{
name: "invalid NodeStatusMaxImages",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.NodeStatusMaxImages = -2
return conf
},
errMsg: "invalid configuration: nodeStatusMaxImages (--node-status-max-images) -2 must be -1 or greater",
errMsg: "invalid configuration: kubeAPIQPS (--kube-api-qps) -1 must not be a negative number",
}, {
name: "invalid NodeStatusMaxImages",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.NodeStatusMaxImages = -2
return conf
},
{
name: "invalid MaxOpenFiles",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxOpenFiles = -1
return conf
},
errMsg: "invalid configuration: maxOpenFiles (--max-open-files) -1 must not be a negative number",
errMsg: "invalid configuration: nodeStatusMaxImages (--node-status-max-images) -2 must be -1 or greater",
}, {
name: "invalid MaxOpenFiles",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxOpenFiles = -1
return conf
},
{
name: "invalid MaxPods",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxPods = -1
return conf
},
errMsg: "invalid configuration: maxPods (--max-pods) -1 must not be a negative number",
errMsg: "invalid configuration: maxOpenFiles (--max-open-files) -1 must not be a negative number",
}, {
name: "invalid MaxPods",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxPods = -1
return conf
},
{
name: "invalid OOMScoreAdj",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.OOMScoreAdj = 1001
return conf
},
errMsg: "invalid configuration: oomScoreAdj (--oom-score-adj) 1001 must be between -1000 and 1000, inclusive",
errMsg: "invalid configuration: maxPods (--max-pods) -1 must not be a negative number",
}, {
name: "invalid OOMScoreAdj",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.OOMScoreAdj = 1001
return conf
},
{
name: "invalid PodsPerCore",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.PodsPerCore = -1
return conf
},
errMsg: "invalid configuration: podsPerCore (--pods-per-core) -1 must not be a negative number",
errMsg: "invalid configuration: oomScoreAdj (--oom-score-adj) 1001 must be between -1000 and 1000, inclusive",
}, {
name: "invalid PodsPerCore",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.PodsPerCore = -1
return conf
},
{
name: "invalid Port",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.Port = 65536
return conf
},
errMsg: "invalid configuration: port (--port) 65536 must be between 1 and 65535, inclusive",
errMsg: "invalid configuration: podsPerCore (--pods-per-core) -1 must not be a negative number",
}, {
name: "invalid Port",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.Port = 65536
return conf
},
{
name: "invalid ReadOnlyPort",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ReadOnlyPort = 65536
return conf
},
errMsg: "invalid configuration: readOnlyPort (--read-only-port) 65536 must be between 0 and 65535, inclusive",
errMsg: "invalid configuration: port (--port) 65536 must be between 1 and 65535, inclusive",
}, {
name: "invalid ReadOnlyPort",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ReadOnlyPort = 65536
return conf
},
{
name: "invalid RegistryBurst",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.RegistryBurst = -1
return conf
},
errMsg: "invalid configuration: registryBurst (--registry-burst) -1 must not be a negative number",
errMsg: "invalid configuration: readOnlyPort (--read-only-port) 65536 must be between 0 and 65535, inclusive",
}, {
name: "invalid RegistryBurst",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.RegistryBurst = -1
return conf
},
{
name: "invalid RegistryPullQPS",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.RegistryPullQPS = -1
return conf
},
errMsg: "invalid configuration: registryPullQPS (--registry-qps) -1 must not be a negative number",
errMsg: "invalid configuration: registryBurst (--registry-burst) -1 must not be a negative number",
}, {
name: "invalid RegistryPullQPS",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.RegistryPullQPS = -1
return conf
},
{
name: "invalid MaxParallelImagePulls",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxParallelImagePulls = utilpointer.Int32(0)
return conf
},
errMsg: "invalid configuration: maxParallelImagePulls 0 must be a positive number",
errMsg: "invalid configuration: registryPullQPS (--registry-qps) -1 must not be a negative number",
}, {
name: "invalid MaxParallelImagePulls",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxParallelImagePulls = utilpointer.Int32(0)
return conf
},
{
name: "invalid MaxParallelImagePulls and SerializeImagePulls combination",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxParallelImagePulls = utilpointer.Int32(3)
conf.SerializeImagePulls = true
return conf
},
errMsg: "invalid configuration: maxParallelImagePulls cannot be larger than 1 unless SerializeImagePulls (--serialize-image-pulls) is set to false",
errMsg: "invalid configuration: maxParallelImagePulls 0 must be a positive number",
}, {
name: "invalid MaxParallelImagePulls and SerializeImagePulls combination",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxParallelImagePulls = utilpointer.Int32(3)
conf.SerializeImagePulls = true
return conf
},
{
name: "valid MaxParallelImagePulls and SerializeImagePulls combination",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxParallelImagePulls = utilpointer.Int32(1)
conf.SerializeImagePulls = true
return conf
},
errMsg: "invalid configuration: maxParallelImagePulls cannot be larger than 1 unless SerializeImagePulls (--serialize-image-pulls) is set to false",
}, {
name: "valid MaxParallelImagePulls and SerializeImagePulls combination",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MaxParallelImagePulls = utilpointer.Int32(1)
conf.SerializeImagePulls = true
return conf
},
{
name: "specify ServerTLSBootstrap without enabling RotateKubeletServerCertificate",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"RotateKubeletServerCertificate": false}
conf.ServerTLSBootstrap = true
return conf
},
errMsg: "invalid configuration: serverTLSBootstrap true requires feature gate RotateKubeletServerCertificate",
}, {
name: "specify ServerTLSBootstrap without enabling RotateKubeletServerCertificate",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"RotateKubeletServerCertificate": false}
conf.ServerTLSBootstrap = true
return conf
},
{
name: "invalid TopologyManagerPolicy",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.TopologyManagerPolicy = "invalid-policy"
return conf
},
errMsg: "invalid configuration: topologyManagerPolicy (--topology-manager-policy) \"invalid-policy\" must be one of: [\"none\" \"best-effort\" \"restricted\" \"single-numa-node\"]",
errMsg: "invalid configuration: serverTLSBootstrap true requires feature gate RotateKubeletServerCertificate",
}, {
name: "invalid TopologyManagerPolicy",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.TopologyManagerPolicy = "invalid-policy"
return conf
},
{
name: "invalid TopologyManagerScope",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.TopologyManagerScope = "invalid-scope"
return conf
},
errMsg: "invalid configuration: topologyManagerScope (--topology-manager-scope) \"invalid-scope\" must be one of: \"container\", or \"pod\"",
errMsg: "invalid configuration: topologyManagerPolicy (--topology-manager-policy) \"invalid-policy\" must be one of: [\"none\" \"best-effort\" \"restricted\" \"single-numa-node\"]",
}, {
name: "invalid TopologyManagerScope",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.TopologyManagerScope = "invalid-scope"
return conf
},
{
name: "ShutdownGracePeriodCriticalPods is greater than ShutdownGracePeriod",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 2 * time.Second}
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second}
return conf
},
errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {2s} must be <= shutdownGracePeriod {1s}",
errMsg: "invalid configuration: topologyManagerScope (--topology-manager-scope) \"invalid-scope\" must be one of: \"container\", or \"pod\"",
}, {
name: "ShutdownGracePeriodCriticalPods is greater than ShutdownGracePeriod",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 2 * time.Second}
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second}
return conf
},
{
name: "ShutdownGracePeriod is less than 1 sec",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Millisecond}
return conf
},
errMsg: "invalid configuration: shutdownGracePeriod {1ms} must be either zero or otherwise >= 1 sec",
errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {2s} must be <= shutdownGracePeriod {1s}",
}, {
name: "ShutdownGracePeriod is less than 1 sec",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Millisecond}
return conf
},
{
name: "ShutdownGracePeriodCriticalPods is less than 1 sec",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Millisecond}
return conf
},
errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {1ms} must be either zero or otherwise >= 1 sec",
errMsg: "invalid configuration: shutdownGracePeriod {1ms} must be either zero or otherwise >= 1 sec",
}, {
name: "ShutdownGracePeriodCriticalPods is less than 1 sec",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Millisecond}
return conf
},
{
name: "specify ShutdownGracePeriod without enabling GracefulNodeShutdown",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second}
return conf
},
errMsg: "invalid configuration: specifying shutdownGracePeriod or shutdownGracePeriodCriticalPods requires feature gate GracefulNodeShutdown",
errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {1ms} must be either zero or otherwise >= 1 sec",
}, {
name: "specify ShutdownGracePeriod without enabling GracefulNodeShutdown",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second}
return conf
},
{
name: "specify ShutdownGracePeriodCriticalPods without enabling GracefulNodeShutdown",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Second}
return conf
},
errMsg: "invalid configuration: specifying shutdownGracePeriod or shutdownGracePeriodCriticalPods requires feature gate GracefulNodeShutdown",
errMsg: "invalid configuration: specifying shutdownGracePeriod or shutdownGracePeriodCriticalPods requires feature gate GracefulNodeShutdown",
}, {
name: "specify ShutdownGracePeriodCriticalPods without enabling GracefulNodeShutdown",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Second}
return conf
},
{
name: "invalid MemorySwap.SwapBehavior",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"NodeSwap": true}
conf.MemorySwap.SwapBehavior = "invalid-behavior"
return conf
},
errMsg: "invalid configuration: memorySwap.swapBehavior \"invalid-behavior\" must be one of: \"\", \"LimitedSwap\", or \"UnlimitedSwap\"",
errMsg: "invalid configuration: specifying shutdownGracePeriod or shutdownGracePeriodCriticalPods requires feature gate GracefulNodeShutdown",
}, {
name: "invalid MemorySwap.SwapBehavior",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"NodeSwap": true}
conf.MemorySwap.SwapBehavior = "invalid-behavior"
return conf
},
{
name: "specify MemorySwap.SwapBehavior without enabling NodeSwap",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"NodeSwap": false}
conf.MemorySwap.SwapBehavior = kubetypes.LimitedSwap
return conf
},
errMsg: "invalid configuration: memorySwap.swapBehavior cannot be set when NodeSwap feature flag is disabled",
errMsg: "invalid configuration: memorySwap.swapBehavior \"invalid-behavior\" must be one of: \"\", \"LimitedSwap\", or \"UnlimitedSwap\"",
}, {
name: "specify MemorySwap.SwapBehavior without enabling NodeSwap",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"NodeSwap": false}
conf.MemorySwap.SwapBehavior = kubetypes.LimitedSwap
return conf
},
{
name: "specify SystemReservedEnforcementKey without specifying SystemReservedCgroup",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnforceNodeAllocatable = []string{kubetypes.SystemReservedEnforcementKey}
conf.SystemReservedCgroup = ""
return conf
},
errMsg: "invalid configuration: systemReservedCgroup (--system-reserved-cgroup) must be specified when \"system-reserved\" contained in enforceNodeAllocatable (--enforce-node-allocatable)",
errMsg: "invalid configuration: memorySwap.swapBehavior cannot be set when NodeSwap feature flag is disabled",
}, {
name: "specify SystemReservedEnforcementKey without specifying SystemReservedCgroup",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnforceNodeAllocatable = []string{kubetypes.SystemReservedEnforcementKey}
conf.SystemReservedCgroup = ""
return conf
},
{
name: "specify KubeReservedEnforcementKey without specifying KubeReservedCgroup",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnforceNodeAllocatable = []string{kubetypes.KubeReservedEnforcementKey}
conf.KubeReservedCgroup = ""
return conf
},
errMsg: "invalid configuration: kubeReservedCgroup (--kube-reserved-cgroup) must be specified when \"kube-reserved\" contained in enforceNodeAllocatable (--enforce-node-allocatable)",
errMsg: "invalid configuration: systemReservedCgroup (--system-reserved-cgroup) must be specified when \"system-reserved\" contained in enforceNodeAllocatable (--enforce-node-allocatable)",
}, {
name: "specify KubeReservedEnforcementKey without specifying KubeReservedCgroup",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnforceNodeAllocatable = []string{kubetypes.KubeReservedEnforcementKey}
conf.KubeReservedCgroup = ""
return conf
},
{
name: "specify NodeAllocatableNoneKey with additional enforcements",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnforceNodeAllocatable = []string{kubetypes.NodeAllocatableNoneKey, kubetypes.KubeReservedEnforcementKey}
return conf
},
errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) may not contain additional enforcements when \"none\" is specified",
errMsg: "invalid configuration: kubeReservedCgroup (--kube-reserved-cgroup) must be specified when \"kube-reserved\" contained in enforceNodeAllocatable (--enforce-node-allocatable)",
}, {
name: "specify NodeAllocatableNoneKey with additional enforcements",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnforceNodeAllocatable = []string{kubetypes.NodeAllocatableNoneKey, kubetypes.KubeReservedEnforcementKey}
return conf
},
{
name: "invalid EnforceNodeAllocatable",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnforceNodeAllocatable = []string{"invalid-enforce-node-allocatable"}
return conf
},
errMsg: "invalid configuration: option \"invalid-enforce-node-allocatable\" specified for enforceNodeAllocatable (--enforce-node-allocatable). Valid options are \"pods\", \"system-reserved\", \"kube-reserved\", or \"none\"",
errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) may not contain additional enforcements when \"none\" is specified",
}, {
name: "invalid EnforceNodeAllocatable",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnforceNodeAllocatable = []string{"invalid-enforce-node-allocatable"}
return conf
},
{
name: "invalid HairpinMode",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.HairpinMode = "invalid-hair-pin-mode"
return conf
},
errMsg: "invalid configuration: option \"invalid-hair-pin-mode\" specified for hairpinMode (--hairpin-mode). Valid options are \"none\", \"hairpin-veth\" or \"promiscuous-bridge\"",
errMsg: "invalid configuration: option \"invalid-enforce-node-allocatable\" specified for enforceNodeAllocatable (--enforce-node-allocatable). Valid options are \"pods\", \"system-reserved\", \"kube-reserved\", or \"none\"",
}, {
name: "invalid HairpinMode",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.HairpinMode = "invalid-hair-pin-mode"
return conf
},
{
name: "specify ReservedSystemCPUs with SystemReservedCgroup",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ReservedSystemCPUs = "0-3"
conf.SystemReservedCgroup = "/system.slice"
return conf
},
errMsg: "invalid configuration: can't use reservedSystemCPUs (--reserved-cpus) with systemReservedCgroup (--system-reserved-cgroup) or kubeReservedCgroup (--kube-reserved-cgroup)",
errMsg: "invalid configuration: option \"invalid-hair-pin-mode\" specified for hairpinMode (--hairpin-mode). Valid options are \"none\", \"hairpin-veth\" or \"promiscuous-bridge\"",
}, {
name: "specify ReservedSystemCPUs with SystemReservedCgroup",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ReservedSystemCPUs = "0-3"
conf.SystemReservedCgroup = "/system.slice"
return conf
},
{
name: "specify ReservedSystemCPUs with KubeReservedCgroup",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ReservedSystemCPUs = "0-3"
conf.KubeReservedCgroup = "/system.slice"
return conf
},
errMsg: "invalid configuration: can't use reservedSystemCPUs (--reserved-cpus) with systemReservedCgroup (--system-reserved-cgroup) or kubeReservedCgroup (--kube-reserved-cgroup)",
errMsg: "invalid configuration: can't use reservedSystemCPUs (--reserved-cpus) with systemReservedCgroup (--system-reserved-cgroup) or kubeReservedCgroup (--kube-reserved-cgroup)",
}, {
name: "specify ReservedSystemCPUs with KubeReservedCgroup",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ReservedSystemCPUs = "0-3"
conf.KubeReservedCgroup = "/system.slice"
return conf
},
{
name: "invalid ReservedSystemCPUs",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ReservedSystemCPUs = "invalid-reserved-system-cpus"
return conf
},
errMsg: "invalid configuration: unable to parse reservedSystemCPUs (--reserved-cpus) invalid-reserved-system-cpus, error:",
errMsg: "invalid configuration: can't use reservedSystemCPUs (--reserved-cpus) with systemReservedCgroup (--system-reserved-cgroup) or kubeReservedCgroup (--kube-reserved-cgroup)",
}, {
name: "invalid ReservedSystemCPUs",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ReservedSystemCPUs = "invalid-reserved-system-cpus"
return conf
},
{
name: "enable MemoryQoS without specifying MemoryThrottlingFactor",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"MemoryQoS": true}
conf.MemoryThrottlingFactor = nil
return conf
},
errMsg: "invalid configuration: memoryThrottlingFactor is required when MemoryQoS feature flag is enabled",
errMsg: "invalid configuration: unable to parse reservedSystemCPUs (--reserved-cpus) invalid-reserved-system-cpus, error:",
}, {
name: "enable MemoryQoS without specifying MemoryThrottlingFactor",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"MemoryQoS": true}
conf.MemoryThrottlingFactor = nil
return conf
},
{
name: "invalid MemoryThrottlingFactor",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MemoryThrottlingFactor = utilpointer.Float64(1.1)
return conf
},
errMsg: "invalid configuration: memoryThrottlingFactor 1.1 must be greater than 0 and less than or equal to 1.0",
errMsg: "invalid configuration: memoryThrottlingFactor is required when MemoryQoS feature flag is enabled",
}, {
name: "invalid MemoryThrottlingFactor",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MemoryThrottlingFactor = utilpointer.Float64(1.1)
return conf
},
{
name: "invalid Taint.TimeAdded",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
now := metav1.Now()
conf.RegisterWithTaints = []v1.Taint{{TimeAdded: &now}}
return conf
},
errMsg: "invalid configuration: taint.TimeAdded is not nil",
errMsg: "invalid configuration: memoryThrottlingFactor 1.1 must be greater than 0 and less than or equal to 1.0",
}, {
name: "invalid Taint.TimeAdded",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
now := metav1.Now()
conf.RegisterWithTaints = []v1.Taint{{TimeAdded: &now}}
return conf
},
{
name: "specify tracing with KubeletTracing disabled",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
samplingRate := int32(99999)
conf.FeatureGates = map[string]bool{"KubeletTracing": false}
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate}
return conf
},
errMsg: "invalid configuration: tracing should not be configured if KubeletTracing feature flag is disabled.",
errMsg: "invalid configuration: taint.TimeAdded is not nil",
}, {
name: "specify tracing with KubeletTracing disabled",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
samplingRate := int32(99999)
conf.FeatureGates = map[string]bool{"KubeletTracing": false}
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate}
return conf
},
{
name: "specify tracing invalid sampling rate",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
samplingRate := int32(-1)
conf.FeatureGates = map[string]bool{"KubeletTracing": true}
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate}
return conf
},
errMsg: "tracing.samplingRatePerMillion: Invalid value: -1: sampling rate must be positive",
errMsg: "invalid configuration: tracing should not be configured if KubeletTracing feature flag is disabled.",
}, {
name: "specify tracing invalid sampling rate",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
samplingRate := int32(-1)
conf.FeatureGates = map[string]bool{"KubeletTracing": true}
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate}
return conf
},
{
name: "specify tracing invalid endpoint",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
ep := "dn%2s://localhost:4317"
conf.FeatureGates = map[string]bool{"KubeletTracing": true}
conf.Tracing = &tracingapi.TracingConfiguration{Endpoint: &ep}
return conf
},
errMsg: "tracing.endpoint: Invalid value: \"dn%2s://localhost:4317\": parse \"dn%2s://localhost:4317\": first path segment in URL cannot contain colon",
errMsg: "tracing.samplingRatePerMillion: Invalid value: -1: sampling rate must be positive",
}, {
name: "specify tracing invalid endpoint",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
ep := "dn%2s://localhost:4317"
conf.FeatureGates = map[string]bool{"KubeletTracing": true}
conf.Tracing = &tracingapi.TracingConfiguration{Endpoint: &ep}
return conf
},
{
name: "invalid GracefulNodeShutdownBasedOnPodPriority",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": true}
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{
{
Priority: 0,
ShutdownGracePeriodSeconds: 0,
}}
return conf
},
errMsg: "invalid configuration: Cannot specify both shutdownGracePeriodByPodPriority and shutdownGracePeriod at the same time",
errMsg: "tracing.endpoint: Invalid value: \"dn%2s://localhost:4317\": parse \"dn%2s://localhost:4317\": first path segment in URL cannot contain colon",
}, {
name: "invalid GracefulNodeShutdownBasedOnPodPriority",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": true}
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{{
Priority: 0,
ShutdownGracePeriodSeconds: 0,
}}
return conf
},
{
name: "Specifying shutdownGracePeriodByPodPriority without enable GracefulNodeShutdownBasedOnPodPriority",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": false}
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{
{
Priority: 0,
ShutdownGracePeriodSeconds: 0,
}}
return conf
},
errMsg: "invalid configuration: Specifying shutdownGracePeriodByPodPriority requires feature gate GracefulNodeShutdownBasedOnPodPriority",
errMsg: "invalid configuration: Cannot specify both shutdownGracePeriodByPodPriority and shutdownGracePeriod at the same time",
}, {
name: "Specifying shutdownGracePeriodByPodPriority without enable GracefulNodeShutdownBasedOnPodPriority",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": false}
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{{
Priority: 0,
ShutdownGracePeriodSeconds: 0,
}}
return conf
},
{
name: "enableSystemLogQuery is enabled without NodeLogQuery feature gate",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnableSystemLogQuery = true
return conf
},
errMsg: "invalid configuration: NodeLogQuery feature gate is required for enableSystemLogHandler",
errMsg: "invalid configuration: Specifying shutdownGracePeriodByPodPriority requires feature gate GracefulNodeShutdownBasedOnPodPriority",
}, {
name: "enableSystemLogQuery is enabled without NodeLogQuery feature gate",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnableSystemLogQuery = true
return conf
},
{
name: "enableSystemLogQuery is enabled without enableSystemLogHandler",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"NodeLogQuery": true}
conf.EnableSystemLogHandler = false
conf.EnableSystemLogQuery = true
return conf
},
errMsg: "invalid configuration: enableSystemLogHandler is required for enableSystemLogQuery",
errMsg: "invalid configuration: NodeLogQuery feature gate is required for enableSystemLogHandler",
}, {
name: "enableSystemLogQuery is enabled without enableSystemLogHandler",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"NodeLogQuery": true}
conf.EnableSystemLogHandler = false
conf.EnableSystemLogQuery = true
return conf
},
}
errMsg: "invalid configuration: enableSystemLogHandler is required for enableSystemLogQuery",
}}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {

View File

@@ -36,183 +36,173 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
} else {
proxyMode = kubeproxyconfig.ProxyModeIPVS
}
successCases := []kubeproxyconfig.KubeProxyConfiguration{
{
BindAddress: "192.168.59.103",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Mode: proxyMode,
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
successCases := []kubeproxyconfig.KubeProxyConfiguration{{
BindAddress: "192.168.59.103",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
{
BindAddress: "192.168.59.103",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Mode: proxyMode,
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
{
BindAddress: "192.168.59.103",
HealthzBindAddress: "",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
{
BindAddress: "fd00:192:168:59::103",
HealthzBindAddress: "",
MetricsBindAddress: "[::1]:10249",
ClusterCIDR: "fd00:192:168:59::/64",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
}, {
BindAddress: "192.168.59.103",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "fd00:192:168::/64",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
}, {
BindAddress: "192.168.59.103",
HealthzBindAddress: "",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24,fd00:192:168::/64",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
DetectLocalMode: kubeproxyconfig.LocalModeInterfaceNamePrefix,
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "vethabcde",
},
}, {
BindAddress: "fd00:192:168:59::103",
HealthzBindAddress: "",
MetricsBindAddress: "[::1]:10249",
ClusterCIDR: "fd00:192:168:59::/64",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
DetectLocalMode: kubeproxyconfig.LocalModeBridgeInterface,
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
BridgeInterface: "avz",
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
}
}, {
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
}, {
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "fd00:192:168::/64",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
}, {
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24,fd00:192:168::/64",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
}, {
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
DetectLocalMode: kubeproxyconfig.LocalModeInterfaceNamePrefix,
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "vethabcde",
},
}, {
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: pointer.Int32(1),
Min: pointer.Int32(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
DetectLocalMode: kubeproxyconfig.LocalModeBridgeInterface,
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
BridgeInterface: "avz",
},
}}
for _, successCase := range successCases {
if errs := Validate(&successCase); len(errs) != 0 {

View File

@@ -57,42 +57,35 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) {
PodInitialBackoffSeconds: podInitialBackoffSeconds,
PodMaxBackoffSeconds: podMaxBackoffSeconds,
PercentageOfNodesToScore: pointer.Int32(35),
Profiles: []config.KubeSchedulerProfile{
{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Score: config.PluginSet{
Disabled: []config.Plugin{{Name: "*"}},
},
Profiles: []config.KubeSchedulerProfile{{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
},
Score: config.PluginSet{
Disabled: []config.Plugin{{Name: "*"}},
},
},
{
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Bind: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomBind"}},
},
PluginConfig: []config.PluginConfig{{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
}},
}, {
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Bind: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomBind"}},
},
},
},
Extenders: []config.Extender{
{
PrioritizeVerb: "prioritize",
Weight: 1,
},
},
}},
Extenders: []config.Extender{{
PrioritizeVerb: "prioritize",
Weight: 1,
}},
}
invalidParallelismValue := validConfig.DeepCopy()
@@ -145,60 +138,46 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) {
extenderNegativeWeight.Extenders[0].Weight = -1
invalidNodePercentage := validConfig.DeepCopy()
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
},
}
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
}}
invalidPluginArgs := validConfig.DeepCopy()
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.InterPodAffinityArgs{},
},
}
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{{
Name: "DefaultPreemption",
Args: &config.InterPodAffinityArgs{},
}}
duplicatedPluginConfig := validConfig.DeepCopy()
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{
{
Name: "config",
},
{
Name: "config",
},
}
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{{
Name: "config",
}, {
Name: "config",
}}
mismatchQueueSort := validConfig.DeepCopy()
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{
{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "PrioritySort"}},
},
},
PluginConfig: []config.PluginConfig{
{
Name: "PrioritySort",
},
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "PrioritySort"}},
},
},
{
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
},
PluginConfig: []config.PluginConfig{
{
Name: "CustomSort",
},
PluginConfig: []config.PluginConfig{{
Name: "PrioritySort",
}},
}, {
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
},
}
PluginConfig: []config.PluginConfig{{
Name: "CustomSort",
}},
}}
extenderDuplicateManagedResource := validConfig.DeepCopy()
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
@@ -455,42 +434,35 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) {
PodInitialBackoffSeconds: podInitialBackoffSeconds,
PodMaxBackoffSeconds: podMaxBackoffSeconds,
PercentageOfNodesToScore: pointer.Int32(35),
Profiles: []config.KubeSchedulerProfile{
{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Score: config.PluginSet{
Disabled: []config.Plugin{{Name: "*"}},
},
Profiles: []config.KubeSchedulerProfile{{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
},
Score: config.PluginSet{
Disabled: []config.Plugin{{Name: "*"}},
},
},
{
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Bind: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomBind"}},
},
PluginConfig: []config.PluginConfig{{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
}},
}, {
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Bind: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomBind"}},
},
},
},
Extenders: []config.Extender{
{
PrioritizeVerb: "prioritize",
Weight: 1,
},
},
}},
Extenders: []config.Extender{{
PrioritizeVerb: "prioritize",
Weight: 1,
}},
}
invalidParallelismValue := validConfig.DeepCopy()
@@ -543,20 +515,16 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) {
extenderNegativeWeight.Extenders[0].Weight = -1
invalidNodePercentage := validConfig.DeepCopy()
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
},
}
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
}}
invalidPluginArgs := validConfig.DeepCopy()
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.InterPodAffinityArgs{},
},
}
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{{
Name: "DefaultPreemption",
Args: &config.InterPodAffinityArgs{},
}}
duplicatedPlugins := validConfig.DeepCopy()
duplicatedPlugins.Profiles[0].Plugins.PreEnqueue.Enabled = []config.Plugin{
@@ -565,44 +533,34 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) {
}
duplicatedPluginConfig := validConfig.DeepCopy()
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{
{
Name: "config",
},
{
Name: "config",
},
}
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{{
Name: "config",
}, {
Name: "config",
}}
mismatchQueueSort := validConfig.DeepCopy()
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{
{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "PrioritySort"}},
},
},
PluginConfig: []config.PluginConfig{
{
Name: "PrioritySort",
},
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "PrioritySort"}},
},
},
{
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
},
PluginConfig: []config.PluginConfig{
{
Name: "CustomSort",
},
PluginConfig: []config.PluginConfig{{
Name: "PrioritySort",
}},
}, {
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
},
}
PluginConfig: []config.PluginConfig{{
Name: "CustomSort",
}},
}}
extenderDuplicateManagedResource := validConfig.DeepCopy()
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
@@ -858,44 +816,37 @@ func TestValidateKubeSchedulerConfigurationV1(t *testing.T) {
},
PodInitialBackoffSeconds: podInitialBackoffSeconds,
PodMaxBackoffSeconds: podMaxBackoffSeconds,
Profiles: []config.KubeSchedulerProfile{
{
SchedulerName: "me",
PercentageOfNodesToScore: pointer.Int32(35),
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Score: config.PluginSet{
Disabled: []config.Plugin{{Name: "*"}},
},
Profiles: []config.KubeSchedulerProfile{{
SchedulerName: "me",
PercentageOfNodesToScore: pointer.Int32(35),
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
},
Score: config.PluginSet{
Disabled: []config.Plugin{{Name: "*"}},
},
},
{
SchedulerName: "other",
PercentageOfNodesToScore: pointer.Int32(35),
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Bind: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomBind"}},
},
PluginConfig: []config.PluginConfig{{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
}},
}, {
SchedulerName: "other",
PercentageOfNodesToScore: pointer.Int32(35),
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Bind: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomBind"}},
},
},
},
Extenders: []config.Extender{
{
PrioritizeVerb: "prioritize",
Weight: 1,
},
},
}},
Extenders: []config.Extender{{
PrioritizeVerb: "prioritize",
Weight: 1,
}},
}
invalidParallelismValue := validConfig.DeepCopy()
@@ -948,60 +899,46 @@ func TestValidateKubeSchedulerConfigurationV1(t *testing.T) {
extenderNegativeWeight.Extenders[0].Weight = -1
invalidNodePercentage := validConfig.DeepCopy()
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
},
}
invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100},
}}
invalidPluginArgs := validConfig.DeepCopy()
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.InterPodAffinityArgs{},
},
}
invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{{
Name: "DefaultPreemption",
Args: &config.InterPodAffinityArgs{},
}}
duplicatedPluginConfig := validConfig.DeepCopy()
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{
{
Name: "config",
},
{
Name: "config",
},
}
duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{{
Name: "config",
}, {
Name: "config",
}}
mismatchQueueSort := validConfig.DeepCopy()
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{
{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "PrioritySort"}},
},
},
PluginConfig: []config.PluginConfig{
{
Name: "PrioritySort",
},
mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "PrioritySort"}},
},
},
{
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
},
PluginConfig: []config.PluginConfig{
{
Name: "CustomSort",
},
PluginConfig: []config.PluginConfig{{
Name: "PrioritySort",
}},
}, {
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
},
}
PluginConfig: []config.PluginConfig{{
Name: "CustomSort",
}},
}}
extenderDuplicateManagedResource := validConfig.DeepCopy()
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{

View File

@@ -27,158 +27,124 @@ func TestValidateConfiguration(t *testing.T) {
name string
config eventratelimitapi.Configuration
expectedResult bool
}{
{
name: "valid server",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Type: "Server",
Burst: 5,
QPS: 1,
},
},
},
expectedResult: true,
}{{
name: "valid server",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Type: "Server",
Burst: 5,
QPS: 1,
}},
},
{
name: "valid namespace",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Type: "Namespace",
Burst: 10,
QPS: 2,
CacheSize: 100,
},
},
},
expectedResult: true,
expectedResult: true,
}, {
name: "valid namespace",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Type: "Namespace",
Burst: 10,
QPS: 2,
CacheSize: 100,
}},
},
{
name: "valid user",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Type: "User",
Burst: 10,
QPS: 2,
CacheSize: 100,
},
},
},
expectedResult: true,
expectedResult: true,
}, {
name: "valid user",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Type: "User",
Burst: 10,
QPS: 2,
CacheSize: 100,
}},
},
{
name: "valid source+object",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Type: "SourceAndObject",
Burst: 5,
QPS: 1,
CacheSize: 1000,
},
},
},
expectedResult: true,
expectedResult: true,
}, {
name: "valid source+object",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Type: "SourceAndObject",
Burst: 5,
QPS: 1,
CacheSize: 1000,
}},
},
{
name: "valid multiple",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Type: "Server",
Burst: 5,
QPS: 1,
},
{
Type: "Namespace",
Burst: 10,
QPS: 2,
CacheSize: 100,
},
{
Type: "SourceAndObject",
Burst: 25,
QPS: 10,
CacheSize: 1000,
},
},
},
expectedResult: true,
expectedResult: true,
}, {
name: "valid multiple",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Type: "Server",
Burst: 5,
QPS: 1,
}, {
Type: "Namespace",
Burst: 10,
QPS: 2,
CacheSize: 100,
}, {
Type: "SourceAndObject",
Burst: 25,
QPS: 10,
CacheSize: 1000,
}},
},
{
name: "missing limits",
config: eventratelimitapi.Configuration{},
expectedResult: false,
expectedResult: true,
}, {
name: "missing limits",
config: eventratelimitapi.Configuration{},
expectedResult: false,
}, {
name: "missing type",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Burst: 25,
QPS: 10,
CacheSize: 1000,
}},
},
{
name: "missing type",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Burst: 25,
QPS: 10,
CacheSize: 1000,
},
},
},
expectedResult: false,
expectedResult: false,
}, {
name: "invalid type",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Type: "unknown-type",
Burst: 25,
QPS: 10,
CacheSize: 1000,
}},
},
{
name: "invalid type",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Type: "unknown-type",
Burst: 25,
QPS: 10,
CacheSize: 1000,
},
},
},
expectedResult: false,
expectedResult: false,
}, {
name: "missing burst",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Type: "Server",
QPS: 1,
}},
},
{
name: "missing burst",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Type: "Server",
QPS: 1,
},
},
},
expectedResult: false,
expectedResult: false,
}, {
name: "missing qps",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Type: "Server",
Burst: 5,
}},
},
{
name: "missing qps",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Type: "Server",
Burst: 5,
},
},
},
expectedResult: false,
expectedResult: false,
}, {
name: "negative cache size",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{{
Type: "Namespace",
Burst: 10,
QPS: 2,
CacheSize: -1,
}},
},
{
name: "negative cache size",
config: eventratelimitapi.Configuration{
Limits: []eventratelimitapi.Limit{
{
Type: "Namespace",
Burst: 10,
QPS: 2,
CacheSize: -1,
},
},
},
expectedResult: false,
},
}
expectedResult: false,
}}
for _, tc := range cases {
errs := ValidateConfiguration(&tc.config)
if e, a := tc.expectedResult, len(errs) == 0; e != a {

View File

@@ -17,9 +17,10 @@ limitations under the License.
package validation
import (
"testing"
api "k8s.io/kubernetes/pkg/apis/core"
internalapi "k8s.io/kubernetes/plugin/pkg/admission/podtolerationrestriction/apis/podtolerationrestriction"
"testing"
)
func TestValidateConfiguration(t *testing.T) {
@@ -28,38 +29,34 @@ func TestValidateConfiguration(t *testing.T) {
config internalapi.Configuration
testName string
testStatus bool
}{
{
config: internalapi.Configuration{
Default: []api.Toleration{
{Key: "foo", Operator: "Exists", Value: "", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]},
{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]},
{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoSchedule"},
{Operator: "Exists", Effect: "NoSchedule"},
},
Whitelist: []api.Toleration{
{Key: "foo", Value: "bar", Effect: "NoSchedule"},
{Key: "foo", Operator: "Equal", Value: "bar"},
},
}{{
config: internalapi.Configuration{
Default: []api.Toleration{
{Key: "foo", Operator: "Exists", Value: "", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]},
{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoExecute", TolerationSeconds: &[]int64{60}[0]},
{Key: "foo", Operator: "Equal", Value: "bar", Effect: "NoSchedule"},
{Operator: "Exists", Effect: "NoSchedule"},
},
testName: "Valid cases",
testStatus: true,
},
{
config: internalapi.Configuration{
Whitelist: []api.Toleration{{Key: "foo", Operator: "Exists", Value: "bar", Effect: "NoSchedule"}},
Whitelist: []api.Toleration{
{Key: "foo", Value: "bar", Effect: "NoSchedule"},
{Key: "foo", Operator: "Equal", Value: "bar"},
},
testName: "Invalid case",
testStatus: false,
},
{
config: internalapi.Configuration{
Default: []api.Toleration{{Operator: "Equal", Value: "bar", Effect: "NoSchedule"}},
},
testName: "Invalid case",
testStatus: false,
testName: "Valid cases",
testStatus: true,
}, {
config: internalapi.Configuration{
Whitelist: []api.Toleration{{Key: "foo", Operator: "Exists", Value: "bar", Effect: "NoSchedule"}},
},
}
testName: "Invalid case",
testStatus: false,
}, {
config: internalapi.Configuration{
Default: []api.Toleration{{Operator: "Equal", Value: "bar", Effect: "NoSchedule"}},
},
testName: "Invalid case",
testStatus: false,
}}
for i := range tests {
errs := ValidateConfiguration(&tests[i].config)

View File

@@ -17,9 +17,10 @@ limitations under the License.
package validation
import (
"testing"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
)
func TestValidateListOptions(t *testing.T) {
@@ -32,164 +33,145 @@ func TestValidateListOptions(t *testing.T) {
opts internalversion.ListOptions
watchListFeatureEnabled bool
expectErrors []string
}{
{
name: "valid-default",
opts: internalversion.ListOptions{},
}{{
name: "valid-default",
opts: internalversion.ListOptions{},
}, {
name: "valid-resourceversionmatch-exact",
opts: internalversion.ListOptions{
ResourceVersion: "1",
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
},
{
name: "valid-resourceversionmatch-exact",
opts: internalversion.ListOptions{
ResourceVersion: "1",
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
},
}, {
name: "invalid-resourceversionmatch-exact",
opts: internalversion.ListOptions{
ResourceVersion: "0",
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
},
{
name: "invalid-resourceversionmatch-exact",
opts: internalversion.ListOptions{
ResourceVersion: "0",
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
},
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch \"exact\" is forbidden for resourceVersion \"0\""},
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch \"exact\" is forbidden for resourceVersion \"0\""},
}, {
name: "valid-resourceversionmatch-notolderthan",
opts: internalversion.ListOptions{
ResourceVersion: "0",
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
},
{
name: "valid-resourceversionmatch-notolderthan",
opts: internalversion.ListOptions{
ResourceVersion: "0",
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
},
}, {
name: "invalid-resourceversionmatch",
opts: internalversion.ListOptions{
ResourceVersion: "0",
ResourceVersionMatch: "foo",
},
{
name: "invalid-resourceversionmatch",
opts: internalversion.ListOptions{
ResourceVersion: "0",
ResourceVersionMatch: "foo",
},
expectErrors: []string{"resourceVersionMatch: Unsupported value: \"foo\": supported values: \"Exact\", \"NotOlderThan\", \"\""},
expectErrors: []string{"resourceVersionMatch: Unsupported value: \"foo\": supported values: \"Exact\", \"NotOlderThan\", \"\""},
}, {
name: "list-sendInitialEvents-forbidden",
opts: internalversion.ListOptions{
SendInitialEvents: boolPtrFn(true),
},
{
name: "list-sendInitialEvents-forbidden",
opts: internalversion.ListOptions{
SendInitialEvents: boolPtrFn(true),
},
expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for list"},
expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for list"},
}, {
name: "valid-watch-default",
opts: internalversion.ListOptions{
Watch: true,
},
{
name: "valid-watch-default",
opts: internalversion.ListOptions{
Watch: true,
},
}, {
name: "valid-watch-sendInitialEvents-on",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
AllowWatchBookmarks: true,
},
{
name: "valid-watch-sendInitialEvents-on",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
AllowWatchBookmarks: true,
},
watchListFeatureEnabled: true,
watchListFeatureEnabled: true,
}, {
name: "valid-watch-sendInitialEvents-off",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(false),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
AllowWatchBookmarks: true,
},
{
name: "valid-watch-sendInitialEvents-off",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(false),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
AllowWatchBookmarks: true,
},
watchListFeatureEnabled: true,
watchListFeatureEnabled: true,
}, {
name: "watch-resourceversionmatch-without-sendInitialEvents-forbidden",
opts: internalversion.ListOptions{
Watch: true,
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
},
{
name: "watch-resourceversionmatch-without-sendInitialEvents-forbidden",
opts: internalversion.ListOptions{
Watch: true,
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
},
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden for watch unless sendInitialEvents is provided"},
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden for watch unless sendInitialEvents is provided"},
}, {
name: "watch-sendInitialEvents-without-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
},
{
name: "watch-sendInitialEvents-without-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
},
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
}, {
name: "watch-sendInitialEvents-with-exact-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
AllowWatchBookmarks: true,
},
{
name: "watch-sendInitialEvents-with-exact-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchExact,
AllowWatchBookmarks: true,
},
watchListFeatureEnabled: true,
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"Exact\": supported values: \"NotOlderThan\""},
watchListFeatureEnabled: true,
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"Exact\": supported values: \"NotOlderThan\""},
}, {
name: "watch-sendInitialEvents-on-with-empty-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: "",
},
{
name: "watch-sendInitialEvents-on-with-empty-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: "",
},
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
}, {
name: "watch-sendInitialEvents-off-with-empty-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(false),
ResourceVersionMatch: "",
},
{
name: "watch-sendInitialEvents-off-with-empty-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(false),
ResourceVersionMatch: "",
},
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
}, {
name: "watch-sendInitialEvents-with-incorrect-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: "incorrect",
AllowWatchBookmarks: true,
},
{
name: "watch-sendInitialEvents-with-incorrect-resourceversionmatch-forbidden",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: "incorrect",
AllowWatchBookmarks: true,
},
watchListFeatureEnabled: true,
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"incorrect\": supported values: \"NotOlderThan\""},
watchListFeatureEnabled: true,
expectErrors: []string{"resourceVersionMatch: Forbidden: sendInitialEvents requires setting resourceVersionMatch to NotOlderThan", "resourceVersionMatch: Unsupported value: \"incorrect\": supported values: \"NotOlderThan\""},
}, {
// note that validating allowWatchBookmarks would break backward compatibility
// because it was possible to request initial events via resourceVersion=0 before this change
name: "watch-sendInitialEvents-no-allowWatchBookmark",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
},
{
// note that validating allowWatchBookmarks would break backward compatibility
// because it was possible to request initial events via resourceVersion=0 before this change
name: "watch-sendInitialEvents-no-allowWatchBookmark",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
},
watchListFeatureEnabled: true,
watchListFeatureEnabled: true,
}, {
name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
AllowWatchBookmarks: true,
},
{
name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
AllowWatchBookmarks: true,
},
expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
expectErrors: []string{"sendInitialEvents: Forbidden: sendInitialEvents is forbidden for watch unless the WatchList feature gate is enabled"},
}, {
name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
AllowWatchBookmarks: true,
Continue: "123",
},
{
name: "watch-sendInitialEvents-no-watchlist-fg-disabled",
opts: internalversion.ListOptions{
Watch: true,
SendInitialEvents: boolPtrFn(true),
ResourceVersionMatch: metav1.ResourceVersionMatchNotOlderThan,
AllowWatchBookmarks: true,
Continue: "123",
},
watchListFeatureEnabled: true,
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden when continue is provided"},
},
}
watchListFeatureEnabled: true,
expectErrors: []string{"resourceVersionMatch: Forbidden: resourceVersionMatch is forbidden when continue is provided"},
}}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {

View File

@@ -136,31 +136,26 @@ func TestValidPatchOptions(t *testing.T) {
tests := []struct {
opts metav1.PatchOptions
patchType types.PatchType
}{
{
opts: metav1.PatchOptions{
Force: boolPtr(true),
FieldManager: "kubectl",
},
patchType: types.ApplyPatchType,
}{{
opts: metav1.PatchOptions{
Force: boolPtr(true),
FieldManager: "kubectl",
},
{
opts: metav1.PatchOptions{
FieldManager: "kubectl",
},
patchType: types.ApplyPatchType,
patchType: types.ApplyPatchType,
}, {
opts: metav1.PatchOptions{
FieldManager: "kubectl",
},
{
opts: metav1.PatchOptions{},
patchType: types.MergePatchType,
patchType: types.ApplyPatchType,
}, {
opts: metav1.PatchOptions{},
patchType: types.MergePatchType,
}, {
opts: metav1.PatchOptions{
FieldManager: "patcher",
},
{
opts: metav1.PatchOptions{
FieldManager: "patcher",
},
patchType: types.MergePatchType,
},
}
patchType: types.MergePatchType,
}}
for _, test := range tests {
t.Run(fmt.Sprintf("%v", test.opts), func(t *testing.T) {
@@ -243,36 +238,30 @@ func TestValidateFieldManagerInvalid(t *testing.T) {
}
func TestValidateManagedFieldsInvalid(t *testing.T) {
tests := []metav1.ManagedFieldsEntry{
{
Operation: metav1.ManagedFieldsOperationUpdate,
FieldsType: "RandomVersion",
APIVersion: "v1",
},
{
Operation: "RandomOperation",
FieldsType: "FieldsV1",
APIVersion: "v1",
},
{
// Operation is missing
FieldsType: "FieldsV1",
APIVersion: "v1",
},
{
Operation: metav1.ManagedFieldsOperationUpdate,
FieldsType: "FieldsV1",
// Invalid fieldManager
Manager: "field\nmanager",
APIVersion: "v1",
},
{
Operation: metav1.ManagedFieldsOperationApply,
FieldsType: "FieldsV1",
APIVersion: "v1",
Subresource: "TooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLong",
},
}
tests := []metav1.ManagedFieldsEntry{{
Operation: metav1.ManagedFieldsOperationUpdate,
FieldsType: "RandomVersion",
APIVersion: "v1",
}, {
Operation: "RandomOperation",
FieldsType: "FieldsV1",
APIVersion: "v1",
}, {
// Operation is missing
FieldsType: "FieldsV1",
APIVersion: "v1",
}, {
Operation: metav1.ManagedFieldsOperationUpdate,
FieldsType: "FieldsV1",
// Invalid fieldManager
Manager: "field\nmanager",
APIVersion: "v1",
}, {
Operation: metav1.ManagedFieldsOperationApply,
FieldsType: "FieldsV1",
APIVersion: "v1",
Subresource: "TooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLongTooLong",
}}
for _, test := range tests {
t.Run(fmt.Sprintf("%#v", test), func(t *testing.T) {
@@ -285,30 +274,25 @@ func TestValidateManagedFieldsInvalid(t *testing.T) {
}
func TestValidateMangedFieldsValid(t *testing.T) {
tests := []metav1.ManagedFieldsEntry{
{
Operation: metav1.ManagedFieldsOperationUpdate,
APIVersion: "v1",
// FieldsType is missing
},
{
Operation: metav1.ManagedFieldsOperationUpdate,
FieldsType: "FieldsV1",
APIVersion: "v1",
},
{
Operation: metav1.ManagedFieldsOperationApply,
FieldsType: "FieldsV1",
APIVersion: "v1",
Subresource: "scale",
},
{
Operation: metav1.ManagedFieldsOperationApply,
FieldsType: "FieldsV1",
APIVersion: "v1",
Manager: "🍔",
},
}
tests := []metav1.ManagedFieldsEntry{{
Operation: metav1.ManagedFieldsOperationUpdate,
APIVersion: "v1",
// FieldsType is missing
}, {
Operation: metav1.ManagedFieldsOperationUpdate,
FieldsType: "FieldsV1",
APIVersion: "v1",
}, {
Operation: metav1.ManagedFieldsOperationApply,
FieldsType: "FieldsV1",
APIVersion: "v1",
Subresource: "scale",
}, {
Operation: metav1.ManagedFieldsOperationApply,
FieldsType: "FieldsV1",
APIVersion: "v1",
Manager: "🍔",
}}
for _, test := range tests {
t.Run(fmt.Sprintf("%#v", test), func(t *testing.T) {
@@ -325,99 +309,90 @@ func TestValidateConditions(t *testing.T) {
name string
conditions []metav1.Condition
validateErrs func(t *testing.T, errs field.ErrorList)
}{
{
name: "bunch-of-invalid-fields",
conditions: []metav1.Condition{{
Type: ":invalid",
Status: "unknown",
ObservedGeneration: -1,
LastTransitionTime: metav1.Time{},
Reason: "invalid;val",
Message: "",
}},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[0].type: Invalid value: ":invalid": name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
needle = `status.conditions[0].status: Unsupported value: "unknown": supported values: "False", "True", "Unknown"`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
needle = `status.conditions[0].observedGeneration: Invalid value: -1: must be greater than or equal to zero`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
needle = `status.conditions[0].lastTransitionTime: Required value: must be set`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
needle = `status.conditions[0].reason: Invalid value: "invalid;val": a condition reason must start with alphabetic character, optionally followed by a string of alphanumeric characters or '_,:', and must end with an alphanumeric character or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', or 'ReasonA,ReasonB', or 'ReasonA:ReasonB', regex used for validation is '[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?')`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
},
}{{
name: "bunch-of-invalid-fields",
conditions: []metav1.Condition{{
Type: ":invalid",
Status: "unknown",
ObservedGeneration: -1,
LastTransitionTime: metav1.Time{},
Reason: "invalid;val",
Message: "",
}},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[0].type: Invalid value: ":invalid": name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
needle = `status.conditions[0].status: Unsupported value: "unknown": supported values: "False", "True", "Unknown"`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
needle = `status.conditions[0].observedGeneration: Invalid value: -1: must be greater than or equal to zero`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
needle = `status.conditions[0].lastTransitionTime: Required value: must be set`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
needle = `status.conditions[0].reason: Invalid value: "invalid;val": a condition reason must start with alphabetic character, optionally followed by a string of alphanumeric characters or '_,:', and must end with an alphanumeric character or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', or 'ReasonA,ReasonB', or 'ReasonA:ReasonB', regex used for validation is '[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?')`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
},
{
name: "duplicates",
conditions: []metav1.Condition{{
Type: "First",
},
{
Type: "Second",
},
{
Type: "First",
},
},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[2].type: Duplicate value: "First"`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
},
}, {
name: "duplicates",
conditions: []metav1.Condition{{
Type: "First",
}, {
Type: "Second",
}, {
Type: "First",
}},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[2].type: Duplicate value: "First"`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
},
{
name: "colon-allowed-in-reason",
conditions: []metav1.Condition{{
Type: "First",
Reason: "valid:val",
}},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[0].reason`
if hasPrefixError(errs, needle) {
t.Errorf("has %q in\n%v", needle, errorsAsString(errs))
}
},
}, {
name: "colon-allowed-in-reason",
conditions: []metav1.Condition{{
Type: "First",
Reason: "valid:val",
}},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[0].reason`
if hasPrefixError(errs, needle) {
t.Errorf("has %q in\n%v", needle, errorsAsString(errs))
}
},
{
name: "comma-allowed-in-reason",
conditions: []metav1.Condition{{
Type: "First",
Reason: "valid,val",
}},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[0].reason`
if hasPrefixError(errs, needle) {
t.Errorf("has %q in\n%v", needle, errorsAsString(errs))
}
},
}, {
name: "comma-allowed-in-reason",
conditions: []metav1.Condition{{
Type: "First",
Reason: "valid,val",
}},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[0].reason`
if hasPrefixError(errs, needle) {
t.Errorf("has %q in\n%v", needle, errorsAsString(errs))
}
},
{
name: "reason-does-not-end-in-delimiter",
conditions: []metav1.Condition{{
Type: "First",
Reason: "valid,val:",
}},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[0].reason: Invalid value: "valid,val:": a condition reason must start with alphabetic character, optionally followed by a string of alphanumeric characters or '_,:', and must end with an alphanumeric character or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', or 'ReasonA,ReasonB', or 'ReasonA:ReasonB', regex used for validation is '[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?')`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
},
}, {
name: "reason-does-not-end-in-delimiter",
conditions: []metav1.Condition{{
Type: "First",
Reason: "valid,val:",
}},
validateErrs: func(t *testing.T, errs field.ErrorList) {
needle := `status.conditions[0].reason: Invalid value: "valid,val:": a condition reason must start with alphabetic character, optionally followed by a string of alphanumeric characters or '_,:', and must end with an alphanumeric character or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', or 'ReasonA,ReasonB', or 'ReasonA:ReasonB', regex used for validation is '[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?')`
if !hasError(errs, needle) {
t.Errorf("missing %q in\n%v", needle, errorsAsString(errs))
}
},
}
}}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
@@ -433,79 +408,66 @@ func TestLabelSelectorMatchExpression(t *testing.T) {
labelSelector *metav1.LabelSelector
wantErrorNumber int
validateErrs func(t *testing.T, errs field.ErrorList)
}{
{
name: "Valid LabelSelector",
labelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"value"},
},
},
},
wantErrorNumber: 0,
validateErrs: nil,
}{{
name: "Valid LabelSelector",
labelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "key",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"value"},
}},
},
{
name: "MatchExpression's key name isn't valid",
labelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "-key",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"value"},
},
},
},
wantErrorNumber: 1,
validateErrs: func(t *testing.T, errs field.ErrorList) {
errMessage := "name part must consist of alphanumeric characters"
if !partStringInErrorMessage(errs, errMessage) {
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
}
},
wantErrorNumber: 0,
validateErrs: nil,
}, {
name: "MatchExpression's key name isn't valid",
labelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "-key",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"value"},
}},
},
{
name: "MatchExpression's operator isn't valid",
labelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key",
Operator: "abc",
Values: []string{"value"},
},
},
},
wantErrorNumber: 1,
validateErrs: func(t *testing.T, errs field.ErrorList) {
errMessage := "not a valid selector operator"
if !partStringInErrorMessage(errs, errMessage) {
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
}
},
wantErrorNumber: 1,
validateErrs: func(t *testing.T, errs field.ErrorList) {
errMessage := "name part must consist of alphanumeric characters"
if !partStringInErrorMessage(errs, errMessage) {
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
}
},
{
name: "MatchExpression's value name isn't valid",
labelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"-value"},
},
},
},
wantErrorNumber: 1,
validateErrs: func(t *testing.T, errs field.ErrorList) {
errMessage := "a valid label must be an empty string or consist of"
if !partStringInErrorMessage(errs, errMessage) {
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
}
},
}, {
name: "MatchExpression's operator isn't valid",
labelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "key",
Operator: "abc",
Values: []string{"value"},
}},
},
}
wantErrorNumber: 1,
validateErrs: func(t *testing.T, errs field.ErrorList) {
errMessage := "not a valid selector operator"
if !partStringInErrorMessage(errs, errMessage) {
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
}
},
}, {
name: "MatchExpression's value name isn't valid",
labelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "key",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"-value"},
}},
},
wantErrorNumber: 1,
validateErrs: func(t *testing.T, errs field.ErrorList) {
errMessage := "a valid label must be an empty string or consist of"
if !partStringInErrorMessage(errs, errMessage) {
t.Errorf("missing %q in\n%v", errMessage, errorsAsString(errs))
}
},
}}
for index, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
allErrs := ValidateLabelSelector(testCase.labelSelector, LabelSelectorValidationOptions{false}, field.NewPath("labelSelector"))

View File

@@ -630,33 +630,27 @@ func TestIsFullyQualifiedName(t *testing.T) {
name string
targetName string
err string
}{
{
name: "name needs to be fully qualified, i.e., contains at least 2 dots",
targetName: "k8s.io",
err: "should be a domain with at least three segments separated by dots",
},
{
name: "name should not include scheme",
targetName: "http://foo.k8s.io",
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
},
{
name: "email should be invalid",
targetName: "example@foo.k8s.io",
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
},
{
name: "name cannot be empty",
targetName: "",
err: "Required value",
},
{
name: "name must conform to RFC 1123",
targetName: "A.B.C",
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
},
}
}{{
name: "name needs to be fully qualified, i.e., contains at least 2 dots",
targetName: "k8s.io",
err: "should be a domain with at least three segments separated by dots",
}, {
name: "name should not include scheme",
targetName: "http://foo.k8s.io",
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
}, {
name: "email should be invalid",
targetName: "example@foo.k8s.io",
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
}, {
name: "name cannot be empty",
targetName: "",
err: "Required value",
}, {
name: "name must conform to RFC 1123",
targetName: "A.B.C",
err: "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
}}
for _, tc := range messageTests {
err := IsFullyQualifiedName(field.NewPath(""), tc.targetName).ToAggregate()
switch {

View File

@@ -23,23 +23,17 @@ import (
)
func TestValidateConfiguration(t *testing.T) {
successCases := []resourcequotaapi.Configuration{
{
LimitedResources: []resourcequotaapi.LimitedResource{
{
Resource: "pods",
MatchContains: []string{"requests.cpu"},
},
},
},
{
LimitedResources: []resourcequotaapi.LimitedResource{
{
Resource: "persistentvolumeclaims",
MatchContains: []string{"requests.storage"},
},
},
},
successCases := []resourcequotaapi.Configuration{{
LimitedResources: []resourcequotaapi.LimitedResource{{
Resource: "pods",
MatchContains: []string{"requests.cpu"},
}},
}, {
LimitedResources: []resourcequotaapi.LimitedResource{{
Resource: "persistentvolumeclaims",
MatchContains: []string{"requests.storage"},
}},
},
}
for i := range successCases {
configuration := successCases[i]

View File

@@ -134,11 +134,9 @@ func TestValidatePolicy(t *testing.T) {
policy := audit.Policy{OmitStages: []audit.Stage{
audit.Stage("foo"),
},
Rules: []audit.PolicyRule{
{
Level: audit.LevelMetadata,
},
},
Rules: []audit.PolicyRule{{
Level: audit.LevelMetadata,
}},
}
errorCases = append(errorCases, policy)

View File

@@ -748,37 +748,31 @@ func TestErrConfigurationInvalidWithErrorsIs(t *testing.T) {
err error
matchAgainst error
expectMatch bool
}{
{
name: "no match",
err: errConfigurationInvalid{errors.New("my-error"), errors.New("my-other-error")},
matchAgainst: fmt.Errorf("no entry %s", "here"),
},
{
name: "match via .Is()",
err: errConfigurationInvalid{errors.New("forbidden"), alwaysMatchingError{}},
matchAgainst: errors.New("unauthorized"),
expectMatch: true,
},
{
name: "match via equality",
err: errConfigurationInvalid{errors.New("err"), someError{}},
matchAgainst: someError{},
expectMatch: true,
},
{
name: "match via nested aggregate",
err: errConfigurationInvalid{errors.New("closed today"), errConfigurationInvalid{errConfigurationInvalid{someError{}}}},
matchAgainst: someError{},
expectMatch: true,
},
{
name: "match via wrapped aggregate",
err: fmt.Errorf("wrap: %w", errConfigurationInvalid{errors.New("err"), someError{}}),
matchAgainst: someError{},
expectMatch: true,
},
}
}{{
name: "no match",
err: errConfigurationInvalid{errors.New("my-error"), errors.New("my-other-error")},
matchAgainst: fmt.Errorf("no entry %s", "here"),
}, {
name: "match via .Is()",
err: errConfigurationInvalid{errors.New("forbidden"), alwaysMatchingError{}},
matchAgainst: errors.New("unauthorized"),
expectMatch: true,
}, {
name: "match via equality",
err: errConfigurationInvalid{errors.New("err"), someError{}},
matchAgainst: someError{},
expectMatch: true,
}, {
name: "match via nested aggregate",
err: errConfigurationInvalid{errors.New("closed today"), errConfigurationInvalid{errConfigurationInvalid{someError{}}}},
matchAgainst: someError{},
expectMatch: true,
}, {
name: "match via wrapped aggregate",
err: fmt.Errorf("wrap: %w", errConfigurationInvalid{errors.New("err"), someError{}}),
matchAgainst: someError{},
expectMatch: true,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {