-module(migration_engine_tests). -include_lib("eunit/include/eunit.hrl"). -include("records.hrl"). -define(LOCK_VERSION, "__migration_lock__"). %% Keep in sync with migration_engine:?ALL_MIGRATIONS (atom → string version). -define(ALL_VERSIONS, [ "20260501120000_base_schema", "20260504150000_test_migration", "20260716230000_ticket_source_and_hash_index", "20260717180000_stats_counters", "20260717190000_admin_stats_indexes", "20260719210000_review_vote" ]). setup() -> mnesia:stop(), mnesia:delete_schema([node()]), mnesia:create_schema([node()]), mnesia:start(), mnesia:create_table(schema_migration, [ {disc_copies, [node()]}, {attributes, record_info(fields, schema_migration)}, {type, set} ]), {ok, _} = migration_engine:start_link(), ok. cleanup(_) -> catch gen_server:stop(migration_engine), catch mnesia:delete_table(schema_migration), mnesia:stop(), mnesia:delete_schema([node()]), ok. migration_engine_test_() -> {foreach, fun setup/0, fun cleanup/1, [ {"ensure_applied applies pending migrations", fun test_ensure_applied/0}, {"ensure_applied is idempotent", fun test_ensure_applied_idempotent/0}, {"lock record is not treated as migration", fun test_lock_not_applied/0}, {"join node waits until migrations applied", fun test_join_wait/0} ]}. test_ensure_applied() -> ?assertEqual(ok, migration_engine:ensure_applied()), Status = migration_engine:status(), ?assertEqual([], maps:get(pending, Status)), Applied = maps:get(applied, Status), lists:foreach(fun(V) -> ?assert(lists:member(V, Applied)) end, ?ALL_VERSIONS). test_ensure_applied_idempotent() -> ?assertEqual(ok, migration_engine:ensure_applied()), ?assertEqual(ok, migration_engine:ensure_applied()). test_lock_not_applied() -> ?assertEqual(ok, migration_engine:ensure_applied()), Status = migration_engine:status(), ?assertNot(lists:member(?LOCK_VERSION, maps:get(applied, Status))). test_join_wait() -> Now = calendar:universal_time(), mnesia:dirty_write(#schema_migration{version = ?LOCK_VERSION, applied_at = Now}), spawn(fun() -> timer:sleep(100), lists:foreach(fun(V) -> mnesia:dirty_write(#schema_migration{version = V, applied_at = Now}) end, ?ALL_VERSIONS), mnesia:dirty_delete({schema_migration, ?LOCK_VERSION}) end), ?assertEqual(ok, migration_engine:ensure_applied()).