diff --git a/Makefile b/Makefile index d2a92f2..8ac3b7f 100644 --- a/Makefile +++ b/Makefile @@ -98,11 +98,15 @@ eunit-verbose: ## Запустить EUnit тесты с подробным вы @echo "Запуск EUnit тестов (verbose)..." @$(REBAR3) eunit --sname $(SNAME)_test --verbose -test-api: ## Запустить Common Test для API +test-api: ## Запустить Common Test для API (порты 18080/18081/18445/18446 — не docker 8080/8445) @echo "Cleaning old data..." @rm -rf logs/test/ct/ct_run.* + @rm -rf data/Mnesia.ct data/Mnesia.ct.* data/mnesia_ct Mnesia.eventhub_api_test@* 2>/dev/null || true @bash scripts/fix-rebar-unit-symlink.sh - @$(REBAR3) ct --sname $(SNAME)_api_test #-v + @HTTP_PORT=18080 WS_PORT=18081 ADMIN_HTTP_PORT=18445 ADMIN_WS_PORT=18446 \ + API_HOST=http://localhost:18080 ADMIN_API_HOST=http://localhost:18445 \ + WS_HOST=ws://localhost:18081 ADMIN_WS_HOST=ws://localhost:18446 \ + $(REBAR3) ct --sname $(SNAME)_api_test #-v wsl-ext4-dirs: ## WSL: каталоги logs/data на ext4 (рекомендуется) @bash scripts/wsl-ext4-dirs.sh diff --git a/config/sys.config b/config/sys.config new file mode 100644 index 0000000..f7dd4cc --- /dev/null +++ b/config/sys.config @@ -0,0 +1,20 @@ +%% Common Test / local API suite — ports that don't clash with docker compose (8080/8445). +[ + {eventhub, [ + {http_port, 18080}, + {ws_port, 18081}, + {admin_http_port, 18445}, + {admin_ws_port, 18446}, + {swagger_http_port, 18447}, + {jwt_secret, <<"ct_jwt_secret_change_me">>}, + {admin_jwt_secret, <<"ct_admin_jwt_secret_change_me">>} + ]}, + {kernel, [ + {logger_level, warning}, + {logger, [ + {handler, default, logger_std_h, + #{formatter => {logger_formatter, #{template => [time, " ", level, ": ", msg, "\n"]}}} + } + ]} + ]} +]. diff --git a/scripts/run-wsl-tests.sh b/scripts/run-wsl-tests.sh index 3c9e65c..9b3021c 100644 --- a/scripts/run-wsl-tests.sh +++ b/scripts/run-wsl-tests.sh @@ -41,9 +41,9 @@ run_ct() { rebar3 ct --suite=api_admins_SUITE --case="${case_name}" --verbose } -if port_busy 8080 || port_busy 8445; then - echo "=== ct: SKIP (порты 8080/8445 заняты — остановите eventhub и повторите) ===" - ss -tln 2>/dev/null | grep -E ':8080|:8445' || true +if port_busy 18080 || port_busy 18445; then + echo "=== ct: SKIP (порты 18080/18445 заняты — остановите CT-сервер и повторите) ===" + ss -tln 2>/dev/null | grep -E ':18080|:18445' || true exit 0 fi diff --git a/test/api/api_test_runner.erl b/test/api/api_test_runner.erl index 9bfa8b0..dcf6db4 100644 --- a/test/api/api_test_runner.erl +++ b/test/api/api_test_runner.erl @@ -13,6 +13,7 @@ get_base_url/0, get_base_ws_url/0, get_admin_ws_url/0, + ensure_local_app_ports/0, get_admin_token/0, get_superadmin_token/0, get_moderator_token/0, @@ -57,32 +58,68 @@ ct_mode() -> -spec get_base_url() -> string(). get_base_url() -> - case ct_mode() of - "remote" -> os:getenv("API_HOST", "http://localhost:8080"); - _ -> "http://localhost:8080" - end. + os:getenv("API_HOST", "http://localhost:18080"). -spec get_admin_url() -> string(). get_admin_url() -> - case ct_mode() of - "remote" -> os:getenv("ADMIN_API_HOST", "http://localhost:8445"); - _ -> "http://localhost:8445" - end. + os:getenv("ADMIN_API_HOST", "http://localhost:18445"). -spec get_base_ws_url() -> string(). get_base_ws_url() -> - case ct_mode() of - "remote" -> os:getenv("WS_HOST", "ws://localhost:8081"); - _ -> "ws://localhost:8081" - end. + os:getenv("WS_HOST", "ws://localhost:18081"). -spec get_admin_ws_url() -> string(). get_admin_ws_url() -> - case ct_mode() of - "remote" -> os:getenv("ADMIN_WS_HOST", "ws://localhost:8446"); - _ -> "ws://localhost:8446" + os:getenv("ADMIN_WS_HOST", "ws://localhost:18446"). + +%% @doc Порты CT-local (не docker 8080/8445). Вызывать до ensure_all_started(eventhub). +-spec ensure_local_app_ports() -> ok. +ensure_local_app_ports() -> + _ = application:load(eventhub), + _ = application:load(mnesia), + application:set_env(eventhub, http_port, env_port("HTTP_PORT", 18080)), + application:set_env(eventhub, ws_port, env_port("WS_PORT", 18081)), + application:set_env(eventhub, admin_http_port, env_port("ADMIN_HTTP_PORT", 18445)), + application:set_env(eventhub, admin_ws_port, env_port("ADMIN_WS_PORT", 18446)), + application:set_env(eventhub, swagger_http_port, env_port("SWAGGER_HTTP_PORT", 18447)), + ensure_fresh_mnesia_dir(), + clear_cached_admin_tokens(), + ok. + +env_port(Name, Default) -> + case os:getenv(Name) of + false -> Default; + "" -> Default; + Val -> list_to_integer(Val) end. +ensure_fresh_mnesia_dir() -> + %% Absolute path under WSL data (CT cwd is logs/test/ct/ct_run.* — relative data/ is missing). + Dir = filename:join([ + os:getenv("HOME", "/home/alexc"), + "eventhub-wsl-data", "data", "mnesia_ct" + ]), + _ = application:load(mnesia), + application:set_env(mnesia, dir, Dir), + _ = (catch mnesia:stop()), + ok = filelib:ensure_dir(filename:join(Dir, ".keep")), + _ = file:del_dir_r(Dir), + _ = (catch mnesia:delete_schema([node()])), + case mnesia:create_schema([node()]) of + ok -> + ok; + {error, {already_exists, _}} -> + ok; + {error, Reason} -> + error({ct_mnesia_create_schema_failed, Reason, Dir, node()}) + end. + +clear_cached_admin_tokens() -> + lists:foreach( + fun(Role) -> _ = persistent_term:erase({?MODULE, admin_token, Role}) end, + [admin, superadmin, moderator, support] + ). + %%%=================================================================== %%% Учётные данные администраторов (из переменных окружения) %%%=================================================================== diff --git a/test/api_admins_SUITE.erl b/test/api_admins_SUITE.erl index ebf79f5..e284ecf 100644 --- a/test/api_admins_SUITE.erl +++ b/test/api_admins_SUITE.erl @@ -63,7 +63,8 @@ init_per_suite(Config) -> ct:pal("Local mode: application already running"), [{started_by_us, false} | Config]; false -> - ct:pal("Local mode: starting application..."), + ct:pal("Local mode: starting application on CT ports (18080/18445)..."), + ok = api_test_runner:ensure_local_app_ports(), {ok, _} = application:ensure_all_started(eventhub), timer:sleep(1000), [{started_by_us, true} | Config] @@ -142,7 +143,7 @@ ct_mode() -> %% @private Ожидание доступности удалённого API. -spec wait_for_remote() -> ok. wait_for_remote() -> - URL = os:getenv("ADMIN_API_HOST", "http://localhost:8445") ++ "/admin/health", + URL = api_test_runner:get_admin_url() ++ "/admin/health", ct:pal("Waiting for remote API: ~s", [URL]), wait_for_health(URL, 30). diff --git a/test/api_users_SUITE.erl b/test/api_users_SUITE.erl index a87cef2..5dcbc0d 100644 --- a/test/api_users_SUITE.erl +++ b/test/api_users_SUITE.erl @@ -69,7 +69,8 @@ init_per_suite(Config) -> ct:pal("Local mode: application already running"), [{started_by_us, false} | Config]; false -> - ct:pal("Local mode: starting application..."), + ct:pal("Local mode: starting application on CT ports (18080/18445)..."), + ok = api_test_runner:ensure_local_app_ports(), {ok, _} = application:ensure_all_started(eventhub), timer:sleep(1000), [{started_by_us, true} | Config] @@ -166,7 +167,7 @@ ct_mode() -> %% @private Ожидание доступности удалённого API. -spec wait_for_remote() -> ok. wait_for_remote() -> - URL = os:getenv("API_HOST", "http://localhost:8080") ++ "/health", + URL = api_test_runner:get_base_url() ++ "/health", ct:pal("Waiting for remote API: ~s", [URL]), wait_for_health(URL, 30).