Merge pull request #117716 from thockin/validation_test_whitespace

Clean up brace whitespace in **/validation_test.go
This commit is contained in:
Kubernetes Prow Robot
2023-05-02 10:02:25 -07:00
committed by GitHub
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 { cases := []struct {
ssv apiserverinternal.ServerStorageVersion ssv apiserverinternal.ServerStorageVersion
expectedErr string expectedErr string
}{ }{{
{ ssv: apiserverinternal.ServerStorageVersion{
ssv: apiserverinternal.ServerStorageVersion{ APIServerID: "-fea",
APIServerID: "-fea", EncodingVersion: "v1alpha1",
EncodingVersion: "v1alpha1", DecodableVersions: []string{"v1alpha1", "v1"},
DecodableVersions: []string{"v1alpha1", "v1"},
},
expectedErr: "apiServerID: Invalid value",
}, },
{ expectedErr: "apiServerID: Invalid value",
ssv: apiserverinternal.ServerStorageVersion{ }, {
APIServerID: "fea", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "v1alpha1", APIServerID: "fea",
DecodableVersions: []string{"v1beta1", "v1"}, EncodingVersion: "v1alpha1",
}, DecodableVersions: []string{"v1beta1", "v1"},
expectedErr: "decodableVersions must include encodingVersion",
}, },
{ expectedErr: "decodableVersions must include encodingVersion",
ssv: apiserverinternal.ServerStorageVersion{ }, {
APIServerID: "fea", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "v1alpha1", APIServerID: "fea",
DecodableVersions: []string{"v1alpha1", "v1", "-fea"}, EncodingVersion: "v1alpha1",
}, DecodableVersions: []string{"v1alpha1", "v1", "-fea"},
expectedErr: "decodableVersions[2]: Invalid value",
}, },
{ expectedErr: "decodableVersions[2]: Invalid value",
ssv: apiserverinternal.ServerStorageVersion{ }, {
APIServerID: "fea", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "v1alpha1", APIServerID: "fea",
DecodableVersions: []string{"v1alpha1", "v1"}, EncodingVersion: "v1alpha1",
}, DecodableVersions: []string{"v1alpha1", "v1"},
expectedErr: "",
}, },
{ expectedErr: "",
ssv: apiserverinternal.ServerStorageVersion{ }, {
APIServerID: "fea", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "mygroup.com/v2", APIServerID: "fea",
DecodableVersions: []string{"v1alpha1", "v1", "mygroup.com/v2"}, EncodingVersion: "mygroup.com/v2",
}, DecodableVersions: []string{"v1alpha1", "v1", "mygroup.com/v2"},
expectedErr: "",
}, },
{ expectedErr: "",
ssv: apiserverinternal.ServerStorageVersion{ }, {
APIServerID: "fea", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "mygroup.com/v2", APIServerID: "fea",
DecodableVersions: []string{"mygroup.com/v2", "/v3"}, EncodingVersion: "mygroup.com/v2",
}, DecodableVersions: []string{"mygroup.com/v2", "/v3"},
expectedErr: `[].decodableVersions[1]: Invalid value: "/v3": group part: must be non-empty`,
}, },
{ expectedErr: `[].decodableVersions[1]: Invalid value: "/v3": group part: must be non-empty`,
ssv: apiserverinternal.ServerStorageVersion{ }, {
APIServerID: "fea", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "mygroup.com/v2", APIServerID: "fea",
DecodableVersions: []string{"mygroup.com/v2", "mygroup.com/"}, 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: "mygroup.com/": version part: must be non-empty`,
ssv: apiserverinternal.ServerStorageVersion{ }, {
APIServerID: "fea", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "/v3", APIServerID: "fea",
DecodableVersions: []string{"mygroup.com/v2", "/v3"}, EncodingVersion: "/v3",
}, DecodableVersions: []string{"mygroup.com/v2", "/v3"},
expectedErr: `[].encodingVersion: Invalid value: "/v3": group part: must be non-empty`,
}, },
{ expectedErr: `[].encodingVersion: Invalid value: "/v3": group part: must be non-empty`,
ssv: apiserverinternal.ServerStorageVersion{ }, {
APIServerID: "fea", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "v1", APIServerID: "fea",
DecodableVersions: []string{"v1", "mygroup_com/v2"}, 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: `[].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", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "v1", APIServerID: "fea",
DecodableVersions: []string{"v1", "mygroup.com/v2_"}, 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_": 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", ssv: apiserverinternal.ServerStorageVersion{
EncodingVersion: "v1", APIServerID: "fea",
DecodableVersions: []string{"v1", "mygroup.com/v2/myresource"}, 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/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 { for _, tc := range cases {
err := validateServerStorageVersion(tc.ssv, field.NewPath("")).ToAggregate() err := validateServerStorageVersion(tc.ssv, field.NewPath("")).ToAggregate()
@@ -142,91 +130,70 @@ func TestValidateCommonVersion(t *testing.T) {
cases := []struct { cases := []struct {
status apiserverinternal.StorageVersionStatus status apiserverinternal.StorageVersionStatus
expectedErr string expectedErr string
}{ }{{
{ status: apiserverinternal.StorageVersionStatus{
status: apiserverinternal.StorageVersionStatus{ StorageVersions: []apiserverinternal.ServerStorageVersion{},
StorageVersions: []apiserverinternal.ServerStorageVersion{}, CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
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{ status: apiserverinternal.StorageVersionStatus{
{ StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1", APIServerID: "1",
EncodingVersion: "v1alpha1", EncodingVersion: "v1alpha1",
}, }, {
{ APIServerID: "2",
APIServerID: "2", EncodingVersion: "v1",
EncodingVersion: "v1", }},
}, CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
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{ status: apiserverinternal.StorageVersionStatus{
{ StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1", APIServerID: "1",
EncodingVersion: "v1alpha1", EncodingVersion: "v1alpha1",
}, }, {
{ APIServerID: "2",
APIServerID: "2", EncodingVersion: "v1alpha1",
EncodingVersion: "v1alpha1", }},
}, CommonEncodingVersion: nil,
},
CommonEncodingVersion: nil,
},
expectedErr: "Invalid value: \"null\": the common encoding version is v1alpha1",
}, },
{ expectedErr: "Invalid value: \"null\": the common encoding version is v1alpha1",
status: apiserverinternal.StorageVersionStatus{ }, {
StorageVersions: []apiserverinternal.ServerStorageVersion{ status: apiserverinternal.StorageVersionStatus{
{ StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1", APIServerID: "1",
EncodingVersion: "v1alpha1", EncodingVersion: "v1alpha1",
}, }, {
{ APIServerID: "2",
APIServerID: "2", EncodingVersion: "v1alpha1",
EncodingVersion: "v1alpha1", }},
}, CommonEncodingVersion: func() *string { a := "v1"; return &a }(),
},
CommonEncodingVersion: func() *string { a := "v1"; return &a }(),
},
expectedErr: "Invalid value: \"v1\": the actual common encoding version is v1alpha1",
}, },
{ expectedErr: "Invalid value: \"v1\": the actual common encoding version is v1alpha1",
status: apiserverinternal.StorageVersionStatus{ }, {
StorageVersions: []apiserverinternal.ServerStorageVersion{ status: apiserverinternal.StorageVersionStatus{
{ StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1", APIServerID: "1",
EncodingVersion: "v1alpha1", EncodingVersion: "v1alpha1",
}, }, {
{ APIServerID: "2",
APIServerID: "2", EncodingVersion: "v1alpha1",
EncodingVersion: "v1alpha1", }},
}, CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
expectedErr: "",
}, },
{ expectedErr: "",
status: apiserverinternal.StorageVersionStatus{ }, {
StorageVersions: []apiserverinternal.ServerStorageVersion{ status: apiserverinternal.StorageVersionStatus{
{ StorageVersions: []apiserverinternal.ServerStorageVersion{{
APIServerID: "1", APIServerID: "1",
EncodingVersion: "v1alpha1", EncodingVersion: "v1alpha1",
}, }},
}, CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
CommonEncodingVersion: func() *string { a := "v1alpha1"; return &a }(),
},
expectedErr: "",
}, },
} expectedErr: "",
}}
for _, tc := range cases { for _, tc := range cases {
err := validateCommonVersion(tc.status, field.NewPath("")) err := validateCommonVersion(tc.status, field.NewPath(""))
if err == nil && len(tc.expectedErr) == 0 { if err == nil && len(tc.expectedErr) == 0 {
@@ -250,78 +217,58 @@ func TestValidateStorageVersionCondition(t *testing.T) {
cases := []struct { cases := []struct {
conditions []apiserverinternal.StorageVersionCondition conditions []apiserverinternal.StorageVersionCondition
expectedErr string expectedErr string
}{ }{{
{ conditions: []apiserverinternal.StorageVersionCondition{{
conditions: []apiserverinternal.StorageVersionCondition{ Type: "-fea",
{ Status: "True",
Type: "-fea", Reason: "unknown",
Status: "True", Message: "unknown",
Reason: "unknown", }},
Message: "unknown", expectedErr: "type: Invalid value",
}, }, {
}, conditions: []apiserverinternal.StorageVersionCondition{{
expectedErr: "type: Invalid value", Type: "fea",
}, Status: "-True",
{ Reason: "unknown",
conditions: []apiserverinternal.StorageVersionCondition{ Message: "unknown",
{ }},
Type: "fea", expectedErr: "status: Invalid value",
Status: "-True", }, {
Reason: "unknown", conditions: []apiserverinternal.StorageVersionCondition{{
Message: "unknown", Type: "fea",
}, Status: "True",
}, Message: "unknown",
expectedErr: "status: Invalid value", }},
}, expectedErr: "Required value: reason cannot be empty",
{ }, {
conditions: []apiserverinternal.StorageVersionCondition{ conditions: []apiserverinternal.StorageVersionCondition{{
{ Type: "fea",
Type: "fea", Status: "True",
Status: "True", Reason: "unknown",
Message: "unknown", }},
}, expectedErr: "Required value: message cannot be empty",
}, }, {
expectedErr: "Required value: reason cannot be empty", conditions: []apiserverinternal.StorageVersionCondition{{
}, Type: "fea",
{ Status: "True",
conditions: []apiserverinternal.StorageVersionCondition{ Reason: "unknown",
{ Message: "unknown",
Type: "fea", }, {
Status: "True", Type: "fea",
Reason: "unknown", Status: "True",
}, Reason: "unknown",
}, Message: "unknown",
expectedErr: "Required value: message cannot be empty", }},
}, expectedErr: `"fea": the type of the condition is not unique, it also appears in conditions[0]`,
{ }, {
conditions: []apiserverinternal.StorageVersionCondition{ conditions: []apiserverinternal.StorageVersionCondition{{
{ Type: "fea",
Type: "fea", Status: "True",
Status: "True", Reason: "unknown",
Reason: "unknown", Message: "unknown",
Message: "unknown", }},
}, expectedErr: "",
{ }}
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 { for _, tc := range cases {
err := validateStorageVersionCondition(tc.conditions, field.NewPath("")).ToAggregate() err := validateStorageVersionCondition(tc.conditions, field.NewPath("")).ToAggregate()
if err == nil && len(tc.expectedErr) == 0 { if err == nil && len(tc.expectedErr) == 0 {
@@ -345,40 +292,31 @@ func TestValidateStorageVersionName(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
expectedErr string expectedErr string
}{ }{{
{ name: "",
name: "", expectedErr: `name must be in the form of <group>.<resource>`,
expectedErr: `name must be in the form of <group>.<resource>`, }, {
}, name: "pods",
{ 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: "core.pods", name: "authentication.k8s.io.tokenreviews",
expectedErr: "", expectedErr: "",
}, }, {
{ name: strings.Repeat("x", 253) + ".tokenreviews",
name: "authentication.k8s.io.tokenreviews", expectedErr: "",
expectedErr: "", }, {
}, name: strings.Repeat("x", 254) + ".tokenreviews",
{ expectedErr: `the group segment must be no more than 253 characters`,
name: strings.Repeat("x", 253) + ".tokenreviews", }, {
expectedErr: "", name: "authentication.k8s.io." + strings.Repeat("x", 63),
}, expectedErr: "",
{ }, {
name: strings.Repeat("x", 254) + ".tokenreviews", name: "authentication.k8s.io." + strings.Repeat("x", 64),
expectedErr: `the group segment must be no more than 253 characters`, expectedErr: `the resource segment must be no more than 63 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 { for _, tc := range cases {
errs := ValidateStorageVersionName(tc.name, false) errs := ValidateStorageVersionName(tc.name, false)
if errs == nil && len(tc.expectedErr) == 0 { 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 name string
obj authorizationapi.SubjectAccessReviewSpec obj authorizationapi.SubjectAccessReviewSpec
msg string msg string
}{ }{{
{ name: "neither request",
name: "neither request", obj: authorizationapi.SubjectAccessReviewSpec{User: "me"},
obj: authorizationapi.SubjectAccessReviewSpec{User: "me"}, msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified", }, {
name: "both requests",
obj: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
User: "me",
}, },
{ msg: "cannot be specified in combination with resourceAttributes",
name: "both requests", }, {
obj: authorizationapi.SubjectAccessReviewSpec{ name: "no subject",
ResourceAttributes: &authorizationapi.ResourceAttributes{}, obj: authorizationapi.SubjectAccessReviewSpec{
NonResourceAttributes: &authorizationapi.NonResourceAttributes{}, ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "me",
},
msg: "cannot be specified in combination with resourceAttributes",
}, },
{ msg: `spec.user: Invalid value: "": at least one of user or group must be specified`,
name: "no subject", }}
obj: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
},
msg: `spec.user: Invalid value: "": at least one of user or group must be specified`,
},
}
for _, c := range errorCases { for _, c := range errorCases {
errs := ValidateSubjectAccessReviewSpec(c.obj, field.NewPath("spec")) errs := ValidateSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
@@ -102,21 +98,18 @@ func TestValidateSelfSAR(t *testing.T) {
name string name string
obj authorizationapi.SelfSubjectAccessReviewSpec obj authorizationapi.SelfSubjectAccessReviewSpec
msg string msg string
}{ }{{
{ name: "neither request",
name: "neither request", obj: authorizationapi.SelfSubjectAccessReviewSpec{},
obj: authorizationapi.SelfSubjectAccessReviewSpec{}, msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified", }, {
name: "both requests",
obj: authorizationapi.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
}, },
{ msg: "cannot be specified in combination with resourceAttributes",
name: "both requests", }}
obj: authorizationapi.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
},
msg: "cannot be specified in combination with resourceAttributes",
},
}
for _, c := range errorCases { for _, c := range errorCases {
errs := ValidateSelfSubjectAccessReviewSpec(c.obj, field.NewPath("spec")) errs := ValidateSelfSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
@@ -136,14 +129,12 @@ func TestValidateSelfSAR(t *testing.T) {
} }
func TestValidateLocalSAR(t *testing.T) { func TestValidateLocalSAR(t *testing.T) {
successCases := []authorizationapi.LocalSubjectAccessReview{ successCases := []authorizationapi.LocalSubjectAccessReview{{
{ Spec: authorizationapi.SubjectAccessReviewSpec{
Spec: authorizationapi.SubjectAccessReviewSpec{ ResourceAttributes: &authorizationapi.ResourceAttributes{},
ResourceAttributes: &authorizationapi.ResourceAttributes{}, User: "user",
User: "user",
},
}, },
} }}
for _, successCase := range successCases { for _, successCase := range successCases {
if errs := ValidateLocalSubjectAccessReview(&successCase); len(errs) != 0 { if errs := ValidateLocalSubjectAccessReview(&successCase); len(errs) != 0 {
t.Errorf("expected success: %v", errs) t.Errorf("expected success: %v", errs)
@@ -154,41 +145,37 @@ func TestValidateLocalSAR(t *testing.T) {
name string name string
obj *authorizationapi.LocalSubjectAccessReview obj *authorizationapi.LocalSubjectAccessReview
msg string msg string
}{ }{{
{ name: "name",
name: "name", obj: &authorizationapi.LocalSubjectAccessReview{
obj: &authorizationapi.LocalSubjectAccessReview{ ObjectMeta: metav1.ObjectMeta{Name: "a"},
ObjectMeta: metav1.ObjectMeta{Name: "a"}, Spec: authorizationapi.SubjectAccessReviewSpec{
Spec: authorizationapi.SubjectAccessReviewSpec{ ResourceAttributes: &authorizationapi.ResourceAttributes{},
ResourceAttributes: &authorizationapi.ResourceAttributes{}, User: "user",
User: "user",
},
}, },
msg: "must be empty except for namespace",
}, },
{ msg: "must be empty except for namespace",
name: "namespace conflict", }, {
obj: &authorizationapi.LocalSubjectAccessReview{ name: "namespace conflict",
ObjectMeta: metav1.ObjectMeta{Namespace: "a"}, obj: &authorizationapi.LocalSubjectAccessReview{
Spec: authorizationapi.SubjectAccessReviewSpec{ ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
ResourceAttributes: &authorizationapi.ResourceAttributes{}, Spec: authorizationapi.SubjectAccessReviewSpec{
User: "user", ResourceAttributes: &authorizationapi.ResourceAttributes{},
}, User: "user",
}, },
msg: "must match metadata.namespace",
}, },
{ msg: "must match metadata.namespace",
name: "nonresource", }, {
obj: &authorizationapi.LocalSubjectAccessReview{ name: "nonresource",
ObjectMeta: metav1.ObjectMeta{Namespace: "a"}, obj: &authorizationapi.LocalSubjectAccessReview{
Spec: authorizationapi.SubjectAccessReviewSpec{ ObjectMeta: metav1.ObjectMeta{Namespace: "a"},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{}, Spec: authorizationapi.SubjectAccessReviewSpec{
User: "user", NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
}, User: "user",
}, },
msg: "disallowed on this kind of request",
}, },
} msg: "disallowed on this kind of request",
}}
for _, c := range errorCases { for _, c := range errorCases {
errs := ValidateLocalSubjectAccessReview(c.obj) 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, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ Type: api.DisruptionTarget,
{ Status: api.ConditionTrue,
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, Action: batch.PodFailurePolicyActionIgnore,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
{ ContainerName: pointer.String("def"),
Type: api.PodConditionType("CustomConditionType"), Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Status: api.ConditionFalse, Values: []int32{4},
},
},
}, },
{ }, {
Action: batch.PodFailurePolicyActionCount, Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("abc"), Operator: batch.PodFailurePolicyOnExitCodesOpNotIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{5, 6, 7},
Values: []int32{1, 2, 3},
},
}, },
{ }},
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, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionFailJob,
Action: batch.PodFailurePolicyActionFailJob, }},
},
},
}, },
}, },
}, },
@@ -331,15 +319,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionFailJob,
Action: batch.PodFailurePolicyActionFailJob, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{11, 11},
Values: []int32{11, 11},
},
}, },
}, }},
}, },
}, },
}, },
@@ -352,21 +338,19 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionFailJob,
Action: batch.PodFailurePolicyActionFailJob, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: func() (values []int32) {
Values: func() (values []int32) { tooManyValues := make([]int32, maxPodFailurePolicyOnExitCodesValues+1)
tooManyValues := make([]int32, maxPodFailurePolicyOnExitCodesValues+1) for i := range tooManyValues {
for i := range tooManyValues { tooManyValues[i] = int32(i)
tooManyValues[i] = int32(i) }
} return tooManyValues
return tooManyValues }(),
}(),
},
}, },
}, }},
}, },
}, },
}, },
@@ -404,21 +388,19 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionFailJob,
Action: batch.PodFailurePolicyActionFailJob, OnPodConditions: func() []batch.PodFailurePolicyOnPodConditionsPattern {
OnPodConditions: func() []batch.PodFailurePolicyOnPodConditionsPattern { tooManyPatterns := make([]batch.PodFailurePolicyOnPodConditionsPattern, maxPodFailurePolicyOnPodConditionsPatterns+1)
tooManyPatterns := make([]batch.PodFailurePolicyOnPodConditionsPattern, maxPodFailurePolicyOnPodConditionsPatterns+1) for i := range tooManyPatterns {
for i := range tooManyPatterns { tooManyPatterns[i] = batch.PodFailurePolicyOnPodConditionsPattern{
tooManyPatterns[i] = batch.PodFailurePolicyOnPodConditionsPattern{ Type: api.PodConditionType(fmt.Sprintf("CustomType_%d", i)),
Type: api.PodConditionType(fmt.Sprintf("CustomType_%d", i)), Status: api.ConditionTrue,
Status: api.ConditionTrue,
}
} }
return tooManyPatterns }
}(), return tooManyPatterns
}, }(),
}, }},
}, },
}, },
}, },
@@ -431,15 +413,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionFailJob,
Action: batch.PodFailurePolicyActionFailJob, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{12, 13, 13, 13},
Values: []int32{12, 13, 13, 13},
},
}, },
}, }},
}, },
}, },
}, },
@@ -452,15 +432,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionFailJob,
Action: batch.PodFailurePolicyActionFailJob, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{19, 11},
Values: []int32{19, 11},
},
}, },
}, }},
}, },
}, },
}, },
@@ -473,15 +451,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionFailJob,
Action: batch.PodFailurePolicyActionFailJob, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{},
Values: []int32{},
},
}, },
}, }},
}, },
}, },
}, },
@@ -494,15 +470,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: "",
Action: "", OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{1, 2, 3},
Values: []int32{1, 2, 3},
},
}, },
}, }},
}, },
}, },
}, },
@@ -515,15 +489,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionFailJob,
Action: batch.PodFailurePolicyActionFailJob, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ Operator: "",
Operator: "", Values: []int32{1, 2, 3},
Values: []int32{1, 2, 3},
},
}, },
}, }},
}, },
}, },
}, },
@@ -536,22 +508,18 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionFailJob,
Action: batch.PodFailurePolicyActionFailJob, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ ContainerName: pointer.String("abc"),
ContainerName: pointer.String("abc"), Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{1, 2, 3},
Values: []int32{1, 2, 3},
},
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
},
},
}, },
}, OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
Type: api.DisruptionTarget,
Status: api.ConditionTrue,
}},
}},
}, },
}, },
}, },
@@ -564,15 +532,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{1, 0, 2},
Values: []int32{1, 0, 2},
},
}, },
}, }},
}, },
}, },
}, },
@@ -585,24 +551,21 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ ContainerName: pointer.String("abc"),
ContainerName: pointer.String("abc"), Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{1, 2, 3},
Values: []int32{1, 2, 3},
},
}, },
{ }, {
Action: batch.PodFailurePolicyActionFailJob, Action: batch.PodFailurePolicyActionFailJob,
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
ContainerName: pointer.String("xyz"), ContainerName: pointer.String("xyz"),
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Values: []int32{5, 6, 7}, Values: []int32{5, 6, 7},
},
}, },
}, }},
}, },
}, },
}, },
@@ -615,16 +578,14 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: "UnknownAction",
Action: "UnknownAction", OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ ContainerName: pointer.String("abc"),
ContainerName: pointer.String("abc"), Operator: batch.PodFailurePolicyOnExitCodesOpIn,
Operator: batch.PodFailurePolicyOnExitCodesOpIn, Values: []int32{1, 2, 3},
Values: []int32{1, 2, 3},
},
}, },
}, }},
}, },
}, },
}, },
@@ -637,15 +598,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{ Operator: "UnknownOperator",
Operator: "UnknownOperator", Values: []int32{1, 2, 3},
Values: []int32{1, 2, 3},
},
}, },
}, }},
}, },
}, },
}, },
@@ -658,16 +617,12 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ Type: api.DisruptionTarget,
{ }},
Type: api.DisruptionTarget, }},
},
},
},
},
}, },
}, },
}, },
@@ -680,17 +635,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ Type: api.DisruptionTarget,
{ Status: "UnknownStatus",
Type: api.DisruptionTarget, }},
Status: "UnknownStatus", }},
},
},
},
},
}, },
}, },
}, },
@@ -703,16 +654,12 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ Status: api.ConditionTrue,
{ }},
Status: api.ConditionTrue, }},
},
},
},
},
}, },
}, },
}, },
@@ -725,17 +672,13 @@ func TestValidateJob(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ Type: api.PodConditionType("Invalid Condition Type"),
{ Status: api.ConditionTrue,
Type: api.PodConditionType("Invalid Condition Type"), }},
Status: api.ConditionTrue, }},
},
},
},
},
}, },
}, },
}, },
@@ -1116,17 +1059,13 @@ func TestValidateJobUpdate(t *testing.T) {
validNodeAffinity := &api.Affinity{ validNodeAffinity := &api.Affinity{
NodeAffinity: &api.NodeAffinity{ NodeAffinity: &api.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{ RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
NodeSelectorTerms: []api.NodeSelectorTerm{ NodeSelectorTerms: []api.NodeSelectorTerm{{
{ MatchExpressions: []api.NodeSelectorRequirement{{
MatchExpressions: []api.NodeSelectorRequirement{ Key: "foo",
{ Operator: api.NodeSelectorOpIn,
Key: "foo", Values: []string{"bar", "value2"},
Operator: api.NodeSelectorOpIn, }},
Values: []string{"bar", "value2"}, }},
},
},
},
},
}, },
}, },
} }
@@ -1134,17 +1073,13 @@ func TestValidateJobUpdate(t *testing.T) {
validPodTemplateWithAffinity.Spec.Affinity = &api.Affinity{ validPodTemplateWithAffinity.Spec.Affinity = &api.Affinity{
NodeAffinity: &api.NodeAffinity{ NodeAffinity: &api.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{ RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
NodeSelectorTerms: []api.NodeSelectorTerm{ NodeSelectorTerms: []api.NodeSelectorTerm{{
{ MatchExpressions: []api.NodeSelectorRequirement{{
MatchExpressions: []api.NodeSelectorRequirement{ Key: "foo",
{ Operator: api.NodeSelectorOpIn,
Key: "foo", Values: []string{"bar", "value"},
Operator: api.NodeSelectorOpIn, }},
Values: []string{"bar", "value"}, }},
},
},
},
},
}, },
}, },
} }
@@ -1242,17 +1177,13 @@ func TestValidateJobUpdate(t *testing.T) {
}, },
update: func(job *batch.Job) { update: func(job *batch.Job) {
job.Spec.PodFailurePolicy = &batch.PodFailurePolicy{ job.Spec.PodFailurePolicy = &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ Type: api.DisruptionTarget,
{ Status: api.ConditionTrue,
Type: api.DisruptionTarget, }},
Status: api.ConditionTrue, }},
},
},
},
},
} }
}, },
err: &field.Error{ err: &field.Error{
@@ -1267,29 +1198,23 @@ func TestValidateJobUpdate(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ Type: api.DisruptionTarget,
{ Status: api.ConditionTrue,
Type: api.DisruptionTarget, }},
Status: api.ConditionTrue, }},
},
},
},
},
}, },
}, },
}, },
update: func(job *batch.Job) { update: func(job *batch.Job) {
job.Spec.PodFailurePolicy.Rules = append(job.Spec.PodFailurePolicy.Rules, batch.PodFailurePolicyRule{ job.Spec.PodFailurePolicy.Rules = append(job.Spec.PodFailurePolicy.Rules, batch.PodFailurePolicyRule{
Action: batch.PodFailurePolicyActionCount, Action: batch.PodFailurePolicyActionCount,
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
{ Type: api.DisruptionTarget,
Type: api.DisruptionTarget, Status: api.ConditionTrue,
Status: api.ConditionTrue, }},
},
},
}) })
}, },
err: &field.Error{ err: &field.Error{
@@ -1304,17 +1229,13 @@ func TestValidateJobUpdate(t *testing.T) {
Selector: validGeneratedSelector, Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGeneratedRestartPolicyNever, Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
PodFailurePolicy: &batch.PodFailurePolicy{ PodFailurePolicy: &batch.PodFailurePolicy{
Rules: []batch.PodFailurePolicyRule{ Rules: []batch.PodFailurePolicyRule{{
{ Action: batch.PodFailurePolicyActionIgnore,
Action: batch.PodFailurePolicyActionIgnore, OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{{
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{ Type: api.DisruptionTarget,
{ Status: api.ConditionTrue,
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 { successCase := []struct {
name string name string
requirements v1.ResourceRequirements requirements v1.ResourceRequirements
}{ }{{
{ name: "Resources with Requests equal to Limits",
name: "Resources with Requests equal to Limits", requirements: v1.ResourceRequirements{
requirements: v1.ResourceRequirements{ Requests: v1.ResourceList{
Requests: v1.ResourceList{ v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"), v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"), },
}, Limits: v1.ResourceList{
Limits: v1.ResourceList{ v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"), v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
},
}, },
}, },
{ }, {
name: "Resources with only Limits", name: "Resources with only Limits",
requirements: v1.ResourceRequirements{ requirements: v1.ResourceRequirements{
Limits: v1.ResourceList{ Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"), v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"), v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("10"), v1.ResourceName("my.org/resource"): resource.MustParse("10"),
},
}, },
}, },
{ }, {
name: "Resources with only Requests", name: "Resources with only Requests",
requirements: v1.ResourceRequirements{ requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{ Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"), v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"), v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("10"), v1.ResourceName("my.org/resource"): resource.MustParse("10"),
},
}, },
}, },
{ }, {
name: "Resources with Requests Less Than Limits", name: "Resources with Requests Less Than Limits",
requirements: v1.ResourceRequirements{ requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{ Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"), v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"), v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
v1.ResourceName("my.org/resource"): resource.MustParse("9"), v1.ResourceName("my.org/resource"): resource.MustParse("9"),
}, },
Limits: v1.ResourceList{ Limits: v1.ResourceList{
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"), v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"), v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName("my.org/resource"): resource.MustParse("9"), v1.ResourceName("my.org/resource"): resource.MustParse("9"),
},
}, },
}, },
} }}
for _, tc := range successCase { for _, tc := range successCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if errs := ValidateResourceRequirements(&tc.requirements, field.NewPath("resources")); len(errs) != 0 { if errs := ValidateResourceRequirements(&tc.requirements, field.NewPath("resources")); len(errs) != 0 {
@@ -94,41 +89,37 @@ func TestValidateResourceRequirements(t *testing.T) {
requirements v1.ResourceRequirements requirements v1.ResourceRequirements
skipLimitValueCheck bool skipLimitValueCheck bool
skipRequestValueCheck bool skipRequestValueCheck bool
}{ }{{
{ name: "Resources with Requests Larger Than Limits",
name: "Resources with Requests Larger Than Limits", requirements: v1.ResourceRequirements{
requirements: v1.ResourceRequirements{ Requests: v1.ResourceList{
Requests: v1.ResourceList{ v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"), v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"), v1.ResourceName("my.org/resource"): resource.MustParse("10m"),
v1.ResourceName("my.org/resource"): resource.MustParse("10m"), },
}, Limits: v1.ResourceList{
Limits: v1.ResourceList{ v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"),
v1.ResourceName(v1.ResourceCPU): resource.MustParse("9"), v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"),
v1.ResourceName(v1.ResourceMemory): resource.MustParse("9G"), v1.ResourceName("my.org/resource"): resource.MustParse("9m"),
v1.ResourceName("my.org/resource"): resource.MustParse("9m"),
},
}, },
}, },
{ }, {
name: "Invalid Resources with Requests", name: "Invalid Resources with Requests",
requirements: v1.ResourceRequirements{ requirements: v1.ResourceRequirements{
Requests: v1.ResourceList{ Requests: v1.ResourceList{
v1.ResourceName("my.org"): resource.MustParse("10m"), v1.ResourceName("my.org"): resource.MustParse("10m"),
},
}, },
skipRequestValueCheck: true,
}, },
{ skipRequestValueCheck: true,
name: "Invalid Resources with Limits", }, {
requirements: v1.ResourceRequirements{ name: "Invalid Resources with Limits",
Limits: v1.ResourceList{ requirements: v1.ResourceRequirements{
v1.ResourceName("my.org"): resource.MustParse("9m"), Limits: v1.ResourceList{
}, v1.ResourceName("my.org"): resource.MustParse("9m"),
}, },
skipLimitValueCheck: true,
}, },
} skipLimitValueCheck: true,
}}
for _, tc := range errorCase { for _, tc := range errorCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
errs := ValidateResourceRequirements(&tc.requirements, field.NewPath("resources")) errs := ValidateResourceRequirements(&tc.requirements, field.NewPath("resources"))
@@ -168,28 +159,22 @@ func TestValidateContainerResourceName(t *testing.T) {
successCase := []struct { successCase := []struct {
name string name string
ResourceName string ResourceName string
}{ }{{
{ name: "CPU resource",
name: "CPU resource", ResourceName: "cpu",
ResourceName: "cpu", }, {
}, name: "Memory resource",
{ ResourceName: "memory",
name: "Memory resource", }, {
ResourceName: "memory", name: "Hugepages resource",
}, ResourceName: "hugepages-2Mi",
{ }, {
name: "Hugepages resource", name: "Namespaced resource",
ResourceName: "hugepages-2Mi", ResourceName: "kubernetes.io/resource-foo",
}, }, {
{ name: "Extended Resource",
name: "Namespaced resource", ResourceName: "my.org/resource-bar",
ResourceName: "kubernetes.io/resource-foo", }}
},
{
name: "Extended Resource",
ResourceName: "my.org/resource-bar",
},
}
for _, tc := range successCase { for _, tc := range successCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) != 0 { if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) != 0 {
@@ -201,20 +186,16 @@ func TestValidateContainerResourceName(t *testing.T) {
errorCase := []struct { errorCase := []struct {
name string name string
ResourceName string ResourceName string
}{ }{{
{ name: "Invalid standard resource",
name: "Invalid standard resource", ResourceName: "cpu-core",
ResourceName: "cpu-core", }, {
}, name: "Invalid namespaced resource",
{ ResourceName: "kubernetes.io/",
name: "Invalid namespaced resource", }, {
ResourceName: "kubernetes.io/", name: "Invalid extended resource",
}, ResourceName: "my.org-foo-resource",
{ }}
name: "Invalid extended resource",
ResourceName: "my.org-foo-resource",
},
}
for _, tc := range errorCase { for _, tc := range errorCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) == 0 { if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) == 0 {
@@ -239,45 +220,38 @@ func TestValidatePodLogOptions(t *testing.T) {
successCase := []struct { successCase := []struct {
name string name string
podLogOptions v1.PodLogOptions podLogOptions v1.PodLogOptions
}{ }{{
{ name: "Empty PodLogOptions",
name: "Empty PodLogOptions", podLogOptions: v1.PodLogOptions{},
podLogOptions: v1.PodLogOptions{}, }, {
name: "PodLogOptions with TailLines",
podLogOptions: v1.PodLogOptions{
TailLines: &positiveLine,
}, },
{ }, {
name: "PodLogOptions with TailLines", name: "PodLogOptions with LimitBytes",
podLogOptions: v1.PodLogOptions{ podLogOptions: v1.PodLogOptions{
TailLines: &positiveLine, LimitBytes: &limitBytesGreaterThan1,
},
}, },
{ }, {
name: "PodLogOptions with LimitBytes", name: "PodLogOptions with only sinceSeconds",
podLogOptions: v1.PodLogOptions{ podLogOptions: v1.PodLogOptions{
LimitBytes: &limitBytesGreaterThan1, SinceSeconds: &sinceSecondsGreaterThan1,
},
}, },
{ }, {
name: "PodLogOptions with only sinceSeconds", name: "PodLogOptions with LimitBytes with TailLines",
podLogOptions: v1.PodLogOptions{ podLogOptions: v1.PodLogOptions{
SinceSeconds: &sinceSecondsGreaterThan1, LimitBytes: &limitBytesGreaterThan1,
}, TailLines: &positiveLine,
}, },
{ }, {
name: "PodLogOptions with LimitBytes with TailLines", name: "PodLogOptions with LimitBytes with TailLines with SinceSeconds",
podLogOptions: v1.PodLogOptions{ podLogOptions: v1.PodLogOptions{
LimitBytes: &limitBytesGreaterThan1, LimitBytes: &limitBytesGreaterThan1,
TailLines: &positiveLine, 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 { for _, tc := range successCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if errs := ValidatePodLogOptions(&tc.podLogOptions); len(errs) != 0 { if errs := ValidatePodLogOptions(&tc.podLogOptions); len(errs) != 0 {
@@ -289,40 +263,36 @@ func TestValidatePodLogOptions(t *testing.T) {
errorCase := []struct { errorCase := []struct {
name string name string
podLogOptions v1.PodLogOptions podLogOptions v1.PodLogOptions
}{ }{{
{ name: "Invalid podLogOptions with Negative TailLines",
name: "Invalid podLogOptions with Negative TailLines", podLogOptions: v1.PodLogOptions{
podLogOptions: v1.PodLogOptions{ TailLines: &negativeLine,
TailLines: &negativeLine, LimitBytes: &limitBytesGreaterThan1,
LimitBytes: &limitBytesGreaterThan1, SinceSeconds: &sinceSecondsGreaterThan1,
SinceSeconds: &sinceSecondsGreaterThan1,
},
}, },
{ }, {
name: "Invalid podLogOptions with zero or negative LimitBytes", name: "Invalid podLogOptions with zero or negative LimitBytes",
podLogOptions: v1.PodLogOptions{ podLogOptions: v1.PodLogOptions{
TailLines: &positiveLine, TailLines: &positiveLine,
LimitBytes: &limitBytesLessThan1, LimitBytes: &limitBytesLessThan1,
SinceSeconds: &sinceSecondsGreaterThan1, SinceSeconds: &sinceSecondsGreaterThan1,
},
}, },
{ }, {
name: "Invalid podLogOptions with zero or negative SinceSeconds", name: "Invalid podLogOptions with zero or negative SinceSeconds",
podLogOptions: v1.PodLogOptions{ podLogOptions: v1.PodLogOptions{
TailLines: &negativeLine, TailLines: &negativeLine,
LimitBytes: &limitBytesGreaterThan1, LimitBytes: &limitBytesGreaterThan1,
SinceSeconds: &sinceSecondsLessThan1, 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 both SinceSeconds and SinceTime set",
podLogOptions: v1.PodLogOptions{
TailLines: &negativeLine,
LimitBytes: &limitBytesGreaterThan1,
SinceSeconds: &sinceSecondsGreaterThan1,
SinceTime: &timestamp,
},
}}
for _, tc := range errorCase { for _, tc := range errorCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if errs := ValidatePodLogOptions(&tc.podLogOptions); len(errs) == 0 { if errs := ValidatePodLogOptions(&tc.podLogOptions); len(errs) == 0 {
@@ -338,54 +308,37 @@ func TestAccumulateUniqueHostPorts(t *testing.T) {
containers []v1.Container containers []v1.Container
accumulator *sets.String accumulator *sets.String
fldPath *field.Path fldPath *field.Path
}{ }{{
{ name: "HostPort is not allocated while containers use the same port with different protocol",
name: "HostPort is not allocated while containers use the same port with different protocol", containers: []v1.Container{{
containers: []v1.Container{ Ports: []v1.ContainerPort{{
{ HostPort: 8080,
Ports: []v1.ContainerPort{ Protocol: v1.ProtocolUDP,
{ }},
HostPort: 8080, }, {
Protocol: v1.ProtocolUDP, Ports: []v1.ContainerPort{{
}, HostPort: 8080,
}, Protocol: v1.ProtocolTCP,
}, }},
{ }},
Ports: []v1.ContainerPort{ accumulator: &sets.String{},
{ fldPath: field.NewPath("spec", "containers"),
HostPort: 8080, }, {
Protocol: v1.ProtocolTCP, name: "HostPort is not allocated while containers use different ports",
}, containers: []v1.Container{{
}, Ports: []v1.ContainerPort{{
}, HostPort: 8080,
}, Protocol: v1.ProtocolUDP,
accumulator: &sets.String{}, }},
fldPath: field.NewPath("spec", "containers"), }, {
}, Ports: []v1.ContainerPort{{
{ HostPort: 8081,
name: "HostPort is not allocated while containers use different ports", Protocol: v1.ProtocolUDP,
containers: []v1.Container{ }},
{ }},
Ports: []v1.ContainerPort{ accumulator: &sets.String{},
{ fldPath: field.NewPath("spec", "containers"),
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 { for _, tc := range successCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if errs := AccumulateUniqueHostPorts(tc.containers, tc.accumulator, tc.fldPath); len(errs) != 0 { if errs := AccumulateUniqueHostPorts(tc.containers, tc.accumulator, tc.fldPath); len(errs) != 0 {
@@ -398,54 +351,37 @@ func TestAccumulateUniqueHostPorts(t *testing.T) {
containers []v1.Container containers []v1.Container
accumulator *sets.String accumulator *sets.String
fldPath *field.Path fldPath *field.Path
}{ }{{
{ name: "HostPort is already allocated while containers use the same port with UDP",
name: "HostPort is already allocated while containers use the same port with UDP", containers: []v1.Container{{
containers: []v1.Container{ Ports: []v1.ContainerPort{{
{ HostPort: 8080,
Ports: []v1.ContainerPort{ Protocol: v1.ProtocolUDP,
{ }},
HostPort: 8080, }, {
Protocol: v1.ProtocolUDP, Ports: []v1.ContainerPort{{
}, HostPort: 8080,
}, Protocol: v1.ProtocolUDP,
}, }},
{ }},
Ports: []v1.ContainerPort{ accumulator: &sets.String{},
{ fldPath: field.NewPath("spec", "containers"),
HostPort: 8080, }, {
Protocol: v1.ProtocolUDP, name: "HostPort is already allocated",
}, containers: []v1.Container{{
}, Ports: []v1.ContainerPort{{
}, HostPort: 8080,
}, Protocol: v1.ProtocolUDP,
accumulator: &sets.String{}, }},
fldPath: field.NewPath("spec", "containers"), }, {
}, Ports: []v1.ContainerPort{{
{ HostPort: 8081,
name: "HostPort is already allocated", Protocol: v1.ProtocolUDP,
containers: []v1.Container{ }},
{ }},
Ports: []v1.ContainerPort{ accumulator: &sets.String{"8080/UDP": sets.Empty{}},
{ fldPath: field.NewPath("spec", "containers"),
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 { for _, tc := range errorCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if errs := AccumulateUniqueHostPorts(tc.containers, tc.accumulator, tc.fldPath); len(errs) == 0 { 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{ Spec: networking.IngressSpec{
DefaultBackend: &defaultBackend, DefaultBackend: &defaultBackend,
Rules: []networking.IngressRule{ Rules: []networking.IngressRule{{
{ Host: "foo.bar.com",
Host: "foo.bar.com", IngressRuleValue: networking.IngressRuleValue{
IngressRuleValue: networking.IngressRuleValue{ HTTP: &networking.HTTPIngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{ Paths: []networking.HTTPIngressPath{{
Paths: []networking.HTTPIngressPath{ Path: "/foo",
{ PathType: &pathTypeImplementationSpecific,
Path: "/foo", Backend: defaultBackend,
PathType: &pathTypeImplementationSpecific, }},
Backend: defaultBackend,
},
},
},
}, },
}, },
}, }},
}, },
Status: networking.IngressStatus{ Status: networking.IngressStatus{
LoadBalancer: networking.IngressLoadBalancerStatus{ LoadBalancer: networking.IngressLoadBalancerStatus{
@@ -595,20 +591,18 @@ func TestValidateIngress(t *testing.T) {
tweakIngress: func(ing *networking.Ingress) { tweakIngress: func(ing *networking.Ingress) {
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{ ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{ HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{ Paths: []networking.HTTPIngressPath{{
{ Path: "/foo",
Path: "/foo", PathType: &pathTypeImplementationSpecific,
PathType: &pathTypeImplementationSpecific, Backend: networking.IngressBackend{
Backend: networking.IngressBackend{ Service: serviceBackend,
Service: serviceBackend, Resource: &api.TypedLocalObjectReference{
Resource: &api.TypedLocalObjectReference{ APIGroup: utilpointer.String("example.com"),
APIGroup: utilpointer.String("example.com"), Kind: "foo",
Kind: "foo", Name: "bar",
Name: "bar",
},
}, },
}, },
}, }},
}, },
} }
}, },
@@ -620,20 +614,18 @@ func TestValidateIngress(t *testing.T) {
tweakIngress: func(ing *networking.Ingress) { tweakIngress: func(ing *networking.Ingress) {
ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{ ing.Spec.Rules[0].IngressRuleValue = networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{ HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{ Paths: []networking.HTTPIngressPath{{
{ Path: "/foo",
Path: "/foo", PathType: &pathTypeImplementationSpecific,
PathType: &pathTypeImplementationSpecific, Backend: networking.IngressBackend{
Backend: networking.IngressBackend{ Service: serviceBackend,
Service: serviceBackend, Resource: &api.TypedLocalObjectReference{
Resource: &api.TypedLocalObjectReference{ APIGroup: utilpointer.String("example.com"),
APIGroup: utilpointer.String("example.com"), Kind: "foo",
Kind: "foo", Name: "bar",
Name: "bar",
},
}, },
}, },
}, }},
}, },
} }
}, },
@@ -790,15 +782,13 @@ func TestValidateIngressRuleValue(t *testing.T) {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
irv := &networking.IngressRuleValue{ irv := &networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{ HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{ Paths: []networking.HTTPIngressPath{{
{ Path: testCase.path,
Path: testCase.path, PathType: &testCase.pathType,
PathType: &testCase.pathType, Backend: networking.IngressBackend{
Backend: networking.IngressBackend{ Service: &serviceBackend,
Service: &serviceBackend,
},
}, },
}, }},
}, },
} }
errs := validateIngressRuleValue(irv, field.NewPath("testing"), IngressValidationOptions{}) errs := validateIngressRuleValue(irv, field.NewPath("testing"), IngressValidationOptions{})
@@ -1638,22 +1628,18 @@ func TestValidateIngressTLS(t *testing.T) {
}, },
Spec: networking.IngressSpec{ Spec: networking.IngressSpec{
DefaultBackend: &defaultBackend, DefaultBackend: &defaultBackend,
Rules: []networking.IngressRule{ Rules: []networking.IngressRule{{
{ Host: "foo.bar.com",
Host: "foo.bar.com", IngressRuleValue: networking.IngressRuleValue{
IngressRuleValue: networking.IngressRuleValue{ HTTP: &networking.HTTPIngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{ Paths: []networking.HTTPIngressPath{{
Paths: []networking.HTTPIngressPath{ Path: "/foo",
{ PathType: &pathTypeImplementationSpecific,
Path: "/foo", Backend: defaultBackend,
PathType: &pathTypeImplementationSpecific, }},
Backend: defaultBackend,
},
},
},
}, },
}, },
}, }},
}, },
Status: networking.IngressStatus{ Status: networking.IngressStatus{
LoadBalancer: networking.IngressLoadBalancerStatus{ LoadBalancer: networking.IngressLoadBalancerStatus{
@@ -1670,11 +1656,9 @@ func TestValidateIngressTLS(t *testing.T) {
wildcardHost := "foo.*.bar.com" wildcardHost := "foo.*.bar.com"
badWildcardTLS := newValid() badWildcardTLS := newValid()
badWildcardTLS.Spec.Rules[0].Host = "*.foo.bar.com" badWildcardTLS.Spec.Rules[0].Host = "*.foo.bar.com"
badWildcardTLS.Spec.TLS = []networking.IngressTLS{ badWildcardTLS.Spec.TLS = []networking.IngressTLS{{
{ Hosts: []string{wildcardHost},
Hosts: []string{wildcardHost}, }}
},
}
badWildcardTLSErr := fmt.Sprintf("spec.tls[0].hosts[0]: Invalid value: '%v'", wildcardHost) badWildcardTLSErr := fmt.Sprintf("spec.tls[0].hosts[0]: Invalid value: '%v'", wildcardHost)
errorCases[badWildcardTLSErr] = badWildcardTLS errorCases[badWildcardTLSErr] = badWildcardTLS
@@ -1696,11 +1680,9 @@ func TestValidateIngressTLS(t *testing.T) {
wildHost := "*.bar.com" wildHost := "*.bar.com"
goodWildcardTLS := newValid() goodWildcardTLS := newValid()
goodWildcardTLS.Spec.Rules[0].Host = "*.bar.com" goodWildcardTLS.Spec.Rules[0].Host = "*.bar.com"
goodWildcardTLS.Spec.TLS = []networking.IngressTLS{ goodWildcardTLS.Spec.TLS = []networking.IngressTLS{{
{ Hosts: []string{wildHost},
Hosts: []string{wildHost}, }}
},
}
validCases[fmt.Sprintf("spec.tls[0].hosts: Valid value: '%v'", wildHost)] = goodWildcardTLS validCases[fmt.Sprintf("spec.tls[0].hosts: Valid value: '%v'", wildHost)] = goodWildcardTLS
for k, v := range validCases { for k, v := range validCases {
errs := validateIngress(&v, IngressValidationOptions{}) errs := validateIngress(&v, IngressValidationOptions{})
@@ -1731,21 +1713,17 @@ func TestValidateEmptyIngressTLS(t *testing.T) {
Namespace: metav1.NamespaceDefault, Namespace: metav1.NamespaceDefault,
}, },
Spec: networking.IngressSpec{ Spec: networking.IngressSpec{
Rules: []networking.IngressRule{ Rules: []networking.IngressRule{{
{ Host: "foo.bar.com",
Host: "foo.bar.com", IngressRuleValue: networking.IngressRuleValue{
IngressRuleValue: networking.IngressRuleValue{ HTTP: &networking.HTTPIngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{ Paths: []networking.HTTPIngressPath{{
Paths: []networking.HTTPIngressPath{ PathType: &pathTypeImplementationSpecific,
{ Backend: defaultBackend,
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 validCases[fmt.Sprintf("spec.tls[0]: Valid value: %v", goodEmptyTLS.Spec.TLS[0])] = goodEmptyTLS
goodEmptyHosts := newValid() goodEmptyHosts := newValid()
goodEmptyHosts.Spec.TLS = []networking.IngressTLS{ goodEmptyHosts.Spec.TLS = []networking.IngressTLS{{
{ Hosts: []string{},
Hosts: []string{}, }}
},
}
validCases[fmt.Sprintf("spec.tls[0]: Valid value: %v", goodEmptyHosts.Spec.TLS[0])] = goodEmptyHosts validCases[fmt.Sprintf("spec.tls[0]: Valid value: %v", goodEmptyHosts.Spec.TLS[0])] = goodEmptyHosts
for k, v := range validCases { for k, v := range validCases {
errs := validateIngress(&v, IngressValidationOptions{}) errs := validateIngress(&v, IngressValidationOptions{})
@@ -1791,21 +1767,17 @@ func TestValidateIngressStatusUpdate(t *testing.T) {
}, },
Spec: networking.IngressSpec{ Spec: networking.IngressSpec{
DefaultBackend: &defaultBackend, DefaultBackend: &defaultBackend,
Rules: []networking.IngressRule{ Rules: []networking.IngressRule{{
{ Host: "foo.bar.com",
Host: "foo.bar.com", IngressRuleValue: networking.IngressRuleValue{
IngressRuleValue: networking.IngressRuleValue{ HTTP: &networking.HTTPIngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{ Paths: []networking.HTTPIngressPath{{
Paths: []networking.HTTPIngressPath{ Path: "/foo",
{ Backend: defaultBackend,
Path: "/foo", }},
Backend: defaultBackend,
},
},
},
}, },
}, },
}, }},
}, },
Status: networking.IngressStatus{ Status: networking.IngressStatus{
LoadBalancer: networking.IngressLoadBalancerStatus{ LoadBalancer: networking.IngressLoadBalancerStatus{
@@ -1867,17 +1839,13 @@ func TestValidateIngressStatusUpdate(t *testing.T) {
func makeNodeSelector(key string, op api.NodeSelectorOperator, values []string) *api.NodeSelector { func makeNodeSelector(key string, op api.NodeSelectorOperator, values []string) *api.NodeSelector {
return &api.NodeSelector{ return &api.NodeSelector{
NodeSelectorTerms: []api.NodeSelectorTerm{ NodeSelectorTerms: []api.NodeSelectorTerm{{
{ MatchExpressions: []api.NodeSelectorRequirement{{
MatchExpressions: []api.NodeSelectorRequirement{ Key: key,
{ Operator: op,
Key: key, Values: values,
Operator: op, }},
Values: values, }},
},
},
},
},
} }
} }
@@ -1901,59 +1869,49 @@ func TestValidateClusterCIDR(t *testing.T) {
name string name string
cc *networking.ClusterCIDR cc *networking.ClusterCIDR
expectErr bool expectErr bool
}{ }{{
{ name: "valid SingleStack IPv4 ClusterCIDR",
name: "valid SingleStack IPv4 ClusterCIDR", cc: makeClusterCIDR(8, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
cc: makeClusterCIDR(8, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), expectErr: false,
expectErr: false, }, {
}, name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits = maxPerNodeHostBits",
{ cc: makeClusterCIDR(16, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
name: "valid SingleStack IPv4 ClusterCIDR, perNodeHostBits = maxPerNodeHostBits", expectErr: false,
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 IPv4 ClusterCIDR, perNodeHostBits > minPerNodeHostBits", }, {
cc: makeClusterCIDR(4, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), name: "valid SingleStack IPv6 ClusterCIDR",
expectErr: false, cc: makeClusterCIDR(8, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
}, expectErr: false,
{ }, {
name: "valid SingleStack IPv6 ClusterCIDR", name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits = maxPerNodeHostBit",
cc: makeClusterCIDR(8, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(64, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: false, expectErr: false,
}, }, {
{ name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits > minPerNodeHostBit",
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits = maxPerNodeHostBit", cc: makeClusterCIDR(4, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
cc: makeClusterCIDR(64, "", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), expectErr: false,
expectErr: false, }, {
}, name: "valid SingleStack IPv6 ClusterCIDR perNodeHostBits=100",
{ cc: makeClusterCIDR(100, "", "fd00:1:1::/16", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
name: "valid SingleStack IPv6 ClusterCIDR, perNodeHostBits > minPerNodeHostBit", expectErr: false,
cc: makeClusterCIDR(4, "", "fd00:1:1::/64", 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 SingleStack IPv6 ClusterCIDR perNodeHostBits=100", }, {
cc: makeClusterCIDR(100, "", "fd00:1:1::/16", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), name: "valid DualStack ClusterCIDR, no NodeSelector",
expectErr: false, cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", nil),
}, 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. // Failure cases.
{ {
name: "invalid ClusterCIDR, no IPv4 or IPv6 CIDR", name: "invalid ClusterCIDR, no IPv4 or IPv6 CIDR",
cc: makeClusterCIDR(8, "", "", nil), cc: makeClusterCIDR(8, "", "", nil),
expectErr: true, expectErr: true,
}, }, {
{
name: "invalid ClusterCIDR, invalid nodeSelector", name: "invalid ClusterCIDR, invalid nodeSelector",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("NoUppercaseOrSpecialCharsLike=Equals", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("NoUppercaseOrSpecialCharsLike=Equals", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
@@ -1963,13 +1921,11 @@ func TestValidateClusterCIDR(t *testing.T) {
name: "invalid SingleStack IPv4 ClusterCIDR, invalid spec.IPv4", name: "invalid SingleStack IPv4 ClusterCIDR, invalid spec.IPv4",
cc: makeClusterCIDR(8, "test", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(8, "test", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
}, }, {
{
name: "invalid Singlestack IPv4 ClusterCIDR, perNodeHostBits > maxPerNodeHostBits", name: "invalid Singlestack IPv4 ClusterCIDR, perNodeHostBits > maxPerNodeHostBits",
cc: makeClusterCIDR(100, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(100, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
}, }, {
{
name: "invalid SingleStack IPv4 ClusterCIDR, perNodeHostBits < minPerNodeHostBits", name: "invalid SingleStack IPv4 ClusterCIDR, perNodeHostBits < minPerNodeHostBits",
cc: makeClusterCIDR(2, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(2, "10.1.0.0/16", "", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
@@ -1979,18 +1935,15 @@ func TestValidateClusterCIDR(t *testing.T) {
name: "invalid SingleStack IPv6 ClusterCIDR, invalid spec.IPv6", name: "invalid SingleStack IPv6 ClusterCIDR, invalid spec.IPv6",
cc: makeClusterCIDR(8, "", "testv6", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(8, "", "testv6", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
}, }, {
{
name: "invalid SingleStack IPv6 ClusterCIDR, valid IPv4 CIDR in spec.IPv6", 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"})), cc: makeClusterCIDR(8, "", "10.2.0.0/16", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
}, }, {
{
name: "invalid SingleStack IPv6 ClusterCIDR, invalid perNodeHostBits > maxPerNodeHostBits", name: "invalid SingleStack IPv6 ClusterCIDR, invalid perNodeHostBits > maxPerNodeHostBits",
cc: makeClusterCIDR(12, "", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(12, "", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
}, }, {
{
name: "invalid SingleStack IPv6 ClusterCIDR, invalid perNodeHostBits < minPerNodeHostBits", name: "invalid SingleStack IPv6 ClusterCIDR, invalid perNodeHostBits < minPerNodeHostBits",
cc: makeClusterCIDR(3, "", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(3, "", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
@@ -2000,18 +1953,15 @@ func TestValidateClusterCIDR(t *testing.T) {
name: "invalid DualStack ClusterCIDR, valid spec.IPv4, invalid spec.IPv6", 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"})), cc: makeClusterCIDR(8, "10.1.0.0/16", "testv6", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
}, }, {
{
name: "invalid DualStack ClusterCIDR, valid spec.IPv6, invalid spec.IPv4", name: "invalid DualStack ClusterCIDR, valid spec.IPv6, invalid spec.IPv4",
cc: makeClusterCIDR(8, "testv4", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(8, "testv4", "fd00::/120", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
}, }, {
{
name: "invalid DualStack ClusterCIDR, invalid perNodeHostBits > maxPerNodeHostBits", 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"})), cc: makeClusterCIDR(24, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
}, }, {
{
name: "invalid DualStack ClusterCIDR, valid IPv6 CIDR in spec.IPv4", 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"})), cc: makeClusterCIDR(8, "fd00::/120", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
expectErr: true, expectErr: true,
@@ -2038,33 +1988,27 @@ func TestValidateClusterConfigUpdate(t *testing.T) {
name string name string
cc *networking.ClusterCIDR cc *networking.ClusterCIDR
expectErr bool expectErr bool
}{ }{{
{ name: "Successful update, no changes to ClusterCIDR.Spec",
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"})),
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), expectErr: false,
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"})),
name: "Failed update, update spec.PerNodeHostBits", expectErr: true,
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.IPv4", }, {
cc: makeClusterCIDR(8, "10.2.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), name: "Failed update, update spec.IPv6",
expectErr: true, cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:2:/112", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})),
}, expectErr: true,
{ }, {
name: "Failed update, update spec.IPv6", name: "Failed update, update spec.NodeSelector",
cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:2:/112", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar"})), cc: makeClusterCIDR(8, "10.1.0.0/16", "fd00:1:1::/64", makeNodeSelector("foo", api.NodeSelectorOpIn, []string{"bar2"})),
expectErr: true, 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 { for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) { t.Run(testCase.name, func(t *testing.T) {
err := ValidateClusterCIDRUpdate(testCase.cc, oldCCC) err := ValidateClusterCIDRUpdate(testCase.cc, oldCCC)
@@ -2244,15 +2188,14 @@ func TestValidateIPAddressUpdate(t *testing.T) {
name string name string
new func(svc *networking.IPAddress) *networking.IPAddress new func(svc *networking.IPAddress) *networking.IPAddress
expectErr bool expectErr bool
}{ }{{
{ name: "Successful update, no changes",
name: "Successful update, no changes", new: func(old *networking.IPAddress) *networking.IPAddress {
new: func(old *networking.IPAddress) *networking.IPAddress { out := old.DeepCopy()
out := old.DeepCopy() return out
return out
},
expectErr: false,
}, },
expectErr: false,
},
{ {
name: "Failed update, update spec.ParentRef", name: "Failed update, update spec.ParentRef",
@@ -2267,8 +2210,7 @@ func TestValidateIPAddressUpdate(t *testing.T) {
return out return out
}, expectErr: true, }, expectErr: true,
}, }, {
{
name: "Failed update, delete spec.ParentRef", name: "Failed update, delete spec.ParentRef",
new: func(svc *networking.IPAddress) *networking.IPAddress { new: func(svc *networking.IPAddress) *networking.IPAddress {
out := svc.DeepCopy() out := svc.DeepCopy()

View File

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

View File

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

View File

@@ -402,12 +402,10 @@ func TestValidateRoleNonResourceURL(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "default", Name: "default",
}, },
Rules: []rbac.PolicyRule{ Rules: []rbac.PolicyRule{{
{ Verbs: []string{"get"},
Verbs: []string{"get"}, NonResourceURLs: []string{"/*"},
NonResourceURLs: []string{"/*"}, }},
},
},
}, },
wantErr: false, wantErr: false,
}.test(t) }.test(t)
@@ -420,13 +418,11 @@ func TestValidateRoleNamespacedNonResourceURL(t *testing.T) {
Namespace: "default", Namespace: "default",
Name: "default", Name: "default",
}, },
Rules: []rbac.PolicyRule{ Rules: []rbac.PolicyRule{{
{ // non-resource URLs are invalid for namespaced rules
// non-resource URLs are invalid for namespaced rules Verbs: []string{"get"},
Verbs: []string{"get"}, NonResourceURLs: []string{"/*"},
NonResourceURLs: []string{"/*"}, }},
},
},
}, },
wantErr: true, wantErr: true,
errType: field.ErrorTypeInvalid, errType: field.ErrorTypeInvalid,
@@ -440,12 +436,10 @@ func TestValidateRoleNonResourceURLNoVerbs(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "default", Name: "default",
}, },
Rules: []rbac.PolicyRule{ Rules: []rbac.PolicyRule{{
{ Verbs: []string{},
Verbs: []string{}, NonResourceURLs: []string{"/*"},
NonResourceURLs: []string{"/*"}, }},
},
},
}, },
wantErr: true, wantErr: true,
errType: field.ErrorTypeRequired, errType: field.ErrorTypeRequired,
@@ -460,14 +454,12 @@ func TestValidateRoleMixedNonResourceAndResource(t *testing.T) {
Name: "default", Name: "default",
Namespace: "default", Namespace: "default",
}, },
Rules: []rbac.PolicyRule{ Rules: []rbac.PolicyRule{{
{ Verbs: []string{"get"},
Verbs: []string{"get"}, NonResourceURLs: []string{"/*"},
NonResourceURLs: []string{"/*"}, APIGroups: []string{"v1"},
APIGroups: []string{"v1"}, Resources: []string{"pods"},
Resources: []string{"pods"}, }},
},
},
}, },
wantErr: true, wantErr: true,
errType: field.ErrorTypeInvalid, errType: field.ErrorTypeInvalid,
@@ -482,13 +474,11 @@ func TestValidateRoleValidResource(t *testing.T) {
Name: "default", Name: "default",
Namespace: "default", Namespace: "default",
}, },
Rules: []rbac.PolicyRule{ Rules: []rbac.PolicyRule{{
{ Verbs: []string{"get"},
Verbs: []string{"get"}, APIGroups: []string{"v1"},
APIGroups: []string{"v1"}, Resources: []string{"pods"},
Resources: []string{"pods"}, }},
},
},
}, },
wantErr: false, wantErr: false,
}.test(t) }.test(t)
@@ -501,12 +491,10 @@ func TestValidateRoleNoAPIGroup(t *testing.T) {
Name: "default", Name: "default",
Namespace: "default", Namespace: "default",
}, },
Rules: []rbac.PolicyRule{ Rules: []rbac.PolicyRule{{
{ Verbs: []string{"get"},
Verbs: []string{"get"}, Resources: []string{"pods"},
Resources: []string{"pods"}, }},
},
},
}, },
wantErr: true, wantErr: true,
errType: field.ErrorTypeRequired, errType: field.ErrorTypeRequired,
@@ -521,12 +509,10 @@ func TestValidateRoleNoResources(t *testing.T) {
Name: "default", Name: "default",
Namespace: "default", Namespace: "default",
}, },
Rules: []rbac.PolicyRule{ Rules: []rbac.PolicyRule{{
{ Verbs: []string{"get"},
Verbs: []string{"get"}, APIGroups: []string{"v1"},
APIGroups: []string{"v1"}, }},
},
},
}, },
wantErr: true, wantErr: true,
errType: field.ErrorTypeRequired, 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 name string
configure func(config *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration configure func(config *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration
errMsg string errMsg string
}{ }{{
{ name: "Success",
name: "Success", configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { return conf
return conf
},
}, },
{ }, {
name: "invalid NodeLeaseDurationSeconds", name: "invalid NodeLeaseDurationSeconds",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.NodeLeaseDurationSeconds = 0 conf.NodeLeaseDurationSeconds = 0
return conf return conf
},
errMsg: "invalid configuration: nodeLeaseDurationSeconds must be greater than 0",
}, },
{ errMsg: "invalid configuration: nodeLeaseDurationSeconds must be greater than 0",
name: "specify EnforceNodeAllocatable without enabling CgroupsPerQOS", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "specify EnforceNodeAllocatable without enabling CgroupsPerQOS",
conf.CgroupsPerQOS = false configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnforceNodeAllocatable = []string{"pods"} conf.CgroupsPerQOS = false
return conf 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: 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 { name: "specify SystemCgroups without CgroupRoot",
conf.SystemCgroups = "/" configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.CgroupRoot = "" conf.SystemCgroups = "/"
return conf conf.CgroupRoot = ""
}, return conf
errMsg: "invalid configuration: systemCgroups (--system-cgroups) was specified and cgroupRoot (--cgroup-root) was not specified",
}, },
{ 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 { name: "invalid EventBurst",
conf.EventBurst = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.EventBurst = -1
}, return conf
errMsg: "invalid configuration: eventBurst (--event-burst) -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 { name: "invalid EventRecordQPS",
conf.EventRecordQPS = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.EventRecordQPS = -1
}, return conf
errMsg: "invalid configuration: eventRecordQPS (--event-qps) -1 must not be a negative number",
}, },
{ errMsg: "invalid configuration: eventRecordQPS (--event-qps) -1 must not be a negative number",
name: "invalid HealthzPort", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid HealthzPort",
conf.HealthzPort = 65536 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.HealthzPort = 65536
}, return conf
errMsg: "invalid configuration: healthzPort (--healthz-port) 65536 must be between 1 and 65535, inclusive",
}, },
{ 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 { name: "specify CPUCFSQuotaPeriod without enabling CPUCFSQuotaPeriod",
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": false} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 200 * time.Millisecond} conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": false}
return conf 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: cpuCFSQuotaPeriod (--cpu-cfs-quota-period) {200ms} requires feature gate CustomCPUCFSQuotaPeriod",
name: "invalid CPUCFSQuotaPeriod", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid CPUCFSQuotaPeriod",
conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": true} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.CPUCFSQuotaPeriod = metav1.Duration{Duration: 2 * time.Second} conf.FeatureGates = map[string]bool{"CustomCPUCFSQuotaPeriod": true}
return conf 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) {2s} must be between 1ms and 1sec, inclusive",
name: "invalid ImageGCHighThresholdPercent", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid ImageGCHighThresholdPercent",
conf.ImageGCHighThresholdPercent = 101 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.ImageGCHighThresholdPercent = 101
}, return conf
errMsg: "invalid configuration: imageGCHighThresholdPercent (--image-gc-high-threshold) 101 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 { name: "invalid ImageGCLowThresholdPercent",
conf.ImageGCLowThresholdPercent = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.ImageGCLowThresholdPercent = -1
}, return conf
errMsg: "invalid configuration: imageGCLowThresholdPercent (--image-gc-low-threshold) -1 must be between 0 and 100, inclusive",
}, },
{ 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 { name: "ImageGCLowThresholdPercent is equal to ImageGCHighThresholdPercent",
conf.ImageGCHighThresholdPercent = 0 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCLowThresholdPercent = 0 conf.ImageGCHighThresholdPercent = 0
return conf 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) 0 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
name: "ImageGCLowThresholdPercent is greater than ImageGCHighThresholdPercent", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "ImageGCLowThresholdPercent is greater than ImageGCHighThresholdPercent",
conf.ImageGCHighThresholdPercent = 0 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ImageGCLowThresholdPercent = 1 conf.ImageGCHighThresholdPercent = 0
return conf 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) 1 must be less than imageGCHighThresholdPercent (--image-gc-high-threshold) 0",
name: "invalid IPTablesDropBit", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid IPTablesDropBit",
conf.IPTablesDropBit = 32 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.IPTablesDropBit = 32
}, return conf
errMsg: "invalid configuration: iptablesDropBit (--iptables-drop-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 { name: "invalid IPTablesMasqueradeBit",
conf.IPTablesMasqueradeBit = 32 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.IPTablesMasqueradeBit = 32
}, return conf
errMsg: "invalid configuration: iptablesMasqueradeBit (--iptables-masquerade-bit) 32 must be between 0 and 31, inclusive",
}, },
{ 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 { name: "invalid KubeAPIBurst",
conf.KubeAPIBurst = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.KubeAPIBurst = -1
}, return conf
errMsg: "invalid configuration: kubeAPIBurst (--kube-api-burst) -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 { name: "invalid KubeAPIQPS",
conf.KubeAPIQPS = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.KubeAPIQPS = -1
}, return conf
errMsg: "invalid configuration: kubeAPIQPS (--kube-api-qps) -1 must not be a negative number",
}, },
{ errMsg: "invalid configuration: kubeAPIQPS (--kube-api-qps) -1 must not be a negative number",
name: "invalid NodeStatusMaxImages", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid NodeStatusMaxImages",
conf.NodeStatusMaxImages = -2 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.NodeStatusMaxImages = -2
}, return conf
errMsg: "invalid configuration: nodeStatusMaxImages (--node-status-max-images) -2 must be -1 or greater",
}, },
{ errMsg: "invalid configuration: nodeStatusMaxImages (--node-status-max-images) -2 must be -1 or greater",
name: "invalid MaxOpenFiles", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid MaxOpenFiles",
conf.MaxOpenFiles = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.MaxOpenFiles = -1
}, return conf
errMsg: "invalid configuration: maxOpenFiles (--max-open-files) -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 { name: "invalid MaxPods",
conf.MaxPods = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.MaxPods = -1
}, return conf
errMsg: "invalid configuration: maxPods (--max-pods) -1 must not be a negative number",
}, },
{ errMsg: "invalid configuration: maxPods (--max-pods) -1 must not be a negative number",
name: "invalid OOMScoreAdj", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid OOMScoreAdj",
conf.OOMScoreAdj = 1001 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.OOMScoreAdj = 1001
}, return conf
errMsg: "invalid configuration: oomScoreAdj (--oom-score-adj) 1001 must be between -1000 and 1000, inclusive",
}, },
{ 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 { name: "invalid PodsPerCore",
conf.PodsPerCore = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.PodsPerCore = -1
}, return conf
errMsg: "invalid configuration: podsPerCore (--pods-per-core) -1 must not be a negative number",
}, },
{ errMsg: "invalid configuration: podsPerCore (--pods-per-core) -1 must not be a negative number",
name: "invalid Port", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid Port",
conf.Port = 65536 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.Port = 65536
}, return conf
errMsg: "invalid configuration: port (--port) 65536 must be between 1 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 { name: "invalid ReadOnlyPort",
conf.ReadOnlyPort = 65536 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.ReadOnlyPort = 65536
}, return conf
errMsg: "invalid configuration: readOnlyPort (--read-only-port) 65536 must be between 0 and 65535, inclusive",
}, },
{ 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 { name: "invalid RegistryBurst",
conf.RegistryBurst = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.RegistryBurst = -1
}, return conf
errMsg: "invalid configuration: registryBurst (--registry-burst) -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 { name: "invalid RegistryPullQPS",
conf.RegistryPullQPS = -1 configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.RegistryPullQPS = -1
}, return conf
errMsg: "invalid configuration: registryPullQPS (--registry-qps) -1 must not be a negative number",
}, },
{ errMsg: "invalid configuration: registryPullQPS (--registry-qps) -1 must not be a negative number",
name: "invalid MaxParallelImagePulls", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid MaxParallelImagePulls",
conf.MaxParallelImagePulls = utilpointer.Int32(0) configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.MaxParallelImagePulls = utilpointer.Int32(0)
}, return conf
errMsg: "invalid configuration: maxParallelImagePulls 0 must be a positive number",
}, },
{ errMsg: "invalid configuration: maxParallelImagePulls 0 must be a positive number",
name: "invalid MaxParallelImagePulls and SerializeImagePulls combination", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid MaxParallelImagePulls and SerializeImagePulls combination",
conf.MaxParallelImagePulls = utilpointer.Int32(3) configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.SerializeImagePulls = true conf.MaxParallelImagePulls = utilpointer.Int32(3)
return conf 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 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 { name: "valid MaxParallelImagePulls and SerializeImagePulls combination",
conf.MaxParallelImagePulls = utilpointer.Int32(1) configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.SerializeImagePulls = true conf.MaxParallelImagePulls = utilpointer.Int32(1)
return conf conf.SerializeImagePulls = true
}, return conf
}, },
{ }, {
name: "specify ServerTLSBootstrap without enabling RotateKubeletServerCertificate", name: "specify ServerTLSBootstrap without enabling RotateKubeletServerCertificate",
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"RotateKubeletServerCertificate": false} conf.FeatureGates = map[string]bool{"RotateKubeletServerCertificate": false}
conf.ServerTLSBootstrap = true conf.ServerTLSBootstrap = true
return conf return conf
},
errMsg: "invalid configuration: serverTLSBootstrap true requires feature gate RotateKubeletServerCertificate",
}, },
{ errMsg: "invalid configuration: serverTLSBootstrap true requires feature gate RotateKubeletServerCertificate",
name: "invalid TopologyManagerPolicy", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid TopologyManagerPolicy",
conf.TopologyManagerPolicy = "invalid-policy" configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf 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: 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 { name: "invalid TopologyManagerScope",
conf.TopologyManagerScope = "invalid-scope" configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf 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: 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 { name: "ShutdownGracePeriodCriticalPods is greater than ShutdownGracePeriod",
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 2 * time.Second} conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second} conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 2 * time.Second}
return conf conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second}
}, return conf
errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {2s} must be <= shutdownGracePeriod {1s}",
}, },
{ errMsg: "invalid configuration: shutdownGracePeriodCriticalPods {2s} must be <= shutdownGracePeriod {1s}",
name: "ShutdownGracePeriod is less than 1 sec", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "ShutdownGracePeriod is less than 1 sec",
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Millisecond} conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
return conf 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: shutdownGracePeriod {1ms} must be either zero or otherwise >= 1 sec",
name: "ShutdownGracePeriodCriticalPods is less than 1 sec", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "ShutdownGracePeriodCriticalPods is less than 1 sec",
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Millisecond} conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": true}
return conf 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: shutdownGracePeriodCriticalPods {1ms} must be either zero or otherwise >= 1 sec",
name: "specify ShutdownGracePeriod without enabling GracefulNodeShutdown", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "specify ShutdownGracePeriod without enabling GracefulNodeShutdown",
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ShutdownGracePeriod = metav1.Duration{Duration: 1 * time.Second} conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
return conf conf.ShutdownGracePeriod = 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 { name: "specify ShutdownGracePeriodCriticalPods without enabling GracefulNodeShutdown",
conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: 1 * time.Second} conf.FeatureGates = map[string]bool{"GracefulNodeShutdown": false}
return conf 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: "invalid MemorySwap.SwapBehavior", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid MemorySwap.SwapBehavior",
conf.FeatureGates = map[string]bool{"NodeSwap": true} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MemorySwap.SwapBehavior = "invalid-behavior" conf.FeatureGates = map[string]bool{"NodeSwap": true}
return conf conf.MemorySwap.SwapBehavior = "invalid-behavior"
}, return conf
errMsg: "invalid configuration: memorySwap.swapBehavior \"invalid-behavior\" must be one of: \"\", \"LimitedSwap\", or \"UnlimitedSwap\"",
}, },
{ 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 { name: "specify MemorySwap.SwapBehavior without enabling NodeSwap",
conf.FeatureGates = map[string]bool{"NodeSwap": false} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MemorySwap.SwapBehavior = kubetypes.LimitedSwap conf.FeatureGates = map[string]bool{"NodeSwap": false}
return conf 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 cannot be set when NodeSwap feature flag is disabled",
name: "specify SystemReservedEnforcementKey without specifying SystemReservedCgroup", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "specify SystemReservedEnforcementKey without specifying SystemReservedCgroup",
conf.EnforceNodeAllocatable = []string{kubetypes.SystemReservedEnforcementKey} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.SystemReservedCgroup = "" conf.EnforceNodeAllocatable = []string{kubetypes.SystemReservedEnforcementKey}
return conf 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: 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 { name: "specify KubeReservedEnforcementKey without specifying KubeReservedCgroup",
conf.EnforceNodeAllocatable = []string{kubetypes.KubeReservedEnforcementKey} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.KubeReservedCgroup = "" conf.EnforceNodeAllocatable = []string{kubetypes.KubeReservedEnforcementKey}
return conf 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: 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 { name: "specify NodeAllocatableNoneKey with additional enforcements",
conf.EnforceNodeAllocatable = []string{kubetypes.NodeAllocatableNoneKey, kubetypes.KubeReservedEnforcementKey} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf 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: enforceNodeAllocatable (--enforce-node-allocatable) may not contain additional enforcements when \"none\" is specified",
name: "invalid EnforceNodeAllocatable", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid EnforceNodeAllocatable",
conf.EnforceNodeAllocatable = []string{"invalid-enforce-node-allocatable"} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf 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: 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 { name: "invalid HairpinMode",
conf.HairpinMode = "invalid-hair-pin-mode" configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf 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-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 { name: "specify ReservedSystemCPUs with SystemReservedCgroup",
conf.ReservedSystemCPUs = "0-3" configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.SystemReservedCgroup = "/system.slice" conf.ReservedSystemCPUs = "0-3"
return conf 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: 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 { name: "specify ReservedSystemCPUs with KubeReservedCgroup",
conf.ReservedSystemCPUs = "0-3" configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.KubeReservedCgroup = "/system.slice" conf.ReservedSystemCPUs = "0-3"
return conf 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: "invalid ReservedSystemCPUs", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid ReservedSystemCPUs",
conf.ReservedSystemCPUs = "invalid-reserved-system-cpus" configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf 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: unable to parse reservedSystemCPUs (--reserved-cpus) invalid-reserved-system-cpus, error:",
name: "enable MemoryQoS without specifying MemoryThrottlingFactor", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "enable MemoryQoS without specifying MemoryThrottlingFactor",
conf.FeatureGates = map[string]bool{"MemoryQoS": true} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.MemoryThrottlingFactor = nil conf.FeatureGates = map[string]bool{"MemoryQoS": true}
return conf conf.MemoryThrottlingFactor = nil
}, return conf
errMsg: "invalid configuration: memoryThrottlingFactor is required when MemoryQoS feature flag is enabled",
}, },
{ errMsg: "invalid configuration: memoryThrottlingFactor is required when MemoryQoS feature flag is enabled",
name: "invalid MemoryThrottlingFactor", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "invalid MemoryThrottlingFactor",
conf.MemoryThrottlingFactor = utilpointer.Float64(1.1) configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf 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 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 { name: "invalid Taint.TimeAdded",
now := metav1.Now() configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.RegisterWithTaints = []v1.Taint{{TimeAdded: &now}} now := metav1.Now()
return conf conf.RegisterWithTaints = []v1.Taint{{TimeAdded: &now}}
}, return conf
errMsg: "invalid configuration: taint.TimeAdded is not nil",
}, },
{ errMsg: "invalid configuration: taint.TimeAdded is not nil",
name: "specify tracing with KubeletTracing disabled", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "specify tracing with KubeletTracing disabled",
samplingRate := int32(99999) configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"KubeletTracing": false} samplingRate := int32(99999)
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate} conf.FeatureGates = map[string]bool{"KubeletTracing": false}
return conf 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: tracing should not be configured if KubeletTracing feature flag is disabled.",
name: "specify tracing invalid sampling rate", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "specify tracing invalid sampling rate",
samplingRate := int32(-1) configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"KubeletTracing": true} samplingRate := int32(-1)
conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate} conf.FeatureGates = map[string]bool{"KubeletTracing": true}
return conf conf.Tracing = &tracingapi.TracingConfiguration{SamplingRatePerMillion: &samplingRate}
}, return conf
errMsg: "tracing.samplingRatePerMillion: Invalid value: -1: sampling rate must be positive",
}, },
{ errMsg: "tracing.samplingRatePerMillion: Invalid value: -1: sampling rate must be positive",
name: "specify tracing invalid endpoint", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "specify tracing invalid endpoint",
ep := "dn%2s://localhost:4317" configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.FeatureGates = map[string]bool{"KubeletTracing": true} ep := "dn%2s://localhost:4317"
conf.Tracing = &tracingapi.TracingConfiguration{Endpoint: &ep} conf.FeatureGates = map[string]bool{"KubeletTracing": true}
return conf 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.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 { name: "invalid GracefulNodeShutdownBasedOnPodPriority",
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": true} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{ conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": true}
{ conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{{
Priority: 0, Priority: 0,
ShutdownGracePeriodSeconds: 0, ShutdownGracePeriodSeconds: 0,
}} }}
return conf return conf
},
errMsg: "invalid configuration: Cannot specify both shutdownGracePeriodByPodPriority and shutdownGracePeriod at the same time",
}, },
{ 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 { name: "Specifying shutdownGracePeriodByPodPriority without enable GracefulNodeShutdownBasedOnPodPriority",
conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": false} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{ conf.FeatureGates = map[string]bool{"GracefulNodeShutdownBasedOnPodPriority": false}
{ conf.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{{
Priority: 0, Priority: 0,
ShutdownGracePeriodSeconds: 0, ShutdownGracePeriodSeconds: 0,
}} }}
return conf return conf
},
errMsg: "invalid configuration: Specifying shutdownGracePeriodByPodPriority requires feature gate GracefulNodeShutdownBasedOnPodPriority",
}, },
{ errMsg: "invalid configuration: Specifying shutdownGracePeriodByPodPriority requires feature gate GracefulNodeShutdownBasedOnPodPriority",
name: "enableSystemLogQuery is enabled without NodeLogQuery feature gate", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "enableSystemLogQuery is enabled without NodeLogQuery feature gate",
conf.EnableSystemLogQuery = true configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
return conf conf.EnableSystemLogQuery = true
}, return conf
errMsg: "invalid configuration: NodeLogQuery feature gate is required for enableSystemLogHandler",
}, },
{ errMsg: "invalid configuration: NodeLogQuery feature gate is required for enableSystemLogHandler",
name: "enableSystemLogQuery is enabled without enableSystemLogHandler", }, {
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { name: "enableSystemLogQuery is enabled without enableSystemLogHandler",
conf.FeatureGates = map[string]bool{"NodeLogQuery": true} configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
conf.EnableSystemLogHandler = false conf.FeatureGates = map[string]bool{"NodeLogQuery": true}
conf.EnableSystemLogQuery = true conf.EnableSystemLogHandler = false
return conf conf.EnableSystemLogQuery = true
}, return conf
errMsg: "invalid configuration: enableSystemLogHandler is required for enableSystemLogQuery",
}, },
} errMsg: "invalid configuration: enableSystemLogHandler is required for enableSystemLogQuery",
}}
for _, tc := range cases { for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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