fix: avoid empty node metrics race in CT (collect on start + poll). Refs EventHub/EventHubBack#47
CI / test (push) Successful in 9m13s
CI / deploy-ift (push) Successful in 2m4s
CI / e2e-ift (push) Failing after 1m51s
CI / deploy-stage (push) Has been skipped
CI / e2e-stage (push) Has been skipped

This commit is contained in:
2026-07-20 01:03:53 +03:00
parent 10f6eef92d
commit 3c6211dd08
2 changed files with 28 additions and 13 deletions
+2 -2
View File
@@ -41,8 +41,8 @@ init([]) ->
mnesia:wait_for_tables([node_metric], 5000), mnesia:wait_for_tables([node_metric], 5000),
% Создаём ETS-таблицу для кеширования предыдущих значений io % Создаём ETS-таблицу для кеширования предыдущих значений io
ets:new(?IO_CACHE_TAB, [named_table, public, set, {keypos, 1}]), ets:new(?IO_CACHE_TAB, [named_table, public, set, {keypos, 1}]),
% Запускаем периодический сбор метрик и очистку % Первый сбор сразу (иначе окно ~5с без метрик), далее по интервалу.
schedule_collect(), self() ! collect,
schedule_cleanup(), schedule_cleanup(),
{ok, #{}}. {ok, #{}}.
+26 -11
View File
@@ -227,6 +227,25 @@ test_calendar_stats(Token) ->
test_node_metrics_history(Token) -> test_node_metrics_history(Token) ->
ct:pal(" TEST: Node metrics history"), ct:pal(" TEST: Node metrics history"),
%% node_monitor пишет раз в 5с; в быстром CI stats-кейс может успеть раньше.
case whereis(node_monitor) of
undefined -> ok;
Pid when is_pid(Pid) -> Pid ! collect
end,
Metrics = wait_node_metrics(Token, 20, 500),
?assert(is_list(Metrics)),
?assert(length(Metrics) >= 1),
First = hd(Metrics),
?assert(maps:is_key(<<"timestamp">>, First)),
?assert(maps:is_key(<<"node">>, First)),
?assert(maps:is_key(<<"memory_total">>, First)),
?assert(maps:is_key(<<"memory_available">>, First)),
?assert(maps:is_key(<<"cpu_utilization">>, First)),
ct:pal(" OK: ~p metrics received", [length(Metrics)]).
wait_node_metrics(_Token, 0, _SleepMs) ->
[];
wait_node_metrics(Token, Attempts, SleepMs) ->
Now = calendar:universal_time(), Now = calendar:universal_time(),
FromSec = calendar:datetime_to_gregorian_seconds(Now) - 300, FromSec = calendar:datetime_to_gregorian_seconds(Now) - 300,
ToSec = calendar:datetime_to_gregorian_seconds(Now) + 300, ToSec = calendar:datetime_to_gregorian_seconds(Now) + 300,
@@ -237,17 +256,13 @@ test_node_metrics_history(Token) ->
Path = <<"/v1/admin/nodes/metrics?from=", From/binary, "&to=", To/binary>>, Path = <<"/v1/admin/nodes/metrics?from=", From/binary, "&to=", To/binary>>,
{ok, 200, _, Body} = api_test_runner:admin_request(get, Path, Token, <<"">>), {ok, 200, _, Body} = api_test_runner:admin_request(get, Path, Token, <<"">>),
Metrics = jsx:decode(list_to_binary(Body), [return_maps]), Metrics = jsx:decode(list_to_binary(Body), [return_maps]),
?assert(is_list(Metrics)), case is_list(Metrics) andalso length(Metrics) >= 1 of
% Так как монитор работает, метрики уже должны быть true ->
?assert(length(Metrics) >= 1), Metrics;
% Проверяем структуру первой метрики false ->
First = hd(Metrics), timer:sleep(SleepMs),
?assert(maps:is_key(<<"timestamp">>, First)), wait_node_metrics(Token, Attempts - 1, SleepMs)
?assert(maps:is_key(<<"node">>, First)), end.
?assert(maps:is_key(<<"memory_total">>, First)),
?assert(maps:is_key(<<"memory_available">>, First)),
?assert(maps:is_key(<<"cpu_utilization">>, First)),
ct:pal(" OK: ~p metrics received", [length(Metrics)]).
test_avg_ticket_resolution_after_close(Token, UserToken) -> test_avg_ticket_resolution_after_close(Token, UserToken) ->
ct:pal(" TEST: avg_ticket_resolution_h after closing ticket"), ct:pal(" TEST: avg_ticket_resolution_h after closing ticket"),