Merge pull request #110576 from DangerOnTheRanger/cel-e2e-part2

Add second set of additional CRD validation E2E tests
This commit is contained in:
Kubernetes Prow Robot 2022-07-08 21:41:58 -07:00 committed by GitHub
commit 9d577d8a29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -61,17 +61,26 @@ var _ = SIGDescribe("CustomResourceValidationRules [Privileged:ClusterAdmin][Alp
return &c
}
// for all new CRD validation features that should be E2E-tested, add them
// into this schema and then add CR requests to the end of the the test
// below ("MUST NOT fail validation...") instead of writing a new and
// separate test
var schemaWithValidationExpression = unmarshallSchema([]byte(`{
"type":"object",
"properties":{
"spec":{
"type":"object",
"x-kubernetes-validations":[
{ "rule":"self.x + self.y > 0" }
{ "rule":"self.x + self.y > 0" },
{ "rule":"self.firstArray.isSorted() && self.secondArray.isSorted() && ((self.firstArray.sum() + self.secondArray.sum()) % 2 == 0)" },
{ "rule":"self.largeArray.all(x, self.largeArray.all(y, y == x))" }
],
"properties":{
"x":{ "type":"integer" },
"y":{ "type":"integer" }
"y":{ "type":"integer" },
"firstArray":{ "type":"array", "maxItems": 1000, "items":{ "type": "integer"} },
"secondArray":{ "type":"array", "maxItems": 1000, "items":{ "type": "integer"} },
"largeArray":{ "type":"array", "maxItems": 725, "items":{ "type": "integer"} }
}
},
"status":{
@ -85,7 +94,7 @@ var _ = SIGDescribe("CustomResourceValidationRules [Privileged:ClusterAdmin][Alp
}
}
}`))
ginkgo.It("MUST NOT fail validation for create of a custom resource that satisfies the x-kubernetes-validator rules", func() {
ginkgo.It("MUST NOT fail validation for create of a custom resource that satisfies the x-kubernetes-validations rules", func() {
ginkgo.By("Creating a custom resource definition with validation rules")
crd := fixtures.NewRandomNameV1CustomResourceDefinitionWithSchema(v1.NamespaceScoped, schemaWithValidationExpression, false)
crd, err := fixtures.CreateNewV1CustomResourceDefinitionWatchUnsafe(crd, apiExtensionClient)
@ -106,13 +115,16 @@ var _ = SIGDescribe("CustomResourceValidationRules [Privileged:ClusterAdmin][Alp
"namespace": f.Namespace.Name,
},
"spec": map[string]interface{}{
"x": int64(1),
"y": int64(0),
"x": int64(1),
"y": int64(0),
"firstArray": []int64{3, 4},
"secondArray": []int64{5, 10},
"largeArray": []int64{2, 2},
},
}}, metav1.CreateOptions{})
framework.ExpectNoError(err, "validation rules satisfied")
})
ginkgo.It("MUST fail validation for create of a custom resource that does not satisfy the x-kubernetes-validator rules", func() {
ginkgo.It("MUST fail validation for create of a custom resource that does not satisfy the x-kubernetes-validations rules", func() {
ginkgo.By("Creating a custom resource definition with validation rules")
crd := fixtures.NewRandomNameV1CustomResourceDefinitionWithSchema(v1.NamespaceScoped, schemaWithValidationExpression, false)
crd, err := fixtures.CreateNewV1CustomResourceDefinitionWatchUnsafe(crd, apiExtensionClient)
@ -144,7 +156,7 @@ var _ = SIGDescribe("CustomResourceValidationRules [Privileged:ClusterAdmin][Alp
}
})
ginkgo.It("MUST fail create of a custom resource definition that contains a x-kubernetes-validator rule that refers to a property that do not exist", func() {
ginkgo.It("MUST fail create of a custom resource definition that contains a x-kubernetes-validations rule that refers to a property that do not exist", func() {
ginkgo.By("Defining a custom resource definition with a validation rule that refers to a property that do not exist")
var schemaWithInvalidValidationRule = unmarshallSchema([]byte(`{
"type":"object",
@ -223,4 +235,102 @@ var _ = SIGDescribe("CustomResourceValidationRules [Privileged:ClusterAdmin][Alp
framework.Failf("expected error message to contain %q, got %q", expectedErrMsg, err.Error())
}
})
ginkgo.It("MUST fail create of a custom resource that exceeds the runtime cost limit for x-kubernetes-validations rule execution", func() {
ginkgo.By("Defining a custom resource definition including an expensive rule on a large amount of data")
crd := fixtures.NewRandomNameV1CustomResourceDefinitionWithSchema(v1.NamespaceScoped, schemaWithValidationExpression, false)
_, err := fixtures.CreateNewV1CustomResourceDefinitionWatchUnsafe(crd, apiExtensionClient)
framework.ExpectNoError(err, "creating CustomResourceDefinition including an expensive rule on a large amount of data")
defer func() {
err = fixtures.DeleteV1CustomResourceDefinition(crd, apiExtensionClient)
framework.ExpectNoError(err, "deleting CustomResourceDefinition")
}()
ginkgo.By("Attempting to create a custom resource that will exceed the runtime cost limit")
crClient, gvr := customResourceClient(crd)
name1 := names.SimpleNameGenerator.GenerateName("cr-1")
_, err = crClient.Namespace(f.Namespace.Name).Create(context.TODO(), &unstructured.Unstructured{Object: map[string]interface{}{
"apiVersion": gvr.Group + "/" + gvr.Version,
"kind": crd.Spec.Names.Kind,
"metadata": map[string]interface{}{
"name": name1,
"namespace": f.Namespace.Name,
},
"spec": map[string]interface{}{
"largeArray": genLargeArray(725, 20),
},
}}, metav1.CreateOptions{})
framework.ExpectError(err, "custom resource creation should be prohibited by runtime cost limit")
expectedErrMsg := "call cost exceeds limit"
if !strings.Contains(err.Error(), expectedErrMsg) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
}
})
ginkgo.It("MUST fail update of a custom resource that does not satisfy a x-kubernetes-validations transition rule", func() {
ginkgo.By("Defining a custom resource definition with a x-kubernetes-validations transition rule")
var schemaWithTransitionRule = unmarshallSchema([]byte(`{
"type":"object",
"properties":{
"spec":{
"type":"object",
"properties":{
"num":{
"type":"integer",
"x-kubernetes-validations":[
{ "rule":"self > oldSelf" }
]
}
}
}
}
}`))
crd := fixtures.NewRandomNameV1CustomResourceDefinitionWithSchema(v1.NamespaceScoped, schemaWithTransitionRule, false)
_, err := fixtures.CreateNewV1CustomResourceDefinitionWatchUnsafe(crd, apiExtensionClient)
framework.ExpectNoError(err, "creating CustomResourceDefinition including an x-kubernetes-validations transition rule")
defer func() {
err = fixtures.DeleteV1CustomResourceDefinition(crd, apiExtensionClient)
framework.ExpectNoError(err, "deleting CustomResourceDefinition")
}()
ginkgo.By("Attempting to create a custom resource")
crClient, gvr := customResourceClient(crd)
name1 := names.SimpleNameGenerator.GenerateName("cr-1")
unstruct, err := crClient.Namespace(f.Namespace.Name).Create(context.TODO(), &unstructured.Unstructured{Object: map[string]interface{}{
"apiVersion": gvr.Group + "/" + gvr.Version,
"kind": crd.Spec.Names.Kind,
"metadata": map[string]interface{}{
"name": name1,
"namespace": f.Namespace.Name,
},
"spec": map[string]interface{}{
"num": int64(10),
},
}}, metav1.CreateOptions{})
framework.ExpectNoError(err, "transition rules do not apply to create operations")
ginkgo.By("Updating a custom resource with a value that does not satisfy an x-kubernetes-validations transition rule")
_, err = crClient.Namespace(f.Namespace.Name).Update(context.TODO(), &unstructured.Unstructured{Object: map[string]interface{}{
"apiVersion": gvr.Group + "/" + gvr.Version,
"kind": crd.Spec.Names.Kind,
"metadata": map[string]interface{}{
"name": name1,
"namespace": f.Namespace.Name,
"resourceVersion": unstruct.GetResourceVersion(),
},
"spec": map[string]interface{}{
"num": int64(9),
},
}}, metav1.UpdateOptions{})
framework.ExpectError(err, "custom resource update should be prohibited by transition rule")
expectedErrMsg := "failed rule"
if !strings.Contains(err.Error(), expectedErrMsg) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
}
})
})
func genLargeArray(n, x int64) []int64 {
arr := make([]int64, n)
for i := int64(0); i < n; i++ {
arr[i] = x
}
return arr
}