Переделать связь нод в кластере на автоматическое обнаружение #9

This commit is contained in:
2026-05-01 22:30:40 +03:00
parent 1787b0f8a3
commit f36dd3bbc1
25 changed files with 870 additions and 332 deletions

View File

@@ -2,97 +2,129 @@
-include_lib("common_test/include/ct.hrl").
-export([all/0, init_per_suite/1, end_per_suite/1]).
-export([auth_test/1, calendar_test/1, event_test/1, booking_test/1]).
-export([search_test/1, reviews_test/1, moderation_test/1]).
-export([tickets_test/1, subscription_test/1, admin_test/1]).
-export([websocket_test/1]).
-export([auth_test/1, calendar_test/1, event_test/1, booking_test/1,
search_test/1, reviews_test/1, moderation_test/1, tickets_test/1,
subscription_test/1, admin_test/1, websocket_test/1]).
-export([future_date/0]).
all() -> [
auth_test,
calendar_test,
event_test,
booking_test,
search_test,
reviews_test,
moderation_test,
tickets_test,
subscription_test,
admin_test,
websocket_test
].
all() ->
[
auth_test,
calendar_test,
event_test,
booking_test,
search_test,
reviews_test,
moderation_test,
tickets_test,
subscription_test,
admin_test,
websocket_test
].
init_per_suite(Config) ->
% Очищаем Mnesia перед тестами
io:format("~n=== Cleaning Mnesia for fresh test run ===~n"),
os:cmd("rm -rf Mnesia.* 2>/dev/null || true"),
timer:sleep(2000),
% Запускаем сервер
io:format("Starting server...~n"),
{ok, _Apps} = application:ensure_all_started(eventhub),
ct:pal("Start Api Testing ~n"),
Mode = os:getenv("CT_MODE", "local"),
ct:pal(" Mode: ~s", [Mode]),
AdminURL = os:getenv("ADMIN_API_HOST"),
ct:pal(" AdminURL: ~s", [AdminURL]),
AdminWsURL = os:getenv("ADMIN_WS_HOST"),
ct:pal(" AdminWsURL: ~s", [AdminWsURL]),
UserURL = os:getenv("API_HOST"),
ct:pal(" UserURL: ~s", [UserURL]),
UserWsURL = os:getenv("WS_HOST"),
ct:pal(" UserWsURL: ~s", [UserWsURL]),
% Компилируем модули из test/api/
code:add_patha("_build/test/lib/eventhub/ebin"),
code:add_patha("test/api"),
case Mode of
"remote" ->
inets:start(),
ssl:start(),
% Отключаем авто-редирект и проверку сертификатов
httpc:set_options([
{autoredirect, false},
{ssl, [{verify, verify_none}]}
]),
wait_for_server(),
timer:sleep(1000),
% Извлекаем учётные данные администраторов из переменных окружения
% и сохраняем их в словаре процесса для api_test_runner
put(admin_super_email,
list_to_binary(os:getenv("ADMIN_SUPER_EMAIL", "superadmin@eventhub.local"))),
put(admin_super_password,
list_to_binary(os:getenv("ADMIN_SUPER_PASSWORD", "123456"))),
put(admin_moder_email,
list_to_binary(os:getenv("ADMIN_MODER_EMAIL", "moderator@eventhub.local"))),
put(admin_moder_password,
list_to_binary(os:getenv("ADMIN_MODER_PASSWORD", "123456"))),
put(admin_support_email,
list_to_binary(os:getenv("ADMIN_SUPPORT_EMAIL", "support@eventhub.local"))),
put(admin_support_password,
list_to_binary(os:getenv("ADMIN_SUPPORT_PASSWORD", "123456"))),
Config;
_ ->
application:ensure_all_started(eventhub),
timer:sleep(3000),
check_admins(),
Config
end.
% Компилируем все файлы в test/api/
compile_api_modules(),
inets:start(),
ssl:start(),
%% Perform healthcheck (simplified)
Url = "http://localhost:8080",
case httpc:request(get, {Url ++ "/health", []}, [], []) of
{ok, {{_Version, 200, _Reason}, _Headers, _Body}} ->
ok; %% Healthcheck passed
_Error ->
ct:log("Healthcheck failed for: ~p", [Url]),
error(healthcheck_failed)
end_per_suite(Config) ->
Mode = os:getenv("CT_MODE", "local"),
case Mode of
"remote" ->
ok;
_ ->
application:stop(eventhub)
end,
Config.
end_per_suite(_Config) ->
application:stop(eventhub),
ok.
%% ── Тестовые обёртки ──────────────────────────────────
auth_test(_) -> api_auth_tests:test().
calendar_test(_) -> api_calendar_tests:test().
event_test(_) -> api_event_tests:test().
booking_test(_) -> api_booking_tests:test().
search_test(_) -> api_search_tests:test().
reviews_test(_) -> api_reviews_tests:test().
moderation_test(_) -> api_moderation_tests:test().
tickets_test(_) -> api_tickets_tests:test().
subscription_test(_) -> api_subscription_tests:test().
admin_test(_) -> api_admin_tests:test().
websocket_test(_) -> api_websocket_tests:test().
compile_api_modules() ->
Files = filelib:wildcard("test/api/*.erl"),
lists:foreach(fun(File) ->
compile:file(File, [report, {outdir, "test/api"}])
end, Files),
code:add_patha("test/api").
%% @doc Проверка наличия администраторов (только в remoteрежиме)
%% Если таблица admin пуста роняем тест явно, чтобы не гадать.
check_admins() ->
case core_admin:list_all() of
[] ->
ct:fail("No admins found in remote cluster. Run init_default_admins first.");
Admins ->
ct:pal("Admins present: ~p", [length(Admins)])
end.
%% ============ ТЕСТЫ-ПРОКСИ ============
%% @doc Ожидание доступности healthcheck-эндпоинта (/health)
wait_for_server() ->
URL = case os:getenv("API_HOST") of
false -> "http://localhost:8080/health";
Host -> Host ++ "/health"
end,
wait_for_server(URL, 30).
auth_test(_Config) ->
api_auth_tests:test().
wait_for_server(URL, 0) ->
ct:fail("Healthcheck ~s not responding after 30 seconds", [URL]);
wait_for_server(URL, Attempts) ->
case httpc:request(get, {URL, []}, [{timeout, 2000}, {ssl, [{verify, verify_none}]}], []) of
{ok, {{_, 200, _}, _, _}} ->
ct:pal("Healthcheck OK", []);
_ ->
timer:sleep(1000),
wait_for_server(URL, Attempts - 1)
end.
calendar_test(_Config) ->
api_calendar_tests:test().
event_test(_Config) ->
api_event_tests:test().
booking_test(_Config) ->
api_booking_tests:test().
search_test(_Config) ->
api_search_tests:test().
reviews_test(_Config) ->
api_reviews_tests:test().
moderation_test(_Config) ->
api_moderation_tests:test().
tickets_test(_Config) ->
api_tickets_tests:test().
subscription_test(_Config) ->
api_subscription_tests:test().
admin_test(_Config) ->
api_admin_tests:test().
websocket_test(_Config) ->
api_websocket_tests:test().
future_date() ->
Now = calendar:universal_time(),
Tomorrow = calendar:gregorian_seconds_to_datetime(
calendar:datetime_to_gregorian_seconds(Now) + 86400
),
{{Y, M, D}, {H, Min, S}} = Tomorrow,
iolist_to_binary(io_lib:format("~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0BZ",
[Y, M, D, H, Min, S])).