113 lines
4.5 KiB
Go
113 lines
4.5 KiB
Go
package webevents
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"data-terminal-cloud/internal/identity"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
func TestServiceCursorIsolationCleanupAndPresenceExpiry(t *testing.T) {
|
|
databaseURL := os.Getenv("TEST_DATABASE_URL")
|
|
if databaseURL == "" {
|
|
t.Skip("TEST_DATABASE_URL is not set")
|
|
}
|
|
ctx := context.Background()
|
|
pool, err := pgxpool.New(ctx, databaseURL)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer pool.Close()
|
|
service := NewService(pool)
|
|
owner := identity.Principal{Issuer: "http://localhost:58180/realms/voice-local", Subject: "00000000-0000-0000-0000-000000000101"}
|
|
outsider := identity.Principal{Issuer: owner.Issuer, Subject: "00000000-0000-0000-0000-000000000103"}
|
|
resourceIDs := []string{uuid.NewString(), uuid.NewString(), uuid.NewString()}
|
|
testStarted := time.Now().UTC().Add(-time.Second)
|
|
defer func() {
|
|
_, _ = pool.Exec(ctx, `DELETE FROM device_presence_state WHERE tenant_id='10000000-0000-0000-0000-000000000001' AND device_id='10000000-0000-0000-0000-000000000501'`)
|
|
_, _ = pool.Exec(ctx, `DELETE FROM web_event WHERE resource_public_id=ANY($1::uuid[]) OR (resource_public_id='10000000-0000-0000-0000-000000000511' AND occurred_at>=$2)`, resourceIDs, testStarted)
|
|
}()
|
|
ids := make([]int64, 3)
|
|
for index, resourceID := range resourceIDs {
|
|
expiresAt := time.Now().UTC().Add(10 * time.Minute)
|
|
if index == 2 {
|
|
expiresAt = time.Now().UTC().Add(-time.Minute)
|
|
}
|
|
if err := pool.QueryRow(ctx, `
|
|
INSERT INTO web_event(tenant_id,household_id,subject_id,event_type,resource_type,resource_public_id,status,expires_at)
|
|
VALUES('10000000-0000-0000-0000-000000000001','10000000-0000-0000-0000-000000000201','10000000-0000-0000-0000-000000000401',
|
|
'conversation.completed','conversation',$1::uuid,$2,$3) RETURNING id`, resourceID, "TEST_"+string(rune('A'+index)), expiresAt).Scan(&ids[index]); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
cursor, err := service.StartingCursor(ctx, owner)
|
|
if err != nil || cursor != ids[1] {
|
|
t.Fatalf("owner starting cursor=%d want=%d err=%v", cursor, ids[1], err)
|
|
}
|
|
outsideCursor, err := service.StartingCursor(ctx, outsider)
|
|
if err != nil || outsideCursor != 0 {
|
|
t.Fatalf("outsider starting cursor=%d err=%v", outsideCursor, err)
|
|
}
|
|
if err := service.ValidateCursor(ctx, owner, 0); err != nil {
|
|
t.Fatalf("zero cursor: %v", err)
|
|
}
|
|
if err := service.ValidateCursor(ctx, owner, ids[0]); err != nil {
|
|
t.Fatalf("valid cursor: %v", err)
|
|
}
|
|
if err := service.ValidateCursor(ctx, owner, ids[2]); !errors.Is(err, ErrCursorUnavailable) {
|
|
t.Fatalf("expired cursor error=%v", err)
|
|
}
|
|
if err := service.ValidateCursor(ctx, outsider, ids[0]); !errors.Is(err, ErrCursorUnavailable) {
|
|
t.Fatalf("cross-user cursor error=%v", err)
|
|
}
|
|
items, err := service.ListAfter(ctx, owner, ids[0], 1)
|
|
if err != nil || len(items) != 1 || items[0].ID != ids[1] || items[0].SubjectID != "10000000-0000-0000-0000-000000000411" {
|
|
t.Fatalf("events=%+v err=%v", items, err)
|
|
}
|
|
allItems, err := service.ListAfter(ctx, owner, 0, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
found := 0
|
|
for _, item := range allItems {
|
|
if item.ID == ids[0] || item.ID == ids[1] {
|
|
found++
|
|
}
|
|
}
|
|
if found != 2 {
|
|
t.Fatalf("active synthetic events found=%d", found)
|
|
}
|
|
outsideItems, err := service.ListAfter(ctx, outsider, 0, 100)
|
|
if err != nil || len(outsideItems) != 0 {
|
|
t.Fatalf("outsider events=%+v err=%v", outsideItems, err)
|
|
}
|
|
deleted, err := service.DeleteExpired(ctx, 1)
|
|
if err != nil || deleted != 1 {
|
|
t.Fatalf("deleted expired events=%d err=%v", deleted, err)
|
|
}
|
|
if err := service.ValidateCursor(ctx, owner, ids[2]); !errors.Is(err, ErrCursorUnavailable) {
|
|
t.Fatalf("deleted cursor error=%v", err)
|
|
}
|
|
|
|
if _, err := pool.Exec(ctx, `
|
|
INSERT INTO device_presence_state(tenant_id,device_id,household_id,subject_id,online,last_seen_at,changed_at)
|
|
VALUES('10000000-0000-0000-0000-000000000001','10000000-0000-0000-0000-000000000501','10000000-0000-0000-0000-000000000201',
|
|
'10000000-0000-0000-0000-000000000401',true,now()-interval '10 minutes',now()-interval '10 minutes')`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expired, err := service.ExpireDevicePresence(ctx, time.Now().UTC().Add(-5*time.Minute), 0)
|
|
if err != nil || expired != 1 {
|
|
t.Fatalf("expired device presence=%d err=%v", expired, err)
|
|
}
|
|
var online bool
|
|
if err := pool.QueryRow(ctx, `SELECT online FROM device_presence_state WHERE tenant_id='10000000-0000-0000-0000-000000000001' AND device_id='10000000-0000-0000-0000-000000000501'`).Scan(&online); err != nil || online {
|
|
t.Fatalf("device presence online=%v err=%v", online, err)
|
|
}
|
|
}
|