@@ -253,3 +253,113 @@ func TestDateMath(t *testing.T) {
253253 _ , err = vm .NewDateConverter (evalCtx , fs .Filter )
254254 assert .Equal (t , nil , err )
255255}
256+
257+ func TestDateBoundaryForBetween (t * testing.T ) {
258+ today := time .Now ()
259+
260+ type testCase struct {
261+ testName string
262+ filter string
263+ match bool
264+ expectedBoundaryTime time.Time
265+ lastEvtTs time.Time
266+ }
267+
268+ tests := []testCase {
269+ {
270+ testName : "within_window_1_day_before_lower_bound" ,
271+ filter : `FILTER last_event BETWEEN "now-2d" AND "now+3d"` ,
272+ match : true ,
273+ expectedBoundaryTime : today .AddDate (0 , 0 , 1 ), // Will exit after 1 day since lower bound is after 2 days
274+ lastEvtTs : today .AddDate (0 , 0 , - 1 ),
275+ },
276+ {
277+ testName : "within_window_including_other_filters" ,
278+ filter : `FILTER AND( last_event BETWEEN "now-2d" AND "now+3d", exists subscription_expires )` ,
279+ match : true ,
280+ expectedBoundaryTime : today .AddDate (0 , 0 , 1 ), // Will exit after 1 day since lower bound is after 2 days
281+ lastEvtTs : today .AddDate (0 , 0 , - 1 ),
282+ },
283+ {
284+ testName : "exact_current_time" ,
285+ filter : `FILTER last_event BETWEEN "now-2d" AND "now+3d"` ,
286+ match : true ,
287+ expectedBoundaryTime : today .AddDate (0 , 0 , 2 ), // Will exit after two days
288+ lastEvtTs : today ,
289+ },
290+ {
291+ testName : "just_inside_lower" ,
292+ filter : `FILTER last_event BETWEEN "now-2d" AND "now+3d"` ,
293+ match : true ,
294+ expectedBoundaryTime : today .Add (time .Minute ), // will be after a minute
295+ lastEvtTs : today .AddDate (0 , 0 , - 2 ).Add (time .Minute ), // 2 days ago + 1 minute
296+ },
297+ {
298+ testName : "just_inside_upper" ,
299+ filter : `FILTER last_event BETWEEN "now-2d" AND "now+3d"` ,
300+ match : true ,
301+ expectedBoundaryTime : today .AddDate (0 , 0 , 5 ).Add (- time .Minute ), // as window is of 5 days and this one just entered
302+ lastEvtTs : today .AddDate (0 , 0 , 3 ).Add (- time .Minute ), // will exit after 2 days later
303+ },
304+ {
305+ testName : "exact_boundary_lower" ,
306+ filter : `FILTER last_event BETWEEN "now-2d" AND "now+3d"` ,
307+ match : false , // going to be false as it thinks it is out of window
308+ expectedBoundaryTime : today , // already in the lowerbound, so should exit now
309+ lastEvtTs : today .AddDate (0 , 0 , - 2 ), // Exactly 2 days ago
310+ },
311+ {
312+ testName : "exact_boundary_upper" ,
313+ filter : `FILTER last_event BETWEEN "now-2d" AND "now+3d"` ,
314+ match : false , // not entered yet
315+ expectedBoundaryTime : today , // should enter right now
316+ lastEvtTs : today .AddDate (0 , 0 , 3 ), // Exactly 3 days in future
317+ },
318+ {
319+ testName : "multiple_date_math" ,
320+ filter : `FILTER AND(last_event BETWEEN "now-2d" AND "now+3d", subscription_expires > "now+1d")` ,
321+ match : true ,
322+ expectedBoundaryTime : today .AddDate (0 , 0 , 2 ), // Will exit after 2 days last_event is in window and subscription_expires date is 6 days later
323+ lastEvtTs : today , // today
324+ },
325+ {
326+ testName : "not_condition" ,
327+ filter : `FILTER NOT(last_event BETWEEN "now-2d" AND "now+3d")` ,
328+ match : true ,
329+ expectedBoundaryTime : today .AddDate (0 , 0 , 1 ), // Will enter after a day as it will be inside of window
330+ lastEvtTs : today .AddDate (0 , 0 , 4 ), // 4 days in the future (right of window)
331+ },
332+ {
333+ testName : "multiple_between" ,
334+ filter : `FILTER AND( last_event BETWEEN "now-2d" AND "now+3d", subscription_expires BETWEEN "now+1d" AND "now+7d")` ,
335+ match : true ,
336+ expectedBoundaryTime : today .AddDate (0 , 0 , 1 ), // Will exit after 1 day due to last_event sliding out of window after 1 day
337+ lastEvtTs : today .AddDate (0 , 0 , - 1 ), // 1 day ago
338+ },
339+ }
340+
341+ for _ , tc := range tests {
342+ t .Run (tc .testName , func (t * testing.T ) {
343+ evalCtx := datasource .NewContextMapTs (map [string ]interface {}{
344+ "last_event" : tc .lastEvtTs ,
345+ "subscription_expires" : today .Add (time .Hour * 24 * 6 ),
346+ "lastevent" : map [string ]time.Time {"signedup" : today },
347+ "first.event" : map [string ]time.Time {"has.period" : today },
348+ }, true , today )
349+
350+ includeCtx := & includectx {ContextReader : evalCtx }
351+
352+ fs := rel .MustParseFilter (tc .filter )
353+
354+ dc , err := vm .NewDateConverterWithAnchorTime (includeCtx , fs .Filter , today )
355+ require .NoError (t , err )
356+ require .True (t , dc .HasDateMath )
357+
358+ matched , evalOk := vm .Matches (includeCtx , fs )
359+ assert .True (t , evalOk )
360+ assert .Equal (t , tc .match , matched )
361+
362+ assert .Equal (t , tc .expectedBoundaryTime .Unix (), dc .Boundary ().Unix ())
363+ })
364+ }
365+ }
0 commit comments