mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
Merge pull request #108011 from cici37/benchmark
Benchmark cel.UnstructuredToVal
This commit is contained in:
commit
889922476a
@ -619,3 +619,47 @@ func TestMapper(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnstructuredToVal(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
if val := UnstructuredToVal([]interface{}{
|
||||
map[string]interface{}{
|
||||
"key": "a",
|
||||
"val": 1,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"key": "b",
|
||||
"val": 2,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"key": "@b",
|
||||
"val": 2,
|
||||
},
|
||||
}, &mapListSchema); val == nil {
|
||||
b.Fatal(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnstructuredToValWithEscape(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
if val := UnstructuredToVal([]interface{}{
|
||||
map[string]interface{}{
|
||||
"key": "a.1",
|
||||
"val": "__i.1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"key": "b.1",
|
||||
"val": 2,
|
||||
},
|
||||
}, &mapListSchema); val == nil {
|
||||
b.Fatal(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,57 @@ var celReservedSymbols = sets.NewString(
|
||||
// expandMatcher matches the escape sequence, characters that are escaped, and characters that are unsupported
|
||||
var expandMatcher = regexp.MustCompile(`(__|[-./]|[^a-zA-Z0-9-./_])`)
|
||||
|
||||
// newCharacterFilter returns a boolean array to indicate the allowed characters
|
||||
func newCharacterFilter(characters string) []bool {
|
||||
maxChar := 0
|
||||
for _, c := range characters {
|
||||
if maxChar < int(c) {
|
||||
maxChar = int(c)
|
||||
}
|
||||
}
|
||||
filter := make([]bool, maxChar+1)
|
||||
|
||||
for _, c := range characters {
|
||||
filter[int(c)] = true
|
||||
}
|
||||
|
||||
return filter
|
||||
}
|
||||
|
||||
type escapeCheck struct {
|
||||
canSkipRegex bool
|
||||
invalidCharFound bool
|
||||
}
|
||||
|
||||
// skipRegexCheck checks if escape would be skipped.
|
||||
// if invalidCharFound is true, it must have invalid character; if invalidCharFound is false, not sure if it has invalid character or not
|
||||
func skipRegexCheck(ident string) escapeCheck {
|
||||
escapeCheck := escapeCheck{canSkipRegex: true, invalidCharFound: false}
|
||||
// skip escape if possible
|
||||
previous_underscore := false
|
||||
for _, c := range ident {
|
||||
if c == '/' || c == '-' || c == '.' {
|
||||
escapeCheck.canSkipRegex = false
|
||||
return escapeCheck
|
||||
}
|
||||
intc := int(c)
|
||||
if intc < 0 || intc >= len(validCharacterFilter) || !validCharacterFilter[intc] {
|
||||
escapeCheck.invalidCharFound = true
|
||||
return escapeCheck
|
||||
}
|
||||
if c == '_' && previous_underscore {
|
||||
escapeCheck.canSkipRegex = false
|
||||
return escapeCheck
|
||||
}
|
||||
|
||||
previous_underscore = c == '_'
|
||||
}
|
||||
return escapeCheck
|
||||
}
|
||||
|
||||
// validCharacterFilter indicates the allowed characters.
|
||||
var validCharacterFilter = newCharacterFilter("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")
|
||||
|
||||
// Escape escapes ident and returns a CEL identifier (of the form '[a-zA-Z_][a-zA-Z0-9_]*'), or returns
|
||||
// false if the ident does not match the supported input format of `[a-zA-Z_.-/][a-zA-Z0-9_.-/]*`.
|
||||
// Escaping Rules:
|
||||
@ -53,6 +104,15 @@ func Escape(ident string) (string, bool) {
|
||||
if celReservedSymbols.Has(ident) {
|
||||
return "__" + ident + "__", true
|
||||
}
|
||||
|
||||
escapeCheck := skipRegexCheck(ident)
|
||||
if escapeCheck.invalidCharFound {
|
||||
return "", false
|
||||
}
|
||||
if escapeCheck.canSkipRegex {
|
||||
return ident, true
|
||||
}
|
||||
|
||||
ok := true
|
||||
ident = expandMatcher.ReplaceAllStringFunc(ident, func(s string) string {
|
||||
switch s {
|
||||
|
@ -170,3 +170,37 @@ func TestEscapingFuzz(t *testing.T) {
|
||||
}
|
||||
|
||||
var validCelIdent = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
|
||||
|
||||
func TestCanSkipRegex(t *testing.T) {
|
||||
cases := []struct {
|
||||
unescaped string
|
||||
canSkip bool
|
||||
invalidCharFound bool
|
||||
}{
|
||||
{unescaped: "a.a", canSkip: false},
|
||||
{unescaped: "a-a", canSkip: false},
|
||||
{unescaped: "a__a", canSkip: false},
|
||||
{unescaped: "a.-/__a", canSkip: false},
|
||||
{unescaped: "a_a", canSkip: true},
|
||||
{unescaped: "a_a_a", canSkip: true},
|
||||
{unescaped: "@", invalidCharFound: true},
|
||||
{unescaped: "👑", invalidCharFound: true},
|
||||
// if escape keyword is detected before invalid character, invalidCharFound
|
||||
{unescaped: "/👑", canSkip: false},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.unescaped, func(t *testing.T) {
|
||||
escapeCheck := skipRegexCheck(tc.unescaped)
|
||||
if escapeCheck.invalidCharFound {
|
||||
if escapeCheck.invalidCharFound != tc.invalidCharFound {
|
||||
t.Errorf("Expected input validation to be %v, but got %t", tc.invalidCharFound, escapeCheck.invalidCharFound)
|
||||
}
|
||||
} else {
|
||||
if escapeCheck.canSkipRegex != tc.canSkip {
|
||||
t.Errorf("Expected %v, but got %t", tc.canSkip, escapeCheck.canSkipRegex)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user