Skip to content

Commit ad33f40

Browse files
committed
add thisweek, thismonth, thisyear filter keywords, rework tests
1 parent afbd851 commit ad33f40

File tree

2 files changed

+200
-97
lines changed

2 files changed

+200
-97
lines changed

pkg/snclient/check_files_test.go

Lines changed: 153 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -129,102 +129,172 @@ func TestCheckFilesNoPermission(t *testing.T) {
129129
StopTestAgent(t, snc)
130130
}
131131

132-
func TestCheckFilesFilterToday(t *testing.T) {
132+
func TestCheckFilesFilterDateKeywords(t *testing.T) {
133133
snc := StartTestAgent(t, "")
134-
// prepare test folder
135134
tmpPath := t.TempDir()
136135

137-
// create file from yesterday
138-
yesterday := time.Now().AddDate(0, 0, -1)
139-
err := os.WriteFile(filepath.Join(tmpPath, "yesterday.txt"), []byte("yesterday"), 0o600)
140-
require.NoError(t, err)
141-
err = os.Chtimes(filepath.Join(tmpPath, "yesterday.txt"), yesterday, yesterday)
142-
require.NoError(t, err)
143-
144-
// create file from today (early morning)
136+
// 1. Prepare files for today vs yesterday
145137
now := time.Now()
146-
todayEarly := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 1, 0, time.Local)
147-
// if we are running at exactly 00:00:00, this test might be flaky if we don't ensure todayEarly is actually today.
148-
// But 1 second after midnight should be safe.
149-
err = os.WriteFile(filepath.Join(tmpPath, "today.txt"), []byte("today"), 0o600)
150-
require.NoError(t, err)
151-
err = os.Chtimes(filepath.Join(tmpPath, "today.txt"), todayEarly, todayEarly)
152-
require.NoError(t, err)
153-
154-
// Test 1: filter=written < today
155-
// Should match yesterday.txt, but NOT today.txt
156-
res := snc.RunCheck("check_files", []string{
157-
"path=" + tmpPath,
158-
"filter=written < today",
159-
"crit=count > 0",
160-
"top-syntax=%(list)",
161-
"detail-syntax=%(filename)",
162-
})
163-
assert.Equal(t, CheckExitCritical, res.State, "state Critical")
164-
assert.Contains(t, string(res.BuildPluginOutput()), "yesterday.txt")
165-
assert.NotContains(t, string(res.BuildPluginOutput()), "today.txt")
138+
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
139+
yesterday := midnight.Add(-1 * time.Second)
140+
today := midnight.Add(1 * time.Second)
141+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "yesterday.txt"), []byte("yesterday"), 0o600))
142+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "yesterday.txt"), yesterday, yesterday))
143+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "today.txt"), []byte("today"), 0o600))
144+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "today.txt"), today, today))
145+
146+
// 2. Prepare files for thisweek vs lastweek
147+
// Monday = 1 ... Sunday = 7 (in Go Sunday is 0)
148+
// We want offset from Monday. 0=Monday, ..., 6=Sunday
149+
offset := (int(now.Weekday()) + 6) % 7
150+
startOfWeek := now.AddDate(0, 0, -offset)
151+
startOfWeekMidnight := time.Date(startOfWeek.Year(), startOfWeek.Month(), startOfWeek.Day(), 0, 0, 0, 0, now.Location())
152+
lastWeek := startOfWeekMidnight.Add(-1 * time.Second)
153+
thisWeek := startOfWeekMidnight.Add(1 * time.Second)
154+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "lastweek.txt"), []byte("lastweek"), 0o600))
155+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "lastweek.txt"), lastWeek, lastWeek))
156+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "thisweek.txt"), []byte("thisweek"), 0o600))
157+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "thisweek.txt"), thisWeek, thisWeek))
158+
159+
// 3. Prepare files for thismonth vs lastmonth
160+
startOfMonthMidnight := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
161+
lastMonth := startOfMonthMidnight.Add(-1 * time.Second)
162+
thisMonth := startOfMonthMidnight.Add(1 * time.Second)
163+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "lastmonth.txt"), []byte("lastmonth"), 0o600))
164+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "lastmonth.txt"), lastMonth, lastMonth))
165+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "thismonth.txt"), []byte("thismonth"), 0o600))
166+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "thismonth.txt"), thisMonth, thisMonth))
167+
168+
// 4. Prepare files for thisyear vs lastyear
169+
startOfYearMidnight := time.Date(now.Year(), time.January, 1, 0, 0, 0, 0, now.Location())
170+
lastYear := startOfYearMidnight.Add(-1 * time.Second)
171+
thisYear := startOfYearMidnight.Add(1 * time.Second)
172+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "lastyear.txt"), []byte("lastyear"), 0o600))
173+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "lastyear.txt"), lastYear, lastYear))
174+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "thisyear.txt"), []byte("thisyear"), 0o600))
175+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "thisyear.txt"), thisYear, thisYear))
176+
177+
tests := []struct {
178+
keyword string
179+
older string
180+
newer string
181+
}{
182+
{"today", "yesterday.txt", "today.txt"},
183+
{"thisweek", "lastweek.txt", "thisweek.txt"},
184+
{"thismonth", "lastmonth.txt", "thismonth.txt"},
185+
{"thisyear", "lastyear.txt", "thisyear.txt"},
186+
}
166187

