mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-30 19:35:06 +00:00
feat: add more time jmespath filters (#5950)
* feat: add more time jmespath filters Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * add time_utc and time_now_utc Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * add time_diff Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * more time filters Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * Update pkg/engine/jmespath/functions.go Signed-off-by: shuting <shutting06@gmail.com> Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Signed-off-by: shuting <shutting06@gmail.com> Co-authored-by: shuting <shutting06@gmail.com>
This commit is contained in:
parent
e323e693b2
commit
91f2622384
4 changed files with 448 additions and 285 deletions
|
@ -70,8 +70,6 @@ var (
|
|||
modulo = "modulo"
|
||||
base64Decode = "base64_decode"
|
||||
base64Encode = "base64_encode"
|
||||
timeSince = "time_since"
|
||||
timeNow = "time_now"
|
||||
pathCanonicalize = "path_canonicalize"
|
||||
truncate = "truncate"
|
||||
semverCompare = "semver_compare"
|
||||
|
@ -81,9 +79,6 @@ var (
|
|||
objectFromLists = "object_from_lists"
|
||||
random = "random"
|
||||
x509_decode = "x509_decode"
|
||||
timeAdd = "time_add"
|
||||
timeParse = "time_parse"
|
||||
timeToCron = "time_to_cron"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -386,6 +381,14 @@ func GetFunctions() []*FunctionEntry {
|
|||
ReturnType: []JpType{JpString},
|
||||
Note: "returns current time in RFC 3339 format",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
Name: timeNowUtc,
|
||||
Handler: jpTimeNowUtc,
|
||||
},
|
||||
ReturnType: []JpType{JpString},
|
||||
Note: "returns current UTC time in RFC 3339 format",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
Name: pathCanonicalize,
|
||||
|
@ -499,7 +502,7 @@ func GetFunctions() []*FunctionEntry {
|
|||
Handler: jpTimeToCron,
|
||||
},
|
||||
ReturnType: []JpType{JpString},
|
||||
Note: "converts an absolute time (RFC 3339) to a cron expression (string).",
|
||||
Note: "converts a time (RFC 3339) to a cron expression (string).",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
|
@ -507,12 +510,11 @@ func GetFunctions() []*FunctionEntry {
|
|||
Arguments: []ArgSpec{
|
||||
{Types: []JpType{JpString}},
|
||||
{Types: []JpType{JpString}},
|
||||
{Types: []JpType{JpString}},
|
||||
},
|
||||
Handler: jpTimeAdd,
|
||||
},
|
||||
ReturnType: []JpType{JpString},
|
||||
Note: "adds duration (third string) to a time value (second string) of a specified layout (first string)",
|
||||
Note: "adds duration (second string) to a time value (first string)",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
|
@ -526,6 +528,78 @@ func GetFunctions() []*FunctionEntry {
|
|||
ReturnType: []JpType{JpString},
|
||||
Note: "changes a time value of a given layout to RFC 3339",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
Name: timeUtc,
|
||||
Arguments: []ArgSpec{
|
||||
{Types: []JpType{JpString}},
|
||||
},
|
||||
Handler: jpTimeUtc,
|
||||
},
|
||||
ReturnType: []JpType{JpString},
|
||||
Note: "calcutes time in UTC from a given time in RFC 3339 format",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
Name: timeDiff,
|
||||
Arguments: []ArgSpec{
|
||||
{Types: []JpType{JpString}},
|
||||
{Types: []JpType{JpString}},
|
||||
},
|
||||
Handler: jpTimeDiff,
|
||||
},
|
||||
ReturnType: []JpType{JpString},
|
||||
Note: "calculate the difference between a start and end date in RFC3339 format",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
Name: timeBefore,
|
||||
Arguments: []ArgSpec{
|
||||
{Types: []JpType{JpString}},
|
||||
{Types: []JpType{JpString}},
|
||||
},
|
||||
Handler: jpTimeBefore,
|
||||
},
|
||||
ReturnType: []JpType{JpBool},
|
||||
Note: "checks if a time is before another time, both in RFC3339 format",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
Name: timeAfter,
|
||||
Arguments: []ArgSpec{
|
||||
{Types: []JpType{JpString}},
|
||||
{Types: []JpType{JpString}},
|
||||
},
|
||||
Handler: jpTimeAfter,
|
||||
},
|
||||
ReturnType: []JpType{JpBool},
|
||||
Note: "checks if a time is after another time, both in RFC3339 format",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
Name: timeBetween,
|
||||
Arguments: []ArgSpec{
|
||||
{Types: []JpType{JpString}},
|
||||
{Types: []JpType{JpString}},
|
||||
{Types: []JpType{JpString}},
|
||||
},
|
||||
Handler: jpTimeBetween,
|
||||
},
|
||||
ReturnType: []JpType{JpBool},
|
||||
Note: "checks if a time is between a start and end time, all in RFC3339 format",
|
||||
},
|
||||
{
|
||||
Entry: &gojmespath.FunctionEntry{
|
||||
Name: timeTruncate,
|
||||
Arguments: []ArgSpec{
|
||||
{Types: []JpType{JpString}},
|
||||
{Types: []JpType{JpString}},
|
||||
},
|
||||
Handler: jpTimeTruncate,
|
||||
},
|
||||
ReturnType: []JpType{JpString},
|
||||
Note: "returns the result of rounding time down to a multiple of duration",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -830,55 +904,6 @@ func jpBase64Encode(arguments []interface{}) (interface{}, error) {
|
|||
return base64.StdEncoding.EncodeToString([]byte(str.String())), nil
|
||||
}
|
||||
|
||||
func jpTimeSince(arguments []interface{}) (interface{}, error) {
|
||||
var err error
|
||||
layout, err := validateArg("", arguments, 0, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ts1, err := validateArg("", arguments, 1, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ts2, err := validateArg("", arguments, 2, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var t1, t2 time.Time
|
||||
if layout.String() != "" {
|
||||
t1, err = time.Parse(layout.String(), ts1.String())
|
||||
} else {
|
||||
t1, err = time.Parse(time.RFC3339, ts1.String())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t2 = time.Now()
|
||||
if ts2.String() != "" {
|
||||
if layout.String() != "" {
|
||||
t2, err = time.Parse(layout.String(), ts2.String())
|
||||
} else {
|
||||
t2, err = time.Parse(time.RFC3339, ts2.String())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return t2.Sub(t1).String(), nil
|
||||
}
|
||||
|
||||
func jpTimeNow(arguments []interface{}) (interface{}, error) {
|
||||
var ts time.Time = time.Now()
|
||||
var t string = ts.Format(time.RFC3339)
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func jpPathCanonicalize(arguments []interface{}) (interface{}, error) {
|
||||
var err error
|
||||
str, err := validateArg(pathCanonicalize, arguments, 0, reflect.String)
|
||||
|
@ -1113,85 +1138,3 @@ func jpX509Decode(arguments []interface{}) (interface{}, error) {
|
|||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func jpTimeToCron(arguments []interface{}) (interface{}, error) {
|
||||
var err error
|
||||
|
||||
ts, err := validateArg("", arguments, 0, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var t time.Time
|
||||
t, err = time.Parse(time.RFC3339, ts.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t = t.UTC()
|
||||
|
||||
var cron string = ""
|
||||
cron += strconv.Itoa(t.Minute()) + " "
|
||||
cron += strconv.Itoa(t.Hour()) + " "
|
||||
cron += strconv.Itoa(t.Day()) + " "
|
||||
cron += strconv.Itoa(int(t.Month())) + " "
|
||||
cron += strconv.Itoa(int(t.Weekday()))
|
||||
|
||||
return cron, nil
|
||||
}
|
||||
|
||||
func jpTimeAdd(arguments []interface{}) (interface{}, error) {
|
||||
var err error
|
||||
layout, err := validateArg("", arguments, 0, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ts, err := validateArg("", arguments, 1, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dr, err := validateArg("", arguments, 2, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var t time.Time
|
||||
if layout.String() != "" {
|
||||
t, err = time.Parse(layout.String(), ts.String())
|
||||
} else {
|
||||
t, err = time.Parse(time.RFC3339, ts.String())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var d time.Duration
|
||||
d, err = time.ParseDuration(dr.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return t.Add(d).Format(time.RFC3339), nil
|
||||
}
|
||||
|
||||
func jpTimeParse(arguments []interface{}) (interface{}, error) {
|
||||
var err error
|
||||
layout, err := validateArg("", arguments, 0, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ts, err := validateArg("", arguments, 1, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var t time.Time
|
||||
t, err = time.Parse(layout.String(), ts.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return t.Format(time.RFC3339), nil
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
@ -1162,36 +1161,6 @@ func Test_Base64Decode_Secret(t *testing.T) {
|
|||
assert.Equal(t, string(result), "Hello, world!")
|
||||
}
|
||||
|
||||
func Test_TimeSince(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_since('', '2021-01-02T15:04:05-07:00', '2021-01-10T03:14:05-07:00')",
|
||||
expectedResult: "180h10m0s",
|
||||
},
|
||||
{
|
||||
test: "time_since('Mon Jan _2 15:04:05 MST 2006', 'Mon Jan 02 15:04:05 MST 2021', 'Mon Jan 10 03:14:16 MST 2021')",
|
||||
expectedResult: "180h10m11s",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PathCanonicalize(t *testing.T) {
|
||||
testCases := []struct {
|
||||
jmesPath string
|
||||
|
@ -1550,118 +1519,3 @@ UFOZZVoELaasWS559wy8og39Eq21dDMynb8Bndn/
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TimeToCron(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_to_cron('2023-02-02T15:04:05Z')",
|
||||
expectedResult: "4 15 2 2 4",
|
||||
},
|
||||
{
|
||||
test: "time_to_cron('2023-02-02T15:04:05-07:00')",
|
||||
expectedResult: "4 22 2 2 4",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TimeAdd(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_add('', '2021-01-02T15:04:05-07:00', '3h')",
|
||||
expectedResult: "2021-01-02T18:04:05-07:00",
|
||||
},
|
||||
{
|
||||
test: "time_add('Mon Jan 02 15:04:05 MST 2006', 'Sat Jan 02 15:04:05 MST 2021', '5h30m40s')",
|
||||
expectedResult: "2021-01-02T20:34:45Z",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TimeParse(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_parse('2006-01-02T15:04:05Z07:00', '2021-01-02T15:04:05-07:00')",
|
||||
expectedResult: "2021-01-02T15:04:05-07:00",
|
||||
},
|
||||
{
|
||||
test: "time_parse('Mon Jan 02 15:04:05 MST 2006', 'Sat Jan 02 15:04:05 MST 2021')",
|
||||
expectedResult: "2021-01-02T15:04:05Z",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TimeNow(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
layout string
|
||||
}{
|
||||
{
|
||||
test: "time_now()",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, time.Now().Format(time.RFC3339))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
182
pkg/engine/jmespath/time.go
Normal file
182
pkg/engine/jmespath/time.go
Normal file
|
@ -0,0 +1,182 @@
|
|||
package jmespath
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// function names
|
||||
var (
|
||||
timeSince = "time_since"
|
||||
timeNow = "time_now"
|
||||
timeNowUtc = "time_now_utc"
|
||||
timeAdd = "time_add"
|
||||
timeParse = "time_parse"
|
||||
timeToCron = "time_to_cron"
|
||||
timeUtc = "time_utc"
|
||||
timeDiff = "time_diff"
|
||||
timeBefore = "time_before"
|
||||
timeAfter = "time_after"
|
||||
timeBetween = "time_between"
|
||||
timeTruncate = "time_truncate"
|
||||
)
|
||||
|
||||
func getTimeArg(f string, arguments []interface{}, index int) (time.Time, error) {
|
||||
var empty time.Time
|
||||
arg, err := validateArg(f, arguments, index, reflect.String)
|
||||
if err != nil {
|
||||
return empty, err
|
||||
}
|
||||
return time.Parse(time.RFC3339, arg.String())
|
||||
}
|
||||
|
||||
func getDurationArg(f string, arguments []interface{}, index int) (time.Duration, error) {
|
||||
var empty time.Duration
|
||||
arg, err := validateArg(f, arguments, index, reflect.String)
|
||||
if err != nil {
|
||||
return empty, err
|
||||
}
|
||||
return time.ParseDuration(arg.String())
|
||||
}
|
||||
|
||||
func jpTimeSince(arguments []interface{}) (interface{}, error) {
|
||||
var err error
|
||||
layout, err := validateArg(timeSince, arguments, 0, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts1, err := validateArg(timeSince, arguments, 1, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts2, err := validateArg(timeSince, arguments, 2, reflect.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var t1, t2 time.Time
|
||||
if layout.String() != "" {
|
||||
t1, err = time.Parse(layout.String(), ts1.String())
|
||||
} else {
|
||||
t1, err = time.Parse(time.RFC3339, ts1.String())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t2 = time.Now()
|
||||
if ts2.String() != "" {
|
||||
if layout.String() != "" {
|
||||
t2, err = time.Parse(layout.String(), ts2.String())
|
||||
} else {
|
||||
t2, err = time.Parse(time.RFC3339, ts2.String())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return t2.Sub(t1).String(), nil
|
||||
}
|
||||
|
||||
func jpTimeNow(arguments []interface{}) (interface{}, error) {
|
||||
return time.Now().Format(time.RFC3339), nil
|
||||
}
|
||||
|
||||
func jpTimeNowUtc(arguments []interface{}) (interface{}, error) {
|
||||
return time.Now().UTC().Format(time.RFC3339), nil
|
||||
}
|
||||
|
||||
func jpTimeToCron(arguments []interface{}) (interface{}, error) {
|
||||
if t, err := getTimeArg(timeToCron, arguments, 0); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
var cron string = ""
|
||||
cron += strconv.Itoa(t.Minute()) + " "
|
||||
cron += strconv.Itoa(t.Hour()) + " "
|
||||
cron += strconv.Itoa(t.Day()) + " "
|
||||
cron += strconv.Itoa(int(t.Month())) + " "
|
||||
cron += strconv.Itoa(int(t.Weekday()))
|
||||
return cron, nil
|
||||
}
|
||||
}
|
||||
|
||||
func jpTimeAdd(arguments []interface{}) (interface{}, error) {
|
||||
if t, err := getTimeArg(timeToCron, arguments, 0); err != nil {
|
||||
return nil, err
|
||||
} else if d, err := getDurationArg(timeToCron, arguments, 1); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return t.Add(d).Format(time.RFC3339), nil
|
||||
}
|
||||
}
|
||||
|
||||
func jpTimeParse(arguments []interface{}) (interface{}, error) {
|
||||
if layout, err := validateArg(timeParse, arguments, 0, reflect.String); err != nil {
|
||||
return nil, err
|
||||
} else if ts, err := validateArg(timeParse, arguments, 1, reflect.String); err != nil {
|
||||
return nil, err
|
||||
} else if t, err := time.Parse(layout.String(), ts.String()); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return t.Format(time.RFC3339), nil
|
||||
}
|
||||
}
|
||||
|
||||
func jpTimeUtc(arguments []interface{}) (interface{}, error) {
|
||||
if t, err := getTimeArg(timeUtc, arguments, 0); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return t.UTC().Format(time.RFC3339), nil
|
||||
}
|
||||
}
|
||||
|
||||
func jpTimeDiff(arguments []interface{}) (interface{}, error) {
|
||||
if t1, err := getTimeArg(timeDiff, arguments, 0); err != nil {
|
||||
return nil, err
|
||||
} else if t2, err := getTimeArg(timeDiff, arguments, 1); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return t2.Sub(t1).String(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func jpTimeBefore(arguments []interface{}) (interface{}, error) {
|
||||
if t1, err := getTimeArg(timeBefore, arguments, 0); err != nil {
|
||||
return nil, err
|
||||
} else if t2, err := getTimeArg(timeBefore, arguments, 1); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return t1.Before(t2), nil
|
||||
}
|
||||
}
|
||||
|
||||
func jpTimeAfter(arguments []interface{}) (interface{}, error) {
|
||||
if t1, err := getTimeArg(timeAfter, arguments, 0); err != nil {
|
||||
return nil, err
|
||||
} else if t2, err := getTimeArg(timeAfter, arguments, 1); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return t1.After(t2), nil
|
||||
}
|
||||
}
|
||||
|
||||
func jpTimeBetween(arguments []interface{}) (interface{}, error) {
|
||||
if t, err := getTimeArg(timeBetween, arguments, 0); err != nil {
|
||||
return nil, err
|
||||
} else if start, err := getTimeArg(timeBetween, arguments, 1); err != nil {
|
||||
return nil, err
|
||||
} else if end, err := getTimeArg(timeBetween, arguments, 2); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return t.After(start) && t.Before(end), nil
|
||||
}
|
||||
}
|
||||
|
||||
func jpTimeTruncate(arguments []interface{}) (interface{}, error) {
|
||||
if t, err := getTimeArg(timeTruncate, arguments, 0); err != nil {
|
||||
return nil, err
|
||||
} else if d, err := getDurationArg(timeTruncate, arguments, 1); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return t.Truncate(d).Format(time.RFC3339), nil
|
||||
}
|
||||
}
|
184
pkg/engine/jmespath/time_test.go
Normal file
184
pkg/engine/jmespath/time_test.go
Normal file
|
@ -0,0 +1,184 @@
|
|||
package jmespath
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func Test_TimeSince(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_since('', '2021-01-02T15:04:05-07:00', '2021-01-10T03:14:05-07:00')",
|
||||
expectedResult: "180h10m0s",
|
||||
},
|
||||
{
|
||||
test: "time_since('Mon Jan _2 15:04:05 MST 2006', 'Mon Jan 02 15:04:05 MST 2021', 'Mon Jan 10 03:14:16 MST 2021')",
|
||||
expectedResult: "180h10m11s",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TimeToCron(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_to_cron('2023-02-02T15:04:05Z')",
|
||||
expectedResult: "4 15 2 2 4",
|
||||
},
|
||||
{
|
||||
test: "time_to_cron(time_utc('2023-02-02T15:04:05-07:00'))",
|
||||
expectedResult: "4 22 2 2 4",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TimeAdd(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_add('2021-01-02T15:04:05-07:00', '3h')",
|
||||
expectedResult: "2021-01-02T18:04:05-07:00",
|
||||
},
|
||||
{
|
||||
test: "time_add(time_parse('Mon Jan 02 15:04:05 MST 2006', 'Sat Jan 02 15:04:05 MST 2021'), '5h30m40s')",
|
||||
expectedResult: "2021-01-02T20:34:45Z",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TimeParse(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_parse('2006-01-02T15:04:05Z07:00', '2021-01-02T15:04:05-07:00')",
|
||||
expectedResult: "2021-01-02T15:04:05-07:00",
|
||||
},
|
||||
{
|
||||
test: "time_parse('Mon Jan 02 15:04:05 MST 2006', 'Sat Jan 02 15:04:05 MST 2021')",
|
||||
expectedResult: "2021-01-02T15:04:05Z",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TimeUtc(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_utc('2023-02-02T15:04:05Z')",
|
||||
expectedResult: "2023-02-02T15:04:05Z",
|
||||
},
|
||||
{
|
||||
test: "time_utc('2023-02-02T15:04:05-07:00')",
|
||||
expectedResult: "2023-02-02T22:04:05Z",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TimeDiff(t *testing.T) {
|
||||
testCases := []struct {
|
||||
test string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
test: "time_diff('2021-01-02T15:04:05-07:00', '2021-01-10T03:14:05-07:00')",
|
||||
expectedResult: "180h10m0s",
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
query, err := New(tc.test)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := query.Search("")
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, ok := res.(string)
|
||||
assert.Assert(t, ok)
|
||||
|
||||
assert.Equal(t, result, tc.expectedResult)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue