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  }