167-
// Test 2: filter=written >= today
168-
// Should match today.txt, but NOT yesterday.txt
169-
res = snc.RunCheck("check_files", []string{
170-
"path=" + tmpPath,
171-
"filter=written >= today",
172-
"crit=count > 0",
173-
"top-syntax=%(list)",
174-
"detail-syntax=%(filename)",
175-
})
176-
assert.Equal(t, CheckExitCritical, res.State, "state Critical")
177-
assert.Contains(t, string(res.BuildPluginOutput()), "today.txt")
178-
assert.NotContains(t, string(res.BuildPluginOutput()), "yesterday.txt")
188+
for _, tc := range tests {
189+
t.Run(tc.keyword, func(t *testing.T) {
190+
// Test: filter=written < keyword (should contain older, not newer)
191+
res := snc.RunCheck("check_files", []string{
192+
"path=" + tmpPath,
193+
"filter=written < " + tc.keyword,
194+
"crit=count > 0",
195+
"top-syntax=%(list)",
196+
"detail-syntax=%(filename)",
197+
})
198+
assert.Equal(t, CheckExitCritical, res.State, fmt.Sprintf("written < %s state Critical", tc.keyword))
199+
assert.Contains(t, string(res.BuildPluginOutput()), tc.older, fmt.Sprintf("written < %s contains older", tc.keyword))
200+
assert.NotContains(t, string(res.BuildPluginOutput()), tc.newer, fmt.Sprintf("written < %s not contains newer", tc.keyword))
201+
202+
// Test: filter=written >= keyword (should contain newer, not older)
203+
res = snc.RunCheck("check_files", []string{
204+
"path=" + tmpPath,
205+
"filter=written >= " + tc.keyword,
206+
"crit=count > 0",
207+
"top-syntax=%(list)",
208+
"detail-syntax=%(filename)",
209+
})
210+
assert.Equal(t, CheckExitCritical, res.State, fmt.Sprintf("written >= %s state Critical", tc.keyword))
211+
assert.Contains(t, string(res.BuildPluginOutput()), tc.newer, fmt.Sprintf("written >= %s contains newer", tc.keyword))
212+
assert.NotContains(t, string(res.BuildPluginOutput()), tc.older, fmt.Sprintf("written >= %s not contains older", tc.keyword))
213+
})
214+
}
179215

180216
StopTestAgent(t, snc)
181217
}
182218

