Files
fn_registry/functions/infra/cron_ticker_test.go
T
egutierrez 9c0d24d3ef feat: funciones Go — core (cron, join_by_key, validate_struct), datascience (pivot, diff_entities), infra (http, cache, cron_ticker)
Nuevas funciones Go con tests en tres dominios:
- core: parse_cron_expr, next_cron_time, join_by_key, validate_struct_fields + tipo CronSchedule
- datascience: pivot (tabla dinámica), diff_entities (comparación de entidades)
- infra: http_get_json, http_post_json, http_download_file, cache_to_sqlite, cron_ticker

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 17:11:12 +02:00

115 lines
2.2 KiB
Go

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
}
}
})
}