setupTestServer reuses the shared dev admin (testuser@tests.bookhoard.internal)
instead of re-inserting it, but never reset its password — once any test
mutated the admin's password, every later test in the run failed to log in
with 401s until the database was manually wiped. The seeding step now
resets the password hash to the known test constant on reuse, so full
integration runs are repeatable against an existing database.
Adds cross_library_move_test.go, seven integration tests covering the
duplicate-content features end to end:
- TestCrossLibraryMovePreservesHistory: a book moved between two same-type
libraries keeps its row ID — progress and annotations survive, no
duplicate, no archived ghost, library_type_name stays truthful.
- TestCrossLibraryCopyStaysIndependent: deliberate copies in two libraries
stay independent rows with isolated progress.
- TestCrossLibraryMoveRejectedForTypeMismatch: a reflowable EPUB is not
repointed between manga libraries; a library_type_mismatch processing
issue is recorded instead.
- TestListHiddenMediaItemsMatchesActiveTwin: archived rows expose their
active same-SHA twin (and rows without one report no match).
- TestMergeArchivedItemIntoActiveTwin: merging moves progress and
annotations onto the active copy and removes the archived row.
- TestMergeArchivedItemRejections: non-admin 403, active source, hash
mismatch, missing target_id, self-merge, and archived target all fail
closed.
- TestLibraryTypeNameTriggerOnLibraryChange: the UPDATE trigger refreshes
library_type_name when a row changes libraries.
Tests create their own temp-dir library folders (host runs don't have
/app/uploads), use unique device identifiers (device_identifier is
UNIQUE and leftover rows broke reruns), and clean up via an explicit
defer that runs while the pool is still open — a t.Cleanup registered
for the same purpose silently no-ops because it executes after
setup.Close has closed the pool.