Change:
}) } } <del> // TestDropDisabledFields tests if the drop functionality is working fine or not with feature gate switch func TestDropDisabledFields(t *testing.T) { testCases := []struct { name               string enableXValidations bool crd                *apiextensions.CustomResourceDefinition oldCRD             *apiextensions.CustomResourceDefinition expectedCRD        *apiextensions.CustomResourceDefinition }{ { name:               "For creation, FG disabled, no XValidations, no field drop", enableXValidations: false, crd:                &apiextensions.CustomResourceDefinition{}, oldCRD:             nil, expectedCRD:        &apiextensions.CustomResourceDefinition{}, }, { name:               "For creation, FG disabled, empty XValidations, no field drop", enableXValidations: false, crd: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{}, }, }, oldCRD: nil, expectedCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{}, }, }, }, { name:               "For creation, FG disabled, set XValidations, drop XValidations", enableXValidations: false, crd: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, Dependencies: apiextensions.JSONSchemaDependencies{ "test": apiextensions.JSONSchemaPropsOrStringArray{ Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "size of scoped field should be greater than 0.", }, }, }, }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "subRule": { Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "isTest == true", Message: "isTest should be true.", }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "isTest": { Type: "boolean", }, }, }, }, }, }, }, }, oldCRD: nil, expectedCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", Dependencies: apiextensions.JSONSchemaDependencies{ "test": apiextensions.JSONSchemaPropsOrStringArray{ Schema: &apiextensions.JSONSchemaProps{ Type: "object", }, }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "subRule": { Type: "object", Properties: map[string]apiextensions.JSONSchemaProps{ "isTest": { Type: "boolean", }, }, }, }, }, }, }, }, }, { name:               "For creation, FG enabled, set XValidations, update with XValidations", enableXValidations: true, crd: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, Dependencies: apiextensions.JSONSchemaDependencies{ "test": apiextensions.JSONSchemaPropsOrStringArray{ Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "size of scoped field should be greater than 0.", }, }, }, }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "subRule": { Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "isTest == true", Message: "isTest should be true.", }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "isTest": { Type: "boolean", }, }, }, }, }, }, }, }, oldCRD: nil, expectedCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, Dependencies: apiextensions.JSONSchemaDependencies{ "test": apiextensions.JSONSchemaPropsOrStringArray{ Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "size of scoped field should be greater than 0.", }, }, }, }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "subRule": { Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "isTest == true", Message: "isTest should be true.", }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "isTest": { Type: "boolean", }, }, }, }, }, }, }, }, }, { name:               "For update, FG disabled, oldCRD XValidation in use, don't drop XValidations", enableXValidations: false, crd: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, Dependencies: apiextensions.JSONSchemaDependencies{ "test": apiextensions.JSONSchemaPropsOrStringArray{ Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "size of scoped field should be greater than 0.", }, }, }, }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "subRule": { Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "isTest == true", Message: "isTest should be true.", }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "isTest": { Type: "boolean", }, }, }, }, }, }, }, }, oldCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", Dependencies: apiextensions.JSONSchemaDependencies{ "test": apiextensions.JSONSchemaPropsOrStringArray{ Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "size of scoped field should be greater than 0.", }, }, }, }, }, }, }, }, }, expectedCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, Dependencies: apiextensions.JSONSchemaDependencies{ "test": apiextensions.JSONSchemaPropsOrStringArray{ Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "size of scoped field should be greater than 0.", }, }, }, }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "subRule": { Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "isTest == true", Message: "isTest should be true.", }, }, Properties: map[string]apiextensions.JSONSchemaProps{ "isTest": { Type: "boolean", }, }, }, }, }, }, }, }, }, { name:               "For update, FG disabled, oldCRD has no XValidations, drop XValidations", enableXValidations: false, crd: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, }, }, }, }, oldCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", }, }, }, }, expectedCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", }, }, }, }, }, { name:               "For update, FG enabled, oldCRD has XValidations, updated to newCRD", enableXValidations: true, crd: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, }, }, }, }, oldCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "old data", Message: "old data", }, }, }, }, }, }, expectedCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, }, }, }, }, }, { name:               "For update, FG enabled, oldCRD has no XValidations, updated to newCRD", enableXValidations: true, crd: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, }, }, }, }, oldCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", }, }, }, }, expectedCRD: &apiextensions.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{Name: "foos.sigs.k8s.io", Annotations: map[string]string{v1beta1.KubeAPIApprovedAnnotation: "valid"}, ResourceVersion: "1"}, Spec: apiextensions.CustomResourceDefinitionSpec{ Validation: &apiextensions.CustomResourceValidation{ OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ Type: "object", XValidations: apiextensions.ValidationRules{ { Rule:    "size(self) > 0", Message: "openAPIV3Schema should contain more than 0 element.", }, }, }, }, }, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CustomResourceValidationExpressions, tc.enableXValidations)() old := tc.oldCRD.DeepCopy() dropDisabledFields(tc.crd, tc.oldCRD) // old crd should never be changed if diff := cmp.Diff(tc.oldCRD, old); diff != "" { t.Fatalf("old crd changed from %v to %v", tc.oldCRD, old) } if diff := cmp.Diff(tc.expectedCRD, tc.crd); diff != "" { t.Fatalf("unexpected crd: %v", tc.crd) } }) } } </del>

Discussion:
This is the tracking issue of promoting CRD validation rules to GA: Listed the blocking issues/features below: [x] [x] [x] [x] Issues be aware of but should not be a GA blocker [ ] [ ] [ ] [ ] [ ] /sig api-machinery /triage accepted
/assign
/cc