github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/ztime/cron/cron_test.go (about) 1 package cron 2 3 import ( 4 "sync" 5 "sync/atomic" 6 "testing" 7 "time" 8 9 "github.com/sohaha/zlsgo" 10 "github.com/sohaha/zlsgo/ztime" 11 ) 12 13 func TestNew(tt *testing.T) { 14 // g := &sync.WaitGroup{} 15 // g.Add(2) 16 t := zlsgo.NewTest(tt) 17 now := time.Now() 18 tt.Log(ztime.FormatTime(now)) 19 20 next, err := ParseNextTime("* * * * *") 21 t.Equal(nil, err) 22 tt.Log(ztime.FormatTime(next)) 23 24 next, err = ParseNextTime("* * * * * *") 25 t.Equal(nil, err) 26 tt.Log(ztime.FormatTime(next)) 27 28 next, err = ParseNextTime("* * * * * * *") 29 t.Equal(nil, err) 30 tt.Log(ztime.FormatTime(next)) 31 32 next, err = ParseNextTime("* * * * * * 999") 33 t.Equal(true, err != nil) 34 t.Log(err) 35 36 next, err = ParseNextTime("12 * * * * * *") 37 t.Equal(nil, err) 38 tt.Log(ztime.FormatTime(next)) 39 40 next, err = ParseNextTime("1 2 * * * * *") 41 t.Equal(nil, err) 42 tt.Log(ztime.FormatTime(next)) 43 44 next, err = ParseNextTime("*/10 * * * * * *") 45 t.Equal(nil, err) 46 tt.Log(ztime.FormatTime(next)) 47 48 next, err = ParseNextTime("0 22 * * 1-5") 49 t.Equal(nil, err) 50 tt.Log(ztime.FormatTime(next)) 51 52 next, err = ParseNextTime("@weekly") 53 t.Equal(nil, err) 54 tt.Log(ztime.FormatTime(next)) 55 } 56 57 func TestRun(tt *testing.T) { 58 t := zlsgo.NewTest(tt) 59 cron := New() 60 now := time.Now() 61 var g sync.WaitGroup 62 g.Add(6) 63 i := int64(0) 64 _, _ = cron.Add("*/2 * * * * * *", func() { 65 t.Equal(true, time.Now().UnixNano() > now.UnixNano()) 66 atomic.AddInt64(&i, 1) 67 }) 68 _, _ = cron.Add("*/5 * * * * * *", func() { 69 ii := atomic.LoadInt64(&i) 70 tt.Log("*/5", ii, time.Since(now).Seconds()) 71 t.Equal(true, time.Now().UnixNano() > now.UnixNano()) 72 g.Done() 73 }) 74 cron.Run(false) 75 g.Wait() 76 cron.Stop() 77 ii := atomic.LoadInt64(&i) 78 tt.Log(ii, time.Since(now).Seconds()) 79 t.EqualTrue(ii >= 12) 80 t.EqualTrue(ii <= 15) 81 } 82 83 type crontimes struct { 84 from string 85 next string 86 } 87 88 type crontest struct { 89 expr string 90 layout string 91 times []crontimes 92 } 93 94 var crontests = []crontest{ 95 // Seconds 96 { 97 "* * * * * * *", 98 "2006-01-02 15:04:05", 99 []crontimes{ 100 {"2013-01-01 00:00:00", "2013-01-01 00:00:01"}, 101 {"2013-01-01 00:00:59", "2013-01-01 00:01:00"}, 102 {"2013-01-01 00:59:59", "2013-01-01 01:00:00"}, 103 {"2013-01-01 23:59:59", "2013-01-02 00:00:00"}, 104 {"2013-02-28 23:59:59", "2013-03-01 00:00:00"}, 105 {"2016-02-28 23:59:59", "2016-02-29 00:00:00"}, 106 {"2012-12-31 23:59:59", "2013-01-01 00:00:00"}, 107 }, 108 }, 109 110 // every 5 Second 111 { 112 "*/5 * * * * * *", 113 "2006-01-02 15:04:05", 114 []crontimes{ 115 {"2013-01-01 00:00:00", "2013-01-01 00:00:05"}, 116 {"2013-01-01 00:00:59", "2013-01-01 00:01:00"}, 117 {"2013-01-01 00:59:59", "2013-01-01 01:00:00"}, 118 {"2013-01-01 23:59:59", "2013-01-02 00:00:00"}, 119 {"2013-02-28 23:59:59", "2013-03-01 00:00:00"}, 120 {"2016-02-28 23:59:59", "2016-02-29 00:00:00"}, 121 {"2012-12-31 23:59:59", "2013-01-01 00:00:00"}, 122 }, 123 }, 124 125 // Minutes 126 { 127 "* * * * *", 128 "2006-01-02 15:04:05", 129 []crontimes{ 130 {"2013-01-01 00:00:00", "2013-01-01 00:01:00"}, 131 {"2013-01-01 00:00:59", "2013-01-01 00:01:00"}, 132 {"2013-01-01 00:59:00", "2013-01-01 01:00:00"}, 133 {"2013-01-01 23:59:00", "2013-01-02 00:00:00"}, 134 {"2013-02-28 23:59:00", "2013-03-01 00:00:00"}, 135 {"2016-02-28 23:59:00", "2016-02-29 00:00:00"}, 136 {"2012-12-31 23:59:00", "2013-01-01 00:00:00"}, 137 }, 138 }, 139 140 // Minutes with interval 141 { 142 "17-43/5 * * * *", 143 "2006-01-02 15:04:05", 144 []crontimes{ 145 {"2013-01-01 00:00:00", "2013-01-01 00:17:00"}, 146 {"2013-01-01 00:16:59", "2013-01-01 00:17:00"}, 147 {"2013-01-01 00:30:00", "2013-01-01 00:32:00"}, 148 {"2013-01-01 00:50:00", "2013-01-01 01:17:00"}, 149 {"2013-01-01 23:50:00", "2013-01-02 00:17:00"}, 150 {"2013-02-28 23:50:00", "2013-03-01 00:17:00"}, 151 {"2016-02-28 23:50:00", "2016-02-29 00:17:00"}, 152 {"2012-12-31 23:50:00", "2013-01-01 00:17:00"}, 153 }, 154 }, 155 156 // Minutes interval, list 157 { 158 "15-30/4,55 * * * *", 159 "2006-01-02 15:04:05", 160 []crontimes{ 161 {"2013-01-01 00:00:00", "2013-01-01 00:15:00"}, 162 {"2013-01-01 00:16:00", "2013-01-01 00:19:00"}, 163 {"2013-01-01 00:30:00", "2013-01-01 00:55:00"}, 164 {"2013-01-01 00:55:00", "2013-01-01 01:15:00"}, 165 {"2013-01-01 23:55:00", "2013-01-02 00:15:00"}, 166 {"2013-02-28 23:55:00", "2013-03-01 00:15:00"}, 167 {"2016-02-28 23:55:00", "2016-02-29 00:15:00"}, 168 {"2012-12-31 23:54:00", "2012-12-31 23:55:00"}, 169 {"2012-12-31 23:55:00", "2013-01-01 00:15:00"}, 170 }, 171 }, 172 173 // Days of week 174 { 175 "0 0 * * MON", 176 "Mon 2006-01-02 15:04", 177 []crontimes{ 178 {"2013-01-01 00:00:00", "Mon 2013-01-07 00:00"}, 179 {"2013-01-28 00:00:00", "Mon 2013-02-04 00:00"}, 180 {"2013-12-30 00:30:00", "Mon 2014-01-06 00:00"}, 181 }, 182 }, 183 { 184 "0 0 * * friday", 185 "Mon 2006-01-02 15:04", 186 []crontimes{ 187 {"2013-01-01 00:00:00", "Fri 2013-01-04 00:00"}, 188 {"2013-01-28 00:00:00", "Fri 2013-02-01 00:00"}, 189 {"2013-12-30 00:30:00", "Fri 2014-01-03 00:00"}, 190 }, 191 }, 192 { 193 "0 0 * * 6,7", 194 "Mon 2006-01-02 15:04", 195 []crontimes{ 196 {"2013-01-01 00:00:00", "Sat 2013-01-05 00:00"}, 197 {"2013-01-28 00:00:00", "Sat 2013-02-02 00:00"}, 198 {"2013-12-30 00:30:00", "Sat 2014-01-04 00:00"}, 199 }, 200 }, 201 202 // Specific days of week 203 { 204 "0 0 * * 6#5", 205 "Mon 2006-01-02 15:04", 206 []crontimes{ 207 {"2013-09-02 00:00:00", "Sat 2013-11-30 00:00"}, 208 }, 209 }, 210 211 // Work day of month 212 { 213 "0 0 14W * *", 214 "Mon 2006-01-02 15:04", 215 []crontimes{ 216 {"2013-03-31 00:00:00", "Mon 2013-04-15 00:00"}, 217 {"2013-08-31 00:00:00", "Fri 2013-09-13 00:00"}, 218 }, 219 }, 220 221 // Work day of month -- end of month 222 { 223 "0 0 30W * *", 224 "Mon 2006-01-02 15:04", 225 []crontimes{ 226 {"2013-03-02 00:00:00", "Fri 2013-03-29 00:00"}, 227 {"2013-06-02 00:00:00", "Fri 2013-06-28 00:00"}, 228 {"2013-09-02 00:00:00", "Mon 2013-09-30 00:00"}, 229 {"2013-11-02 00:00:00", "Fri 2013-11-29 00:00"}, 230 }, 231 }, 232 233 // Last day of month 234 { 235 "0 0 L * *", 236 "Mon 2006-01-02 15:04", 237 []crontimes{ 238 {"2013-09-02 00:00:00", "Mon 2013-09-30 00:00"}, 239 {"2014-01-01 00:00:00", "Fri 2014-01-31 00:00"}, 240 {"2014-02-01 00:00:00", "Fri 2014-02-28 00:00"}, 241 {"2016-02-15 00:00:00", "Mon 2016-02-29 00:00"}, 242 }, 243 }, 244 245 // Last work day of month 246 { 247 "0 0 LW * *", 248 "Mon 2006-01-02 15:04", 249 []crontimes{ 250 {"2013-09-02 00:00:00", "Mon 2013-09-30 00:00"}, 251 {"2013-11-02 00:00:00", "Fri 2013-11-29 00:00"}, 252 {"2014-08-15 00:00:00", "Fri 2014-08-29 00:00"}, 253 }, 254 }, 255 } 256 257 func TestExpressions(T *testing.T) { 258 t := zlsgo.NewTest(T) 259 for _, test := range crontests { 260 for _, times := range test.times { 261 from, _ := time.Parse("2006-01-02 15:04:05", times.from) 262 expr, err := Parse(test.expr) 263 t.EqualExit(nil, err) 264 next := expr.Next(from) 265 nextstr := next.Format(test.layout) 266 t.Equal(nextstr, times.next) 267 } 268 } 269 } 270 271 func TestZero(t *testing.T) { 272 from, _ := time.Parse("2006-01-02", "2013-08-31") 273 next, _ := Parse("* * * * * 1980") 274 if next.Next(from).IsZero() == false { 275 t.Error(`("* * * * * 1980").Next("2013-08-31").IsZero() returned 'false', expected 'true'`) 276 } 277 278 next, _ = Parse("* * * * * 2050") 279 if next.Next(from).IsZero() == true { 280 t.Error(`("* * * * * 2050").Next("2013-08-31").IsZero() returned 'true', expected 'false'`) 281 } 282 283 next, _ = Parse("* * * * * 2099") 284 if next.Next(time.Time{}).IsZero() == false { 285 t.Error(`("* * * * * 2014").Next(time.Time{}).IsZero() returned 'true', expected 'false'`) 286 } 287 } 288 289 func TestNextN(t *testing.T) { 290 expected := []string{ 291 "Sat, 30 Nov 2013 00:00:00", 292 "Sat, 29 Mar 2014 00:00:00", 293 "Sat, 31 May 2014 00:00:00", 294 "Sat, 30 Aug 2014 00:00:00", 295 "Sat, 29 Nov 2014 00:00:00", 296 } 297 from, _ := time.Parse("2006-01-02 15:04:05", "2013-09-02 08:44:30") 298 n, _ := Parse("0 0 * * 6#5") 299 result := n.NextN(from, uint(len(expected))) 300 if len(result) != len(expected) { 301 t.Errorf(`MustParse("0 0 * * 6#5").NextN("2013-09-02 08:44:30", 5):\n"`) 302 t.Errorf(` Expected %d returned time values but got %d instead`, len(expected), len(result)) 303 } 304 for i, next := range result { 305 nextStr := next.Format("Mon, 2 Jan 2006 15:04:15") 306 if nextStr != expected[i] { 307 t.Errorf(`MustParse("0 0 * * 6#5").NextN("2013-09-02 08:44:30", 5):\n"`) 308 t.Errorf(` result[%d]: expected "%s" but got "%s"`, i, expected[i], nextStr) 309 } 310 } 311 } 312 313 func TestNextN_every5min(t *testing.T) { 314 expected := []string{ 315 "Mon, 2 Sep 2013 08:45:00", 316 "Mon, 2 Sep 2013 08:50:00", 317 "Mon, 2 Sep 2013 08:55:00", 318 "Mon, 2 Sep 2013 09:00:00", 319 "Mon, 2 Sep 2013 09:05:00", 320 } 321 from, _ := time.Parse("2006-01-02 15:04:05", "2013-09-02 08:44:32") 322 n, _ := Parse("*/5 * * * *") 323 result := n.NextN(from, uint(len(expected))) 324 if len(result) != len(expected) { 325 t.Errorf(`MustParse("*/5 * * * *").NextN("2013-09-02 08:44:30", 5):\n"`) 326 t.Errorf(` Expected %d returned time values but got %d instead`, len(expected), len(result)) 327 } 328 for i, next := range result { 329 nextStr := next.Format("Mon, 2 Jan 2006 15:04:05") 330 if nextStr != expected[i] { 331 t.Errorf(`MustParse("*/5 * * * *").NextN("2013-09-02 08:44:30", 5):\n"`) 332 t.Errorf(` result[%d]: expected "%s" but got "%s"`, i, expected[i], nextStr) 333 } 334 } 335 } 336 337 func TestInterval_Interval60Issue(t *testing.T) { 338 _, err := Parse("*/60 * * * * *") 339 if err == nil { 340 t.Errorf("parsing with interval 60 should return err") 341 } 342 343 _, err = Parse("*/61 * * * * *") 344 if err == nil { 345 t.Errorf("parsing with interval 61 should return err") 346 } 347 348 _, err = Parse("2/60 * * * * *") 349 if err == nil { 350 t.Errorf("parsing with interval 60 should return err") 351 } 352 353 _, err = Parse("2-20/61 * * * * *") 354 if err == nil { 355 t.Errorf("parsing with interval 60 should return err") 356 } 357 }