Files
ITWorx-Pulse-Public/internal/dashboard/repository_integration_test.go
ITWorx Pulse release export bd774932d5
Public source validation / validate (push) Failing after 3m8s
Publish ITWorx Pulse source
2026-09-03 02:09:19 +02:00

114 lines
4.4 KiB
Go

package dashboard
import (
"context"
"errors"
"os"
"testing"
"time"
"github.com/itworx/pulse/internal/database"
)
func TestDashboardRepositoryPostgreSQL(t *testing.T) {
dsn := os.Getenv("PULSE_TEST_DATABASE_URL")
if dsn == "" {
t.Skip("PULSE_TEST_DATABASE_URL is not set")
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
pool, err := database.NewPool(ctx, database.Config{URL: dsn, MaxConns: 10, MinConns: 1})
if err != nil {
t.Fatal(err)
}
defer pool.Close()
if err := database.Migrate(ctx, pool); err != nil {
t.Fatal(err)
}
actor := "00000000-0000-0000-0000-0000000003a1"
otherActor := "00000000-0000-0000-0000-0000000003a2"
if _, err := pool.Exec(ctx, "INSERT INTO users (id, external_subject, display_name) VALUES ($1, $2, $3) ON CONFLICT (id) DO NOTHING", actor, actor, "M3 actor"); err != nil {
t.Fatal(err)
}
if _, err := pool.Exec(ctx, "INSERT INTO users (id, external_subject, display_name) VALUES ($1, $2, $3) ON CONFLICT (id) DO NOTHING", otherActor, otherActor, "M3 other actor"); err != nil {
t.Fatal(err)
}
repo := Repository{Pool: pool}
id := "00000000-0000-0000-0000-0000000003d1"
_, _ = pool.Exec(ctx, "DELETE FROM dashboards WHERE id=$1 OR slug IN ('m3-repo','m3-repo-copy')", id)
doc := Document{"schemaVersion": 2, "id": id, "slug": "m3-repo", "name": "M3 Repo", "scope": "personal", "variables": []any{}, "widgets": []any{}, "settings": map[string]any{"refreshSeconds": 30}}
summary, version, err := repo.Create(ctx, actor, doc, "initial")
if err != nil {
t.Fatal(err)
}
if version.Number != 1 || summary.Revision != 1 {
t.Fatalf("create=%+v/%+v", summary, version)
}
same, err := repo.UpdateDocument(ctx, id, actor, 1, doc, "noop")
if err != nil || same.Revision != 1 {
t.Fatalf("noop=%+v err=%v", same, err)
}
doc["name"] = "Changed"
updated, err := repo.UpdateDocument(ctx, id, actor, 1, doc, "edit")
if err != nil || updated.Revision != 2 || updated.CurrentVersion != 2 {
t.Fatalf("update=%+v err=%v", updated, err)
}
if _, err := repo.UpdateDocument(ctx, id, actor, 1, doc, "stale"); !errors.Is(err, ErrConflict) {
t.Fatalf("expected conflict, got %v", err)
}
restored, err := repo.Restore(ctx, id, actor, 2, 1)
if err != nil || restored.Revision != 3 || restored.CurrentVersion != 3 {
t.Fatalf("restore=%+v err=%v", restored, err)
}
versions, err := repo.Versions(ctx, id, actor, 10)
if err != nil || len(versions) != 3 {
t.Fatalf("versions=%d err=%v", len(versions), err)
}
historical, err := repo.GetVersion(ctx, id, actor, 1)
if err != nil || historical.Number != 1 {
t.Fatalf("historical=%+v err=%v", historical, err)
}
if _, _, err := repo.Get(ctx, id, otherActor); !errors.Is(err, ErrNotFound) {
t.Fatalf("personal dashboard leaked through direct read: %v", err)
}
if otherVersions, err := repo.Versions(ctx, id, otherActor, 10); err != nil || len(otherVersions) != 0 {
t.Fatalf("personal dashboard versions leaked: count=%d err=%v", len(otherVersions), err)
}
if _, err := repo.GetVersion(ctx, id, otherActor, 1); !errors.Is(err, ErrNotFound) {
t.Fatalf("personal dashboard version leaked through direct read: %v", err)
}
if _, _, err := repo.Create(ctx, actor, doc, "duplicate"); !errors.Is(err, ErrConflict) {
t.Fatalf("expected duplicate conflict, got %v", err)
}
cloned, clonedVersion, err := repo.Clone(ctx, actor, id, "m3-repo-copy", "M3 Repo Copy")
if err != nil || cloned.ID == id || clonedVersion.Number != 1 || cloned.Scope != "personal" {
t.Fatalf("clone=%+v/%+v err=%v", cloned, clonedVersion, err)
}
listed, err := repo.List(ctx, actor, 10)
if err != nil || len(listed) < 2 {
t.Fatalf("list=%d err=%v", len(listed), err)
}
edited, err := repo.UpdateMetadata(ctx, id, actor, 3, "M3 Repo Renamed", "updated")
if err != nil || edited.Revision != 4 {
t.Fatalf("metadata=%+v err=%v", edited, err)
}
archived, err := repo.Archive(ctx, id, actor, 4)
if err != nil || archived.ArchivedAt == nil || archived.Revision != 5 {
t.Fatalf("archive=%+v err=%v", archived, err)
}
if _, err := pool.Exec(ctx, "UPDATE dashboard_versions SET change_summary='bad' WHERE dashboard_id=$1", id); err == nil {
t.Fatal("expected immutable version failure")
}
if _, err := pool.Exec(ctx, "DELETE FROM dashboards WHERE id=$1", id); err != nil {
t.Fatal(err)
}
if _, err := pool.Exec(ctx, "DELETE FROM dashboards WHERE id=$1", cloned.ID); err != nil {
t.Fatal(err)
}
}