veylant/internal/routing/cache_test.go
2026-02-23 13:35:04 +01:00

96 lines
2.8 KiB
Go

package routing_test
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"github.com/veylant/ia-gateway/internal/routing"
)
func makeRule(name, tenantID string, priority int) routing.RoutingRule {
return routing.RoutingRule{
Name: name,
TenantID: tenantID,
Priority: priority,
IsEnabled: true,
Conditions: []routing.Condition{},
Action: routing.Action{Provider: "openai"},
}
}
func TestRuleCache_Get_LoadsFromStore(t *testing.T) {
store := routing.NewMemStore()
_, err := store.Create(context.Background(), makeRule("r1", "t1", 100))
require.NoError(t, err)
cache := routing.NewRuleCache(store, 30*time.Second, zap.NewNop())
rules, err := cache.Get(context.Background(), "t1")
require.NoError(t, err)
assert.Len(t, rules, 1)
assert.Equal(t, "r1", rules[0].Name)
}
func TestRuleCache_Get_ReturnsCachedOnSecondCall(t *testing.T) {
store := routing.NewMemStore()
_, err := store.Create(context.Background(), makeRule("r1", "t1", 100))
require.NoError(t, err)
cache := routing.NewRuleCache(store, 30*time.Second, zap.NewNop())
// First call loads from store
rules1, err := cache.Get(context.Background(), "t1")
require.NoError(t, err)
// Add another rule to the store — should NOT appear before cache expiry
_, err = store.Create(context.Background(), makeRule("r2", "t1", 200))
require.NoError(t, err)
rules2, err := cache.Get(context.Background(), "t1")
require.NoError(t, err)
assert.Equal(t, len(rules1), len(rules2), "cache should serve stale data within TTL")
}
func TestRuleCache_Invalidate_ForcesReload(t *testing.T) {
store := routing.NewMemStore()
_, err := store.Create(context.Background(), makeRule("r1", "t1", 100))
require.NoError(t, err)
cache := routing.NewRuleCache(store, 30*time.Second, zap.NewNop())
_, err = cache.Get(context.Background(), "t1")
require.NoError(t, err)
// Add a new rule and invalidate
_, err = store.Create(context.Background(), makeRule("r2", "t1", 200))
require.NoError(t, err)
cache.Invalidate("t1")
rules, err := cache.Get(context.Background(), "t1")
require.NoError(t, err)
assert.Len(t, rules, 2, "after invalidation, new rule should be visible")
}
func TestRuleCache_EmptyTenant_ReturnsEmpty(t *testing.T) {
store := routing.NewMemStore()
cache := routing.NewRuleCache(store, 30*time.Second, zap.NewNop())
rules, err := cache.Get(context.Background(), "unknown-tenant")
require.NoError(t, err)
assert.Empty(t, rules)
}
func TestRuleCache_StartStop_NoRace(t *testing.T) {
store := routing.NewMemStore()
cache := routing.NewRuleCache(store, 10*time.Millisecond, zap.NewNop())
cache.Start()
// Perform some gets while refresh loop runs
for i := 0; i < 5; i++ {
_, _ = cache.Get(context.Background(), "t1")
time.Sleep(5 * time.Millisecond)
}
cache.Stop()
}