test(ws): cover resolveAgentUUIDCached cache hit fast path

The existing tests exercise only the DB fallback path via errorAgentStore.
Add a test that primes the router cache with a stub implementing both
agent.Agent and agentUUIDProvider, then asserts the cache-aware helper
returns the cached UUID without touching the store — the raison d'etre
of the helper. Uses the same sentinel-error store so a broken fast path
surfaces as a sentinel error rather than a silent pass.
This commit is contained in:
viettranx committed 2026-04-11 21:22:23 +07:00
1 parent de4f742b0e
commit c7a93703ba
1 file changed
+55
@@ -8,6 +8,7 @@ import (
"github.com/google/uuid"
"github.com/nextlevelbuilder/goclaw/internal/agent"
"github.com/nextlevelbuilder/goclaw/internal/providers"
"github.com/nextlevelbuilder/goclaw/internal/store"
)
@@ -74,3 +75,57 @@ func TestResolveAgentUUIDCached_UUIDInputTakesDBPath(t *testing.T) {
t.Errorf("expected sentinel miss error, got %v", err)
}
}
// cacheHitStubAgent implements agent.Agent + agentUUIDProvider so it can be
// registered in the router and the cache-aware helper can extract its UUID
// without hitting the store.
type cacheHitStubAgent struct {
id string
uid uuid.UUID
}
func (s *cacheHitStubAgent) ID() string { return s.id }
func (s *cacheHitStubAgent) UUID() uuid.UUID { return s.uid }
func (s *cacheHitStubAgent) Run(context.Context, agent.RunRequest) (*agent.RunResult, error) {
return nil, nil
}
func (s *cacheHitStubAgent) IsRunning() bool { return false }
func (s *cacheHitStubAgent) Model() string { return "test-model" }
func (s *cacheHitStubAgent) ProviderName() string { return "test" }
func (s *cacheHitStubAgent) Provider() providers.Provider { return nil }
// TestResolveAgentUUIDCached_CacheHitSkipsDBPath pins the fast path: when the
// caller passes an agent_key AND the Loop is cached in the router AND the
// cached Loop satisfies agentUUIDProvider, the helper must return the cached
// UUID without invoking the store. The store is an errorAgentStore that
// returns a sentinel error on any call — if the fast path misbehaves and
// falls through to the DB lookup, that sentinel surfaces as a test failure.
func TestResolveAgentUUIDCached_CacheHitSkipsDBPath(t *testing.T) {
r := agent.NewRouter()
expectedUUID := uuid.New()
agentKey := "cached-agent"
// Prime the router cache via a resolver that returns the stub. Router.Get
// canonicalizes under `tenantID:agentKey` so a subsequent cache-aware
// lookup with the same (ctx, agentKey) resolves via the fast path.
r.SetResolver(func(_ context.Context, _ string) (agent.Agent, error) {
return &cacheHitStubAgent{id: agentKey, uid: expectedUUID}, nil
})
tenantID := uuid.New()
ctx := store.WithTenantID(context.Background(), tenantID)
if _, err := r.Get(ctx, agentKey); err != nil {
t.Fatalf("prime Router.Get: %v", err)
}
// Any store call is a test failure. If the fast path works, the store is
// never touched and no error surfaces.
stub := &errorAgentStore{err: errSentinelMiss}
got, err := resolveAgentUUIDCached(ctx, r, stub, agentKey)
if err != nil {
t.Fatalf("fast path returned error %v — expected cache hit without DB lookup", err)
}
if got != expectedUUID {
t.Errorf("fast path returned UUID %v, want %v", got, expectedUUID)
}
}