From e4d16f34c15affdf4411d5bd1b19991b5fa27f2a Mon Sep 17 00:00:00 2001 From: Joe Betz Date: Mon, 7 Aug 2023 12:41:52 -0400 Subject: [PATCH] Add test coverage of result size of string operations --- .../validation/validation_test.go | 26 +++++++++++++++++++ .../schema/cel/celcoststability_test.go | 1 + .../apiserver/schema/cel/compilation_test.go | 4 +-- .../apiserver/pkg/cel/library/cost_test.go | 24 +++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation_test.go index 11ef6fd24ba..1d7316e58dc 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation_test.go @@ -9315,6 +9315,32 @@ func TestValidateCustomResourceDefinitionValidation(t *testing.T) { forbidden("spec.validation.openAPIV3Schema.properties[f].x-kubernetes-validations[0].messageExpression"), }, }, + { + name: "x-kubernetes-validations rule with lowerAscii check should be within estimated cost limit", + opts: validationOptions{requireStructuralSchema: true}, + input: apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensions.JSONSchemaProps{ + "f": { + Type: "array", + MaxItems: pointer.Int64(5), + Items: &apiextensions.JSONSchemaPropsOrArray{ + Schema: &apiextensions.JSONSchemaProps{ + Type: "string", + MaxLength: pointer.Int64(5), + }, + }, + XValidations: apiextensions.ValidationRules{ + { + Rule: "self.all(x, self.exists_one(y, x.lowerAscii() == y.lowerAscii()))", + }, + }, + }, + }, + }, + }, + }, { name: "x-kubernetes-validations rule invalidated by messageExpression exceeding per-CRD estimated cost limit", opts: validationOptions{requireStructuralSchema: true}, diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/celcoststability_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/celcoststability_test.go index ab614bcd390..5e1a9bbca67 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/celcoststability_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/celcoststability_test.go @@ -115,6 +115,7 @@ func TestCelCostStability(t *testing.T) { "self.val1.substring(4, 10).trim() == 'takes'": 6, "self.val1.upperAscii() == 'ROOK TAKES 👑'": 6, "self.val1.lowerAscii() == 'rook takes 👑'": 6, + "self.val1.lowerAscii() == self.val1.lowerAscii()": 10, }, }, {name: "escaped strings", diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/compilation_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/compilation_test.go index 1b575ba30a6..768fb24157c 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/compilation_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/compilation_test.go @@ -1691,9 +1691,9 @@ func TestCostEstimation(t *testing.T) { objType = withRule(objType, "self.str.replace(self.before, self.after) == 'does not matter'") return &objType }, - expectedCalcCost: 629154, + expectedCalcCost: 629152, // cost is based on the result size of the replace() call setMaxElements: 10, - expectedSetCost: 16, + expectedSetCost: 14, }, { name: "extended library split", diff --git a/staging/src/k8s.io/apiserver/pkg/cel/library/cost_test.go b/staging/src/k8s.io/apiserver/pkg/cel/library/cost_test.go index 93566135a3f..280de1bc0e7 100644 --- a/staging/src/k8s.io/apiserver/pkg/cel/library/cost_test.go +++ b/staging/src/k8s.io/apiserver/pkg/cel/library/cost_test.go @@ -227,12 +227,36 @@ func TestStringLibrary(t *testing.T) { expectEsimatedCost: checker.CostEstimate{Min: 3, Max: 3}, expectRuntimeCost: 3, }, + { + name: "lowerAsciiEquals", + expr: "'ABCDEFGHIJ abcdefghij'.lowerAscii() == 'abcdefghij ABCDEFGHIJ'.lowerAscii()", + expectEsimatedCost: checker.CostEstimate{Min: 7, Max: 9}, + expectRuntimeCost: 9, + }, { name: "upperAscii", expr: "'ABCDEFGHIJ abcdefghij'.upperAscii()", expectEsimatedCost: checker.CostEstimate{Min: 3, Max: 3}, expectRuntimeCost: 3, }, + { + name: "upperAsciiEquals", + expr: "'ABCDEFGHIJ abcdefghij'.upperAscii() == 'abcdefghij ABCDEFGHIJ'.upperAscii()", + expectEsimatedCost: checker.CostEstimate{Min: 7, Max: 9}, + expectRuntimeCost: 9, + }, + { + name: "quote", + expr: "strings.quote('ABCDEFGHIJ abcdefghij')", + expectEsimatedCost: checker.CostEstimate{Min: 3, Max: 3}, + expectRuntimeCost: 3, + }, + { + name: "quoteEquals", + expr: "strings.quote('ABCDEFGHIJ abcdefghij') == strings.quote('ABCDEFGHIJ abcdefghij')", + expectEsimatedCost: checker.CostEstimate{Min: 7, Max: 11}, + expectRuntimeCost: 9, + }, { name: "replace", expr: "'abc 123 def 123'.replace('123', '456')",