183-
func TestCheckFilesFilterTodayUTC(t *testing.T) {
219+
func TestCheckFilesFilterDateKeywordsUTC(t *testing.T) {
184220
snc := StartTestAgent(t, "")
185-
// prepare test folder
186221
tmpPath := t.TempDir()
187222

188-
nowUTC := time.Now().UTC()
189-
midnightUTC := time.Date(nowUTC.Year(), nowUTC.Month(), nowUTC.Day(), 0, 0, 0, 0, time.UTC)
190-
191-
// create file before UTC midnight
192-
yesterdayUTC := midnightUTC.Add(-1 * time.Second)
193-
err := os.WriteFile(filepath.Join(tmpPath, "yesterday_utc.txt"), []byte("yesterday_utc"), 0o600)
194-
require.NoError(t, err)
195-
err = os.Chtimes(filepath.Join(tmpPath, "yesterday_utc.txt"), yesterdayUTC, yesterdayUTC)
196-
require.NoError(t, err)
197-
198-
// create file after UTC midnight
199-
todayUTC := midnightUTC.Add(1 * time.Second)
200-
err = os.WriteFile(filepath.Join(tmpPath, "today_utc.txt"), []byte("today_utc"), 0o600)
201-
require.NoError(t, err)
202-
err = os.Chtimes(filepath.Join(tmpPath, "today_utc.txt"), todayUTC, todayUTC)
203-
require.NoError(t, err)
204-
205-
// Test 1: filter=written < today:utc
206-
res := snc.RunCheck("check_files", []string{
207-
"path=" + tmpPath,
208-
"filter=written < today:utc",
209-
"crit=count > 0",
210-
"top-syntax=%(list)",
211-
"detail-syntax=%(filename)",
212-
})
213-
assert.Equal(t, CheckExitCritical, res.State, "state Critical")
214-
assert.Contains(t, string(res.BuildPluginOutput()), "yesterday_utc.txt")
215-
assert.NotContains(t, string(res.BuildPluginOutput()), "today_utc.txt")
223+
// 1. Prepare files for today:utc vs yesterday
224+
now := time.Now().UTC()
225+
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
226+
yesterday := midnight.Add(-1 * time.Second)
227+
today := midnight.Add(1 * time.Second)
228+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "yesterday_utc.txt"), []byte("yesterday_utc"), 0o600))
229+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "yesterday_utc.txt"), yesterday, yesterday))
230+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "today_utc.txt"), []byte("today_utc"), 0o600))
231+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "today_utc.txt"), today, today))
232+
233+
// 2. Prepare files for thisweek:utc vs lastweek
234+
offset := (int(now.Weekday()) + 6) % 7
235+
startOfWeek := now.AddDate(0, 0, -offset)
236+
startOfWeekMidnight := time.Date(startOfWeek.Year(), startOfWeek.Month(), startOfWeek.Day(), 0, 0, 0, 0, time.UTC)
237+
lastWeek := startOfWeekMidnight.Add(-1 * time.Second)
238+
thisWeek := startOfWeekMidnight.Add(1 * time.Second)
239+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "lastweek_utc.txt"), []byte("lastweek_utc"), 0o600))
240+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "lastweek_utc.txt"), lastWeek, lastWeek))
241+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "thisweek_utc.txt"), []byte("thisweek_utc"), 0o600))
242+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "thisweek_utc.txt"), thisWeek, thisWeek))
243+
244+
// 3. Prepare files for thismonth:utc vs lastmonth
245+
startOfMonthMidnight := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC)
246+
lastMonth := startOfMonthMidnight.Add(-1 * time.Second)
247+
thisMonth := startOfMonthMidnight.Add(1 * time.Second)
248+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "lastmonth_utc.txt"), []byte("lastmonth_utc"), 0o600))
249+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "lastmonth_utc.txt"), lastMonth, lastMonth))
250+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "thismonth_utc.txt"), []byte("thismonth_utc"), 0o600))
251+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "thismonth_utc.txt"), thisMonth, thisMonth))
252+
253+
// 4. Prepare files for thisyear:utc vs lastyear
254+
startOfYearMidnight := time.Date(now.Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
255+
lastYear := startOfYearMidnight.Add(-1 * time.Second)
256+
thisYear := startOfYearMidnight.Add(1 * time.Second)
257+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "lastyear_utc.txt"), []byte("lastyear_utc"), 0o600))
258+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "lastyear_utc.txt"), lastYear, lastYear))
259+
require.NoError(t, os.WriteFile(filepath.Join(tmpPath, "thisyear_utc.txt"), []byte("thisyear_utc"), 0o600))
260+
require.NoError(t, os.Chtimes(filepath.Join(tmpPath, "thisyear_utc.txt"), thisYear, thisYear))
261+
262+
tests := []struct {
263+
keyword string
264+
older string
265+
newer string
266+
}{
267+
{"today:utc", "yesterday_utc.txt", "today_utc.txt"},
268+
{"thisweek:utc", "lastweek_utc.txt", "thisweek_utc.txt"},
269+
{"thismonth:utc", "lastmonth_utc.txt", "thismonth_utc.txt"},
270+
{"thisyear:utc", "lastyear_utc.txt", "thisyear_utc.txt"},
271+
}
216272

