package cron import ( "fmt" "sync" "testing" "time" ) // Many tests schedule a job for every second, and then wait at most a second // for it to run. This amount is just slightly larger than 1 second to // compensate for a few milliseconds of runtime. const ONE_SECOND = 1*time.Second + 10*time.Millisecond // Start and stop cron with no entries. func TestNoEntries(t *testing.T) { cron := New() cron.Start() select { case <-time.After(ONE_SECOND): t.FailNow() case <-stop(cron): } } // Start, stop, then add an entry. Verify entry doesn't run. func TestStopCausesJobsToNotRun(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(1) cron := New() cron.Start() cron.Stop() cron.AddFunc("", "* * * * * ?", func() { wg.Done() }) select { case <-time.After(ONE_SECOND): // No job ran! case <-wait(wg): t.FailNow() } } // Add a job, start cron, expect it runs. func TestAddBeforeRunning(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(1) cron := New() cron.AddFunc("", "* * * * * ?", func() { wg.Done() }) cron.Start() defer cron.Stop() // Give cron 2 seconds to run our job (which is always activated). select { case <-time.After(ONE_SECOND): t.FailNow() case <-wait(wg): } } // Start cron, add a job, expect it runs. func TestAddWhileRunning(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(1) cron := New() cron.Start() defer cron.Stop() cron.AddFunc("", "* * * * * ?", func() { wg.Done() }) select { case <-time.After(ONE_SECOND): t.FailNow() case <-wait(wg): } } // Test timing with Entries. func TestSnapshotEntries(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(1) cron := New() cron.AddFunc("", "@every 2s", func() { wg.Done() }) cron.Start() defer cron.Stop() // Cron should fire in 2 seconds. After 1 second, call Entries. select { case <-time.After(ONE_SECOND): cron.Entries() } // Even though Entries was called, the cron should fire at the 2 second mark. select { case <-time.After(ONE_SECOND): t.FailNow() case <-wait(wg): } } // Test that the entries are correctly sorted. // Add a bunch of long-in-the-future entries, and an immediate entry, and ensure // that the immediate entry runs immediately. // Also: Test that multiple jobs run in the same instant. func TestMultipleEntries(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(2) cron := New() cron.AddFunc("", "0 0 0 1 1 ?", func() {}) cron.AddFunc("", "* * * * * ?", func() { wg.Done() }) cron.AddFunc("", "0 0 0 31 12 ?", func() {}) cron.AddFunc("", "* * * * * ?", func() { wg.Done() }) cron.Start() defer cron.Stop() select { case <-time.After(ONE_SECOND): t.FailNow() case <-wait(wg): } } // Test running the same job twice. func TestRunningJobTwice(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(2) cron := New() cron.AddFunc("", "0 0 0 1 1 ?", func() {}) cron.AddFunc("", "0 0 0 31 12 ?", func() {}) cron.AddFunc("", "* * * * * ?", func() { wg.Done() }) cron.Start() defer cron.Stop() select { case <-time.After(2 * ONE_SECOND): t.FailNow() case <-wait(wg): } } func TestRunningMultipleSchedules(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(2) cron := New() cron.AddFunc("", "0 0 0 1 1 ?", func() {}) cron.AddFunc("", "0 0 0 31 12 ?", func() {}) cron.AddFunc("", "* * * * * ?", func() { wg.Done() }) cron.Schedule("", "", Every(time.Minute), FuncJob(func() {})) cron.Schedule("", "", Every(time.Second), FuncJob(func() { wg.Done() })) cron.Schedule("", "", Every(time.Hour), FuncJob(func() {})) cron.Start() defer cron.Stop() select { case <-time.After(2 * ONE_SECOND): t.FailNow() case <-wait(wg): } } // Test that the cron is run in the local time zone (as opposed to UTC). func TestLocalTimezone(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(1) now := time.Now().Local() spec := fmt.Sprintf("%d %d %d %d %d ?", now.Second()+1, now.Minute(), now.Hour(), now.Day(), now.Month()) cron := New() cron.AddFunc("", spec, func() { wg.Done() }) cron.Start() defer cron.Stop() select { case <-time.After(ONE_SECOND): t.FailNow() case <-wait(wg): } } type testJob struct { wg *sync.WaitGroup name string } func (t testJob) Run() { t.wg.Done() } // Simple test using Runnables. func TestJob(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(1) cron := New() cron.AddJob("", "0 0 0 30 Feb ?", testJob{wg, "job0"}) cron.AddJob("", "0 0 0 1 1 ?", testJob{wg, "job1"}) cron.AddJob("", "* * * * * ?", testJob{wg, "job2"}) cron.AddJob("", "1 0 0 1 1 ?", testJob{wg, "job3"}) cron.Schedule("", "", Every(5*time.Second+5*time.Nanosecond), testJob{wg, "job4"}) cron.Schedule("", "", Every(5*time.Minute), testJob{wg, "job5"}) cron.Start() defer cron.Stop() select { case <-time.After(ONE_SECOND): t.FailNow() case <-wait(wg): } // Ensure the entries are in the right order. expecteds := []string{"job2", "job4", "job5", "job1", "job3", "job0"} var actuals []string for _, entry := range cron.Entries() { actuals = append(actuals, entry.Job.(testJob).name) } for i, expected := range expecteds { if actuals[i] != expected { t.Errorf("Jobs not in the right order. (expected) %s != %s (actual)", expecteds, actuals) t.FailNow() } } } func wait(wg *sync.WaitGroup) chan bool { ch := make(chan bool) go func() { wg.Wait() ch <- true }() return ch } func stop(cron *Cron) chan bool { ch := make(chan bool) go func() { cron.Stop() ch <- true }() return ch } <html> <head><title>PANIC: session(release): write data/sessions/0/6/06f4790ed9609760: no space left on device</title> <meta charset="utf-8" /> <style type="text/css"> html, body { font-family: "Roboto", sans-serif; color: #333333; background-color: #ea5343; margin: 0px; } h1 { color: #d04526; background-color: #ffffff; padding: 20px; border-bottom: 1px dashed #2b3848; } pre { margin: 20px; padding: 20px; border: 2px solid #2b3848; background-color: #ffffff; white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ } </style> </head><body> <h1>PANIC</h1> <pre style="font-weight: bold;">session(release): write data/sessions/0/6/06f4790ed9609760: no space left on device</pre> <pre>github.com/go-macaron/session@v0.0.0-20190805070824-1a3cdc6f5659/session.go:199 (0x8b2934) gopkg.in/macaron.v1@v1.3.9/context.go:79 (0x83d0a0) github.com/go-macaron/inject@v0.0.0-20160627170012-d8a0b8677191/inject.go:157 (0x80ab07) github.com/go-macaron/inject@v0.0.0-20160627170012-d8a0b8677191/inject.go:135 (0x80a8a8) gopkg.in/macaron.v1@v1.3.9/context.go:121 (0x83d1f8) gopkg.in/macaron.v1@v1.3.9/context.go:112 (0x84fdb5) gopkg.in/macaron.v1@v1.3.9/recovery.go:161 (0x84fda8) gopkg.in/macaron.v1@v1.3.9/logger.go:40 (0x840c73) github.com/go-macaron/inject@v0.0.0-20160627170012-d8a0b8677191/inject.go:157 (0x80ab07) github.com/go-macaron/inject@v0.0.0-20160627170012-d8a0b8677191/inject.go:135 (0x80a8a8) gopkg.in/macaron.v1@v1.3.9/context.go:121 (0x83d1f8) gopkg.in/macaron.v1@v1.3.9/router.go:187 (0x850fc6) gopkg.in/macaron.v1@v1.3.9/router.go:303 (0x8493e5) gopkg.in/macaron.v1@v1.3.9/macaron.go:220 (0x841fca) net/http/server.go:2836 (0x7a79b2) net/http/server.go:1924 (0x7a341b) runtime/asm_amd64.s:1373 (0x46f9f0) </pre> </body> </html>