Files
fn_registry/functions/infra/cache_to_sqlite_test.go
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

135 lines
2.6 KiB
Go

package infra
import (
"encoding/json"
"fmt"
"os"
"sync"
"testing"
"time"
)
func tempDB(t *testing.T) string {
t.Helper()
f, err := os.CreateTemp(t.TempDir(), "cache_*.db")
if err != nil {
t.Fatal(err)
}
f.Close()
return f.Name()
}
func TestCacheToSQLite_SetGet(t *testing.T) {
t.Run("Set/Get basico", func(t *testing.T) {
c, err := CacheToSQLite(tempDB(t), "default")
if err != nil {
t.Fatal(err)
}
defer c.Close()
payload, _ := json.Marshal(map[string]int{"x": 1})
if err := c.Set("foo", payload, 0); err != nil {
t.Fatal(err)
}
got, ok := c.Get("foo")
if !ok {
t.Fatal("expected cache hit")
}
var result map[string]int
json.Unmarshal(got, &result)
if result["x"] != 1 {
t.Errorf("got %v, want x=1", result)
}
})
}
func TestCacheToSQLite_TTLExpirado(t *testing.T) {
t.Run("TTL expirado", func(t *testing.T) {
c, err := CacheToSQLite(tempDB(t), "default")
if err != nil {
t.Fatal(err)
}
defer c.Close()
payload, _ := json.Marshal("hello")
c.Set("temp", payload, 50*time.Millisecond)
time.Sleep(100 * time.Millisecond)
_, ok := c.Get("temp")
if ok {
t.Error("expected cache miss after TTL expiry")
}
})
}
func TestCacheToSQLite_GetOrSet(t *testing.T) {
t.Run("GetOrSet con factory", func(t *testing.T) {
c, err := CacheToSQLite(tempDB(t), "default")
if err != nil {
t.Fatal(err)
}
defer c.Close()
calls := 0
factory := func() ([]byte, error) {
calls++
return json.Marshal("computed")
}
v1, err := c.GetOrSet("k", factory, time.Minute)
if err != nil {
t.Fatal(err)
}
v2, err := c.GetOrSet("k", factory, time.Minute)
if err != nil {
t.Fatal(err)
}
if string(v1) != string(v2) {
t.Errorf("v1=%s v2=%s, want equal", v1, v2)
}
if calls != 1 {
t.Errorf("factory called %d times, want 1", calls)
}
})
}
func TestCacheToSQLite_Concurrencia(t *testing.T) {
t.Run("Concurrencia (goroutines)", func(t *testing.T) {
c, err := CacheToSQLite(tempDB(t), "parallel")
if err != nil {
t.Fatal(err)
}
defer c.Close()
var wg sync.WaitGroup
errs := make(chan error, 40)
for i := 0; i < 20; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
key := fmt.Sprintf("key_%d", n)
payload, _ := json.Marshal(n)
if err := c.Set(key, payload, 0); err != nil {
errs <- err
return
}
got, ok := c.Get(key)
if !ok {
errs <- fmt.Errorf("miss for key %s", key)
return
}
var val int
json.Unmarshal(got, &val)
if val != n {
errs <- fmt.Errorf("key %s: got %d want %d", key, val, n)
}
}(i)
}
wg.Wait()
close(errs)
for err := range errs {
t.Error(err)
}
})
}