package infra import ( "context" "testing" "time" ) func allMinutes() []int { s := make([]int, 60) for i := range s { s[i] = i } return s } func allHours() []int { s := make([]int, 24) for i := range s { s[i] = i } return s } func allDays() []int { s := make([]int, 31) for i := range s { s[i] = i + 1 } return s } func allMonths() []int { s := make([]int, 12) for i := range s { s[i] = i + 1 } return s } func allDOW() []int { s := make([]int, 7) for i := range s { s[i] = i } return s } func TestCronTicker(t *testing.T) { t.Run("context cancel cierra el channel", func(t *testing.T) { sched := CronTickerSchedule{ Minute: allMinutes(), Hour: allHours(), DayOfMonth: allDays(), Month: allMonths(), DayOfWeek: allDOW(), } ctx, cancel := context.WithCancel(context.Background()) ch := CronTicker(sched, ctx) // Cancel immediately. cancel() // Channel should close without blocking. timeout := time.After(2 * time.Second) select { case _, ok := <-ch: if ok { // Might receive one tick before cancel propagates — acceptable. } // Drain remaining. for range ch { } case <-timeout: t.Error("channel did not close within 2s after context cancel") } }) t.Run("ticker emite al llegar el momento del schedule", func(t *testing.T) { // Use a schedule that fires every minute (all minutes). // The next tick is at most 60s away. We use a short-lived context // to avoid waiting: instead we verify the channel is not nil and // that cancellation closes it cleanly. sched := CronTickerSchedule{ Minute: allMinutes(), Hour: allHours(), DayOfMonth: allDays(), Month: allMonths(), DayOfWeek: allDOW(), } ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer cancel() ch := CronTicker(sched, ctx) if ch == nil { t.Fatal("CronTicker returned nil channel") } // Wait for context to expire, then confirm channel closes. <-ctx.Done() timeout := time.After(2 * time.Second) for { select { case _, ok := <-ch: if !ok { return // channel closed, test passes } case <-timeout: t.Error("channel did not close within 2s after context timeout") return } } }) }