217-
// Test 2: filter=written >= today:utc
218-
res = snc.RunCheck("check_files", []string{
219-
"path=" + tmpPath,
220-
"filter=written >= today:utc",
221-
"crit=count > 0",
222-
"top-syntax=%(list)",
223-
"detail-syntax=%(filename)",
224-
})
225-
assert.Equal(t, CheckExitCritical, res.State, "state Critical")
226-
assert.Contains(t, string(res.BuildPluginOutput()), "today_utc.txt")
227-
assert.NotContains(t, string(res.BuildPluginOutput()), "yesterday_utc.txt")
273+
for _, tc := range tests {
274+
t.Run(tc.keyword, func(t *testing.T) {
275+
res := snc.RunCheck("check_files", []string{
276+
"path=" + tmpPath,
277+
"filter=written < " + tc.keyword,
278+
"crit=count > 0",
279+
"top-syntax=%(list)",
280+
"detail-syntax=%(filename)",
281+
})
282+
assert.Equal(t, CheckExitCritical, res.State, fmt.Sprintf("written < %s state Critical", tc.keyword))
283+
assert.Contains(t, string(res.BuildPluginOutput()), tc.older, fmt.Sprintf("written < %s contains older", tc.keyword))
284+
assert.NotContains(t, string(res.BuildPluginOutput()), tc.newer, fmt.Sprintf("written < %s not contains newer", tc.keyword))
285+
286+
res = snc.RunCheck("check_files", []string{
287+
"path=" + tmpPath,
288+
"filter=written >= " + tc.keyword,
289+
"crit=count > 0",
290+
"top-syntax=%(list)",
291+
"detail-syntax=%(filename)",
292+
})
293+
assert.Equal(t, CheckExitCritical, res.State, fmt.Sprintf("written >= %s state Critical", tc.keyword))
294+
assert.Contains(t, string(res.BuildPluginOutput()), tc.newer, fmt.Sprintf("written >= %s contains newer", tc.keyword))
295+
assert.NotContains(t, string(res.BuildPluginOutput()), tc.older, fmt.Sprintf("written >= %s not contains older", tc.keyword))
296+
})
297+
}
228298

229299
StopTestAgent(t, snc)
230300
}

pkg/snclient/condition.go

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -766,23 +766,56 @@ func (c *Condition) getUnit(keyword string) Unit {
766766
return UNone
767767
}
768768

769+
func (c *Condition) getRefTime(str string) (time.Time, string) {
770+
if strings.HasSuffix(strings.ToLower(str), ":utc") {
771+
return time.Now().UTC(), str[0 : len(str)-4]
772+
}
773+
774+
return time.Now(), str
775+
}
776+
777+
func (c *Condition) expandDateKeyword(str string) (bool, error) {
778+
now, keyword := c.getRefTime(str)
779+
780+
if strings.EqualFold(keyword, "today") {
781+
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
782+
c.value = fmt.Sprintf("%d", midnight.Unix())
783+
784+
return true, nil
785+
}
786+
787+
if strings.EqualFold(keyword, "thisweek") {
788+
offset := (int(now.Weekday()) + 6) % 7 // 0 = Monday … 6 = Sunday
789+
startOfWeek := now.AddDate(0, 0, -offset)
790+
midnight := time.Date(startOfWeek.Year(), startOfWeek.Month(), startOfWeek.Day(), 0, 0, 0, 0, now.Location())
791+
c.value = fmt.Sprintf("%d", midnight.Unix())
792+
793+
return true, nil
794+
}
795+
796+
if strings.EqualFold(keyword, "thismonth") {
797+
midnight := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
798+
c.value = fmt.Sprintf("%d", midnight.Unix())
799+
800+
return true, nil
801+
}
802+
803+
if strings.EqualFold(keyword, "thisyear") {
804+
midnight := time.Date(now.Year(), time.January, 1, 0, 0, 0, 0, now.Location())
805+
c.value = fmt.Sprintf("%d", midnight.Unix())
806+
807+
return true, nil
808+
}
809+
810+
return false, nil
811+
}
812+
769813
func (c *Condition) expandUnitByType(str string) error {
770-
// valid units might be "today"
814+
// valid units might be "today", "thisweek", "thismonth", "thisyear" and ":utc" variants
771815
unit := c.getUnit(c.keyword)
772816
if unit == UDate || unit == UTimestamp {
773-
if strings.EqualFold(str, "today") {
774-
now := time.Now()
775-
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
776-
c.value = fmt.Sprintf("%d", midnight.Unix())
777-
778-
return nil
779-
}
780-
if strings.EqualFold(str, "today:utc") {
781-
now := time.Now().UTC()
782-
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
783-
c.value = fmt.Sprintf("%d", midnight.Unix())
784-
785-
return nil
817+
if done, err := c.expandDateKeyword(str); done || err != nil {
818+
return err
786819
}
787820
}
788821

0 commit comments

Comments
 (0)