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) } }