mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-17 04:15:05 +00:00
test(cache,sessions,knowledgegraph): slim wave 3 coverage push
Add Wave 3 package coverage: - cache/permission_cache_test.go: PermissionCache 9 methods + invalidation - sessions/key_extra_test.go: session key builders - sessions/manager_extra_test.go: SetHistory, Save, loadAll - knowledgegraph/extractor_helpers_test.go: Extract with mock provider, splitChunks, mergeResults
This commit is contained in:
1 parent
bdbed9a35e
commit
83a6b3c68f
4 files changed
+1180
No files matched your search
+275
@@ -0,0 +1,275 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nextlevelbuilder/goclaw/internal/bus"
|
||||
)
|
||||
|
||||
func TestPermissionCache_TenantRole(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
tenantID := uuid.New()
|
||||
userID := "user-1"
|
||||
|
||||
// miss before set
|
||||
_, ok := pc.GetTenantRole(ctx, tenantID, userID)
|
||||
if ok {
|
||||
t.Fatal("expected cache miss before SetTenantRole")
|
||||
}
|
||||
|
||||
// set then hit
|
||||
pc.SetTenantRole(ctx, tenantID, userID, "admin")
|
||||
role, ok := pc.GetTenantRole(ctx, tenantID, userID)
|
||||
if !ok {
|
||||
t.Fatal("expected cache hit after SetTenantRole")
|
||||
}
|
||||
if role != "admin" {
|
||||
t.Fatalf("expected role 'admin', got %q", role)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_AgentAccess(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
agentID := uuid.New()
|
||||
userID := "user-2"
|
||||
|
||||
// miss
|
||||
_, _, ok := pc.GetAgentAccess(ctx, agentID, userID)
|
||||
if ok {
|
||||
t.Fatal("expected cache miss before SetAgentAccess")
|
||||
}
|
||||
|
||||
// set with allowed=true, role=editor
|
||||
pc.SetAgentAccess(ctx, agentID, userID, true, "editor")
|
||||
|
||||
allowed, role, ok := pc.GetAgentAccess(ctx, agentID, userID)
|
||||
if !ok {
|
||||
t.Fatal("expected cache hit after SetAgentAccess")
|
||||
}
|
||||
if !allowed {
|
||||
t.Fatal("expected allowed=true")
|
||||
}
|
||||
if role != "editor" {
|
||||
t.Fatalf("expected role 'editor', got %q", role)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_AgentAccess_Denied(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
agentID := uuid.New()
|
||||
userID := "user-denied"
|
||||
|
||||
pc.SetAgentAccess(ctx, agentID, userID, false, "")
|
||||
|
||||
allowed, role, ok := pc.GetAgentAccess(ctx, agentID, userID)
|
||||
if !ok {
|
||||
t.Fatal("expected cache hit")
|
||||
}
|
||||
if allowed {
|
||||
t.Fatal("expected allowed=false")
|
||||
}
|
||||
if role != "" {
|
||||
t.Fatalf("expected empty role, got %q", role)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_TeamAccess(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
teamID := uuid.New()
|
||||
userID := "user-3"
|
||||
|
||||
// miss
|
||||
_, ok := pc.GetTeamAccess(ctx, teamID, userID)
|
||||
if ok {
|
||||
t.Fatal("expected cache miss before SetTeamAccess")
|
||||
}
|
||||
|
||||
// set true
|
||||
pc.SetTeamAccess(ctx, teamID, userID, true)
|
||||
|
||||
allowed, ok := pc.GetTeamAccess(ctx, teamID, userID)
|
||||
if !ok {
|
||||
t.Fatal("expected cache hit after SetTeamAccess")
|
||||
}
|
||||
if !allowed {
|
||||
t.Fatal("expected allowed=true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_TeamAccess_False(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
teamID := uuid.New()
|
||||
userID := "user-4"
|
||||
|
||||
pc.SetTeamAccess(ctx, teamID, userID, false)
|
||||
|
||||
allowed, ok := pc.GetTeamAccess(ctx, teamID, userID)
|
||||
if !ok {
|
||||
t.Fatal("expected cache hit")
|
||||
}
|
||||
if allowed {
|
||||
t.Fatal("expected allowed=false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_Close_Idempotent(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
pc.Close()
|
||||
pc.Close() // must not panic
|
||||
}
|
||||
|
||||
func TestPermissionCache_HandleInvalidation_TenantUsers(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
tenantID := uuid.New()
|
||||
|
||||
// populate tenant roles for two users
|
||||
pc.SetTenantRole(ctx, tenantID, "u1", "admin")
|
||||
pc.SetTenantRole(ctx, tenantID, "u2", "viewer")
|
||||
|
||||
// invalidate tenant_users → clears all tenant roles
|
||||
pc.HandleInvalidation(bus.CacheInvalidatePayload{Kind: bus.CacheKindTenantUsers, Key: "u1"})
|
||||
|
||||
// both should be gone
|
||||
if _, ok := pc.GetTenantRole(ctx, tenantID, "u1"); ok {
|
||||
t.Error("u1 tenant role should be cleared after tenant_users invalidation")
|
||||
}
|
||||
if _, ok := pc.GetTenantRole(ctx, tenantID, "u2"); ok {
|
||||
t.Error("u2 tenant role should be cleared after tenant_users invalidation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_HandleInvalidation_AgentAccess_WithKey(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
agentID1 := uuid.New()
|
||||
agentID2 := uuid.New()
|
||||
|
||||
pc.SetAgentAccess(ctx, agentID1, "u1", true, "admin")
|
||||
pc.SetAgentAccess(ctx, agentID1, "u2", true, "viewer")
|
||||
pc.SetAgentAccess(ctx, agentID2, "u1", true, "admin")
|
||||
|
||||
// invalidate agent_access for agentID1 only
|
||||
pc.HandleInvalidation(bus.CacheInvalidatePayload{Kind: bus.CacheKindAgentAccess, Key: agentID1.String()})
|
||||
|
||||
// agentID1 entries should be gone
|
||||
if _, _, ok := pc.GetAgentAccess(ctx, agentID1, "u1"); ok {
|
||||
t.Error("agentID1:u1 access should be cleared")
|
||||
}
|
||||
if _, _, ok := pc.GetAgentAccess(ctx, agentID1, "u2"); ok {
|
||||
t.Error("agentID1:u2 access should be cleared")
|
||||
}
|
||||
// agentID2 should still be cached
|
||||
if _, _, ok := pc.GetAgentAccess(ctx, agentID2, "u1"); !ok {
|
||||
t.Error("agentID2:u1 access should still be cached")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_HandleInvalidation_AgentAccess_ClearAll(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
agentID := uuid.New()
|
||||
|
||||
pc.SetAgentAccess(ctx, agentID, "u1", true, "admin")
|
||||
|
||||
// empty Key → clear all
|
||||
pc.HandleInvalidation(bus.CacheInvalidatePayload{Kind: bus.CacheKindAgentAccess, Key: ""})
|
||||
|
||||
if _, _, ok := pc.GetAgentAccess(ctx, agentID, "u1"); ok {
|
||||
t.Error("agent access should be cleared when Key is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_HandleInvalidation_TeamAccess_WithKey(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
teamID1 := uuid.New()
|
||||
teamID2 := uuid.New()
|
||||
|
||||
pc.SetTeamAccess(ctx, teamID1, "u1", true)
|
||||
pc.SetTeamAccess(ctx, teamID1, "u2", false)
|
||||
pc.SetTeamAccess(ctx, teamID2, "u1", true)
|
||||
|
||||
// invalidate team_access for teamID1 only
|
||||
pc.HandleInvalidation(bus.CacheInvalidatePayload{Kind: bus.CacheKindTeamAccess, Key: teamID1.String()})
|
||||
|
||||
if _, ok := pc.GetTeamAccess(ctx, teamID1, "u1"); ok {
|
||||
t.Error("teamID1:u1 access should be cleared")
|
||||
}
|
||||
if _, ok := pc.GetTeamAccess(ctx, teamID1, "u2"); ok {
|
||||
t.Error("teamID1:u2 access should be cleared")
|
||||
}
|
||||
if _, ok := pc.GetTeamAccess(ctx, teamID2, "u1"); !ok {
|
||||
t.Error("teamID2:u1 access should still be cached")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_HandleInvalidation_TeamAccess_ClearAll(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
teamID := uuid.New()
|
||||
|
||||
pc.SetTeamAccess(ctx, teamID, "u1", true)
|
||||
|
||||
pc.HandleInvalidation(bus.CacheInvalidatePayload{Kind: bus.CacheKindTeamAccess, Key: ""})
|
||||
|
||||
if _, ok := pc.GetTeamAccess(ctx, teamID, "u1"); ok {
|
||||
t.Error("team access should be cleared when Key is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionCache_HandleInvalidation_UnknownKind(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
// unknown kind should not panic
|
||||
pc.HandleInvalidation(bus.CacheInvalidatePayload{Kind: "unknown_kind", Key: "anything"})
|
||||
}
|
||||
|
||||
func TestPermissionCache_MultipleUsers_Isolation(t *testing.T) {
|
||||
pc := NewPermissionCache()
|
||||
defer pc.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
tenantID := uuid.New()
|
||||
|
||||
pc.SetTenantRole(ctx, tenantID, "user-a", "admin")
|
||||
pc.SetTenantRole(ctx, tenantID, "user-b", "viewer")
|
||||
|
||||
roleA, okA := pc.GetTenantRole(ctx, tenantID, "user-a")
|
||||
roleB, okB := pc.GetTenantRole(ctx, tenantID, "user-b")
|
||||
|
||||
if !okA || roleA != "admin" {
|
||||
t.Errorf("user-a: expected admin, got %q ok=%v", roleA, okA)
|
||||
}
|
||||
if !okB || roleB != "viewer" {
|
||||
t.Errorf("user-b: expected viewer, got %q ok=%v", roleB, okB)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user