Files
neural-hunt/internal/data/admin_control_test.go
groot 47c523dd98
All checks were successful
release-tag / release-image (push) Successful in 3m51s
RC-14
2026-08-14 06:17:30 +02:00

121 lines
3.8 KiB
Go

package data
import (
"context"
"errors"
"testing"
"time"
"neuralhunt/internal/auth"
)
func TestRetiringTaskDoesNotCreateInheritedSuccessor(t *testing.T) {
ctx := context.Background()
db, err := OpenSQLite(ctx, t.TempDir()+"/retire.db")
if err != nil {
t.Fatal(err)
}
defer db.Close()
s := New(db)
if err := s.EnsureActiveTasks(ctx, 1, 28); err != nil {
t.Fatal(err)
}
ts, err := s.ActiveTasks(ctx)
if err != nil || len(ts) != 1 {
t.Fatalf("active tasks len=%d err=%v", len(ts), err)
}
pred := ts[0]
if err := s.UpdateTaskConfig(ctx, pred.ID, "Limited Series", "", "", ""); err != nil {
t.Fatal(err)
}
if err := s.SetTaskRetireAfterCompletion(ctx, pred.ID, true); err != nil {
t.Fatal(err)
}
if err := s.CloseTask(ctx, pred.ID); err != nil {
t.Fatal(err)
}
if _, err := s.EnsureSuccessorTask(ctx, pred.ID, 28); !errors.Is(err, ErrTaskRetiring) {
t.Fatalf("expected ErrTaskRetiring, got %v", err)
}
var children int
if err := db.QueryRowContext(ctx, `SELECT count(*) FROM tasks WHERE parent_task_id=?`, pred.ID).Scan(&children); err != nil {
t.Fatal(err)
}
if children != 0 {
t.Fatalf("retiring task got %d inherited successors", children)
}
if err := s.EnsureActiveTasks(ctx, 1, 28); err != nil {
t.Fatal(err)
}
active, err := s.ActiveTasks(ctx)
if err != nil || len(active) != 1 {
t.Fatalf("replacement active tasks len=%d err=%v", len(active), err)
}
if active[0].ParentTaskID != nil {
t.Fatalf("replacement should be a fresh root task, parent=%v", *active[0].ParentTaskID)
}
}
func TestArtifactTransferPreservesWinnerAndAdminDropHasNoGameWin(t *testing.T) {
ctx := context.Background()
db, err := OpenSQLite(ctx, t.TempDir()+"/ownership.db")
if err != nil {
t.Fatal(err)
}
defer db.Close()
s := New(db)
jwk := auth.PublicJWK{Kty: "EC", Crv: "P-256", X: "AQ", Y: "Ag"}
if err := s.UpsertClient(ctx, "client_a", jwk); err != nil {
t.Fatal(err)
}
if err := s.UpsertClient(ctx, "client_b", jwk); err != nil {
t.Fatal(err)
}
if err := s.EnsureActiveTasks(ctx, 1, 28); err != nil {
t.Fatal(err)
}
ts, _ := s.ActiveTasks(ctx)
id := ts[0].ID
if _, err := db.ExecContext(ctx, `UPDATE tasks SET status='completed',completed_at=?,winner_client_id='client_a',artifact_owner_client_id='client_a',artifact_origin='win',artifact_status='ready',artifact_uri='/artifacts/a/image.svg' WHERE id=?`, time.Now().UTC().UnixMilli(), id); err != nil {
t.Fatal(err)
}
from, err := s.TransferArtifact(ctx, id, "client_b", "admin transfer test")
if err != nil {
t.Fatal(err)
}
if from != "client_a" {
t.Fatalf("from=%q", from)
}
var winner, owner string
if err := db.QueryRowContext(ctx, `SELECT winner_client_id,artifact_owner_client_id FROM tasks WHERE id=?`, id).Scan(&winner, &owner); err != nil {
t.Fatal(err)
}
if winner != "client_a" || owner != "client_b" {
t.Fatalf("winner=%q owner=%q", winner, owner)
}
var transfers int
if err := db.QueryRowContext(ctx, `SELECT count(*) FROM artifact_transfers WHERE task_id=? AND from_client_id='client_a' AND to_client_id='client_b'`, id).Scan(&transfers); err != nil {
t.Fatal(err)
}
if transfers != 1 {
t.Fatalf("transfer audit count=%d", transfers)
}
drop, err := s.CreateAdminArtifactDrop(ctx, "client_b", id, "ULTRA RARE", 28)
if err != nil {
t.Fatal(err)
}
if drop.Status != "completed" || drop.ArtifactStatus != "pending" || drop.ArtifactOrigin != "admin_drop" || !drop.RetireAfterCompletion {
t.Fatalf("unexpected admin drop: %+v", drop)
}
if drop.WinnerClientID != nil {
t.Fatalf("admin drop must not create a historical game winner: %+v", drop.WinnerClientID)
}
if drop.ArtifactOwnerClientID == nil || *drop.ArtifactOwnerClientID != "client_b" {
t.Fatalf("admin drop owner=%v", drop.ArtifactOwnerClientID)
}
if drop.ArtifactRarityOverride != "ULTRA RARE" {
t.Fatalf("admin drop rarity override=%q", drop.ArtifactRarityOverride)
}
}