From af88267a7af0eb9ba983f8c064581d17fbf7051e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chrz=C4=85szcz?= Date: Mon, 11 Mar 2024 12:11:34 +0100 Subject: [PATCH] Introduce log_helper, and use it in config_parser_SUITE Small tests used logger_ct_backend, but it was meant for big tests: - The default formatter was used in small tests (no app.config), requiring regexp matching. - RPC was used, but it was not needed. Advantages of the new helper: - Concise and simple eunit-like assertions - Does not consume unwanted received messages thanks to pattern matching in 'receive' - Easier set-up and tear-down with one handler per testcase. --- test/config_parser_SUITE.erl | 70 +++++++++++++----------------------- test/log_helper.erl | 20 +++++++++++ test/log_helper.hrl | 27 ++++++++++++++ 3 files changed, 72 insertions(+), 45 deletions(-) create mode 100644 test/log_helper.erl create mode 100644 test/log_helper.hrl diff --git a/test/config_parser_SUITE.erl b/test/config_parser_SUITE.erl index 9d3b0c33da8..92fc944b434 100644 --- a/test/config_parser_SUITE.erl +++ b/test/config_parser_SUITE.erl @@ -2,6 +2,7 @@ -compile([export_all, nowarn_export_all]). -include_lib("eunit/include/eunit.hrl"). +-include("log_helper.hrl"). -define(HOST, <<"example.com">>). @@ -233,8 +234,7 @@ groups() -> incorrect_module]}, {services, [parallel], [service_domain_db, service_mongoose_system_metrics]}, - {logs, [], [no_warning_about_subdomain_patterns, - no_warning_for_resolvable_domain]} + {logs, [], log_cases()} ]. init_per_suite(Config) -> @@ -259,11 +259,22 @@ end_per_group(dynamic_domains, _Config) -> end_per_group(_, _Config) -> ok. -init_per_testcase(_, Config) -> +init_per_testcase(CaseName, Config) -> + case lists:member(CaseName, log_cases()) of + true -> log_helper:set_up(); + false -> ok + end, Config. -end_per_testcase(_, _Config) -> - ok. +end_per_testcase(CaseName, _Config) -> + case lists:member(CaseName, log_cases()) of + true -> log_helper:tear_down(); + false -> ok + end. + +log_cases() -> + [no_warning_about_subdomain_patterns, + no_warning_for_resolvable_domain]. sample_pgsql(Config) -> test_config_file(Config, "mongooseim-pgsql"). @@ -2910,64 +2921,33 @@ service_mongoose_system_metrics(_Config) -> ?err(T(#{<<"tracking_id">> => #{<<"secret">> => 666, <<"id">> => 666}})), ?err(T(#{<<"report">> => <<"maybe">>})). +%% Logs + no_warning_about_subdomain_patterns(_Config) -> check_module_defaults(mod_vcard), check_iqdisc(mod_vcard), P = [modules, mod_vcard], T = fun(Opts) -> #{<<"modules">> => #{<<"mod_vcard">> => Opts}} end, - - Node = #{node => mongooseim@localhost}, - logger_ct_backend:start(Node), - logger_ct_backend:capture(warning, Node), - ?cfgh(P ++ [host], {prefix, <<"vjud.">>}, T(#{<<"host">> => <<"vjud.@HOST@">>})), + ?assertNoLog(warning, #{what := cfg_validate_domain}), + ?cfgh(P ++ [host], {fqdn, <<"vjud.test">>}, T(#{<<"host">> => <<"vjud.test">>})), - - logger_ct_backend:stop_capture(Node), - logger_ct_backend:stop(Node), - - FilterFun = fun(_, Msg) -> - re:run(Msg, "test") /= nomatch orelse - re:run(Msg, "example.com") /= nomatch - end, - Logs = logger_ct_backend:recv(FilterFun), - - ?assertNotEqual(0, length(Logs)), - AnyContainsExampleCom = lists:any(fun({_, Msg}) -> - re:run(Msg, "example.com") /= nomatch - end, Logs), - ?eq(false, AnyContainsExampleCom). + ?assertLog(warning, #{what := cfg_validate_domain, reason := nxdomain, domain := "vjud.test"}). no_warning_for_resolvable_domain(_Config) -> T = fun(Opts) -> #{<<"modules">> => #{<<"mod_http_upload">> => Opts}} end, P = [modules, mod_http_upload], RequiredOpts = #{<<"s3">> => http_upload_s3_required_opts()}, - - Node = #{node => mongooseim@localhost}, - logger_ct_backend:start(Node), - logger_ct_backend:capture(warning, Node), - ?cfgh(P ++ [host], {fqdn, <<"example.org">>}, T(RequiredOpts#{<<"host">> => <<"example.org">>})), + ?assertNoLog(_, #{what := cfg_validate_domain}), + ?cfgh(P ++ [host], {fqdn, <<"something.invalid">>}, T(RequiredOpts#{<<"host">> => <<"something.invalid">>})), - - logger_ct_backend:stop_capture(Node), - logger_ct_backend:stop(Node), - - FilterFun = fun(_, Msg) -> - re:run(Msg, "example.org") /= nomatch orelse - re:run(Msg, "something.invalid") /= nomatch - end, - Logs = logger_ct_backend:recv(FilterFun), - - ?assertNotEqual(0, length(Logs)), - ResolvableDomainInLogs = lists:any(fun({_, Msg}) -> - re:run(Msg, "example.org") /= nomatch - end, Logs), - ?eq(false, ResolvableDomainInLogs). + ?assertLog(warning, #{what := cfg_validate_domain, reason := nxdomain, + domain := "something.invalid"}). %% Helpers for module tests diff --git a/test/log_helper.erl b/test/log_helper.erl new file mode 100644 index 00000000000..3e62d7b8a8a --- /dev/null +++ b/test/log_helper.erl @@ -0,0 +1,20 @@ +%% Helper module for checking expected log messages +%% For assertions, see log_helper.hrl + +-module(log_helper). +-compile([export_all, nowarn_export_all]). + +%% Call in init_per_testcase +set_up() -> + logger:add_handler(handler_id(), ?MODULE, #{receiver => self()}). + +%% Call in end_per_testcase +tear_down() -> + logger:remove_handler(handler_id()). + +%% Logger callback +log(Event, #{receiver := Receiver}) -> + Receiver ! {log, Event}. + +handler_id() -> + list_to_atom(pid_to_list(self())). diff --git a/test/log_helper.hrl b/test/log_helper.hrl new file mode 100644 index 00000000000..3e22aae7bfa --- /dev/null +++ b/test/log_helper.hrl @@ -0,0 +1,27 @@ +%% Assertions for expected logs. Naming follows eunit.hrl +%% For set-up and tear-down, see log_helper.erl + +-define(assertNoLog(LevelPattern, MsgPattern), + case ?receiveLog(LevelPattern, MsgPattern) of + no_log -> ok; + _ -> ct:fail("Received unexpected log") + end). + +-define(assertLog(LevelPattern, MsgPattern), + case ?receiveLog(LevelPattern, MsgPattern) of + no_log -> ct:fail("Expected log not received"); + _ -> ok + end). + +-define(receiveLog(LevelPattern, MsgPattern), + ?wrap(receive + {log, #{level := Level = LevelPattern, + msg := {report, Msg = MsgPattern}}} -> + ct:log("Received ~p log: ~p", [Level, Msg]), + {Level, Msg} + after + 0 -> no_log + end)). + +%% Wrap in a fun to avoid unsafe variables +-define(wrap(Expr), (fun() -> Expr end)()).