@@ -17,6 +17,7 @@ package cel
17
17
import (
18
18
"bytes"
19
19
"context"
20
+ "errors"
20
21
"fmt"
21
22
"os"
22
23
"reflect"
@@ -1766,6 +1767,95 @@ func TestEstimateCostAndRuntimeCost(t *testing.T) {
1766
1767
}
1767
1768
}
1768
1769
1770
+ func TestCostLimit (t * testing.T ) {
1771
+ cases := []struct {
1772
+ name string
1773
+ expr string
1774
+ decls []EnvOption
1775
+ costLimit uint64
1776
+ in any
1777
+ err error
1778
+ }{
1779
+ {
1780
+ name : "greater" ,
1781
+ expr : `val1 > val2` ,
1782
+ decls : []EnvOption {
1783
+ Variable ("val1" , IntType ),
1784
+ Variable ("val2" , IntType ),
1785
+ },
1786
+ in : map [string ]any {"val1" : 1 , "val2" : 2 },
1787
+ costLimit : 10 ,
1788
+ },
1789
+ {
1790
+ name : "greater - error" ,
1791
+ expr : `val1 > val2` ,
1792
+ decls : []EnvOption {
1793
+ Variable ("val1" , IntType ),
1794
+ Variable ("val2" , IntType ),
1795
+ },
1796
+ in : map [string ]any {"val1" : 1 , "val2" : 2 },
1797
+ costLimit : 0 ,
1798
+ err : errors .New ("actual cost limit exceeded" ),
1799
+ },
1800
+ }
1801
+
1802
+ for _ , tst := range cases {
1803
+ tc := tst
1804
+ t .Run (tc .name , func (t * testing.T ) {
1805
+ t .Parallel ()
1806
+ envOpts := []EnvOption {
1807
+ CostEstimatorOptions (
1808
+ checker .OverloadCostEstimate (overloads .TimestampToYear , estimateTimestampToYear ),
1809
+ ),
1810
+ }
1811
+ envOpts = append (envOpts , tc .decls ... )
1812
+ env := testEnv (t , envOpts ... )
1813
+ ast , iss := env .Compile (tc .expr )
1814
+ if iss .Err () != nil {
1815
+ t .Fatalf ("env.Compile(%v) failed: %v" , tc .expr , iss .Err ())
1816
+ }
1817
+ est , err := env .EstimateCost (ast , testCostEstimator {hints : map [string ]uint64 {}})
1818
+ if err != nil {
1819
+ t .Fatalf ("Env.EstimateCost(ast *Ast, estimator checker.CostEstimator) failed to estimate cost: %s\n " , err )
1820
+ }
1821
+
1822
+ checkedAst , iss := env .Check (ast )
1823
+ if iss .Err () != nil {
1824
+ t .Fatalf (`Env.Check(ast *Ast) failed to check expression: %v` , iss .Err ())
1825
+ }
1826
+ // Evaluate expression.
1827
+ program , err := env .Program (checkedAst ,
1828
+ CostTracking (testRuntimeCostEstimator {}),
1829
+ CostTrackerOptions (
1830
+ interpreter .OverloadCostTracker (overloads .TimestampToYear , trackTimestampToYear ),
1831
+ ),
1832
+ CostLimit (tc .costLimit ),
1833
+ )
1834
+ if err != nil {
1835
+ t .Fatalf (`Env.Program(ast *Ast, opts ...ProgramOption) failed to construct program: %v` , err )
1836
+ }
1837
+ _ , details , err := program .Eval (tc .in )
1838
+ if err != nil && tc .err == nil {
1839
+ t .Fatalf (`Program.Eval(vars any) failed to evaluate expression: %v` , err )
1840
+ }
1841
+ actualCost := details .ActualCost ()
1842
+ if actualCost == nil {
1843
+ t .Errorf (`EvalDetails.ActualCost() got nil for "%s" cost, wanted %d` , tc .expr , actualCost )
1844
+ }
1845
+ if err == nil {
1846
+ if est .Min > * actualCost || est .Max < * actualCost {
1847
+ t .Errorf ("EvalDetails.ActualCost() failed to return a runtime cost %d is the range of estimate cost [%d, %d]" , * actualCost ,
1848
+ est .Min , est .Max )
1849
+ }
1850
+ } else {
1851
+ if ! strings .Contains (err .Error (), tc .err .Error ()) {
1852
+ t .Fatalf ("program.Eval() got error %v, wanted error containing %v" , err , tc .err )
1853
+ }
1854
+ }
1855
+ })
1856
+ }
1857
+ }
1858
+
1769
1859
func TestPartialVars (t * testing.T ) {
1770
1860
env := testEnv (t ,
1771
1861
Variable ("x" , StringType ),
0 commit comments