summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl15
-rw-r--r--lib/diameter/test/Makefile12
-rw-r--r--lib/diameter/test/diameter.spec1
-rw-r--r--lib/diameter/test/diameter_3xxx_SUITE.erl152
-rw-r--r--lib/diameter/test/diameter_app_SUITE.erl104
-rw-r--r--lib/diameter/test/diameter_capx_SUITE.erl206
-rw-r--r--lib/diameter/test/diameter_codec_SUITE.erl140
-rw-r--r--lib/diameter/test/diameter_compiler_SUITE.erl104
-rw-r--r--lib/diameter/test/diameter_config_SUITE.erl74
-rw-r--r--lib/diameter/test/diameter_ct.hrl22
-rw-r--r--lib/diameter/test/diameter_dist_SUITE.erl314
-rw-r--r--lib/diameter/test/diameter_distribution_SUITE.erl333
-rw-r--r--lib/diameter/test/diameter_dpr_SUITE.erl125
-rw-r--r--lib/diameter/test/diameter_event_SUITE.erl78
-rw-r--r--lib/diameter/test/diameter_examples_SUITE.erl238
-rw-r--r--lib/diameter/test/diameter_failover_SUITE.erl102
-rw-r--r--lib/diameter/test/diameter_gen_sctp_SUITE.erl35
-rw-r--r--lib/diameter/test/diameter_gen_tcp_SUITE.erl37
-rw-r--r--lib/diameter/test/diameter_gh.spec4
-rw-r--r--lib/diameter/test/diameter_length_SUITE.erl84
-rw-r--r--lib/diameter/test/diameter_pool_SUITE.erl97
-rw-r--r--lib/diameter/test/diameter_reg_SUITE.erl82
-rw-r--r--lib/diameter/test/diameter_relay_SUITE.erl161
-rw-r--r--lib/diameter/test/diameter_stats_SUITE.erl71
-rw-r--r--lib/diameter/test/diameter_sync_SUITE.erl81
-rw-r--r--lib/diameter/test/diameter_tls_SUITE.erl190
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl519
-rw-r--r--lib/diameter/test/diameter_transport_SUITE.erl123
-rw-r--r--lib/diameter/test/diameter_util.erl198
-rw-r--r--lib/diameter/test/diameter_watchdog_SUITE.erl129
-rw-r--r--lib/diameter/test/modules.mk3
31 files changed, 1894 insertions, 1940 deletions
diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl
index 9ac9f2d59c..f40f2b1fc4 100644
--- a/lib/diameter/src/transport/diameter_tcp.erl
+++ b/lib/diameter/src/transport/diameter_tcp.erl
@@ -43,6 +43,7 @@
-export([listener/1,%% diameter_sync callback
info/1]). %% service_info callback
+%% test
-export([ports/0,
ports/1]).
@@ -450,16 +451,20 @@ sock(_, Sock) ->
resolve(Type, S) ->
Sock = sock(Type, S),
try
- ok(portnr(Sock))
+ {ok, T} = portnr(Sock),
+ T
catch
_:_ -> Sock
end.
-portnr(Sock)
- when is_port(Sock) ->
- portnr(gen_tcp, Sock);
+%% Assume either ssl or gen_tcp. In particular, this can't deal with a
+%% transport module that called start/3 with an own module option.
portnr(Sock) ->
- portnr(ssl, Sock).
+ try
+ {ok, _} = portnr(ssl, Sock)
+ catch
+ _:_ -> portnr(gen_tcp, Sock)
+ end.
%% ---------------------------------------------------------------------------
%% # handle_call/3
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index b537292834..3ae0f8eaf8 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -91,8 +91,6 @@ info:
@echo ========================================
@$(call list,MODULES)
@echo
- @$(call list,HRL_FILES)
- @echo
@$(call list,SUITES)
@echo
@echo erl = $(shell which erl)
@@ -116,6 +114,7 @@ help:
@echo
@echo " $(SUITES):"
@echo " Compile and run a specific test suite."
+ @echo " Prefix with _ to run without common_test."
@echo
@echo " clean | realclean:"
@echo " Remove generated files."
@@ -142,6 +141,14 @@ $(SUITES): log opt
| awk '{print} / FAILED /{rc=1} END{exit rc}' rc=0
# Shorter in sed but requires a GNU extension (ie. Q).
+# Run suites without common_test.
+$(SUITES:%=_%): opt
+ $(ERL) -noinput \
+ -pa ../ebin \
+ -sname diameter_test_$@ \
+ -s diameter$@_SUITE run \
+ -s init stop
+
cover: log opt coverspec
$(ERL) -noinput \
-pa $(realpath ../ebin) \
@@ -173,7 +180,6 @@ release_tests_spec:
$(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(TEST_SPEC_FILE) \
$(COVER_SPEC_FILE) \
- $(HRL_FILES) \
"$(RELSYSDIR)"
$(MAKE) $(DATA_DIRS:%/=release_data_%)
$(MAKE) $(ERL_FILES:%=/%)
diff --git a/lib/diameter/test/diameter.spec b/lib/diameter/test/diameter.spec
index fae7863bec..be62bb7f2b 100644
--- a/lib/diameter/test/diameter.spec
+++ b/lib/diameter/test/diameter.spec
@@ -1 +1,2 @@
{suites, "../diameter_test", all}.
+{skip_suites, "../diameter_test", [diameter_gen_sctp_SUITE], "Fails due to suspect gen_sctp behaviour."}.
diff --git a/lib/diameter/test/diameter_3xxx_SUITE.erl b/lib/diameter/test/diameter_3xxx_SUITE.erl
index 0f060c4ba7..63de2467a3 100644
--- a/lib/diameter/test/diameter_3xxx_SUITE.erl
+++ b/lib/diameter/test/diameter_3xxx_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,19 +26,17 @@
-module(diameter_3xxx_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_group/2,
- end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2]).
-
-%% testcases
--export([start/1,
- send_unknown_application/1,
+ traffic/1]).
+
+%% internal
+-export([send_unknown_application/1,
send_unknown_command/1,
send_ok/1,
send_invalid_hdr_bits/1,
@@ -47,9 +45,7 @@
send_5xxx_missing_avp/1,
send_double_error/1,
send_3xxx/1,
- send_5xxx/1,
- counters/1,
- stop/1]).
+ send_5xxx/1]).
%% diameter callbacks
-export([peer_up/3,
@@ -67,11 +63,7 @@
%% ===========================================================================
-define(util, diameter_util).
--define(testcase(), proplists:get_value(testcase, get(?MODULE))).
--define(group(Config), begin
- put(?MODULE, Config),
- ?util:name(proplists:get_value(group, Config))
- end).
+-define(testcase(), get(?MODULE)).
-define(L, atom_to_list).
-define(A, list_to_atom).
@@ -106,34 +98,15 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 90}}].
all() ->
- [{group, ?util:name([E,D])} || E <- ?ERRORS, D <- ?RFCS].
-
-groups() ->
- Tc = tc(),
- [{?util:name([E,D]), [], [start] ++ Tc ++ [counters, stop]}
- || E <- ?ERRORS, D <- ?RFCS].
-
-init_per_suite(Config) ->
- ok = diameter:start(),
- Config.
+ [traffic].
-end_per_suite(_Config) ->
- ok = diameter:stop().
+traffic(_Config) ->
+ run().
-init_per_group(Group, Config) ->
- [{group, Group} | Config].
-
-end_per_group(_, _) ->
- ok.
-
-init_per_testcase(Name, Config) ->
- [{testcase, Name} | Config].
-
-end_per_testcase(_, _) ->
- ok.
+%% ===========================================================================
tc() ->
[send_unknown_application,
@@ -147,25 +120,36 @@ tc() ->
send_3xxx,
send_5xxx].
-%% ===========================================================================
+%% run/0
+
+run() ->
+ ?util:run([[{{?MODULE, run, [{E,D}]}, 60000} || E <- ?ERRORS,
+ D <- ?RFCS]]).
+
+%% run/1
-%% start/1
+run({F, [_,_] = G}) ->
+ put(?MODULE, F),
+ apply(?MODULE, F, [G]);
-start(Config) ->
- Group = proplists:get_value(group, Config),
- [Errors, RFC] = ?util:name(Group),
- ok = diameter:start_service(?SERVER, ?SERVICE(?L(Group),
- Errors,
- RFC)),
+run({E,D}) ->
+ try
+ run([E,D])
+ after
+ ok = diameter:stop()
+ end;
+
+run([Errors, RFC] = G) ->
+ Name = ?L(Errors) ++ "," ++ ?L(RFC),
+ ok = diameter:start(),
+ ok = diameter:start_service(?SERVER, ?SERVICE(Name, Errors, RFC)),
ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT,
callback,
rfc6733)),
LRef = ?util:listen(?SERVER, tcp),
- ?util:connect(?CLIENT, tcp, LRef).
-
-%% stop/1
-
-stop(_Config) ->
+ ?util:connect(?CLIENT, tcp, LRef),
+ ?util:run([{?MODULE, run, [{F,G}]} || F <- tc()]),
+ _ = counters(G),
ok = diameter:remove_transport(?CLIENT, true),
ok = diameter:remove_transport(?SERVER, true),
ok = diameter:stop_service(?SERVER),
@@ -175,9 +159,7 @@ stop(_Config) ->
%%
%% Check that counters are as expected.
-counters(Config) ->
- Group = proplists:get_value(group, Config),
- [_Errors, _Rfc] = G = ?util:name(Group),
+counters([_Errors, _RFC] = G) ->
[] = ?util:run([[fun counters/3, K, S, G]
|| K <- [statistics, transport, connections],
S <- [?CLIENT, ?SERVER]]).
@@ -379,10 +361,7 @@ send_unknown_application([_,_]) ->
%% UNSUPPORTED_APPLICATION
'Failed-AVP' = [],
'AVP' = []}
- = call();
-
-send_unknown_application(Config) ->
- send_unknown_application(?group(Config)).
+ = call().
%% send_unknown_command/1
%%
@@ -398,10 +377,7 @@ send_unknown_command([_,_]) ->
%% UNSUPPORTED_COMMAND
'Failed-AVP' = [],
'AVP' = []}
- = call();
-
-send_unknown_command(Config) ->
- send_unknown_command(?group(Config)).
+ = call().
%% send_ok/1
%%
@@ -412,10 +388,7 @@ send_ok([_,_]) ->
#diameter_base_STA{'Result-Code' = 5002, %% UNKNOWN_SESSION_ID
'Failed-AVP' = [],
'AVP' = []}
- = call();
-
-send_ok(Config) ->
- send_ok(?group(Config)).
+ = call().
%% send_invalid_hdr_bits/1
%%
@@ -433,10 +406,7 @@ send_invalid_hdr_bits([_,_]) ->
#'diameter_base_answer-message'{'Result-Code' = 3008, %% INVALID_HDR_BITS
'Failed-AVP' = [],
'AVP' = []}
- = call();
-
-send_invalid_hdr_bits(Config) ->
- send_invalid_hdr_bits(?group(Config)).
+ = call().
%% send_missing_avp/1
%%
@@ -454,10 +424,7 @@ send_missing_avp([_,_]) ->
#diameter_base_STA{'Result-Code' = 5005, %% MISSING_AVP
'Failed-AVP' = [_],
'AVP' = []}
- = call();
-
-send_missing_avp(Config) ->
- send_missing_avp(?group(Config)).
+ = call().
%% send_ignore_missing_avp/1
%%
@@ -475,10 +442,7 @@ send_ignore_missing_avp([_,_]) ->
#diameter_base_STA{'Result-Code' = 2001, %% SUCCESS
'Failed-AVP' = [],
'AVP' = []}
- = call();
-
-send_ignore_missing_avp(Config) ->
- send_ignore_missing_avp(?group(Config)).
+ = call().
%% send_5xxx_missing_avp/1
%%
@@ -501,10 +465,7 @@ send_5xxx_missing_avp([_,_]) ->
#diameter_base_STA{'Result-Code' = 2001, %% SUCCESS
'Failed-AVP' = [],
'AVP' = []}
- = call();
-
-send_5xxx_missing_avp(Config) ->
- send_5xxx_missing_avp(?group(Config)).
+ = call().
%% send_double_error/1
%%
@@ -522,10 +483,7 @@ send_double_error([_,_]) ->
#'diameter_base_answer-message'{'Result-Code' = 3008, %% INVALID_HDR_BITS
'Failed-AVP' = [],
'AVP' = []}
- = call();
-
-send_double_error(Config) ->
- send_double_error(?group(Config)).
+ = call().
%% send_3xxx/1
%%
@@ -536,10 +494,7 @@ send_3xxx([_,_]) ->
#'diameter_base_answer-message'{'Result-Code' = 3999,
'Failed-AVP' = [],
'AVP' = []}
- = call();
-
-send_3xxx(Config) ->
- send_3xxx(?group(Config)).
+ = call().
%% send_5xxx/1
%%
@@ -555,10 +510,7 @@ send_5xxx([_,_]) ->
#'diameter_base_answer-message'{'Result-Code' = 5999,
'Failed-AVP' = [],
'AVP' = []}
- = call();
-
-send_5xxx(Config) ->
- send_5xxx(?group(Config)).
+ = call().
%% ===========================================================================
diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl
index ef4a28d3f4..0211ab1982 100644
--- a/lib/diameter/test/diameter_app_SUITE.erl
+++ b/lib/diameter/test/diameter_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,22 +24,24 @@
-module(diameter_app_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
- all/0,
- init_per_suite/1,
- end_per_suite/1]).
+ all/0]).
%% testcases
-export([keys/1,
vsn/1,
- modules/1,
- exports/1,
+ modules/1,
+ exports/1,
release/1,
- xref/1,
+ xref/1,
relup/1]).
--include("diameter_ct.hrl").
-
+-define(util, diameter_util).
-define(A, list_to_atom).
%% Modules not in the app and that should not have dependencies on it
@@ -57,7 +59,7 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 20}}].
all() ->
[keys,
@@ -68,12 +70,22 @@ all() ->
xref,
relup].
-init_per_suite(Config) ->
- [{application, ?APP, App}] = diameter_util:consult(?APP, app),
- [{app, App} | Config].
+%% ===========================================================================
+
+run() ->
+ run(all()).
+
+run(List) ->
+ Tmp = ?util:mktemp(filename:join(?util:tmpdir(), "diameter_app")),
+ try
+ run([{priv_dir, Tmp}], List)
+ after
+ file:del_dir_r(Tmp)
+ end.
-end_per_suite(_Config) ->
- ok.
+run(Config, List) ->
+ [{application, diameter, App}] = ?util:consult(diameter, app),
+ ?util:run([{{?MODULE, F, [{App, Config}]}, 10000} || F <- List]).
%% ===========================================================================
%% # keys/1
@@ -82,10 +94,12 @@ end_per_suite(_Config) ->
%% also be caught by other testcases.
%% ===========================================================================
-keys(Config) ->
- App = fetch(app, Config),
+keys({App, _Config}) ->
[] = lists:filter(fun(K) -> not lists:keymember(K, 1, App) end,
- [vsn, description, modules, registered, applications]).
+ [vsn, description, modules, registered, applications]);
+
+keys(Config) ->
+ run(Config, [keys]).
%% ===========================================================================
%% # vsn/1
@@ -93,8 +107,11 @@ keys(Config) ->
%% Ensure that our app version sticks to convention.
%% ===========================================================================
+vsn({App, _Config}) ->
+ true = is_vsn(fetch(vsn, App));
+
vsn(Config) ->
- true = is_vsn(fetch(vsn, fetch(app, Config))).
+ run(Config, [vsn]).
%% ===========================================================================
%% # modules/1
@@ -103,15 +120,17 @@ vsn(Config) ->
%% compiler/info modules.
%% ===========================================================================
-modules(Config) ->
- Mods = fetch(modules, fetch(app, Config)),
+modules({App, _Config}) ->
+ Mods = fetch(modules, App),
Installed = code_mods(),
Help = lists:sort(?INFO_MODULES ++ ?COMPILER_MODULES),
+ {[], Help} = {Mods -- Installed, lists:sort(Installed -- Mods)};
- {[], Help} = {Mods -- Installed, lists:sort(Installed -- Mods)}.
+modules(Config) ->
+ run(Config, [modules]).
code_mods() ->
- Dir = code:lib_dir(?APP, ebin),
+ Dir = code:lib_dir(diameter, ebin),
{ok, Files} = file:list_dir(Dir),
[?A(lists:reverse(R)) || N <- Files, "maeb." ++ R <- [lists:reverse(N)]].
@@ -121,9 +140,12 @@ code_mods() ->
%% Ensure that no module does export_all.
%% ===========================================================================
+exports({App, _Config}) ->
+ Mods = fetch(modules, App),
+ [] = [M || M <- Mods, exports_all(M)];
+
exports(Config) ->
- Mods = fetch(modules, fetch(app, Config)),
- [] = [M || M <- Mods, exports_all(M)].
+ run(Config, [exports]).
exports_all(Mod) ->
Opts = fetch(options, Mod:module_info(compile)),
@@ -136,8 +158,7 @@ exports_all(Mod) ->
%% Ensure that it's possible to build a minimal release with our app file.
%% ===========================================================================
-release(Config) ->
- App = fetch(app, Config),
+release({App, Config}) ->
Rel = {release,
{"diameter test release", fetch(vsn, App)},
{erts, erlang:system_info(version)},
@@ -146,13 +167,16 @@ release(Config) ->
ok = write_file(filename:join([Dir, "diameter_test.rel"]), Rel),
{ok, _, []} = systools:make_script("diameter_test", [{path, [Dir]},
{outdir, Dir},
- silent]).
+ silent]);
+
+release(Config) ->
+ run(Config, [release]).
%% sasl need to be included to avoid a missing_sasl warning, error
%% in the case of relup/1.
appvsn(Name) ->
- [{application, Name, App}] = diameter_util:consult(Name, app),
+ [{application, Name, App}] = ?util:consult(Name, app),
fetch(vsn, App).
%% ===========================================================================
@@ -162,8 +186,7 @@ appvsn(Name) ->
%% or one in an application we haven't declared as a dependency. (Almost.)
%% ===========================================================================
-xref(Config) ->
- App = fetch(app, Config),
+xref({App, _Config}) ->
Mods = fetch(modules, App), %% modules listed in the app file
%% List of application names extracted from runtime_dependencies.
@@ -179,7 +202,7 @@ xref(Config) ->
%% the sense that there's no .app file, and isn't listed in
%% applications.
ok = lists:foreach(fun(A) -> add_application(XRef, A) end,
- [?APP, erts | fetch(applications, App)]),
+ [diameter, erts | fetch(applications, App)]),
{ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
{ok, RTmods} = xref:analyze(XRef, {module_use, Mods}),
@@ -212,7 +235,10 @@ xref(Config) ->
%% The declared application versions are ignored since we only
%% know what we see now.
[] = lists:filter(fun(M) -> not lists:member(app(M), Deps) end,
- RTdeps -- Mods).
+ RTdeps -- Mods);
+
+xref(Config) ->
+ run(Config, [xref]).
ignored({FromMod,_,_}, {ToMod,_,_} = To, Rel)->
%% diameter_tcp does call ssl despite the latter not being listed
@@ -281,7 +307,7 @@ add_application(XRef, App, Dir)
{ok, App} = xref:add_application(XRef, Dir, []).
make_name(Suf) ->
- list_to_atom(atom_to_list(?APP) ++ "_" ++ atom_to_list(Suf)).
+ list_to_atom("diameter_" ++ atom_to_list(Suf)).
%% ===========================================================================
%% # relup/1
@@ -289,11 +315,10 @@ make_name(Suf) ->
%% Ensure that we can generate release upgrade files using our appup file.
%% ===========================================================================
-relup(Config) ->
- [{Vsn, Up, Down}] = diameter_util:consult(?APP, appup),
+relup({App, Config}) ->
+ [{Vsn, Up, Down}] = ?util:consult(diameter, appup),
true = is_vsn(Vsn),
- App = fetch(app, Config),
Rel = [{erts, erlang:system_info(version)}
| [{A, appvsn(A)} || A <- [sasl | fetch(applications, App)]]],
@@ -314,7 +339,10 @@ relup(Config) ->
{ok, _, _, []} = systools:make_relup(Name, UpFrom, DownTo, [{path, [Dir]},
{outdir, Dir},
- silent]).
+ silent]);
+
+relup(Config) ->
+ run(Config, [relup]).
acc_rel(Dir, Rel, List) ->
lists:foldl(fun(T,A) -> acc_rel(Dir, Rel, T, A) end,
diff --git a/lib/diameter/test/diameter_capx_SUITE.erl b/lib/diameter/test/diameter_capx_SUITE.erl
index 51b6c1d7f2..852450bc9f 100644
--- a/lib/diameter/test/diameter_capx_SUITE.erl
+++ b/lib/diameter/test/diameter_capx_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,39 +25,30 @@
-module(diameter_capx_SUITE).
+%% testcases, no common_test dependency
+-export([run/0]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_group/2,
- end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2]).
-
-%% testcases
--export([start/1,
- vendor_id/1,
- start_services/1,
- add_listeners/1,
- s_no_common_application/1,
- c_no_common_application/1,
- s_no_common_security/1,
- c_no_common_security/1,
- s_unknown_peer/1,
- c_unknown_peer/1,
- s_unable/1,
- c_unable/1,
- s_client_reject/1,
- c_client_reject/1,
- remove_listeners/1,
- stop_services/1,
- stop/1]).
+ traffic/1]).
%% diameter callbacks
-export([peer_up/4,
peer_down/4]).
+%% internal
+-export([s_no_common_application/1,
+ s_no_common_security/1,
+ s_unknown_peer/1,
+ s_unable/1,
+ s_client_reject/1,
+ c_no_common_application/1,
+ c_no_common_security/1,
+ c_unknown_peer/1,
+ c_unable/1,
+ c_client_reject/1]).
+
-include("diameter.hrl").
-include("diameter_gen_base_rfc3588.hrl").
%% Use only the Vendor-Specific-Application-Id record from the base
@@ -108,7 +99,7 @@
-define(caps, #diameter_caps).
-define(packet, #diameter_packet).
--define(fail(T), erlang:error({T, process_info(self(), messages)})).
+-define(fail(T), error({T, process_info(self(), messages)})).
-define(TIMEOUT, 10000).
@@ -117,56 +108,15 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
-
-all() -> [start,
- vendor_id,
- start_services,
- add_listeners]
- ++ [{group, D, P} || D <- ?DICTS, P <- [[], [parallel]]]
- ++ [remove_listeners,
- stop_services,
- stop].
-
-groups() ->
- Tc = lists:flatmap(fun tc/1, tc()),
- [{D, [], Tc} || D <- ?DICTS].
-
-init_per_suite(Config) ->
- lists:foreach(fun load_dict/1, ?NOAPPS),
- Config.
+ [{timetrap, {seconds, 20}}].
-end_per_suite(_Config) ->
- [] = [Mod || N <- ?NOAPPS,
- Mod <- [dict(N)],
- false <- [code:delete(Mod)]],
- ok.
-
-%% Generate a unique hostname for each testcase so that watchdogs
-%% don't prevent a connection from being brought up immediately.
-init_per_testcase(Name, Config) ->
- [{host, ?L(Name) ++ "." ++ diameter_util:unique_string()}
- | Config].
-
-init_per_group(Name, Config) ->
- [{rfc, Name} | Config].
+all() ->
+ [traffic].
-end_per_group(_, _) ->
- ok.
+traffic(_Config) ->
+ run().
-end_per_testcase(N, _)
- when N == start;
- N == vendor_id;
- N == start_services;
- N == add_listeners;
- N == remove_listeners;
- N == stop_services;
- N == stop ->
- ok;
-
-end_per_testcase(Name, Config) ->
- CRef = ?util:read_priv(Config, Name),
- ok = diameter:remove_transport(?CLIENT, CRef).
+%% ===========================================================================
%% Testcases all come in two flavours, client and server.
tc(Name) ->
@@ -179,17 +129,46 @@ tc() ->
unable,
client_reject].
-%% ===========================================================================
-%% start/stop testcases
+run() ->
+ try
+ ?util:run([{fun traffic/0, 15000}])
+ after
+ ok = diameter:stop(),
+ [] = [M || N <- ?NOAPPS,
+ M <- [dict(N)],
+ B <- [code:delete(M)],
+ _ <- [code:purge(M)],
+ not B]
+ end.
+
+traffic() ->
+ lists:foreach(fun load_dict/1, ?NOAPPS),
+ ok = diameter:start(),
+ _ = vendor_id(),
+ ok = diameter:start_service(?SERVER, ?SERVICE),
+ ok = diameter:start_service(?CLIENT, ?SERVICE),
+ LRefs = add_listeners(),
+ ?util:run([[fun traffic/3, F, D, LRefs] || D <- ?DICTS,
+ N <- tc(),
+ F <- tc(N)]),
+ ok = diameter:remove_transport(?SERVER, true),
+ ok = diameter:stop_service(?CLIENT),
+ ok = diameter:stop_service(?SERVER).
-start(_Config) ->
- ok = diameter:start().
+%% Generate a unique hostname for each testcase so that watchdogs
+%% don't prevent a connection from being brought up immediately.
+traffic(F, Dict, {_Base, _Acct} = LRefs) ->
+ apply(?MODULE,
+ F,
+ [[{lref, LRefs},
+ {rfc, Dict},
+ {host, ?L(F) ++ "." ++ ?util:unique_string()}]]).
%% Ensure that both integer and list-valued vendor id's can be
%% configured in a Vendor-Specific-Application-Id, the arity having
%% changed between RFC 3588 and RFC 6733.
-vendor_id(_Config) ->
- [] = ?util:run([[fun vid/1, V] || V <- [1, [1], [1,2], x]]).
+vendor_id() ->
+ ?util:run([[fun vid/1, V] || V <- [1, [1], [1,2], x]]).
vid(V) ->
RC = diameter:start_service(make_ref(),
@@ -203,14 +182,10 @@ vid(x, {error, _}) ->
vid(_, ok) ->
ok.
-start_services(_Config) ->
- ok = diameter:start_service(?SERVER, ?SERVICE),
- ok = diameter:start_service(?CLIENT, ?SERVICE).
-
%% One server that responds only to base accounting, one that responds
%% to both this and the common application. Share a common service just
%% to simplify config, and because we can.
-add_listeners(Config) ->
+add_listeners() ->
Acct = [listen(?SERVER,
[{capabilities, [{'Origin-Host', ?HOST(H)},
{'Auth-Application-Id', []}]},
@@ -224,17 +199,7 @@ add_listeners(Config) ->
{capabilities_cb, [fun server_capx/3, base]}])
|| {A,H} <- [{[base3588, acct3588], "base3588-srv"},
{[base6733, acct6733], "base6733-srv"}]],
- ?util:write_priv(Config, ?MODULE, {Base, Acct}). %% lref/2 reads
-
-remove_listeners(_Config) ->
- ok = diameter:remove_transport(?SERVER, true).
-
-stop_services(_Config) ->
- ok = diameter:stop_service(?CLIENT),
- ok = diameter:stop_service(?SERVER).
-
-stop(_Config) ->
- ok = diameter:stop().
+ {Base, Acct}.
%% ===========================================================================
%% All the testcases come in pairs, one for receiving an event on the
@@ -338,13 +303,10 @@ s_client_reject(Config) ->
receive
?event{service = ?SERVER,
info = {up, LRef,
- {_, ?caps{origin_host = {_, OH}}},
- {listen, _},
- ?packet{}}}
- = Info ->
- Info
- after ?TIMEOUT ->
- ?fail({LRef, OH})
+ {_, ?caps{origin_host = {_, OH}}},
+ {listen, _},
+ ?packet{}}} ->
+ ok
end.
c_client_reject(Config) ->
@@ -404,12 +366,9 @@ server_closed(Config, F, RC) ->
info = {closed, LRef,
{'CER', RC,
?caps{origin_host = {_, OH}},
- ?packet{}}
- = Reason,
+ ?packet{}},
{listen, _}}} ->
- Reason
- after ?TIMEOUT ->
- ?fail({LRef, OH})
+ ok
end.
%% server_reject/3
@@ -425,12 +384,9 @@ server_reject(Config, F, RC) ->
info = {closed, LRef,
{'CER', {capabilities_cb, _, RC},
?caps{origin_host = {_, OH}},
- ?packet{}}
- = Reason,
+ ?packet{}},
{listen, _}}} ->
- Reason
- after ?TIMEOUT ->
- ?fail({LRef, OH})
+ ok
end.
%% client_closed/4
@@ -459,8 +415,6 @@ client_recv(CRef) ->
?event{service = ?CLIENT,
info = {closed, CRef, Reason, {connect, _}}} ->
Reason
- after ?TIMEOUT ->
- ?fail(CRef)
end.
%% server_capx/3
@@ -504,20 +458,14 @@ listen(Name, Opts) ->
connect(Config, T, Opts) ->
{_, H} = lists:keyfind(host, 1, Config),
LRef = lref(Config, T),
- CRef = connect(LRef, [{capabilities, [{'Origin-Host', ?HOST(H)}]}
- | Opts]),
- Name = lists:takewhile(fun(C) -> C /= $. end, H),
- ?util:write_priv(Config, Name, CRef), %% end_per_testcase reads
- {CRef, LRef}.
-
-connect(LRef, Opts) ->
[PortNr] = ?util:lport(tcp, LRef),
- {ok, CRef} = diameter:add_transport(?CLIENT,
- {connect, opts(PortNr, Opts)}),
- CRef.
+ {ok, CRef}
+ = diameter:add_transport(?CLIENT, {connect, opts(H, PortNr, Opts)}),
+ {CRef, LRef}.
-opts(PortNr, Opts) ->
- [{transport_module, diameter_tcp},
+opts(Host, PortNr, Opts) ->
+ [{capabilities, [{'Origin-Host', ?HOST(Host)}]},
+ {transport_module, diameter_tcp},
{transport_config, [{raddr, ?ADDR},
{rport, PortNr},
{ip, ?ADDR},
@@ -531,7 +479,7 @@ lref(rfc6733, [_, LRef]) ->
lref(Config, T) ->
lref(proplists:get_value(rfc, Config),
- case ?util:read_priv(Config, ?MODULE) of
+ case proplists:get_value(lref, Config) of
{R, _} when T == base ->
R;
{_, R} when T == acct ->
diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl
index 17112794e4..ff8a031460 100644
--- a/lib/diameter/test/diameter_codec_SUITE.erl
+++ b/lib/diameter/test/diameter_codec_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,86 +28,110 @@
-module(diameter_codec_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_group/2,
- end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2]).
-
-%% testcases
--export([base/1,
+ base/1,
gen/1,
lib/1,
unknown/1,
- success/1,
- grouped_error/1,
- failed_error/1]).
+ recode/1]).
--include("diameter_ct.hrl").
-include("diameter.hrl").
+-define(util, diameter_util).
-define(L, atom_to_list).
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 10}}].
+ [{timetrap, {seconds, 15}}].
all() ->
- [base, gen, lib, unknown, {group, recode}].
+ [base, gen, lib, unknown, recode].
-groups() ->
- [{recode, [], [success,
- grouped_error,
- failed_error]}].
+base(_Config) ->
+ run(base).
-init_per_suite(Config) ->
- Config.
+gen(_Config) ->
+ run(gen).
-end_per_suite(_Config) ->
- ok.
+lib(_Config) ->
+ run(lib).
-init_per_group(recode, Config) ->
- ok = diameter:start(),
- Config.
+unknown(Config) ->
+ Priv = proplists:get_value(priv_dir, Config),
+ Data = proplists:get_value(data_dir, Config),
+ unknown(Priv, Data).
+
+recode(_Config) ->
+ run(recode).
+
+%% ===========================================================================
+
+%% run/0
+
+run() ->
+ run(all()).
+
+%% run/1
-end_per_group(_, _) ->
- ok = diameter:stop().
+run(base) ->
+ diameter_codec_test:base();
-init_per_testcase(gen, Config) ->
- [{application, ?APP, App}] = diameter_util:consult(?APP, app),
+run(gen) ->
+ [{application, diameter, App}] = diameter_util:consult(diameter, app),
{modules, Ms} = lists:keyfind(modules, 1, App),
[_|_] = Gs = lists:filter(fun(M) ->
lists:prefix("diameter_gen_", ?L(M))
end,
Ms),
- [{dicts, Gs} | Config];
+ lists:foreach(fun diameter_codec_test:gen/1, Gs);
-init_per_testcase(_Name, Config) ->
- Config.
+run(lib) ->
+ diameter_codec_test:lib();
-end_per_testcase(_, _) ->
- ok.
-
-%% ===========================================================================
-
-base(_Config) ->
- diameter_codec_test:base().
+%% Have a separate AVP dictionary just to exercise more code.
+run(unknown) ->
+ PD = ?util:mktemp(filename:join(?util:tmpdir(), "diameter_codec")),
+ DD = filename:join([code:lib_dir(diameter),
+ "test",
+ "diameter_codec_SUITE_data"]),
+ try
+ unknown(PD, DD)
+ after
+ file:del_dir_r(PD)
+ end;
+
+run(success) ->
+ success();
+
+run(grouped_error) ->
+ grouped_error();
+
+run(failed_error) ->
+ failed_error();
+
+run(recode) ->
+ ok = diameter:start(),
+ try
+ ?util:run([{?MODULE, run, [F]} || F <- [success,
+ grouped_error,
+ failed_error]])
+ after
+ ok = diameter:stop()
+ end;
-gen([{dicts, Ms} | _]) ->
- lists:foreach(fun diameter_codec_test:gen/1, Ms).
+run(List) ->
+ ?util:run([{{?MODULE, run, [F]}, 10000} || F <- List]).
-lib(_Config) ->
- diameter_codec_test:lib().
+%% ===========================================================================
-%% Have a separate AVP dictionary just to exercise more code.
-unknown(Config) ->
- Priv = proplists:get_value(priv_dir, Config),
- Data = proplists:get_value(data_dir, Config),
+unknown(Priv, Data) ->
ok = make(Data, "recv.dia"),
ok = make(Data, "avps.dia"),
{ok, _, _} = compile("diameter_test_avps.erl"),
@@ -130,7 +154,7 @@ compile(File, Opts) ->
%% ===========================================================================
%% Ensure a Grouped AVP is represented by a list in the avps field.
-success(_) ->
+success() ->
Avps = [{295, <<1:32>>}, %% Termination-Cause
{284, [{280, "Proxy-Host"}, %% Proxy-Info
{33, "Proxy-State"}, %%
@@ -145,13 +169,13 @@ success(_) ->
value = 2,
data = <<2:32>>}]],
errors = []}
- = str(recode(str(Avps))).
+ = str(repkg(str(Avps))).
%% ===========================================================================
%% Ensure a Grouped AVP is represented by a list in the avps field
%% even in the case of a decode error on a component AVP.
-grouped_error(_) ->
+grouped_error() ->
Avps = [{295, <<1:32>>}, %% Termination-Cause
{284, [{295, <<0:32>>}, %% Proxy-Info, Termination-Cause
{280, "Proxy-Host"},
@@ -166,13 +190,13 @@ grouped_error(_) ->
#diameter_avp{code = 280},
#diameter_avp{code = 33}]],
errors = [{5004, #diameter_avp{code = 284}}]}
- = str(recode(str(Avps))).
+ = str(repkg(str(Avps))).
%% ===========================================================================
%% Ensure that a failed decode in Failed-AVP is acceptable, and that
%% the component AVPs are decoded if possible.
-failed_error(_) ->
+failed_error() ->
Avps = [{279, [{295, <<0:32>>}, %% Failed-AVP, Termination-Cause
{258, <<1:32>>}, %% Auth-Application-Id
{284, [{280, "Proxy-Host"}, %% Proxy-Info
@@ -195,7 +219,7 @@ failed_error(_) ->
value = 2,
data = <<2:32>>}]]],
errors = []}
- = sta(recode(sta(Avps))).
+ = sta(repkg(sta(Avps))).
%% ===========================================================================
@@ -279,9 +303,9 @@ avp([{_,_} | _] = Avps) ->
avp(V) ->
V.
-%% recode/1
+%% repkg/1
-recode(Msg) ->
+repkg(Msg) ->
recode(Msg, diameter_gen_base_rfc6733).
recode(#diameter_packet{} = Pkt, Dict) ->
diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl
index 73fe1ef6e0..a33da0f64e 100644
--- a/lib/diameter/test/diameter_compiler_SUITE.erl
+++ b/lib/diameter/test/diameter_compiler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,16 +24,17 @@
-module(diameter_compiler_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- init_per_suite/1,
- end_per_suite/1]).
-
-%% testcases
--export([format/1, format/2,
- replace/1, replace/2,
- generate/1, generate/4,
- flatten1/1, flatten1/3,
+ format/1,
+ replace/1,
+ generate/1,
+ flatten1/1,
flatten2/1]).
-export([dict/0]). %% fake dictionary module
@@ -364,7 +365,7 @@
%% ===========================================================================
suite() ->
- [{timetrap, {minutes, 10}}].
+ [{timetrap, {seconds, 45}}].
all() ->
[format,
@@ -373,33 +374,37 @@ all() ->
flatten1,
flatten2].
-%% Error handling testcases will make an erroneous dictionary out of
-%% the base dictionary and check that the expected error results.
-%% ?REPLACE encodes the modifications and expected error.
-init_per_suite(Config) ->
+%% ===========================================================================
+
+%% run/0
+
+run() ->
+ run(all()).
+
+%% run/1
+
+run(List) ->
Path = filename:join([code:lib_dir(diameter, src), "dict", ?base]),
{ok, Bin} = file:read_file(Path),
- [{base, Bin} | Config].
-
-end_per_suite(_Config) ->
- ok.
+ ?util:run([{{?MODULE, F, [Bin]}, 30000} || F <- List]).
%% ===========================================================================
%% format/1
%%
%% Ensure that parse o format is the identity map.
-format(Config) ->
- Bin = proplists:get_value(base, Config),
- [] = ?util:run([{?MODULE, [format, M, Bin]}
- || E <- ?REPLACE,
- {ok, M} <- [norm(E)]]).
+format(<<_/binary>> = Bin) ->
+ ?util:run([{?MODULE, format, [{M, Bin}]} || E <- ?REPLACE,
+ {ok, M} <- [norm(E)]]);
-format(Mods, Bin) ->
+format({Mods, Bin}) ->
B = modify(Bin, Mods),
{ok, Dict} = parse(B, []),
{ok, D} = parse(diameter_make:format(Dict), []),
- {Dict, Dict} = {Dict, D}.
+ {Dict, Dict} = {Dict, D};
+
+format(_Config) ->
+ run([format]).
parse(File, Opts) ->
case diameter_make:codec(File, [parse, hrl, return | Opts]) of
@@ -415,20 +420,21 @@ parse(File, Opts) ->
%% Ensure the expected success/error when parsing a morphed common
%% dictionary.
-replace(Config) ->
- Bin = proplists:get_value(base, Config),
- [] = ?util:run([{?MODULE, [replace, N, Bin]}
- || E <- ?REPLACE,
- N <- [norm(E)]]).
+replace(<<_/binary>> = Bin) ->
+ ?util:run([{?MODULE, replace, [{N, Bin}]} || E <- ?REPLACE,
+ N <- [norm(E)]]);
-replace({E, Mods}, Bin) ->
+replace({{E, Mods}, Bin}) ->
B = modify(Bin, Mods),
case {E, parse(B, [{include, here()}]), Mods} of
{ok, {ok, Dict}, _} ->
Dict;
{_, {error, {E,_} = T}, _} when E /= ok ->
diameter_make:format_error(T)
- end.
+ end;
+
+replace(_Config) ->
+ run([replace]).
re({RE, Repl}, Bin) ->
re:replace(Bin, RE, Repl, [multiline]).
@@ -438,15 +444,14 @@ re({RE, Repl}, Bin) ->
%%
%% Ensure success when generating code and compiling.
-generate(Config) ->
- Bin = proplists:get_value(base, Config),
+generate(<<_/binary>> = Bin) ->
Rs = lists:zip(?REPLACE, lists:seq(1, length(?REPLACE))),
- [] = ?util:run([{?MODULE, [generate, M, Bin, N, T]}
- || {E,N} <- Rs,
- {ok, M} <- [norm(E)],
- T <- [erl, hrl, parse, forms]]).
+ ?util:run([{?MODULE, generate, [{M, Bin, N, T}]}
+ || {E,N} <- Rs,
+ {ok, M} <- [norm(E)],
+ T <- [erl, hrl, parse, forms]]);
-generate(Mods, Bin, N, Mode) ->
+generate({Mods, Bin, N, Mode}) ->
B = modify(Bin, Mods ++ [{"@name .*", "@name dict" ++ ?L(N)}]),
{ok, Dict} = parse(B, []),
File = "dict" ++ integer_to_list(N),
@@ -454,7 +459,10 @@ generate(Mods, Bin, N, Mode) ->
[{name, File},
{prefix, "base"},
Mode])},
- generate(Mode, File, Dict).
+ generate(Mode, File, Dict);
+
+generate(_Config) ->
+ run([generate]).
generate(erl, File, _) ->
{ok, _} = compile:file(File ++ ".erl", [return_errors]);
@@ -473,21 +481,21 @@ generate(hrl, _, _) ->
%% ===========================================================================
%% flatten1/1
-flatten1(_Config) ->
+flatten1({Key, BaseD, FlatD}) ->
+ Vs = orddict:fetch(Key, BaseD),
+ Vs = orddict:fetch(Key, FlatD);
+
+flatten1(_) ->
[Vsn | BaseD] = diameter_gen_base_rfc6733:dict(),
{ok, I} = parse("@inherits diameter_gen_base_rfc6733\n", []),
[Vsn | FlatD] = diameter_make:flatten(I),
- [] = ?util:run([{?MODULE, [flatten1, K, BaseD, FlatD]}
- || K <- [avp_types, grouped, enum]]).
-
-flatten1(Key, BaseD, FlatD) ->
- Vs = orddict:fetch(Key, BaseD),
- Vs = orddict:fetch(Key, FlatD).
+ ?util:run([{?MODULE, flatten1, [{K, BaseD, FlatD}]}
+ || K <- [avp_types, grouped, enum]]).
%% ===========================================================================
%% flatten2/1
-flatten2(_Config) ->
+flatten2(_) ->
Dict1 =
"@name diameter_test1\n"
"@prefix diameter_test1\n"
diff --git a/lib/diameter/test/diameter_config_SUITE.erl b/lib/diameter/test/diameter_config_SUITE.erl
index 31a6b49041..90773e8f6d 100644
--- a/lib/diameter/test/diameter_config_SUITE.erl
+++ b/lib/diameter/test/diameter_config_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,14 +25,15 @@
-module(diameter_config_SUITE).
--export([suite/0,
- all/0]).
+%% testscases, no common_test dependency
+-export([run/0,
+ run/1]).
-%% testcases
--export([start/1,
+%% common_test wrapping
+-export([suite/0,
+ all/0,
start_service/1,
- add_transport/1,
- stop/1]).
+ add_transport/1]).
-define(util, diameter_util).
@@ -204,38 +205,53 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 15}}].
all() ->
- [start,
- start_service,
- add_transport,
- stop].
+ [start_service,
+ add_transport].
+
+start_service(_Config) ->
+ run([start_service]).
+
+add_transport(_Config) ->
+ run([add_transport]).
%% ===========================================================================
-start(_) ->
- ok = diameter:start().
+run() ->
+ run(all()).
-start_service(T)
- when is_tuple(T) ->
- do(fun start/3, T);
+run(List)
+ when is_list(List) ->
+ try
+ ?util:run([[[fun run/1, {F, 5000}] || F <- List]])
+ after
+ dbg:stop_clear(),
+ diameter:stop()
+ end;
+
+run({F, Tmo}) ->
+ ok = diameter:start(),
+ try
+ ?util:run([{[fun run/1, F], Tmo}])
+ after
+ ok = diameter:stop()
+ end;
-start_service(_) ->
- [] = ?util:run([{?MODULE, start_service, [T]}
- || T <- [lists:keyfind(capabilities, 1, ?TRANSPORT_CONFIG)
- | ?SERVICE_CONFIG]]).
+run(start_service) ->
+ ?util:run([[fun start/1, T]
+ || T <- [lists:keyfind(capabilities, 1, ?TRANSPORT_CONFIG)
+ | ?SERVICE_CONFIG]]);
-add_transport(T)
- when is_tuple(T) ->
- do(fun add/3, T);
+run(add_transport) ->
+ ?util:run([[fun add/1, T] || T <- ?TRANSPORT_CONFIG]).
-add_transport(_) ->
- [] = ?util:run([{?MODULE, add_transport, [T]}
- || T <- ?TRANSPORT_CONFIG]).
+start(T) ->
+ do(fun start/3, T).
-stop(_) ->
- ok = diameter:stop().
+add(T) ->
+ do(fun add/3, T).
%% ===========================================================================
diff --git a/lib/diameter/test/diameter_ct.hrl b/lib/diameter/test/diameter_ct.hrl
deleted file mode 100644
index fdf8782456..0000000000
--- a/lib/diameter/test/diameter_ct.hrl
+++ /dev/null
@@ -1,22 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--define(APP, diameter).
--define(ERROR(T), erlang:error({?MODULE, ?LINE, T})).
diff --git a/lib/diameter/test/diameter_dist_SUITE.erl b/lib/diameter/test/diameter_dist_SUITE.erl
index aa2141d744..7c66a711c8 100644
--- a/lib/diameter/test/diameter_dist_SUITE.erl
+++ b/lib/diameter/test/diameter_dist_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2019-2021. All Rights Reserved.
+%% Copyright Ericsson AB 2019-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,15 +25,13 @@
-module(diameter_dist_SUITE).
--export([
- suite/0,
- all/0,
- init_per_suite/1,
- end_per_suite/1
-]).
+%% all tests, no common_test dependency
+-export([run/0]).
-%% testcases
--export([send/1]).
+%% common_test wrapping
+-export([suite/0,
+ all/0,
+ traffic/1]).
%% diameter callbacks
-export([peer_up/3,
@@ -45,61 +43,210 @@
handle_error/4,
handle_request/3]).
-%% Internal export for RPC
--export([start_server/5, start_client/6]).
+%% rpc calls
+-export([start/1,
+ call/1,
+ connect/1,
+ ping/1]).
-include("diameter.hrl").
-include("diameter_gen_base_rfc6733.hrl").
--include_lib("common_test/include/ct.hrl").
-
%% ===========================================================================
+-define(util, diameter_util).
+
-define(CLIENT, 'CLIENT').
-define(SERVER, 'SERVER').
-define(REALM, "erlang.org").
-define(DICT, diameter_gen_base_rfc6733).
-define(ADDR, {127,0,0,1}).
+
+%% Config for diameter:start_service/2.
+-define(SERVICE(Host),
+ [{'Origin-Host', Host ++ [$.|?REALM]},
+ {'Origin-Realm', ?REALM},
+ {'Host-IP-Address', [?ADDR]},
+ {'Vendor-Id', 12345},
+ {'Product-Name', "OTP/diameter"},
+ {'Auth-Application-Id', [?DICT:id()]},
+ {'Origin-State-Id', origin()},
+ {spawn_opt, {diameter_dist, route_session, [#{id => []}]}},
+ {sequence, fun sequence/0},
+ {string_decode, false},
+ {application, [{dictionary, ?DICT},
+ {module, ?MODULE},
+ {request_errors, callback},
+ {answer_errors, callback}]}]).
+
-define(SUCCESS, 2001).
-define(BUSY, 3004).
-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT').
-define(MOVED, ?'DIAMETER_BASE_TERMINATION-CAUSE_USER_MOVED').
-define(TIMEOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_SESSION_TIMEOUT').
+-define(L, atom_to_list).
+-define(A, list_to_atom).
+
+%% The order here is significant and causes the server to listen
+%% before the clients connect. The server listens on the first node,
+%% and distributes requests to the other two.
+-define(NODES, [{server0, ?SERVER},
+ {server1, ?SERVER},
+ {server2, ?SERVER},
+ {client, ?CLIENT}]).
+
%% ===========================================================================
+%% common_test wrapping
suite() ->
- [{timetrap, {seconds, 30}}].
+ [{timetrap, {seconds, 90}}].
all() ->
- [send].
-
-init_per_suite(Config) ->
- {ok, ServerPeer, ServerNode} = ?CT_PEER(),
- ListenPort = erpc:call(ServerNode, ?MODULE, start_server, [?SERVER, "server0", 0, 0, 30]),
- %% Distributed workers
- Peer1 = start_worker(?SERVER),
- Peer2 = start_worker(?SERVER),
- %% Diameter client
- {ok, ClientPeer, ClientNode} = ?CT_PEER(),
- ok = erpc:call(ClientNode, ?MODULE, start_client, [?CLIENT, ListenPort, "client", 99, 0, 32]),
- %% unlink peers, assuming end_per_suite is executed reliably
- Peers = [ServerPeer, Peer1, Peer2, ClientPeer],
- [unlink(P) || P <- Peers],
- [{server, ServerNode}, {client, ClientNode}, {peers, Peers} | Config].
-
-end_per_suite(Config) ->
- [peer:stop(P) || P <- proplists:get_value(peers, Config)].
-
-%% Basic test
-send(Config) when is_list(Config) ->
- ServerNode = proplists:get_value(server, Config),
- ClientNode = proplists:get_value(client, Config),
- %% Send 100 requests and ensure the node name sent as User-Name isn't
- %% the node terminating transport.
- send(ServerNode, ClientNode, 100, dict:new()).
-
-send(Server0, _Client, 0, Dict) ->
+ [traffic].
+
+traffic(_Config) ->
+ run().
+
+%% ===========================================================================
+
+%% run/0
+
+run() ->
+ [] = ?util:run([{fun traffic/0, 60000}]).
+ %% process for linked peers to die with
+
+%% traffic/0
+
+traffic() ->
+ true = is_alive(), %% need distribution for peer nodes
+ Nodes = enslave(),
+ [] = ping(lists:droplast(Nodes)), %% drop client node
+ [] = start(Nodes),
+ ok = connect(Nodes),
+ ok = send(Nodes).
+
+%% enslave/1
+%%
+%% Start four slave nodes, three to implement a Diameter server,
+%% one to implement a client.
+
+enslave() ->
+ Here = filename:dirname(code:which(?MODULE)),
+ Ebin = filename:join([Here, "..", "ebin"]),
+ Dirs = [Here, Ebin],
+ Args = [["-pa" | [lists:flatten(io_lib:format("~s", [D])) || D <- Dirs]],
+ ["-setcookie", ?L(erlang:get_cookie())]],
+ [{N,S} || A <- [lists:append(Args)],
+ {M,S} <- ?NODES,
+ N <- [start(M, A)]].
+
+start(Name, Args) ->
+ {ok, _, Node} = peer:start_link(#{name => Name, args => Args}),
+ Node.
+
+%% ping/1
+%%
+%% Ensure the server nodes are connected so that diameter_dist can attach.
+
+ping({S, Nodes}) ->
+ ?SERVER = S, %% assert
+ [N || {N,_} <- Nodes,
+ node() /= N,
+ pang <- [net_adm:ping(N)]];
+
+ping(Nodes) ->
+ [{N,RC} || {N,S} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, ping, [{S,Nodes}])],
+ RC /= []].
+
+%% start/1
+%%
+%% Start diameter services.
+
+%% There's no need to start diameter on a node that only services
+%% diameter_dist as a handler of incoming requests, but the
+%% diameter_dist server must be started since the servers communicate
+%% to determine who services what. The typical case is probably that
+%% handler nodes also want to be able to send Diameter requests, in
+%% which case the application needs to be started and diameter_dist is
+%% started as a part of this, but only start the server here to ensure
+%% everything still works as expected.
+start({_SvcName, [_, {S1, _}, {S2, _}, _]})
+ when node() == S1; %% server1
+ node() == S2 -> %% server2
+ Mod = diameter_dist,
+ {ok, _} = gen_server:start({local, Mod}, Mod, _Args = [], _Opts = []),
+ ok;
+
+start({SvcName, [{S0, _}, _, _, {C, _}]})
+ when node() == S0; %% server0
+ node() == C -> %% client
+ ok = diameter:start(),
+ ok = diameter:start_service(SvcName, ?SERVICE((?L(SvcName))));
+
+start(Nodes) ->
+ [{N,RC} || {N,S} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, start, [{S, Nodes}])],
+ RC /= ok].
+
+sequence() ->
+ sequence(sname()).
+
+sequence(client) ->
+ {0,32};
+sequence(Server) ->
+ "server" ++ N = ?L(Server),
+ {list_to_integer(N), 30}.
+
+origin() ->
+ origin(sname()).
+
+origin(client) ->
+ 99;
+origin(Server) ->
+ "server" ++ N = ?L(Server),
+ list_to_integer(N).
+
+%% connect/1
+%%
+%% Establish one connection from the client, terminated on the first
+%% server node, the others handling requests.
+
+connect({?SERVER, [{Node, _} | _], []})
+ when Node == node() -> %% server0
+ [_LRef = ?util:listen(?SERVER, tcp)];
+
+connect({?SERVER, _, [_] = Acc}) -> %% server[12]: register to receive requests
+ ok = diameter_dist:attach([?SERVER]),
+ Acc;
+
+connect({?CLIENT, [{Node, _} | _], [LRef]}) ->
+ ?util:connect(?CLIENT, tcp, {Node, LRef}),
+ ok;
+
+connect(Nodes) ->
+ lists:foldl(fun({N,S}, A) ->
+ rpc:call(N, ?MODULE, connect, [{S, Nodes, A}])
+ end,
+ [],
+ Nodes).
+
+%% ===========================================================================
+%% traffic testcases
+
+%% send/1
+%%
+%% Send 100 requests and ensure the node name sent as User-Name isn't
+%% the node terminating transport.
+
+send(Nodes) ->
+ send(Nodes, 100, dict:new()).
+
+%% send/2
+
+send(Nodes, 0, Dict) ->
+ [{Server0, _} | _] = Nodes,
Node = atom_to_binary(Server0, utf8),
{false, _} = {dict:is_key(Node, Dict), dict:to_list(Dict)},
%% Check that counters have been incremented as expected on server0.
@@ -112,71 +259,38 @@ send(Server0, _Client, 0, Dict) ->
Stats},
{[{send, 0, 100, 2001}], _}
= {[{D,R,N,C} || {{{0,275,R}, D, {'Result-Code', C}}, N} <- Stats],
- Stats};
+ Stats},
+ ok;
-send(Server0, Client, N, Dict) ->
- Req = #diameter_base_STR{'Destination-Realm' = ?REALM,
- 'Auth-Application-Id' = ?DICT:id(),
- 'Termination-Cause' = ?LOGOUT},
+send(Nodes, N, Dict) ->
#diameter_base_STA{'Result-Code' = ?SUCCESS,
'User-Name' = [ServerNode]}
- = rpc:call(Client, diameter, call, [?CLIENT, ?DICT, Req, []]),
+ = send(Nodes, str(?LOGOUT)),
true = is_binary(ServerNode),
- send(Server0, Client, N-1, dict:update_counter(ServerNode, 1, Dict)).
+ send(Nodes, N-1, dict:update_counter(ServerNode, 1, Dict)).
%% ===========================================================================
-%% Utilities
-%% Starts a peer node with Diameter server running
-start_server(Server, Host, Origin, SeqFrom, SeqTo) ->
- ok = diameter:start(),
- ok = diameter:start_service(Server, service_opt(Host, Origin, SeqFrom, SeqTo)),
- %% Listener config
- ListenConfig = [{transport_module, diameter_tcp}, {transport_config, [{ip, ?ADDR},
- {port, 0}, {accept, {256, 0, 0, 1}}, {accept, ["256.0.0.1", ["^.+$"]]}]}],
- %% start listener on Server0, get the listener port number
- {ok, ListenRef} = diameter:add_transport(Server, {listen, ListenConfig}),
- %% wait for listener to be up
- [_] = diameter_reg:wait({diameter_tcp, listener, {ListenRef, '_'}}),
- [{listen, ListenPort, _}] = diameter_tcp:ports(),
- ListenPort.
-
-%% Starts Diameter client node connected to Server
-start_client(Client, ServerPort, Host, Origin, SeqFrom, SeqTo) ->
- ok = diameter:start(),
- ok = diameter:start_service(Client, service_opt(Host, Origin, SeqFrom, SeqTo)),
- %% Establish connection to the server
- ConnectConfig = [{transport_module, diameter_tcp},
- {transport_config, [{raddr, ?ADDR}, {rport, ServerPort}]}],
- true = diameter:subscribe(Client),
- {ok, Ref} = diameter:add_transport(Client, {connect, ConnectConfig}),
- receive
- {diameter_event, Client, {up, Ref, _, _, _}} -> ok
- end.
-
-%% Returns config for diameter:start_service/2.
-service_opt(Host, Origin, SeqFrom, SeqTo) ->
- [{'Origin-Host', Host ++ [$.|?REALM]},
- {'Origin-Realm', ?REALM},
- {'Host-IP-Address', [?ADDR]},
- {'Vendor-Id', 12345},
- {'Product-Name', "OTP/diameter"},
- {'Auth-Application-Id', [?DICT:id()]},
- {'Origin-State-Id', Origin},
- {spawn_opt, {diameter_dist, route_session, [#{id => []}]}},
- {sequence, fun () -> {SeqFrom, SeqTo} end}, %% use 'fun' for fun and piggy-back testing
- {string_decode, false},
- {application, [{dictionary, ?DICT},
- {module, ?MODULE},
- {request_errors, callback},
- {answer_errors, callback}]}].
-
-%% Starts a distributed worker node
-start_worker(AttachTo) ->
- {ok, Peer, Node} = ?CT_PEER(),
- {ok, _} = erpc:call(Node, gen_server, start, [{local, diameter_dist}, diameter_dist, [], []]),
- ok = erpc:call(Node, diameter_dist, attach, [[AttachTo]]),
- Peer.
+str(Cause) ->
+ #diameter_base_STR{'Destination-Realm' = ?REALM,
+ 'Auth-Application-Id' = ?DICT:id(),
+ 'Termination-Cause' = Cause}.
+
+%% send/2
+
+send(Nodes, Req) ->
+ {Node, _} = lists:last(Nodes),
+ rpc:call(Node, ?MODULE, call, [Req]).
+
+%% call/1
+
+call(Req) ->
+ diameter:call(?CLIENT, ?DICT, Req, []).
+
+%% sname/0
+
+sname() ->
+ ?A(hd(string:tokens(?L(node()), "@"))).
%% ===========================================================================
%% diameter callbacks
diff --git a/lib/diameter/test/diameter_distribution_SUITE.erl b/lib/diameter/test/diameter_distribution_SUITE.erl
index 7cb977f5d4..592ec24e64 100644
--- a/lib/diameter/test/diameter_distribution_SUITE.erl
+++ b/lib/diameter/test/diameter_distribution_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2021. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,18 +25,19 @@
-module(diameter_distribution_SUITE).
--export([
- suite/0,
- all/0,
- init_per_suite/1,
- end_per_suite/1
-]).
+%% testcases, no common_test dependency
+-export([run/0]).
-%% testcases
--export([send_local/1,
- send_remote/1,
- send_timeout/1,
- send_failover/1]).
+%% common_test wrapping
+-export([suite/0,
+ all/0,
+ traffic/1]).
+
+%% rpc calls
+-export([ping/1,
+ start/1,
+ connect/1,
+ call/1]).
%% diameter callbacks
-export([peer_up/3,
@@ -48,95 +49,212 @@
handle_error/5,
handle_request/3]).
-%% Internal export for RPC
--export([start_server/5, start_client/6, call/1]).
-
-include("diameter.hrl").
-include("diameter_gen_base_rfc6733.hrl").
--include_lib("common_test/include/ct.hrl").
-
%% ===========================================================================
+-define(util, diameter_util).
+
-define(CLIENT, 'CLIENT').
-define(SERVER, 'SERVER').
-define(REALM, "erlang.org").
-define(DICT, diameter_gen_base_rfc6733).
-define(ADDR, {127,0,0,1}).
+
+%% Config for diameter:start_service/2.
+-define(SERVICE(Host),
+ [{'Origin-Host', Host ++ [$.|?REALM]},
+ {'Origin-Realm', ?REALM},
+ {'Host-IP-Address', [?ADDR]},
+ {'Vendor-Id', 12345},
+ {'Product-Name', "OTP/diameter"},
+ {'Auth-Application-Id', [?DICT:id()]},
+ {'Origin-State-Id', origin()},
+ {share_peers, peers()},
+ {use_shared_peers, peers()},
+ {restrict_connections, false},
+ {spawn_opt, {diameter_dist, spawn_local, []}},
+ {sequence, fun sequence/0},
+ {application, [{dictionary, ?DICT},
+ {module, ?MODULE},
+ {request_errors, callback},
+ {answer_errors, callback}]}]).
+
-define(SUCCESS, 2001).
-define(BUSY, 3004).
-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT').
-define(MOVED, ?'DIAMETER_BASE_TERMINATION-CAUSE_USER_MOVED').
-define(TIMEOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_SESSION_TIMEOUT').
+-define(L, atom_to_list).
+-define(A, list_to_atom).
+
+%% The order here is significant and causes the server to listen
+%% before the clients connect.
+-define(NODES, [{server, ?SERVER},
+ {client0, ?CLIENT},
+ {client1, ?CLIENT},
+ {client2, ?CLIENT}]).
+
+%% Options to ct_slave:start/2.
+-define(TIMEOUTS, [{T, 15000} || T <- [boot_timeout,
+ init_timeout,
+ start_timeout]]).
+
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 30}}].
+ [{timetrap, {seconds, 90}}].
all() ->
- [send_local,
- send_remote,
- send_timeout,
- send_failover].
-
-init_per_suite(Config) ->
- {ok, ServerPeer, ServerNode} = ?CT_PEER(),
- ListenPort = erpc:call(ServerNode, ?MODULE, start_server, [?SERVER, "server0", 99, 0, 32]),
- %% client nodes
- Indices = lists:seq(0, 2),
- {_Ok, ClientPeers, Nodes} = lists:unzip3([{ok, _P, _N} = ?CT_PEER() || _ <- Indices]),
- %% Ensure the client nodes are connected since the sharing of
- %% transports is only between connected nodes.
- [pong = erpc:call(N, net_adm, ping, [M]) || N <- Nodes, M <- Nodes, N < M],
- %% Start diameter clients
- %% not exactly multi-call, call args are different
- [ok = erpc:call(N, ?MODULE, start_client,
- [?CLIENT, ListenPort, "client" ++ integer_to_list(Seq), Seq, Seq, 30])
- || {N, Seq} <- lists:zip(Nodes, Indices)],
- %% unlink peers, assuming end_per_suite is executed reliably
- Peers = [ServerPeer | ClientPeers],
- [unlink(P) || P <- Peers],
- [{server, ServerNode}, {clients, Nodes}, {peers, Peers} | Config].
-
-end_per_suite(Config) ->
- [peer:stop(P) || P <- proplists:get_value(peers, Config)].
+ [traffic].
+
+traffic(_Config) ->
+ traffic().
%% ===========================================================================
-%% traffic testcases
-%% send_local/1
+run() ->
+ [] = ?util:run([{fun traffic/0, 60000}]).
+ %% process for linked peers to die with
+
+%% traffic/0
+
+traffic() ->
+ true = is_alive(), %% need distribution for peer nodes
+ Nodes = enslave(),
+ [] = ping(Nodes), %% drop client node
+ [] = start(Nodes),
+ [_] = connect(Nodes),
+ [] = send(Nodes).
+
+%% enslave/0
%%
+%% Start four slave nodes, one to implement a Diameter server,
+%% three to implement a client.
+
+enslave() ->
+ Here = filename:dirname(code:which(?MODULE)),
+ Ebin = filename:join([Here, "..", "ebin"]),
+ Dirs = [Here, Ebin],
+ Args = [["-pa" | [lists:flatten(io_lib:format("~s", [D])) || D <- Dirs]],
+ ["-setcookie", ?L(erlang:get_cookie())]],
+ [{N,S} || A <- [lists:append(Args)],
+ {M,S} <- ?NODES,
+ N <- [start(M, A)]].
+
+start(Name, Args) ->
+ {ok, _, Node} = peer:start_link(#{name => Name, args => Args}),
+ Node.
+
+%% ping/1
+%%
+%% Ensure the client nodes are connected since the sharing of
+%% transports is only between connected nodes.
+
+ping({?SERVER, _Nodes}) ->
+ [];
+
+ping({?CLIENT, Nodes}) ->
+ [N || {N,_} <- Nodes,
+ node() /= N,
+ pang <- [net_adm:ping(N)]];
+
+ping(Nodes) ->
+ [{N,RC} || {N,S} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, ping, [{S, Nodes}])],
+ RC /= []].
+
+%% start/1
+%%
+%% Start diameter services.
+
+start(SvcName)
+ when is_atom(SvcName) ->
+ ok = diameter:start(),
+ ok = diameter:start_service(SvcName, ?SERVICE((?L(SvcName))));
+
+start(Nodes) ->
+ [{N,RC} || {N,S} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, start, [S])],
+ RC /= ok].
+
+sequence() ->
+ sequence(sname()).
+
+sequence(server) ->
+ {0,32};
+sequence(Client) ->
+ "client" ++ N = ?L(Client),
+ {list_to_integer(N), 30}.
+
+origin() ->
+ origin(sname()).
+
+origin(server) ->
+ 99;
+origin(Client) ->
+ "client" ++ N = ?L(Client),
+ list_to_integer(N).
+
+peers() ->
+ peers(sname()).
+
+peers(server) -> true;
+peers(client0) -> [node() | nodes()];
+peers(client1) -> fun erlang:nodes/0;
+peers(client2) -> nodes().
+
+%% connect/1
+%%
+%% Establish one connection to the server from each of the client
+%% nodes.
+
+connect({?SERVER, _, []}) ->
+ [_LRef = ?util:listen(?SERVER, tcp)];
+
+connect({?CLIENT, [{Node, _} | _], [LRef] = Acc}) ->
+ ?util:connect(?CLIENT, tcp, {Node, LRef}),
+ Acc;
+
+connect(Nodes) ->
+ lists:foldl(fun({N,S}, A) ->
+ rpc:call(N, ?MODULE, connect, [{S, Nodes, A}])
+ end,
+ [],
+ Nodes).
+
+%% ===========================================================================
+
+%% send/1
+
+send(Nodes) ->
+ ?util:run([[fun send/2, Nodes, T]
+ || T <- [local, remote, timeout, failover]]).
+
+%% send/2
+
%% Send a request from the first client node, using a the local
%% transport.
-
-send_local(Config) ->
+send(Nodes, local) ->
#diameter_base_STA{'Result-Code' = ?SUCCESS}
- = send(Config, local, str(?LOGOUT)).
+ = send(Nodes, 0, str(?LOGOUT));
-%% send_remote/1
-%%
%% Send a request from the first client node, using a transport on the
%% another node.
-
-send_remote(Config) ->
+send(Nodes, remote) ->
#diameter_base_STA{'Result-Code' = ?SUCCESS}
- = send(Config, remote, str(?LOGOUT)).
+ = send(Nodes, 1, str(?LOGOUT));
-%% send_timeout/1
-%%
%% Send a request that the server discards.
+send(Nodes, timeout) ->
+ {error, timeout} = send(Nodes, 1, str(?TIMEOUT));
-send_timeout(Config) ->
- {error, timeout} = send(Config, remote, str(?TIMEOUT)).
-
-%% send_failover/1
-%%
-%% Send a request that causes the server to remote transports down.
-
-send_failover(Config) ->
+%% Send a request that causes the server to take the transport down.
+send(Nodes, failover) ->
#'diameter_base_answer-message'{'Result-Code' = ?BUSY}
- = send(Config, remote, str(?MOVED)).
+ = send(Nodes, 2, str(?MOVED)).
%% ===========================================================================
@@ -145,68 +263,20 @@ str(Cause) ->
'Auth-Application-Id' = ?DICT:id(),
'Termination-Cause' = Cause}.
-%% send/2
+%% send/3
-send(Config, Where, Req) ->
- [Node | _] = proplists:get_value(clients, Config) ,
+send([_, {Node, _} | _], Where, Req) ->
rpc:call(Node, ?MODULE, call, [{Where, Req}]).
%% call/1
call({Where, Req}) ->
- diameter:call(?CLIENT, ?DICT, Req, [{extra, [{Where, node()}]}]).
-
+ diameter:call(?CLIENT, ?DICT, Req, [{extra, [{Where, sname()}]}]).
-%% Starts a peer node with Diameter server running
-start_server(Server, Host, Origin, SeqFrom, SeqTo) ->
- ok = diameter:start(),
- ok = diameter:start_service(Server, service_opt(Host, Origin, SeqFrom, SeqTo)),
- %% Listener config
- ListenConfig = [{transport_module, diameter_tcp}, {transport_config, [{ip, ?ADDR},
- {port, 0}, {accept, {256, 0, 0, 1}}, {accept, ["256.0.0.1", ["^.+$"]]}]}],
- %% start listener on Server0, get the listener port number
- {ok, ListenRef} = diameter:add_transport(Server, {listen, ListenConfig}),
- %% wait for listener to be up
- [_] = diameter_reg:wait({diameter_tcp, listener, {ListenRef, '_'}}),
- [{listen, ListenPort, _}] = diameter_tcp:ports(),
- ListenPort.
-
-%% Starts Diameter client node connected to Server
-start_client(Client, ServerPort, Host, Origin, SeqFrom, SeqTo) ->
- ok = diameter:start(),
- ok = diameter:start_service(Client, service_opt(Host, Origin, SeqFrom, SeqTo)),
- %% Establish connection to the server
- ConnectConfig = [{transport_module, diameter_tcp},
- {transport_config, [{ip, ?ADDR}, {port, 0}, {raddr, ?ADDR}, {rport, ServerPort}]}],
- true = diameter:subscribe(Client),
- {ok, Ref} = diameter:add_transport(Client, {connect, ConnectConfig}),
- receive
- {diameter_event, Client, {up, Ref, _, _, _}} -> ok
- end.
+%% sname/0
-%% Config for diameter:start_service/2.
-service_opt(Host, Origin, SeqFrom, SeqTo) ->
- [{'Origin-Host', Host ++ [$.|?REALM]},
- {'Origin-Realm', ?REALM},
- {'Host-IP-Address', [?ADDR]},
- {'Vendor-Id', 12345},
- {'Product-Name', "OTP/diameter"},
- {'Auth-Application-Id', [?DICT:id()]},
- {'Origin-State-Id', Origin},
- {share_peers, peers(Host)},
- {use_shared_peers, peers(Host)},
- {restrict_connections, false},
- {spawn_opt, {diameter_dist, spawn_local, []}},
- {sequence, fun () -> {SeqFrom, SeqTo} end},
- {application, [{dictionary, ?DICT},
- {module, ?MODULE},
- {request_errors, callback},
- {answer_errors, callback}]}].
-
-peers("server0") -> true;
-peers("client0") -> [node() | nodes()];
-peers("client1") -> fun erlang:nodes/0;
-peers("client2") -> nodes().
+sname() ->
+ ?A(hd(string:tokens(?L(node()), "@"))).
%% ===========================================================================
%% diameter callbacks
@@ -223,18 +293,26 @@ peer_down(_SvcName, _Peer, State) ->
%% pick_peer/4
-pick_peer([LP], [_, _], ?CLIENT, _State, {local, _Client0Node}) ->
+pick_peer([LP], _, ?CLIENT, _State, {0, client0}) ->
{ok, LP};
-pick_peer([_], [RP | _], ?CLIENT, _State, {remote, _Client0Node}) ->
+pick_peer(_, Peers, ?CLIENT, _State, {1, client0}) ->
+ [RP] = [T || {_, #diameter_caps{origin_state_id = {[1],_}}} = T <- Peers],
{ok, RP};
-pick_peer([LP], [], ?CLIENT, _State, {remote, _Client0Node}) ->
- {ok, LP}.
+%% Sending on the remote transport causes the server to take the
+%% transport down. Retransmission on the local.
+pick_peer(LP, RP, ?CLIENT, _State, {2, client0}) ->
+ {ok, case [T || {_, #diameter_caps{origin_state_id = {[2],_}}} = T <- RP] of
+ [T] ->
+ T;
+ _ ->
+ hd([_] = LP)
+ end}.
%% prepare_request/4
-prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, {_, _Client0Node}) ->
+prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, {_, client0}) ->
#diameter_packet{msg = Req}
= Pkt,
#diameter_caps{origin_host = {OH, _},
@@ -246,25 +324,26 @@ prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, {_, _Client0Node}) ->
%% prepare_retransmit/4
-prepare_retransmit(Pkt, ?CLIENT, _, {_, _Client0Node}) ->
+prepare_retransmit(Pkt, ?CLIENT, _, {_, client0}) ->
#diameter_packet{msg = #diameter_base_STR{'Termination-Cause' = ?MOVED}}
= Pkt, %% assert
{send, Pkt}.
%% handle_answer/5
-handle_answer(Pkt, _Req, ?CLIENT, _Peer, {_, _Client0Node}) ->
+handle_answer(Pkt, _Req, ?CLIENT, _Peer, {_, client0}) ->
#diameter_packet{msg = Rec, errors = []} = Pkt,
Rec.
%% handle_error/5
-handle_error(Reason, _Req, ?CLIENT, _Peer, {_, _Client0Node}) ->
+handle_error(Reason, _Req, ?CLIENT, _Peer, {_, client0}) ->
{error, Reason}.
%% handle_request/3
handle_request(Pkt, ?SERVER, Peer) ->
+ server = sname(), %% assert
#diameter_packet{msg = Req}
= Pkt,
request(Req, Peer).
diff --git a/lib/diameter/test/diameter_dpr_SUITE.erl b/lib/diameter/test/diameter_dpr_SUITE.erl
index 779b919d3c..45f4ec9b5a 100644
--- a/lib/diameter/test/diameter_dpr_SUITE.erl
+++ b/lib/diameter/test/diameter_dpr_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,22 +24,26 @@
-module(diameter_dpr_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_group/2,
- end_per_group/2]).
-
-%% testcases
--export([start/1,
- connect/1,
+ client/1,
+ server/1,
+ uncommon/1,
+ transport/1,
+ service/1,
+ application/1]).
+
+%% internal
+-export([connect/1,
send_dpr/1,
remove_transport/1,
stop_service/1,
- check/1,
- stop/1]).
+ check/1]).
%% disconnect_cb
-export([disconnect/5]).
@@ -84,42 +88,54 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 30}}].
all() ->
- [{group, R} || R <- [client, server, uncommon | ?REASONS]].
+ [client, server, uncommon, transport, service, application].
-%% The group determines how transports are terminated: by remove_transport,
-%% stop_service or application stop.
-groups() ->
- [{R, [], [start, send_dpr, stop]} || R <- [client, server, uncommon]]
- ++ [{R, [], Ts} || Ts <- [tc()], R <- ?REASONS].
+-define(tc(Name), Name(_) -> run([Name])).
-init_per_suite(Config) -> %% not need, but a useful place to enable trace
- Config.
+?tc(client).
+?tc(server).
+?tc(uncommon).
+?tc(transport).
+?tc(service).
+?tc(application).
-end_per_suite(_Config) ->
- ok.
+%% ===========================================================================
-init_per_group(Name, Config) ->
- [{group, Name} | Config].
+%% run/0
-end_per_group(_, _) ->
- ok.
+run() ->
+ run(all()).
-tc() ->
- [start, connect, remove_transport, stop_service, check, stop].
+%% run/1
-%% ===========================================================================
+run(List)
+ when is_list(List) ->
+ try
+ ?util:run([[{[fun run/1, T], 15000} || T <- List]])
+ after
+ diameter:stop()
+ end;
-%% start/1
-
-start(Config)
- when is_list(Config) ->
- Grp = group(Config),
+run(Grp) ->
ok = diameter:start(),
ok = diameter:start_service(?SERVER, service(?SERVER, Grp)),
- ok = diameter:start_service(?CLIENT, service(?CLIENT, Grp)).
+ ok = diameter:start_service(?CLIENT, service(?CLIENT, Grp)),
+ _ = lists:foldl(fun(F,A) -> apply(?MODULE, F, [A]) end,
+ [{group, Grp}],
+ tc(Grp)),
+ ok = diameter:stop().
+
+tc(T)
+ when T == client;
+ T == server;
+ T == uncommon ->
+ [send_dpr];
+
+tc(_) ->
+ [connect, remove_transport, stop_service, check].
service(?SERVER = Svc, _) ->
?SERVICE(Svc)
@@ -192,26 +208,30 @@ sender(_) ->
%% connect/1
connect(Config) ->
- Pid = spawn(fun init/0), %% process for disconnect_cb to bang
+ Self = self(),
Grp = group(Config),
+ Pid = spawn(fun() -> init(Self) end), %% process for disconnect_cb to bang
LRef = ?util:listen(?SERVER, tcp),
Refs = [?util:connect(?CLIENT, tcp, LRef, opts(RCs, {Grp, Pid}))
|| RCs <- ?RETURNS],
- ?util:write_priv(Config, config, [Pid | Refs]).
+ Pid ! (Grp == application orelse length(Refs)),
+ [{config, [Pid | Refs]} | Config].
%% remove_transport/1
%% Remove all the client transports only in the transport group.
remove_transport(Config) ->
transport == group(Config)
- andalso (ok = diameter:remove_transport(?CLIENT, true)).
+ andalso (ok = diameter:remove_transport(?CLIENT, true)),
+ Config.
%% stop_service/1
%% Stop the service only in the service group.
stop_service(Config) ->
service == group(Config)
- andalso (ok = diameter:stop_service(?CLIENT)).
+ andalso (ok = diameter:stop_service(?CLIENT)),
+ Config.
%% check/1
@@ -219,16 +239,11 @@ stop_service(Config) ->
%% for the timing reason explained below.
check(Config) ->
Grp = group(Config),
- [Pid | Refs] = ?util:read_priv(Config, config),
+ [Pid | Refs] = proplists:get_value(config, Config),
Pid ! self(), %% ask for dictionary
Dict = receive {Pid, D} -> D end, %% get it
check(Refs, ?RETURNS, Grp, Dict). %% check for callbacks
-%% stop/1
-
-stop(_Config) ->
- ok = diameter:stop().
-
%% ===========================================================================
%% Whether or not there are callbacks after diameter:stop() depends on
@@ -258,8 +273,7 @@ check1(Ref, [], _, Dict) ->
%% ----------------------------------------
group(Config) ->
- {group, Grp} = lists:keyfind(group, 1, Config),
- Grp.
+ proplists:get_value(group, Config).
%% Configure the callback with the group name (= disconnect reason) as
%% extra argument.
@@ -274,13 +288,18 @@ disconnect(Reason, Ref, Peer, {Reason, Pid}, RC) ->
Pid ! {Reason, Ref},
RC.
-init() ->
- exit(recv(dict:new())).
+init(Pid) ->
+ monitor(process, Pid),
+ exit(recv(receive T -> T end, dict:new())).
-recv(Dict) ->
+recv(true, Dict) ->
+ recv(0, Dict);
+recv(N, Dict) ->
receive
- Pid when is_pid(Pid) ->
+ Pid when N == 0, is_pid(Pid) ->
Pid ! {self(), Dict};
{Reason, Ref} ->
- recv(dict:store(Ref, Reason, Dict))
+ recv(N - 1, dict:store(Ref, Reason, Dict));
+ {'DOWN', _, process, _, _} ->
+ ok
end.
diff --git a/lib/diameter/test/diameter_event_SUITE.erl b/lib/diameter/test/diameter_event_SUITE.erl
index 6d1d1dfd8f..f4cb5e6d79 100644
--- a/lib/diameter/test/diameter_event_SUITE.erl
+++ b/lib/diameter/test/diameter_event_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2020. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,20 +26,18 @@
-module(diameter_event_SUITE).
+%% testcase, no common_test dependency
+-export([run/0]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_testcase/2,
- end_per_testcase/2]).
-
-%% testcases
--export([start/1,
- start_server/1,
- up/1,
+ traffic/1]).
+
+%% internal
+-export([up/1,
down/1,
- cea_timeout/1,
- stop/1]).
+ cea_timeout/1]).
-include("diameter.hrl").
@@ -77,43 +75,44 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 90}}].
all() ->
- [start,
- start_server,
- up,
- down,
- cea_timeout,
- stop].
-
-%% Not used, but a convenient place to enable trace.
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
+ [traffic].
-init_per_testcase(Name, Config) ->
- [{name, Name} | Config].
-
-end_per_testcase(_, _) ->
- ok.
+traffic(_Config) ->
+ run().
%% ===========================================================================
-%% start/stop testcases
-start(_Config) ->
- ok = diameter:start().
+%% run/0
-start_server(Config) ->
+run() ->
+ ok = diameter:start(),
+ try
+ ?util:run([{fun traffic/0, 60000}])
+ after
+ ok = diameter:stop()
+ end.
+
+%% traffic/0
+
+traffic() ->
+ PortNr = start_server(),
+ Config = [{portnr, PortNr}],
+ Funs = [up, down, cea_timeout],
+ ?util:run([[{?MODULE, F, [[{name, F} | Config]]} || F <- Funs]]).
+
+%% start_server/0
+
+start_server() ->
diameter:subscribe(?SERVER),
ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER, [?DICT_COMMON])),
LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx_cb/2},
{capx_timeout, ?SERVER_CAPX_TMO}]),
[PortNr] = ?util:lport(tcp, LRef),
- ?util:write_priv(Config, portnr, PortNr),
- start = event(?SERVER).
+ start = event(?SERVER),
+ PortNr.
%% Connect with matching capabilities and expect the connection to
%% come up.
@@ -158,9 +157,6 @@ cea_timeout(Config) ->
start = event(Svc),
{{closed, Ref, {'CEA', timeout}, T}, _} = {event(Svc), T}.
-stop(_Config) ->
- ok = diameter:stop().
-
%% ----------------------------------------
%% Keep the server from sending CEA until the client has timed out.
@@ -201,7 +197,7 @@ start_service(Name, Opts) ->
diameter:start_service(Name, [{monitor, self()} | Opts]).
opts(Config, Opts) ->
- PortNr = ?util:read_priv(Config, portnr),
+ PortNr = proplists:get_value(portnr, Config),
{connect, [{transport_module, diameter_tcp},
{transport_config, [{ip, ?ADDR}, {port, 0},
diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl
index b718899353..f02e74aef6 100644
--- a/lib/diameter/test/diameter_examples_SUITE.erl
+++ b/lib/diameter/test/diameter_examples_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2021. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,29 +24,31 @@
-module(diameter_examples_SUITE).
+%% testcase, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_group/2,
- end_per_group/2]).
-
-%% testcases
--export([dict/1,
- code/1,
- start/1,
- traffic/1]).
+ dict/1,
+ code/1]).
+%% rpc calls
-export([install/1,
- call/1]).
+ start/1,
+ traffic/1]).
-include("diameter.hrl").
--include_lib("common_test/include/ct.hrl").
-
%% ===========================================================================
+-define(util, diameter_util).
+
+%% The order here is significant and causes the server to listen
+%% before the clients connect.
+-define(NODES, [server, client]).
+
%% @inherits dependencies between example dictionaries. This is needed
%% in order compile them in the right order. Can't compile to erl to
%% find out since @inherits is a beam dependency.
@@ -58,56 +60,55 @@
-define(DICT0, [rfc3588_base, rfc6733_base]).
%% Transport protocols over which the example Diameter nodes are run.
--define(PROTS, [tcp, sctp]).
+-define(PROTS, [sctp || ?util:have_sctp()] ++ [tcp]).
+
+-define(L, atom_to_list).
+-define(A, list_to_atom).
%% ===========================================================================
+%% common_test wrapping
suite() ->
- [{timetrap, {minutes, 2}}].
+ [{timetrap, {seconds, 45}}].
all() ->
- [dict,
- code,
- {group, all}].
-
-groups() ->
- Tc = tc(),
- [{all, [parallel], [{group, P} || P <- ?PROTS]}
- | [{P, [], Tc} || P <- ?PROTS]].
-
-%% Not used, but a convenient place to enable trace.
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(all, Config) ->
- Config;
-
-init_per_group(tcp = N, Config) ->
- [{group, N} | Config];
-
-init_per_group(sctp = N, Config) ->
- case diameter_util:have_sctp() of
- true ->
- [{group, N} | Config];
- false->
- {skip, no_sctp}
- end.
+ [dict, code].
+
+dict(_Config) ->
+ run([dict]).
+
+code(Config) ->
+ run([{code, proplists:get_value(priv_dir, Config)}]).
+
+%% ===========================================================================
+
+%% run/0
-end_per_group(_, _) ->
- ok.
+run() ->
+ run(all()).
-tc() ->
- [traffic].
+%% run/1
+
+run(dict) ->
+ compile_dicts();
+%% The example code doesn't use the example dictionaries, so a
+%% separate testcase.
+
+run(code) ->
+ run_code(?util:tmpdir());
+run({code, Tmpdir}) ->
+ run_code(Tmpdir);
+
+%% Eg. erl -noinput -s diameter_examples_SUITE run code -s init stop ...
+run(List) ->
+ ?util:run([{[fun run/1, T], 30000} || T <- List]).
%% ===========================================================================
-%% dict/1
+%% compile_dicts/0
%%
%% Compile example dictionaries in examples/dict.
-dict(_Config) ->
+compile_dicts() ->
Dirs = [filename:join(H ++ ["examples", "dict"])
|| H <- [[code:lib_dir(diameter)], [here(), ".."]]],
[] = [{F,D,RC} || {_,F} <- sort(find_files(Dirs, ".*\\.dia$")),
@@ -201,26 +202,35 @@ make_name(Dict) ->
{string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}.
%% ===========================================================================
-%% code/1
+%% compile_code/1
%%
%% Compile example code under examples/code.
-code(Config) ->
- {ok, Peer, Node} = ?CT_PEER(),
- [] = rpc:call(Node,
- ?MODULE,
- install,
- [proplists:get_value(priv_dir, Config)]),
- peer:stop(Peer).
-
-%% Compile on another node since the code path may be modified.
-install(PrivDir) ->
- Top = install(here(), PrivDir),
+compile_code(Tmpdir) ->
+ {ok, Pid, Node} = slave(peer:random_name(), here()),
+ try
+ {ok, _Ebin} = rpc:call(Node, ?MODULE, install, [Tmpdir])
+ after
+ peer:stop(Pid)
+ end.
+
+%% Compile in another node since the code path is modified.
+install(Tmpdir) ->
+ {Top, Dia, Ebin} = install(here(), Tmpdir),
+
+ %% Prepend the created directory just so that code:lib_dir/1 finds
+ %% it when compile:file/2 tries to resolve include_lib.
+ true = code:add_patha(Ebin),
+ Dia = code:lib_dir(diameter), %% assert
+
Src = filename:join([Top, "examples", "code"]),
Files = find_files([Src], ".*\\.erl$"),
- [] = [{F,E} || {_,F} <- Files,
- {error, _, _} = E <- [compile:file(F, [warnings_as_errors,
- return_errors])]].
+ [] = [{F,T} || {_,F} <- Files,
+ T <- [compile:file(F, [warnings_as_errors,
+ return_errors,
+ {outdir, Ebin}])],
+ ok /= element(1, T)],
+ {ok, Ebin}.
%% Copy include files into a temporary directory and adjust the code
%% path in order for example code to be able to include them with
@@ -230,20 +240,15 @@ install(PrivDir) ->
%% preprocessor to find these otherwise. Generated hrls are only be
%% under include in an installation. ("Installing" them locally is
%% anathema.)
-install(Dir, PrivDir) ->
- %% Remove the path added to the peer (needed for the rpc:call/4 in
- %% compile/1 to find ?MODULE) so the call to code:lib_dir/2 below
- %% returns the installed path.
- [Ebin | _] = code:get_path(),
- true = code:del_path(Ebin),
+install(Dir, Tmpdir) ->
Top = top(Dir, code:lib_dir(diameter)),
%% Create a new diameter/include in priv_dir. Copy all includes
%% there, from below ../include and ../src/gen if they exist (in
%% the repo).
- Tmp = filename:join([PrivDir, "diameter"]),
- TmpInc = filename:join([PrivDir, "diameter", "include"]),
- TmpEbin = filename:join([PrivDir, "diameter", "ebin"]),
+ Tmp = filename:join([Tmpdir, "diameter"]),
+ TmpInc = filename:join([Tmp, "include"]),
+ TmpEbin = filename:join([Tmp, "ebin"]),
[] = [{T,E} || T <- [Tmp, TmpInc, TmpEbin],
{error, E} <- [file:make_dir(T)]],
@@ -254,13 +259,7 @@ install(Dir, PrivDir) ->
B <- [filename:basename(F)],
D <- [filename:join([TmpInc, B])],
{error, E} <- [file:copy(F,D)]],
-
- %% Prepend the created directory just so that code:lib_dir/1 finds
- %% it when compile:file/2 tries to resolve include_lib.
- true = code:add_patha(TmpEbin),
- Tmp = code:lib_dir(diameter), %% assert
- %% Return the top directory containing examples/code.
- Top.
+ {Top, Tmp, TmpEbin}.
find_files(Dirs, RE) ->
lists:foldl(fun(D,A) -> fold_files(D, RE, A) end,
@@ -275,6 +274,23 @@ store(Path, Dict) ->
%% ===========================================================================
+%% enslave/1
+%%
+%% Start two nodes: one for the server, one for the client.
+
+enslave(Prefix) ->
+ [{S,N} || D <- [here()],
+ S <- ?NODES,
+ M <- [lists:append(["diameter", Prefix, ?L(S)])],
+ {ok, _, N} <- [slave(M,D)]].
+
+slave(Name, Dir) ->
+ Args = [["-pa" | [lists:flatten(io_lib:format("~s", [D]))
+ || D <- [Dir, filename:join([Dir, "..", "ebin"])]]],
+ ["-setcookie", ?L(erlang:get_cookie())]],
+ {ok, _Pid, _Node} = peer:start_link(#{name => Name,
+ args => lists:append(Args)}).
+
here() ->
filename:dirname(code:which(?MODULE)).
@@ -285,21 +301,34 @@ top(Dir, LibDir) ->
false -> LibDir
end.
-%% start/1
+%% start/2
-start({server, Prot}) ->
+start({server, Prot, Ebin}) ->
+ true = code:add_patha(Ebin),
ok = diameter:start(),
ok = server:start(),
{ok, Ref} = server:listen({Prot, any, 3868}),
- [_] = diameter_util:lport(Prot, Ref),
+ [_] = ?util:lport(Prot, Ref),
ok;
-start({client = Svc, Prot}) ->
+start({client = Svc, Prot, Ebin}) ->
+ true = code:add_patha(Ebin),
ok = diameter:start(),
true = diameter:subscribe(Svc),
ok = client:start(),
{ok, Ref} = client:connect({Prot, loopback, loopback, 3868}),
- receive #diameter_event{info = {up, Ref, _, _, _}} -> ok end.
+ receive
+ #diameter_event{info = {up, Ref, _, _, _}} ->
+ ok
+ after
+ 2000 ->
+ timeout
+ end;
+
+start([Prot, Ebin | Nodes]) ->
+ [] = [RC || {S,N} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, start, [{S, Prot, Ebin}])],
+ RC /= ok].
%% traffic/1
%%
@@ -309,21 +338,32 @@ traffic(server) ->
ok;
traffic(client) ->
- {_, MRef} = spawn_monitor(fun() -> call(100) end),
+ {_, MRef} = spawn_monitor(fun() -> exit(call(100)) end),
receive {'DOWN', MRef, process, _, Reason} -> Reason end;
-traffic(Config) ->
- Prot = proplists:get_value(group, Config),
- {ok, ServerPeer, ServerNode} = ?CT_PEER(),
- ok = rpc:call(ServerNode, ?MODULE, start, [{server, Prot}]),
- {ok, ClientPeer, ClientNode} = ?CT_PEER(),
- ok = rpc:call(ClientNode, ?MODULE, start, [{client, Prot}]),
- ok = rpc:call(ClientNode, ?MODULE, traffic, [client]),
- peer:stop(ClientPeer),
- peer:stop(ServerPeer).
+traffic({Prot, Ebin}) ->
+ Nodes = enslave(?L(Prot)),
+ [] = start([Prot, Ebin | Nodes]),
+ [] = [RC || {T,N} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, traffic, [T])],
+ RC /= ok].
+
+%% run_code/1
+
+run_code(Tmpdir) ->
+ true = is_alive(), %% need distribution for peer nodes
+ Tmp = ?util:mktemp(filename:join(Tmpdir, "diameter_examples")),
+ try
+ {ok, Ebin} = compile_code(Tmp),
+ [] = ?util:run([[fun traffic/1, {T, Ebin}] || T <- ?PROTS])
+ after
+ file:del_dir_r(Tmp)
+ end.
+
+%% call/1
call(0) ->
- exit(ok);
+ ok;
call(N) ->
{ok, _} = client:call(),
diff --git a/lib/diameter/test/diameter_failover_SUITE.erl b/lib/diameter/test/diameter_failover_SUITE.erl
index 8a3b3e8413..0c78119e50 100644
--- a/lib/diameter/test/diameter_failover_SUITE.erl
+++ b/lib/diameter/test/diameter_failover_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,20 +36,19 @@
-module(diameter_failover_SUITE).
+%% testcases, no common_test dependency
+-export([run/0]).
+
+%% common_test wrapping
-export([suite/0,
- all/0]).
-
-%% testcases
--export([start/1,
- start_services/1,
- connect/1,
- send_ok/1,
- send_nok/1,
- send_discard_1/1,
- send_discard_2/1,
- stop_services/1,
- empty/1,
- stop/1]).
+ all/0,
+ parallel/1]).
+
+%% internal
+-export([send_ok/0,
+ send_nok/0,
+ send_discard_1/0,
+ send_discard_2/0]).
%% diameter callbacks
-export([pick_peer/4,
@@ -112,50 +111,61 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 90}}].
all() ->
- [start,
- start_services,
- connect,
- send_ok,
- send_nok,
- send_discard_1,
- send_discard_2,
- stop_services,
- empty,
- stop].
+ [parallel].
+
+parallel(_Config) ->
+ run().
%% ===========================================================================
-%% start/stop testcases
-start(_Config) ->
- ok = diameter:start().
+%% run/0
+
+run() ->
+ ok = diameter:start(),
+ try
+ ?util:run([{fun traffic/0, 60000}])
+ after
+ ok = diameter:stop()
+ end.
+
+%% traffic/0
-start_services(_Config) ->
+traffic() ->
+ Servers = start_services(),
+ ok = connect(Servers),
+ [] = send(),
+ [] = stop_services(),
+ [] = ets:tab2list(diameter_request).
+
+%% start_services/0
+
+start_services() ->
Servers = [server(N) || N <- ?SERVERS],
[] = [T || C <- ?CLIENTS,
T <- [diameter:start_service(C, ?SERVICE(C))],
T /= ok],
+ Servers.
- {save_config, Servers}.
+%% send/0
-connect(Config) ->
- {start_services, Servers} = proplists:get_value(saved_config, Config),
+send() ->
+ Funs = [send_ok, send_nok, send_discard_1, send_discard_2],
+ ?util:run([[{?MODULE, F, []} || F <- Funs]]).
- lists:foreach(fun(C) -> connect(C, Servers) end, ?CLIENTS).
+%% connect/1
-stop_services(_Config) ->
- [] = [{H,T} || H <- ?CLIENTS ++ ?SERVERS,
- T <- [diameter:stop_service(H)],
- T /= ok].
+connect(Servers) ->
+ lists:foreach(fun(C) -> connect(C, Servers) end, ?CLIENTS).
-%% Ensure transports have been removed from request table.
-empty(_Config) ->
- [] = ets:tab2list(diameter_request).
+%% stop_services/0
-stop(_Config) ->
- ok = diameter:stop().
+stop_services() ->
+ [{H,T} || H <- ?CLIENTS ++ ?SERVERS,
+ T <- [diameter:stop_service(H)],
+ T /= ok].
%% ----------------------------------------
@@ -171,7 +181,7 @@ connect(Name, Refs) ->
%% Send an STR and expect success after SERVER3 answers after a couple
%% of failovers.
-send_ok(_Config) ->
+send_ok() ->
Req = #diameter_base_STR{'Destination-Realm' = realm(?SERVER1),
'Termination-Cause' = ?LOGOUT,
'Auth-Application-Id' = ?APP_ID},
@@ -180,19 +190,19 @@ send_ok(_Config) ->
= call(?CLIENT1, Req).
%% Send an STR and expect failure when both servers fail.
-send_nok(_Config) ->
+send_nok() ->
Req = #diameter_base_STR{'Destination-Realm' = realm(?SERVER4),
'Termination-Cause' = ?LOGOUT,
'Auth-Application-Id' = ?APP_ID},
{failover, ?LOGOUT} = call(?CLIENT1, Req).
%% Send an STR and have prepare_retransmit discard it.
-send_discard_1(_Config) ->
+send_discard_1() ->
Req = #diameter_base_STR{'Destination-Realm' = realm(?SERVER1),
'Termination-Cause' = ?TIMEOUT,
'Auth-Application-Id' = ?APP_ID},
{rejected, ?TIMEOUT} = call(?CLIENT2, Req).
-send_discard_2(_Config) ->
+send_discard_2() ->
Req = #diameter_base_STR{'Destination-Realm' = realm(?SERVER4),
'Termination-Cause' = ?MOVED,
'Auth-Application-Id' = ?APP_ID},
diff --git a/lib/diameter/test/diameter_gen_sctp_SUITE.erl b/lib/diameter/test/diameter_gen_sctp_SUITE.erl
index d3b2e89297..1333431943 100644
--- a/lib/diameter/test/diameter_gen_sctp_SUITE.erl
+++ b/lib/diameter/test/diameter_gen_sctp_SUITE.erl
@@ -27,14 +27,19 @@
-module(diameter_gen_sctp_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
init_per_suite/1,
end_per_suite/1]).
%% testcases
--export([send_one_from_many/1, send_one_from_many/0,
- send_many_from_one/1, send_many_from_one/0,
+-export([send_one_from_many/1,
+ send_many_from_one/1,
receive_what_was_sent/1]).
-include_lib("kernel/include/inet_sctp.hrl").
@@ -67,7 +72,7 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 10}}].
+ [{timetrap, {seconds, 15}}].
all() ->
[send_one_from_many,
@@ -89,13 +94,20 @@ end_per_suite(_Config) ->
%% ===========================================================================
-%% send_one_from_many/0
+%% run/0
+
+run() ->
+ run(all()).
+
+%% run/1
+
+run(List) ->
+ diameter_util:run([{{?MODULE, F, [[]]}, 10000} || F <- List]).
+
+%% send_one_from_many/1
%%
%% Demonstrates sluggish delivery of messages.
-send_one_from_many() ->
- [{timetrap, {seconds, 30}}].
-
send_one_from_many(_) ->
?OK = send_multiple(128, 1, 1024).
@@ -402,23 +414,20 @@ unmark(Bin) ->
%% ===========================================================================
-%% send_many_from_one/0
+%% send_many_from_one/1
%%
%% Demonstrates sluggish delivery of messages.
-send_many_from_one() ->
- [{timetrap, {seconds, 30}}].
-
send_many_from_one(_) ->
?OK = send_multiple(1, 128, 1024).
%% ===========================================================================
-%% receive_what_was_sent/1
+%% receive_what_was_sent/0
%%
%% Demonstrates reception of a message that differs from that sent.
-receive_what_was_sent(_Config) ->
+receive_what_was_sent(_) ->
?OK = send_multiple(1, 1, 1024*32).
%% ===========================================================================
diff --git a/lib/diameter/test/diameter_gen_tcp_SUITE.erl b/lib/diameter/test/diameter_gen_tcp_SUITE.erl
index db42ea813e..d1e01da27e 100644
--- a/lib/diameter/test/diameter_gen_tcp_SUITE.erl
+++ b/lib/diameter/test/diameter_gen_tcp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,11 +27,14 @@
-module(diameter_gen_tcp_SUITE).
--export([suite/0,
- all/0]).
+%% testcases, not common_test dependency
+-export([run/0,
+ run/1]).
-%% testcases
--export([send_long/1,
+%% common_test wrapping
+-export([suite/0,
+ all/0,
+ send_long/1,
connect/1]).
-define(LOOPBACK, {127,0,0,1}).
@@ -46,13 +49,29 @@ all() ->
[connect, %% Appears to fail only when run first.
send_long].
+send_long(_) ->
+ send_long().
+
+connect(_) ->
+ connect().
+
%% ===========================================================================
-%% send_long/1
+%% run/0
+
+run() ->
+ run(all()).
+
+%% run/1
+
+run(List) ->
+ diameter_util:run([{{?MODULE, F, [[]]}, 10000} || F <- List]).
+
+%% send_long/0
%%
%% Test that a long message is received.
-send_long(_) ->
+send_long() ->
{Sock, SendF} = connection(),
B = binary:copy(<<$X>>, 1 bsl 20),
ok = SendF(B),
@@ -101,13 +120,13 @@ send(Sock, Bin) ->
%% ===========================================================================
-%% connect/1
+%% connect/0
%%
%% Test that simultaneous connections succeed. This fails sporadically
%% on OS X at the time of writing, when gen_tcp:connect/2 returns
%% {error, econnreset}.
-connect(_) ->
+connect() ->
{ok, LSock} = gen_tcp:listen(0, ?GEN_OPTS),
{ok, {_,PortNr}} = inet:sockname(LSock),
Count = lists:seq(1,8), %% 8 simultaneous connects
diff --git a/lib/diameter/test/diameter_gh.spec b/lib/diameter/test/diameter_gh.spec
index 45adb931e1..9662044402 100644
--- a/lib/diameter/test/diameter_gh.spec
+++ b/lib/diameter/test/diameter_gh.spec
@@ -1,4 +1,2 @@
{suites, "../diameter_test", all}.
-{skip_cases,"../diameter_test",diameter_gen_sctp_SUITE,
- [send_one_from_many,send_many_from_one],
- "SCTP does not work on Github actions"}.
+{skip_suites, "../diameter_test", [diameter_gen_sctp_SUITE], "SCTP does not work on Github actions"}.
diff --git a/lib/diameter/test/diameter_length_SUITE.erl b/lib/diameter/test/diameter_length_SUITE.erl
index daaaae6e00..66d1be114f 100644
--- a/lib/diameter/test/diameter_length_SUITE.erl
+++ b/lib/diameter/test/diameter_length_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,20 +24,14 @@
-module(diameter_length_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_group/2,
- end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2]).
-
-%% testcases
--export([start/1,
- send/1,
- stop/1]).
+ parallel/1]).
%% diameter callbacks
-export([peer_up/3,
@@ -83,39 +77,20 @@
-define(LOGOUT,
?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT').
--define(GROUPS, [exit, handle, discard]).
-
-define(L, atom_to_list).
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 120}}].
all() ->
- [{group, G} || G <- ?GROUPS].
-
-groups() ->
- [{G, [], [start, send, stop]} || G <- ?GROUPS].
-
-init_per_suite(Config) ->
- ok = diameter:start(),
- Config.
-
-end_per_suite(_Config) ->
- ok = diameter:stop().
-
-init_per_group(Group, Config) ->
- [{group, Group} | Config].
-
-end_per_group(_, _) ->
- ok.
+ [parallel].
-init_per_testcase(_Name, Config) ->
- Config.
+parallel(_Config) ->
+ run().
-end_per_testcase(_, _) ->
- ok.
+%% ===========================================================================
origin(exit) -> 0;
origin(handle) -> 1;
@@ -127,25 +102,39 @@ origin(2) -> discard.
%% ===========================================================================
+run() ->
+ run([exit, handle, discard]).
+
+run(List)
+ when is_list(List) ->
+ ok = diameter:start(),
+ try
+ ?util:run([[{[fun run/1, T], 30000} || T <- List]])
+ after
+ ok = diameter:stop()
+ end;
+
+run(Group) ->
+ start(Group),
+ send(Group),
+ stop().
+
%% start/1
-start(Config) ->
- Group = proplists:get_value(group, Config),
+start(Group) ->
ok = diameter:start_service(?SERVER, ?SERVICE(?L(Group))),
ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)),
- LRef = ?util:listen(?SERVER,
- tcp,
- [{length_errors, Group}]),
+ LRef = ?util:listen(?SERVER, tcp, [{length_errors, Group}]),
?util:connect(?CLIENT,
tcp,
LRef,
[{capabilities, [{'Origin-State-Id', origin(Group)}]}]).
-%% stop/1
+%% stop/0
-stop(_Config) ->
- ok = diameter:remove_transport(?CLIENT, true),
+stop() ->
ok = diameter:remove_transport(?SERVER, true),
+ ok = diameter:remove_transport(?CLIENT, true),
ok = diameter:stop_service(?SERVER),
ok = diameter:stop_service(?CLIENT).
@@ -194,10 +183,7 @@ send(discard) ->
{error, timeout}
= call(4),
#diameter_base_STA{'Result-Code' = ?SUCCESS}
- = call(0);
-
-send(Config) ->
- send(proplists:get_value(group, Config)).
+ = call(0).
%% ===========================================================================
diff --git a/lib/diameter/test/diameter_pool_SUITE.erl b/lib/diameter/test/diameter_pool_SUITE.erl
index a36a4fa17a..40d34c6237 100644
--- a/lib/diameter/test/diameter_pool_SUITE.erl
+++ b/lib/diameter/test/diameter_pool_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,17 +25,16 @@
-module(diameter_pool_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- init_per_testcase/2,
- end_per_testcase/2,
- init_per_suite/1,
- end_per_suite/1]).
-
-%% testcases
--export([tcp_connect/1,
- sctp_connect/1,
- any_connect/1]).
+ tcp/1,
+ sctp/1,
+ any/1]).
%% ===========================================================================
@@ -62,44 +61,53 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 30}}].
+ [{timetrap, {seconds, 45}}].
all() ->
- [tcp_connect,
- sctp_connect,
- any_connect].
+ [tcp, sctp, any].
-init_per_testcase(_Name, Config) ->
- Config.
+tcp(_Config) ->
+ run([tcp]).
-end_per_testcase(_Name, _Config) ->
- diameter:stop().
-
-init_per_suite(Config) ->
- [{sctp, ?util:have_sctp()} | Config].
+sctp(_Config) ->
+ case ?util:have_sctp() of
+ true -> run([sctp]);
+ false -> {skip, no_sctp}
+ end.
-end_per_suite(_Config) ->
- ok.
+any(_Config) ->
+ run([any]).
%% ===========================================================================
-tcp_connect(_Config) ->
- connect(tcp, tcp).
+%% run/0
-sctp_connect(Config) ->
- case lists:member({sctp, true}, Config) of
- true -> connect(sctp, sctp);
- false -> {skip, no_sctp}
- end.
+run() ->
+ run(all()).
+
+%% run/1
+
+run(tcp = T) ->
+ connect(T, T);
-any_connect(_Config) ->
- connect(any, tcp).
+run(sctp = T) ->
+ connect(T, T);
+
+run(any = T) ->
+ connect(T, tcp);
+
+run(List) ->
+ ok = diameter:start(),
+ try
+ ?util:run([[{[fun run/1, T], 30000} || T <- List]])
+ after
+ ok = diameter:stop()
+ end.
%% connect/2
%% Establish multiple connections between a client and server.
connect(ClientProt, ServerProt) ->
- ok = diameter:start(),
[] = [{S,T} || S <- ["server", "client"],
T <- [diameter:start_service(S, ?SERVICE(S))],
T /= ok],
@@ -108,20 +116,24 @@ connect(ClientProt, ServerProt) ->
LRef = ?util:listen("server", ServerProt, [{pool_size, 4}]),
{4,0} = count("server", LRef, accept), %% 4 transports, no connections
%% Establish 5 connections.
- Ref = ?util:connect("client", ClientProt, LRef, [{pool_size, 5}]),
- {5,5} = count("client", Ref, pool), %% 5 connections
+ N = pool_size(5), %% connections to establish
+ Ref = ?util:connect("client", ClientProt, LRef, [{pool_size, N}]),
+ {N,N} = count("client", Ref, pool), %% N connections
%% Ensure the server has started replacement transports within a
%% reasonable time. Sleepsince there's no guarantee the
%% replacements have been started before the client has received
%% 'up' events. (Although it's likely.)
- sleep(),
- {9,5} = count("server", LRef, accept), %% 5 connections + 4 accepting
+ timer:sleep(1000),
+ N4 = N + 4,
+ {N4,N} = count("server", LRef, accept), %% N connections + 4 accepting
%% Ensure there are still the expected number of accepting transports
%% after stopping the client service.
ok = diameter:stop_service("client"),
- sleep(),
+ timer:sleep(1000),
{4,0} = count("server", LRef, accept), %% 4 transports, no connections
%% Done.
+ ok = diameter:remove_transport("client", true),
+ ok = diameter:remove_transport("server", true),
ok = diameter:stop_service("server").
count(Name, Ref, Key) ->
@@ -131,5 +143,10 @@ count(Name, Ref, Key) ->
{Key, Ps} = lists:keyfind(Key, 1, T),
{length(Ps), length(Cs)}. %% number of processes, connections
-sleep() ->
- receive after 1000 -> ok end.
+%% Simultaneous connections are often refused on Darwin: don't try to
+%% establish more than one.
+pool_size(N) ->
+ case os:type() of
+ {_, 'darwin'} -> 1;
+ _ -> rand:uniform(N)
+ end.
diff --git a/lib/diameter/test/diameter_reg_SUITE.erl b/lib/diameter/test/diameter_reg_SUITE.erl
index cd9242faa8..02e10ffb74 100644
--- a/lib/diameter/test/diameter_reg_SUITE.erl
+++ b/lib/diameter/test/diameter_reg_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,86 +24,76 @@
-module(diameter_reg_SUITE).
--export([suite/0,
- all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1]).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
-%% testcases
--export([add/1,
- add_new/1,
- remove/1,
- down/1,
- terms/1,
- pids/1]).
+%% common_test wrapping
+-export([all/0,
+ parallel/1]).
--define(reg, diameter_reg).
--define(util, diameter_util).
+-define(reg, diameter_reg).
%% ===========================================================================
-suite() ->
- [{timetrap, {seconds, 60}}].
-
all() ->
- [{group, all},
- {group, all, [parallel]}].
+ [parallel].
-groups() ->
- [{all, [], tc()}].
+parallel(_Config) ->
+ run().
-tc() ->
- [add,
- add_new,
- remove,
- down,
- terms,
- pids].
+%% ===========================================================================
-init_per_suite(Config) ->
- ok = diameter:start(),
- Config.
+%% run/0
-end_per_suite(_Config) ->
- ok = diameter:stop().
+run() ->
+ run([add, add_new, remove, down, terms, pids]).
-%% ===========================================================================
+%% run/1
+
+run(List)
+ when is_list(List) ->
+ ok = diameter:start(),
+ try
+ diameter_util:run([{[fun run/1, T], 10000} || T <- List])
+ after
+ ok = diameter:stop()
+ end;
-add(_) ->
+run(add) ->
Ref = make_ref(),
true = ?reg:add(Ref),
true = ?reg:add(Ref),
[{Ref, Pid}] = ?reg:match(Ref),
- Pid = self().
+ Pid = self();
-add_new(_) ->
+run(add_new) ->
Ref = make_ref(),
true = ?reg:add_new(Ref),
- false = ?reg:add_new(Ref).
+ false = ?reg:add_new(Ref);
-remove(_) ->
+run(remove) ->
Ref = make_ref(),
true = ?reg:add_new(Ref),
true = ?reg:add_new({Ref}),
true = ?reg:remove({Ref}),
[{Ref, Pid}] = ?reg:match(Ref),
- Pid = self().
+ Pid = self();
-down(_) ->
+run(down) ->
Ref = make_ref(),
{_, MRef} = spawn_monitor(fun() -> ?reg:add_new(Ref), timer:sleep(1000) end),
receive {'DOWN', MRef, process, _, _} -> ok end,
timer:sleep(1000),
- [] = ?reg:match(Ref).
+ [] = ?reg:match(Ref);
-terms(_) ->
+run(terms) ->
Ref = make_ref(),
true = ?reg:add_new(Ref),
[[Pid]] = [L || {T,L} <- ?reg:terms(), T == Ref],
- Pid = self().
+ Pid = self();
-pids(_) ->
+run(pids) ->
Ref = make_ref(),
true = ?reg:add_new(Ref),
%% Don't match [[Ref]] since this will only necessarily be the
diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl
index 9de5cbe685..2502820e0f 100644
--- a/lib/diameter/test/diameter_relay_SUITE.erl
+++ b/lib/diameter/test/diameter_relay_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,26 +34,13 @@
-module(diameter_relay_SUITE).
+%% testcases, no common_test dependency
+-export([run/0]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0]).
-
-%% testcases
--export([start/1,
- start_services/1,
- connect/1,
- send1/1,
- send2/1,
- send3/1,
- send4/1,
- send_loop/1,
- send_timeout_1/1,
- send_timeout_2/1,
- info/1,
- counters/1,
- disconnect/1,
- stop_services/1,
- stop/1]).
+ parallel/1]).
%% diameter callbacks
-export([pick_peer/4,
@@ -115,41 +102,37 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 30}}].
all() ->
- [start,
- start_services,
- connect,
- {group, all},
- counters,
- {group, all, [parallel]},
- disconnect,
- stop_services,
- stop].
-
-groups() ->
- [{all, [], tc()}].
+ [parallel].
-%% Traffic cases run when services are started and connections
-%% established.
-tc() ->
- [send1,
- send2,
- send3,
- send4,
- send_loop,
- send_timeout_1,
- send_timeout_2,
- info].
+parallel(_Config) ->
+ run().
%% ===========================================================================
-%% start/stop testcases
-start(_Config) ->
- ok = diameter:start().
+%% run/0
+
+run() ->
+ ok = diameter:start(),
+ try
+ ?util:run([{fun traffic/0, 20000}])
+ after
+ ok = diameter:stop()
+ end.
-start_services(_Config) ->
+%% traffic/0
+
+traffic() ->
+ Servers = start_services(),
+ Conns = connect(Servers),
+ [] = send(),
+ [] = counters(),
+ [] = disconnect(Conns),
+ [] = stop_services().
+
+start_services() ->
[S1,S2,S3,S4] = [server(N, ?DICT_COMMON) || N <- [?SERVER1,
?SERVER2,
?SERVER3,
@@ -158,30 +141,32 @@ start_services(_Config) ->
ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)),
- {save_config, [{?RELAY1, [S1,S2,R2]},
- {?RELAY2, [S3,S4]},
- {?CLIENT, [R1,R2]}]}.
-
-connect(Config) ->
- {_, Conns} = proplists:get_value(saved_config, Config),
+ [{?RELAY1, [S1,S2,R2]}, {?RELAY2, [S3,S4]}, {?CLIENT, [R1,R2]}].
- ?util:write_priv(Config,
- "cfg",
- lists:flatmap(fun({CN,Ss}) -> connect(CN, Ss) end,
- Conns)).
+connect(Servers) ->
+ lists:flatmap(fun({CN,Ss}) -> connect(CN, Ss) end, Servers).
-disconnect(Config) ->
- [] = [{T,C} || C <- ?util:read_priv(Config, "cfg"),
- T <- [break(C)],
- T /= ok].
+disconnect(Conns) ->
+ [{T,C} || C <- Conns,
+ T <- [break(C)],
+ T /= ok].
-stop_services(_Config) ->
- [] = [{H,T} || H <- ?SERVICES,
- T <- [diameter:stop_service(H)],
- T /= ok].
+stop_services() ->
+ [{H,T} || H <- ?SERVICES,
+ T <- [diameter:stop_service(H)],
+ T /= ok].
-stop(_Config) ->
- ok = diameter:stop().
+%% Traffic cases run when services are started and connections
+%% established.
+send() ->
+ ?util:run([[fun traffic/1, T] || T <- [send1,
+ send2,
+ send3,
+ send4,
+ send_loop,
+ send_timeout_1,
+ send_timeout_2,
+ info]]).
%% ----------------------------------------
@@ -203,50 +188,50 @@ connect(Name, Refs) ->
%% traffic testcases
%% Send an STR intended for a specific server and expect success.
-send1(_Config) ->
- call(?SERVER1).
-send2(_Config) ->
- call(?SERVER2).
-send3(_Config) ->
- call(?SERVER3).
-send4(_Config) ->
- call(?SERVER4).
+traffic(send1) ->
+ call(?SERVER1);
+traffic(send2) ->
+ call(?SERVER2);
+traffic(send3) ->
+ call(?SERVER3);
+traffic(send4) ->
+ call(?SERVER4);
%% Send an ASR that loops between the relays (RELAY1 -> RELAY2 ->
%% RELAY1) and expect the loop to be detected.
-send_loop(_Config) ->
+traffic(send_loop) ->
Req = ['ASR', {'Destination-Realm', realm(?SERVER1)},
{'Destination-Host', ?SERVER1},
{'Auth-Application-Id', ?APP_ID}],
#'diameter_base_answer-message'{'Result-Code' = ?LOOP_DETECTED}
- = call(Req, [{filter, realm}]).
+ = call(Req, [{filter, realm}]);
%% Send a RAR that is incorrectly routed and then discarded and expect
%% different results depending on whether or not we or the relay
%% timeout first.
-send_timeout_1(_Config) ->
+traffic(send_timeout_1) ->
#'diameter_base_answer-message'{'Result-Code' = ?UNABLE_TO_DELIVER}
- = send_timeout(7000).
-send_timeout_2(_Config) ->
- {error, timeout} = send_timeout(3000).
+ = traffic({timeout, 7000});
+traffic(send_timeout_2) ->
+ {error, timeout} = traffic({timeout, 3000});
-send_timeout(Tmo) ->
+traffic({timeout, Tmo}) ->
Req = ['RAR', {'Destination-Realm', realm(?SERVER1)},
{'Destination-Host', ?SERVER1},
{'Auth-Application-Id', ?APP_ID},
{'Re-Auth-Request-Type', ?AUTHORIZE_ONLY}],
- call(Req, [{filter, realm}, {timeout, Tmo}]).
+ call(Req, [{filter, realm}, {timeout, Tmo}]);
-info(_Config) ->
+traffic(info) ->
%% Wait for RELAY1 to have answered all requests, so that the
%% suite doesn't end before all answers are sent and counted.
receive after 6000 -> ok end,
[] = ?util:info().
-counters(_Config) ->
- [] = ?util:run([[fun counters/2, K, S]
- || K <- [statistics, transport, connections],
- S <- ?SERVICES]).
+counters() ->
+ ?util:run([[fun counters/2, K, S]
+ || K <- [statistics, transport, connections],
+ S <- ?SERVICES]).
counters(Key, Svc) ->
counters(Key, Svc, [_|_] = diameter:service_info(Svc, Key)).
diff --git a/lib/diameter/test/diameter_stats_SUITE.erl b/lib/diameter/test/diameter_stats_SUITE.erl
index 4716082394..b48e7a84bf 100644
--- a/lib/diameter/test/diameter_stats_SUITE.erl
+++ b/lib/diameter/test/diameter_stats_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,55 +24,52 @@
-module(diameter_stats_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1]).
-
-%% testcases
--export([reg/1,
- incr/1,
- read/1,
- sum/1,
- flush/1]).
+ parallel/1]).
-define(stat, diameter_stats).
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 30}}].
all() ->
- [{group, all},
- {group, all, [parallel]}].
+ [parallel].
-groups() ->
- [{all, [], tc()}].
+parallel(_Config) ->
+ run().
-tc() ->
- [reg,
- incr,
- read,
- sum,
- flush].
+%% ===========================================================================
-init_per_suite(Config) ->
- ok = diameter:start(),
- Config.
+%% run/0
-end_per_suite(_Config) ->
- ok = diameter:stop().
+run() ->
+ run([reg, incr, read, sum, flush]).
-%% ===========================================================================
+%% run/1
+
+run(List)
+ when is_list(List) ->
+ ok = diameter:start(),
+ try
+ diameter_util:run([{[fun run/1, T], 15000} || T <- List])
+ after
+ ok = diameter:stop()
+ end;
-reg(_) ->
+run(reg) ->
Ref = '$1',
true = ?stat:reg(Ref),
- false = ?stat:reg(Ref). %% duplicate
+ false = ?stat:reg(Ref); %% duplicate
-incr(_) ->
+run(incr) ->
Ref = '_',
Ctr = x,
false = ?stat:incr(Ctr), %% not registered,
@@ -83,9 +80,9 @@ incr(_) ->
2 = ?stat:incr(Ctr, self(), 2)
end),
ok = fold(Ctr, Ref, 3), %% folded
- ?stat:flush([self(), Ref]).
+ ?stat:flush([self(), Ref]);
-read(_) ->
+run(read) ->
Ref = make_ref(),
C1 = {a,b},
C2 = {b,a},
@@ -99,9 +96,9 @@ read(_) ->
= ?stat:read([self(), Ref, make_ref()]),
[] = ?stat:read([]),
[] = ?stat:read([make_ref()]),
- ?stat:flush([self(), Ref, make_ref()]).
+ ?stat:flush([self(), Ref, make_ref()]);
-sum(_) ->
+run(sum) ->
Ref = make_ref(),
C1 = {a,b},
C2 = {b,a},
@@ -116,9 +113,9 @@ sum(_) ->
[{Self, [{C1,1}, {C2,2}]}]
= ?stat:sum([self()]),
[{Ref, [{C1,7}]}, {Self, [{C1,1}, {C2,2}]}]
- = ?stat:flush([self(), Ref]).
+ = ?stat:flush([self(), Ref]);
-flush(_) ->
+run(flush) ->
Ref = make_ref(),
Ctr = '_',
true = ?stat:reg(Ref),
diff --git a/lib/diameter/test/diameter_sync_SUITE.erl b/lib/diameter/test/diameter_sync_SUITE.erl
index 2785bd92d6..395c99bd0b 100644
--- a/lib/diameter/test/diameter_sync_SUITE.erl
+++ b/lib/diameter/test/diameter_sync_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,63 +24,59 @@
-module(diameter_sync_SUITE).
+%% testcases, no common_test depedency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1]).
-
-%% testcases
--export([call/1,
- cast/1,
- timeout/1,
- flush/1]).
+ parallel/1]).
-define(sync, diameter_sync).
--define(util, diameter_util).
-
--define(TIMEOUT, infinity).
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 15}}].
all() ->
- [{group, all},
- {group, all, [parallel]}].
+ [parallel].
-groups() ->
- [{all, [], tc()}].
+parallel(_Config) ->
+ run().
-tc() ->
- [call,
- cast,
- timeout,
- flush].
+%% ===========================================================================
-init_per_suite(Config) ->
- ok = diameter:start(),
- Config.
+%% run/0
-end_per_suite(_Config) ->
- ok = diameter:stop().
+run() ->
+ run([call, cast, timeout, flush]).
-%% ===========================================================================
+%% run/1
+
+run(List)
+ when is_list(List) ->
+ ok = diameter:start(),
+ try
+ diameter_util:run([{[fun run/1, T], 10000} || T <- List])
+ after
+ ok = diameter:stop()
+ end;
-call(_) ->
+run(call) ->
Ref = make_ref(),
Q = {q, Ref},
F = fun() -> Ref end,
- Ref = ?sync:call(Q, F, infinity, ?TIMEOUT),
+ Ref = ?sync:call(Q, F, infinity, infinity),
Ref = ?sync:call(Q, F, 0, infinity),
Ref = call(Q, F),
Ref = call(Q, {fun(_) -> Ref end, x}),
timeout = call(Q, fun() -> exit(unexpected) end),
{_,_,_} = call(Q, {erlang, now, []}),
- {_,_,_} = call(Q, [fun erlang:now/0]).
+ {_,_,_} = call(Q, [fun erlang:now/0]);
-cast(_) ->
+run(cast) ->
Ref = make_ref(),
Q = {q, Ref},
false = ?sync:carp(Q),
@@ -95,26 +91,21 @@ cast(_) ->
true = 2 =< ?sync:pending(),
true = lists:member(Q, ?sync:queues()),
%% ... and that the max number of requests is respected.
- rejected = ?sync:call(Q, {erlang, now, []}, 1, ?TIMEOUT),
- rejected = ?sync:cast(Q, {erlang, now, []}, 1, ?TIMEOUT),
+ rejected = ?sync:call(Q, {erlang, now, []}, 1, infinity),
+ rejected = ?sync:cast(Q, {erlang, now, []}, 1, infinity),
%% Monitor on the identifiable request and see that exits when we
%% let the blocking request finish.
MRef = erlang:monitor(process, Pid),
{value, P} = ?sync:carp(Q),
P ! Ref,
- Ref = receive
- {'DOWN', MRef, process, _, Reason} ->
- Reason
- after ?TIMEOUT ->
- false
- end.
-
-timeout(_) ->
+ Ref = receive {'DOWN', MRef, process, _, Reason} -> Reason end;
+
+run(timeout) ->
Q = make_ref(),
ok = ?sync:cast(Q, {timer, sleep, [2000]}, infinity, 2000),
- timeout = ?sync:call(Q, fun() -> ok end, infinity, 1000).
+ timeout = ?sync:call(Q, fun() -> ok end, infinity, 1000);
-flush(_) ->
+run(flush) ->
Q = make_ref(),
F = {timer, sleep, [2000]},
ok = cast(Q, F),
diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl
index 1ad897dcd2..4e8cde95d3 100644
--- a/lib/diameter/test/diameter_tls_SUITE.erl
+++ b/lib/diameter/test/diameter_tls_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,27 +34,15 @@
-module(diameter_tls_SUITE).
+%% testcases, no common_test dependency
+-export([run/0]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
init_per_suite/1,
- end_per_suite/1]).
-
-%% testcases
--export([start_ssl/1,
- start_diameter/1,
- make_certs/1, make_certs/0,
- start_services/1,
- add_transports/1,
- send1/1,
- send2/1,
- send3/1,
- send4/1,
- send5/1,
- remove_transports/1,
- stop_services/1,
- stop_diameter/1,
- stop_ssl/1]).
+ end_per_suite/1,
+ parallel/1]).
%% diameter callbacks
-export([prepare_request/3,
@@ -126,34 +114,22 @@
-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT').
%% ===========================================================================
+%% common_test wrapping
suite() ->
- [{timetrap, {seconds, 60}}].
+ [{timetrap, {seconds, 90}}].
all() ->
- [start_ssl,
- start_diameter,
- make_certs,
- start_services,
- add_transports,
- {group, all},
- {group, all, [parallel]},
- remove_transports,
- stop_services,
- stop_diameter,
- stop_ssl].
-
-groups() ->
- [{all, [], tc()}].
+ [parallel].
%% Shouldn't really have to know about crypto here but 'ok' from
%% ssl:start() isn't enough to guarantee that TLS is available.
init_per_suite(Config) ->
try
- false /= os:find_executable("openssl")
- orelse throw({?MODULE, no_openssl}),
- ok == (catch crypto:start())
- orelse throw({?MODULE, no_crypto}),
+ [] == (catch make_certs(dir(Config)))
+ orelse throw({?MODULE, no_certs}),
+ ok == crypto:start() orelse throw({?MODULE, no_crypto}),
+ ok == ssl:start() orelse throw({?MODULE, no_ssl}),
Config
catch
{?MODULE, E} ->
@@ -161,87 +137,81 @@ init_per_suite(Config) ->
end.
end_per_suite(_Config) ->
+ ssl:stop(),
crypto:stop().
-%% Testcases to run when services are started and connections
-%% established.
-tc() ->
- [send1,
- send2,
- send3,
- send4,
- send5].
-
-%% ===========================================================================
-%% testcases
-
-start_ssl(_Config) ->
- ok = ssl:start().
-
-start_diameter(_Config) ->
- ok = diameter:start().
+parallel(Config) ->
+ run(dir(Config), false).
-make_certs() ->
- [{timetrap, {minutes, 2}}].
+dir(Config) ->
+ proplists:get_value(priv_dir, Config).
-make_certs(Config) ->
- Dir = proplists:get_value(priv_dir, Config),
+%% ===========================================================================
- [] = ?util:run([[fun make_cert/2, Dir, B] || B <- ["server1",
- "server2",
- "server4",
- "server5",
- "client"]]).
+run() ->
+ Tmp = ?util:mktemp(filename:join(?util:tmpdir(), "diameter_tls")),
+ try
+ run(Tmp, true)
+ after
+ file:del_dir_r(Tmp)
+ end.
-start_services(Config) ->
- Dir = proplists:get_value(priv_dir, Config),
- Servers = [server(S, sopts(S, Dir)) || S <- ?SERVERS],
+run(Dir, B) ->
+ crypto:start(),
+ ssl:start(),
+ try
+ ?util:run([{[fun traffic/2, Dir, B], 60000}])
+ after
+ diameter:stop(),
+ ssl:stop(),
+ crypto:stop()
+ end.
+traffic(Dir, true) ->
+ [] = make_certs(Dir),
+ traffic(Dir, false);
+
+traffic(Dir, false) ->
+ ok = diameter:start(),
+ Servers = start_services(Dir),
+ Connections = add_transports(Dir, Servers),
+ [] = ?util:run([[fun call/1, S] || S <- ?util:scramble(?SERVERS)]),
+ [] = remove_transports(Connections),
+ [] = stop_services().
+
+make_certs(Dir) ->
+ ?util:run([[fun make_cert/2, Dir, B] || B <- ["server1",
+ "server2",
+ "server4",
+ "server5",
+ "client"]]).
+
+start_services(Dir) ->
+ Servers = [{S, {_,_} = server(S, sopts(S, Dir))} || S <- ?SERVERS],
ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)),
+ Servers.
- {save_config, [Dir | Servers]}.
-
-add_transports(Config) ->
- {_, [Dir | Servers]} = proplists:get_value(saved_config, Config),
-
+add_transports(Dir, Servers) ->
true = diameter:subscribe(?CLIENT),
-
Opts = ssl_options(Dir, "client"),
- Connections = [connect(?CLIENT, S, copts(N, Opts))
- || {S,N} <- lists:zip(Servers, ?SERVERS)],
-
- ?util:write_priv(Config, "cfg", lists:zip(Servers, Connections)).
-
+ [{N, S, connect(?CLIENT, S, copts(N, Opts))} || {N,S} <- Servers].
%% Remove the client transports and expect the corresponding server
%% transport to go down.
-remove_transports(Config) ->
- Ts = ?util:read_priv(Config, "cfg"),
+remove_transports(Connections) ->
[] = [T || S <- ?SERVERS, T <- [diameter:subscribe(S)], T /= true],
- lists:map(fun disconnect/1, Ts).
+ [] = ?util:run([[fun disconnect/1, T] || T <- Connections]),
+ [S || S <- ?SERVERS,
+ I <- [receive #diameter_event{service = S, info = I} -> I end],
+ down /= catch element(1, I)].
-stop_services(_Config) ->
- [] = [{H,T} || H <- [?CLIENT | ?SERVERS],
- T <- [diameter:stop_service(H)],
- T /= ok].
+disconnect({_, {_LRef, _PortNr}, CRef}) ->
+ ok = diameter:remove_transport(?CLIENT, CRef).
-stop_diameter(_Config) ->
- ok = diameter:stop().
-
-stop_ssl(_Config) ->
- ok = ssl:stop().
-
-%% Send an STR intended for a specific server and expect success.
-send1(_Config) ->
- call(?SERVER1).
-send2(_Config) ->
- call(?SERVER2).
-send3(_Config) ->
- call(?SERVER3).
-send4(_Config) ->
- call(?SERVER4).
-send5(_Config) ->
- call(?SERVER5).
+stop_services() ->
+ [{H,T} || H <- [?CLIENT | ?SERVERS],
+ T <- [diameter:stop_service(H)],
+ T /= ok].
%% ===========================================================================
%% diameter callbacks
@@ -285,6 +255,7 @@ handle_request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId}},
%% ===========================================================================
%% support functions
+%% Send an STR intended for a specific server and expect success.
call(Server) ->
Realm = realm(Server),
Req = ['STR', {'Destination-Realm', Realm},
@@ -301,10 +272,6 @@ call(Req, Opts) ->
set([H|T], Vs) ->
[H | Vs ++ T].
-disconnect({{LRef, _PortNr}, CRef}) ->
- ok = diameter:remove_transport(?CLIENT, CRef),
- receive #diameter_event{info = {down, LRef, _, _}} -> ok end.
-
realm(Host) ->
tl(lists:dropwhile(fun(C) -> C /= $. end, Host)).
@@ -364,11 +331,12 @@ ssl([{ssl_options = T, Opts}]) ->
connect(Host, {_LRef, PortNr}, {Caps, Opts}) ->
{ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr, Caps, Opts)),
- receive
- #diameter_event{service = Host,
- info = {up, Ref, _, _, #diameter_packet{}}} ->
- ok
- end,
+ {up, Ref, _, _, #diameter_packet{}}
+ = receive
+ #diameter_event{service = Host, info = Info}
+ when element(2, Info) == Ref ->
+ Info
+ end,
Ref.
copts(S, Opts)
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index a12759bac2..95ea6be020 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2021. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,25 +25,17 @@
-module(diameter_traffic_SUITE).
+%% all tests, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_group/1,
- init_per_group/2,
- end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2]).
+ parallel/1]).
%% testcases
--export([rfc4005/1,
- start/1,
- start_services/1,
- add_transports/1,
- result_codes/1,
- send_ok/1,
+-export([send_ok/1,
send_nok/1,
send_eval/1,
send_bad_answer/1,
@@ -97,11 +89,7 @@
send_multiple_filters_1/1,
send_multiple_filters_2/1,
send_multiple_filters_3/1,
- send_anything/1,
- remove_transports/1,
- empty/1,
- stop_services/1,
- stop/1]).
+ send_anything/1]).
%% diameter callbacks
-export([peer_up/4,
@@ -127,14 +115,6 @@
%% ===========================================================================
-%% Fraction of shuffle/parallel groups to randomly skip.
--define(SKIP, 0.90).
-
-%% Positive number of testcases from which to select (randomly) from
-%% tc(), the list of testcases to run, or [] to run all. The random
-%% selection is to limit the time it takes for the suite to run.
--define(LIMIT, #{tcp => 42, sctp => 5}).
-
-define(util, diameter_util).
-define(A, list_to_atom).
@@ -164,30 +144,19 @@
%% Which dictionary to use in the clients.
-define(RFCS, [rfc3588, rfc6733, rfc4005]).
-%% Whether to decode stringish Diameter types to strings, or leave
-%% them as binary.
--define(STRING_DECODES, [false, true]).
-
%% Which transport protocol to use.
--define(TRANSPORTS, [tcp, sctp]).
-
-%% Send from a dedicated process?
--define(SENDERS, [true, false]).
-
-%% Message callbacks from diameter_{tcp,sctp}?
--define(CALLBACKS, [true, false]).
-
--record(group,
- {transport,
- strings,
- encoding,
- client_service,
- client_dict,
- client_sender,
- server_service,
- server_decoding,
- server_sender,
- server_throttle}).
+-define(TRANSPORTS, [sctp || ?util:have_sctp()] ++ [tcp]).
+
+-record(group, {transport,
+ strings,
+ encoding,
+ client_service,
+ client_dict,
+ client_sender,
+ server_service,
+ server_decoding,
+ server_sender,
+ server_throttle}).
%% Not really what we should be setting unless the message is sent in
%% the common application but diameter doesn't care.
@@ -270,285 +239,156 @@
?'DIAMETER_BASE_TERMINATION-CAUSE_USER_MOVED').
%% ===========================================================================
+%% common_test wrapping
suite() ->
- [{timetrap, {seconds, 10}}].
+ [{timetrap, {seconds, 90}}].
all() ->
- [rfc4005, start, result_codes, {group, traffic}, empty, stop].
-
-%% Redefine this to run one or more groups for debugging purposes.
--define(GROUPS, []).
-%-define(GROUPS, [[sctp,rfc6733,record,map,false,false,true,false]]).
-
-%% Issues with gen_sctp sporadically cause huge numbers of failed
-%% testcases when running testcases in parallel.
-groups() ->
- Names = names([] == ?GROUPS orelse ?GROUPS),
- [{P, [P], Ts} || Ts <- [tc()], P <- [shuffle, parallel]]
- ++
- [{?util:name(N), [], [{group, if T == sctp; S -> shuffle;
- true -> parallel end}]}
- || [T,_,_,_,S|_] = N <- Names]
- ++
- [{T, [], [{group, ?util:name(N)} || N <- Names,
- T == hd(N)]}
- || T <- ?TRANSPORTS]
- ++
- [{traffic, [], [{group, T} || T <- ?TRANSPORTS]}].
-
-names() ->
- [[T,R,E,D,S,ST,SS,CS] || T <- ?TRANSPORTS,
- R <- ?RFCS,
- E <- ?ENCODINGS,
- D <- ?DECODINGS,
- S <- ?STRING_DECODES,
- ST <- ?CALLBACKS,
- SS <- ?SENDERS,
- CS <- ?SENDERS,
- ?SKIP =< rand:uniform()].
-
-names(true) ->
- names(names());
-
-names(Names) ->
- [N || N <- Names,
- [CS,SS|_] <- [lists:reverse(N)],
- SS orelse CS]. %% avoid deadlock
-
-%% --------------------
-
-init_per_suite() ->
- [{timetrap, {seconds, 60}}].
-
-init_per_suite(Config) ->
- [{rfc4005, compile_and_load()}, {sctp, ?util:have_sctp()} | Config].
-
-end_per_suite(_Config) ->
- code:delete(nas4005),
- code:purge(nas4005),
- ok.
+ [parallel].
-%% --------------------
+parallel(_Config) ->
+ run().
-init_per_group(_) ->
- [{timetrap, {seconds, 30}}].
+%% ===========================================================================
-init_per_group(Name, Config)
- when Name == shuffle;
- Name == parallel ->
- start_services(Config),
- add_transports(Config),
- replace({sleep, Name == parallel}, Config);
+%% run/0
+%%
+%% The test cases proper, do or (meaningfully) die.
+%%
+%% Randomly choose one of many configuration possibilities. Testing
+%% all of them takes too much time, and randomly skipping various
+%% cases (as used to be the case) just unnecessary complexity. There
+%% are run night after night in on various hosts, so just choosing a
+%% configuration results in sufficient coverage over time.
+
+run() ->
+ Svc = ?util:unique_string(),
+ run(#group{transport = ?util:choose(?TRANSPORTS),
+ strings = bool(),
+ encoding = ?util:choose(?ENCODINGS),
+ client_service = [$C | Svc],
+ client_dict = appdict(?util:choose(?RFCS)),
+ client_sender = bool(),
+ server_service = [$S | Svc],
+ server_decoding = ?util:choose(?DECODINGS),
+ server_sender = true, %% avoid deadlock
+ server_throttle = bool()}).
+
+%% run/1
+
+run(#group{} = Cfg) ->
+ _ = result_codes(Cfg),
+ io:format("config: ~p~n", [Cfg]),
+ try
+ ?util:run([{[fun traffic/1, Cfg], 60000}])
+ after
+ code:delete(nas4005),
+ code:purge(nas4005),
+ diameter:stop()
+ end.
-init_per_group(sctp = Name, Config) ->
- {_, Sctp} = lists:keyfind(Name, 1, Config),
- if Sctp ->
- Config;
- true ->
- {skip, Name}
- end;
+%% traffic/1
-init_per_group(Name, Config) ->
- Nas = proplists:get_value(rfc4005, Config, false),
- case ?util:name(Name) of
- [_,R,_,_,_,_,_,_] when R == rfc4005, true /= Nas ->
- {skip, rfc4005};
- [T,R,E,D,S,ST,SS,CS] ->
- G = #group{transport = T,
- strings = S,
- encoding = E,
- client_service = [$C|?util:unique_string()],
- client_dict = appdict(R),
- client_sender = CS,
- server_service = [$S|?util:unique_string()],
- server_decoding = D,
- server_sender = SS,
- server_throttle = ST},
- replace([{group, G}, {runlist, select(T)}], Config);
- _ ->
- Config
- end.
+traffic(#group{} = Cfg) ->
+ _ = compile_and_load(),
+ ok = diameter:start(),
+ LRef = server(Cfg),
+ ok = client(Cfg, LRef),
+ [] = send(Cfg),
+ ok = stop_services(Cfg),
+ [] = ets:tab2list(diameter_request).
-end_per_group(Name, Config)
- when Name == shuffle;
- Name == parallel ->
- remove_transports(Config),
- stop_services(Config);
+%% start_service/2
-end_per_group(_, _) ->
+start_service(Svc, Opts) ->
+ {ok, _} = {diameter:start_service(Svc, Opts), Opts},
ok.
-select(T) ->
- try maps:get(T, ?LIMIT) of
- N ->
- lists:sublist(?util:scramble(tc()), max(5, rand:uniform(N)))
- catch
- error:_ -> ?LIMIT
- end.
+%% send/1
-%% --------------------
-
-%% Work around common_test accumulating Config improperly, causing
-%% testcases to get Config from groups and suites they're not in.
-init_per_testcase(N, Config)
- when N == rfc4005;
- N == start;
- N == result_codes;
- N == empty;
- N == stop ->
- Config;
-
-%% Skip testcases that can reasonably fail under SCTP.
-init_per_testcase(Name, Config) ->
- TCs = proplists:get_value(runlist, Config, []),
- Run = [] == TCs orelse lists:member(Name, TCs),
- case [G || #group{transport = sctp} = G
- <- [proplists:get_value(group, Config)]]
- of
- [_] when Name == send_maxlen;
- Name == send_long ->
- {skip, sctp};
- _ when not Run ->
- {skip, random};
- _ ->
- proplists:get_value(sleep, Config, false)
- andalso timer:sleep(rand:uniform(200)),
- [{testcase, Name} | Config]
- end.
+send(Cfg) ->
+ Ref = make_ref(),
+ Refs = [R || {F,1} <- module_info(exports),
+ "send_" ++ _ <- [atom_to_list(F)],
+ I <- [fun() -> exit({Ref, send(F, Cfg)}) end],
+ {_,R} <- [spawn_monitor(I)]],
+ lists:filter(fun({R,_}) -> R /= Ref; (_) -> true end, wait(Refs)).
-end_per_testcase(_, _) ->
- ok.
+%% send/2
-%% replace/2
-%%
-%% Work around common_test running init functions inappropriately, and
-%% this accumulating more config than expected.
-
-replace(Pairs, Config)
- when is_list(Pairs) ->
- lists:foldl(fun replace/2, Config, Pairs);
-
-replace({Key, _} = T, Config) ->
- [T | lists:keydelete(Key, 1, Config)].
-
-%% --------------------
-
-%% Testcases to run when services are started and connections
-%% established.
-tc() ->
- [send_ok,
- send_nok,
- send_eval,
- send_bad_answer,
- send_protocol_error,
- send_experimental_result,
- send_arbitrary,
- send_proxy_info,
- send_unknown,
- send_unknown_short,
- send_unknown_mandatory,
- send_unknown_short_mandatory,
- send_noreply,
- send_grouped_error,
- send_unsupported,
- send_unsupported_app,
- send_error_bit,
- send_unsupported_version,
- send_long_avp_length,
- send_short_avp_length,
- send_zero_avp_length,
- send_invalid_avp_length,
- send_invalid_reject,
- send_unexpected_mandatory_decode,
- send_unexpected_mandatory,
- send_too_many,
- send_long,
- send_maxlen,
- send_nopeer,
- send_noapp,
- send_discard,
- send_any_1,
- send_any_2,
- send_all_1,
- send_all_2,
- send_timeout,
- send_error,
- send_detach,
- send_encode_error,
- send_destination_1,
- send_destination_2,
- send_destination_3,
- send_destination_4,
- send_destination_5,
- send_destination_6,
- send_bad_option_1,
- send_bad_option_2,
- send_bad_filter_1,
- send_bad_filter_2,
- send_bad_filter_3,
- send_bad_filter_4,
- send_multiple_filters_1,
- send_multiple_filters_2,
- send_multiple_filters_3,
- send_anything].
+send(F, #group{transport = sctp})
+ when F == send_long;
+ F == send_maxlen ->
+ ok;
-%% ===========================================================================
-%% start/stop testcases
+send(F, Cfg) ->
+ timer:sleep(rand:uniform(2000)),
+ apply(?MODULE, F, [[{testcase, F}, {group, Cfg}]]).
-start(_Config) ->
- ok = diameter:start().
+%% wait/1
-start_services(Config) ->
- #group{client_service = CN,
- server_service = SN,
- server_decoding = SD}
- = Grp
- = group(Config),
- ok = diameter:start_service(SN, [{traffic_counters, bool()},
- {decode_format, SD}
- | ?SERVICE(SN, Grp)]),
- ok = diameter:start_service(CN, [{traffic_counters, bool()},
- {sequence, ?CLIENT_MASK},
- {decode_format, map},
- {strict_arities, decode}
- | ?SERVICE(CN, Grp)]).
+wait(Refs)
+ when is_list(Refs) ->
+ lists:map(fun wait/1, Refs);
-bool() ->
- 0.5 =< rand:uniform().
+wait(MRef) ->
+ receive {'DOWN', MRef, process, _, T} -> T end.
+
+%% ===========================================================================
-add_transports(Config) ->
+%% server/1
+
+server(Config) ->
#group{transport = T,
- encoding = E,
- client_service = CN,
client_sender = CS,
server_service = SN,
+ server_decoding = SD,
server_sender = SS,
server_throttle = ST}
+ = Grp
= group(Config),
- LRef = ?util:listen(SN,
- [T,
- {sender, SS},
- {message_cb, ST andalso {?MODULE, message, [0]}}]
- ++ [{packet, hd(?util:scramble([false, raw]))}
- || T == sctp andalso CS]
- ++ [{unordered, unordered()} || T == sctp],
- [{capabilities_cb, fun capx/2},
- {pool_size, 8}
- | server_apps()]),
- Cs = [?util:connect(CN,
- [T, {sender, CS} | client_opts(T)],
- LRef,
- [{id, Id}
- | client_apps(R, [{'Origin-State-Id', origin(Id)}])])
- || D <- ?DECODINGS, %% for multiple candidate peers
- R <- ?RFCS,
- R /= rfc4005 orelse have_nas(),
- Id <- [{D,E}]],
- ?util:write_priv(Config, "transport", [LRef | Cs]).
+ ok = start_service(SN, [{traffic_counters, bool()},
+ {decode_format, SD}
+ | ?SERVICE(SN, Grp)]),
+ Cfg = [{sender, SS},
+ {message_cb, ST andalso {?MODULE, message, [0]}}]
+ ++ [{packet, ?util:choose([false, raw])} || T == sctp andalso CS]
+ ++ [{unordered, unordered()} || T == sctp],
+ Opts = [{capabilities_cb, fun capx/2},
+ {pool_size, 8}
+ | server_apps()],
+ _LRef = ?util:listen(SN, [T | Cfg], Opts).
+
+%% client/1
+
+client(Config, LRef) ->
+ #group{transport = T,
+ encoding = E,
+ client_service = CN,
+ client_sender = CS}
+ = Grp
+ = group(Config),
+ ok = start_service(CN, [{traffic_counters, bool()},
+ {sequence, ?CLIENT_MASK},
+ {decode_format, map},
+ {strict_arities, decode}
+ | ?SERVICE(CN, Grp)]),
+ _ = [?util:connect(CN, [T | C], LRef, O)
+ || C <- [[{sender, CS} | client_opts(T)]],
+ D <- ?DECODINGS, %% for multiple candidate peers
+ R <- ?RFCS,
+ R /= rfc4005 orelse have_nas(),
+ I <- [{D,E}],
+ O <- [[{id, I}
+ | client_apps(R, [{'Origin-State-Id', origin(I)}])]]],
+ ok.
+
+bool() ->
+ 0.5 =< rand:uniform().
unordered() ->
- element(rand:uniform(4), {true, false, 1, 2}).
+ ?util:choose([true, false, 1, 2]).
client_opts(tcp) ->
[];
@@ -567,32 +407,19 @@ server_apps() ->
{capabilities, [{'Auth-Application-Id', [0] ++ [1 || B]}, %% common, NAS
{'Acct-Application-Id', [3]}]}]. %% accounting
+client_apps(rfc4005, Caps) ->
+ [{applications, [nas4005]},
+ {capabilities, [{'Auth-Application-Id', [1]}, %% NAS
+ {'Acct-Application-Id', []}
+ | Caps]}];
client_apps(D, Caps) ->
- if D == rfc4005 ->
- [{applications, [nas4005]},
- {capabilities, [{'Auth-Application-Id', [1]}, %% NAS
- {'Acct-Application-Id', []}
- | Caps]}];
- true ->
- D0 = dict0(D),
- [{applications, [acct(D0), D0]},
- {capabilities, Caps}]
- end.
+ D0 = dict0(D),
+ [{applications, [acct(D0), D0]},
+ {capabilities, Caps}].
have_nas() ->
false /= code:is_loaded(nas4005).
-remove_transports(Config) ->
- #group{client_service = CN,
- server_service = SN}
- = group(Config),
- [LRef | Cs] = ?util:read_priv(Config, "transport"),
- try
- [] = [T || C <- Cs, T <- [?util:disconnect(CN, C, SN, LRef)], T /= ok]
- after
- ok = diameter:remove_transport(SN, LRef)
- end.
-
stop_services(Config) ->
#group{client_service = CN,
server_service = SN}
@@ -600,24 +427,12 @@ stop_services(Config) ->
ok = diameter:stop_service(CN),
ok = diameter:stop_service(SN).
-%% Ensure even transports have been removed from request table.
-empty(_Config) ->
- [] = ets:tab2list(diameter_request).
-
-stop(_Config) ->
- ok = diameter:stop().
-
capx(_, #diameter_caps{origin_host = {OH,DH}}) ->
io:format("connection: ~p -> ~p~n", [DH,OH]),
ok.
%% ===========================================================================
-%% Fail only this testcase if the RFC 4005 dictionary hasn't been
-%% successfully compiled and loaded.
-rfc4005(Config) ->
- true = proplists:get_value(rfc4005, Config).
-
%% Ensure that result codes have the expected values.
result_codes(_Config) ->
{2001,
@@ -1135,6 +950,8 @@ send_anything(Config) ->
%% ===========================================================================
+group(#group{} = Rec) ->
+ Rec;
group(Config) ->
#group{} = proplists:get_value(group, Config).
@@ -1903,25 +1720,19 @@ message(ack, _, N) ->
%% ------------------------------------------------------------------------
compile_and_load() ->
- try
- Path = hd([P || H <- [[here(), ".."], [code:lib_dir(diameter)]],
- P <- [filename:join(H ++ ["examples",
- "dict",
- "rfc4005_nas.dia"])],
- {ok, _} <- [file:read_file_info(P)]]),
- {ok, [Forms]}
- = diameter_make:codec(Path, [return,
- forms,
- {name, "nas4005"},
- {prefix, "nas"},
- {inherits, "common/diameter_gen_base_rfc3588"}]),
- {ok, nas4005, Bin, []} = compile:forms(Forms, [debug_info, return]),
- {module, nas4005} = code:load_binary(nas4005, "nas4005", Bin),
- true
- catch
- E:R:Stack ->
- {E, R, Stack}
- end.
+ Path = hd([P || H <- [[here(), ".."], [code:lib_dir(diameter)]],
+ P <- [filename:join(H ++ ["examples",
+ "dict",
+ "rfc4005_nas.dia"])],
+ {ok, _} <- [file:read_file_info(P)]]),
+ Opts = [return,
+ forms,
+ {name, "nas4005"},
+ {prefix, "nas"},
+ {inherits, "common/diameter_gen_base_rfc3588"}],
+ {ok, [Forms]} = diameter_make:codec(Path, Opts),
+ {ok, nas4005, Bin, []} = compile:forms(Forms, [debug_info, return]),
+ {module, nas4005} = code:load_binary(nas4005, "nas4005", Bin).
here() ->
filename:dirname(code:which(?MODULE)).
diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl
index 284d2b9566..9b763141ff 100644
--- a/lib/diameter/test/diameter_transport_SUITE.erl
+++ b/lib/diameter/test/diameter_transport_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,23 +25,17 @@
-module(diameter_transport_SUITE).
+%% all tests, no common_test dependency
+-export([run/0]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- groups/0,
- init_per_suite/1,
- end_per_suite/1]).
-
-%% testcases
--export([start/1,
- tcp_accept/1,
- tcp_connect/1,
- sctp_accept/1,
- sctp_connect/1,
- reconnect/1, reconnect/0,
- stop/1]).
+ parallel/1]).
-export([accept/1,
connect/1,
+ reconnect/1,
init/2]).
-include_lib("kernel/include/inet_sctp.hrl").
@@ -84,93 +78,63 @@
-define(SCTP(Sock, Data), {sctp, Sock, _, _, Data}).
%% ===========================================================================
+%% common_test wrapping
suite() ->
- [{timetrap, {seconds, 15}}].
+ [{timetrap, {seconds, 270}}].
all() ->
- [start,
- {group, all},
- {group, all, [parallel]},
- stop].
+ [parallel].
-groups() ->
- [{all, [], tc()}].
+parallel(_) ->
+ run().
-tc() ->
- [tcp_accept,
- tcp_connect,
- sctp_accept,
- sctp_connect,
- reconnect].
+%% ===========================================================================
-init_per_suite(Config) ->
- [{sctp, ?util:have_sctp()} | Config].
+%% run/0
-end_per_suite(_Config) ->
- ok.
+run() ->
+ ok = diameter:start(),
+ try
+ ?util:run([[fun run/1, {P,F}]
+ || P <- [sctp || ?util:have_sctp()] ++ [tcp],
+ F <- [connect, accept, reconnect]])
+ after
+ diameter:stop()
+ end.
-%% ===========================================================================
+%% run/1
-start(_Config) ->
- ok = diameter:start().
+run({Prot, reconnect}) ->
+ reconnect(Prot);
-stop(_Config) ->
- ok = diameter:stop().
+run({Prot, accept}) ->
+ accept(Prot);
+
+run({Prot, connect}) ->
+ connect(Prot).
%% ===========================================================================
-%% tcp_accept/1
-%% sctp_accept/1
+%% accept/1
%%
%% diameter transport accepting, test code connecting.
-tcp_accept(_) ->
- accept(tcp).
-
-sctp_accept(Config) ->
- case lists:member({sctp, true}, Config) of
- true -> accept(sctp);
- false -> {skip, no_sctp}
- end.
-
-%% Start multiple accepting transport processes that are connected to
-%% with an equal number of connecting processes using gen_tcp/sctp
-%% directly.
-
--define(PEER_COUNT, 8).
-
accept(Prot) ->
Ref = make_ref(),
true = diameter_reg:add_new({diameter_config, transport, Ref}), %% fake it
T = {Prot, Ref},
- [] = ?util:run(?util:scramble(acc(2*?PEER_COUNT, T, []))).
-
-acc(0, _, Acc) ->
- Acc;
-acc(N, T, Acc) ->
- acc(N-1, T, [{?MODULE, [init,
- element(1 + N rem 2, {accept, gen_connect}),
- T]}
- | Acc]).
+ ?util:run([{{?MODULE, [init, X, T]}, 15000}
+ || X <- [accept, gen_connect]]).
%% ===========================================================================
-%% tcp_connect/1
-%% sctp_connect/1
+%% connect/1
%%
%% Test code accepting, diameter transport connecting.
-tcp_connect(_) ->
- connect(tcp).
-
-sctp_connect(Config) ->
- case lists:member({sctp, true}, Config) of
- true -> connect(sctp);
- false -> {skip, no_sctp}
- end.
-
connect(Prot) ->
T = {Prot, make_ref()},
- [] = ?util:run([{?MODULE, [init, X, T]} || X <- [gen_accept, connect]]).
+ ?util:run([{{?MODULE, [init, X, T]}, 15000}
+ || X <- [gen_accept, connect]]).
%% ===========================================================================
%% reconnect/1
@@ -179,9 +143,6 @@ connect(Prot) ->
%% doesn't try to establish a new connection until the old one is
%% broken.
-reconnect() ->
- [{timetrap, {minutes, 4}}].
-
reconnect({listen, Ref}) ->
SvcName = make_ref(),
ok = start_service(SvcName),
@@ -222,10 +183,11 @@ reconnect({connect, Ref}) ->
MRef = erlang:monitor(process, Pid),
?RECV({'DOWN', MRef, process, _, _});
-reconnect(_) ->
+reconnect(Prot) ->
Ref = make_ref(),
- [] = ?util:run([{?MODULE, [reconnect, {T, Ref}]}
- || T <- [listen, connect]]).
+ ?util:run([{{?MODULE, [reconnect, {T, Ref}]}, 240000}
+ || Prot == tcp, %% ignore sctp
+ T <- [listen, connect]]).
start_service(SvcName) ->
OH = diameter_util:unique_string(),
@@ -430,8 +392,9 @@ gen_send(tcp, Sock, Bin) ->
gen_recv(sctp, Sock) ->
{_OS, _IS, Id} = getr(assoc),
receive
- ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], Bin})
+ ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = I}], Bin})
when is_binary(Bin) ->
+ {Id, _} = {I, Id}, %% assert
Bin
end;
gen_recv(tcp, Sock) ->
diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl
index e2fd3333d3..18b12da827 100644
--- a/lib/diameter/test/diameter_util.erl
+++ b/lib/diameter/test/diameter_util.erl
@@ -31,6 +31,9 @@
fold/3,
foldl/3,
scramble/1,
+ choose/1,
+ tmpdir/0,
+ mktemp/1,
unique_string/0,
have_sctp/0,
eprof/1]).
@@ -42,11 +45,6 @@
disconnect/4,
info/0]).
-%% common_test-specific
--export([write_priv/3,
- read_priv/2,
- map_priv/3]).
-
-define(L, atom_to_list).
%% ---------------------------------------------------------------------------
@@ -102,18 +100,37 @@ consult(Path) ->
%% ---------------------------------------------------------------------------
%% run/1
%%
-%% Evaluate functions in parallel and return a list of those that
-%% failed to return. The fun takes a boolean (did the function return
-%% or not), the function that was evaluated, the return value or exit
-%% reason and the prevailing accumulator.
+%% Evaluate functions in parallel and raise an error exception if any
+%% fail to return.
run(L) ->
- fold(fun cons/4, [], L).
-
-cons(true, _, _, Acc) ->
- Acc;
-cons(false, F, RC, Acc) ->
- [{F, RC} | Acc].
+ Ref = make_ref(),
+ AccF = fun(I, [F|T]) ->
+ Ref == (catch element(1, I))
+ orelse error(#{failed => F, reason => I}),
+ T
+ end,
+ Pid = self(),
+ Funs = [fun() -> down(Pid, self()), {Ref, eval(F)} end || F <- L],
+ [] = fold(AccF, L, Funs).
+
+%% down/2
+
+down(Parent, Worker)
+ when is_pid(Parent) ->
+ spawn(fun() ->
+ monitor(process, Worker),
+ down(monitor(process, Parent), Worker)
+ end);
+
+%% Die with the worker, kill the worker if the parent dies.
+down(MRef, Pid) ->
+ receive
+ {'DOWN', MRef, process, _, _} ->
+ exit(Pid, kill);
+ {'DOWN', _, process, Pid, _} ->
+ ok
+ end.
%% ---------------------------------------------------------------------------
%% fold/3
@@ -121,61 +138,43 @@ cons(false, F, RC, Acc) ->
%% Parallel fold. Results are folded in the order received.
fold(Fun, Acc0, L)
- when is_function(Fun, 4) ->
- Ref = make_ref(),
- %% Spawn a middleman to collect down messages from processes
- %% spawned for each function so as not to assume that all DOWN
- %% messages are ours.
- MRef = run1([fun fold/4, Ref, Fun, Acc0, L], Ref),
- {Ref, RC} = down(MRef),
- RC.
-
-fold(Ref, Fun, Acc0, L) ->
- recv(run(Ref, L), Ref, Fun, Acc0).
-
-run(Ref, L) ->
- [{run1(F, Ref), F} || F <- L].
-
-run1(F, Ref) ->
- {_, MRef} = spawn_monitor(fun() -> exit({Ref, eval(F)}) end),
- MRef.
-
-recv([], _, _, Acc) ->
+ when is_list(L) ->
+ fold(Fun, Acc0, lists:foldl(fun(F,A) ->
+ {P,M} = spawn_eval(F),
+ A#{M => P}
+ end,
+ #{},
+ L));
+
+fold(_, Acc, Map)
+ when 0 == map_size(Map) ->
Acc;
-recv(L, Ref, Fun, Acc) ->
- {MRef, R} = down(),
- {MRef, F} = lists:keyfind(MRef, 1, L),
- recv(lists:keydelete(MRef, 1, L),
- Ref,
- Fun,
- acc(R, Ref, F, Fun, Acc)).
-acc({Ref, RC}, Ref, F, Fun, Acc) ->
- Fun(true, F, RC, Acc);
-acc(Reason, _, F, Fun, Acc) ->
- Fun(false, F, Reason, Acc).
+fold(Fun, Acc, #{} = Map) ->
+ receive
+ {'DOWN', MRef, process, _, Info} when is_map_key(MRef, Map) ->
+ fold(Fun, Fun(Info, Acc), maps:remove(MRef, Map))
+ end.
-down(MRef) ->
- receive {'DOWN', MRef, process, _, Reason} -> Reason end.
+%% spawn_eval/1
-down() ->
- receive {'DOWN', MRef, process, _, Reason} -> {MRef, Reason} end.
+spawn_eval(F) ->
+ spawn_monitor(fun() -> exit(eval(F)) end).
%% ---------------------------------------------------------------------------
%% foldl/3
%%
%% Parallel fold. Results are folded in order of the function list.
-foldl(Fun, Acc0, L)
- when is_function(Fun, 4) ->
- Ref = make_ref(),
- recvl(run(Ref, L), Ref, Fun, Acc0).
+foldl(Fun, Acc0, L) ->
+ lists:foldl(fun(R,A) -> acc(Fun, R, A) end,
+ Acc0,
+ [M || F <- L, {_,M} <- [spawn_eval(F)]]).
-recvl([], _, _, Acc) ->
- Acc;
-recvl([{MRef, F} | L], Ref, Fun, Acc) ->
- R = down(MRef),
- recvl(L, Ref, Fun, acc(R, Ref, F, Fun, Acc)).
+%% acc/3
+
+acc(Fun, MRef, Acc) ->
+ receive {'DOWN', MRef, process, _, Info} -> Fun(Info, Acc) end.
%% ---------------------------------------------------------------------------
%% scramble/1
@@ -186,6 +185,33 @@ scramble(L) ->
[X || {_,X} <- lists:sort([{rand:uniform(), T} || T <- L])].
%% ---------------------------------------------------------------------------
+%% choose/1
+%%
+%% Return a random element from a list.
+
+choose([_|_] = List) ->
+ hd(lists:nthtail(rand:uniform(length(List)) - 1, List)).
+
+%% ---------------------------------------------------------------------------
+%% tmpdir/0
+
+tmpdir() ->
+ case os:getenv("TMPDIR") of
+ false ->
+ "/tmp";
+ Dir ->
+ Dir
+ end.
+
+%% mktemp/1
+
+mktemp(Prefix) ->
+ Suf = integer_to_list(erlang:monotonic_time()),
+ Tmp = Prefix ++ "." ++ Suf,
+ ok = file:make_dir(Tmp),
+ Tmp.
+
+%% ---------------------------------------------------------------------------
%% unique_string/0
unique_string() ->
@@ -208,8 +234,7 @@ have_sctp(_) ->
{ok, Sock} ->
gen_sctp:close(Sock),
true;
- {error, E} when E == eprotonosupport;
- E == esocktnosupport -> %% fail on any other reason
+ _ ->
false
end.
@@ -218,6 +243,13 @@ have_sctp(_) ->
%%
%% Evaluate a function in one of a number of forms.
+eval({F, infinity}) ->
+ eval(F);
+eval({F, Tmo})
+ when is_integer(Tmo) ->
+ {ok, _} = timer:exit_after(Tmo, timeout),
+ eval(F);
+
eval({M,[F|A]})
when is_atom(F) ->
apply(M,F,A);
@@ -231,55 +263,13 @@ eval([F|A])
eval(L)
when is_list(L) ->
- run(L);
+ [eval(F) || F <- L];
eval(F)
when is_function(F,0) ->
F().
%% ---------------------------------------------------------------------------
-%% write_priv/3
-%%
-%% Write an arbitrary term to a named file.
-
-write_priv(Config, Name, Term) ->
- write(path(Config, Name), Term).
-
-write(Path, Term) ->
- ok = file:write_file(Path, term_to_binary(Term)).
-
-%% read_priv/2
-%%
-%% Read a term from a file.
-
-read_priv(Config, Name) ->
- read(path(Config, Name)).
-
-read(Path) ->
- {ok, Bin} = file:read_file(Path),
- binary_to_term(Bin).
-
-%% map_priv/3
-%%
-%% Modify a term in a file and return both old and new values.
-
-map_priv(Config, Name, Fun1) ->
- map(path(Config, Name), Fun1).
-
-map(Path, Fun1) ->
- T0 = read(Path),
- T1 = Fun1(T0),
- write(Path, T1),
- {T0, T1}.
-
-path(Config, Name)
- when is_atom(Name) ->
- path(Config, ?L(Name));
-path(Config, Name) ->
- Dir = proplists:get_value(priv_dir, Config),
- filename:join([Dir, Name]).
-
-%% ---------------------------------------------------------------------------
%% lport/2
%%
%% Lookup the port number of a tcp/sctp listening transport.
diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl
index f3f168e671..02f15ff21b 100644
--- a/lib/diameter/test/diameter_watchdog_SUITE.erl
+++ b/lib/diameter/test/diameter_watchdog_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,18 +25,22 @@
-module(diameter_watchdog_SUITE).
+%% testcases, no common_test dependency
+-export([run/0,
+ run/1]).
+
+%% common_test wrapping
-export([suite/0,
all/0,
- init_per_suite/1,
- end_per_suite/1]).
-
-%% testcases
--export([reopen/0, reopen/1, reopen/4, reopen/6,
- suspect/1, suspect/4,
- okay/1, okay/4]).
-
--export([id/1, %% jitter callback
- run1/1,
+ reopen/1,
+ suspect/1,
+ okay/1]).
+
+%% internal callbacks
+-export([reopen/4, reopen/6,
+ suspect/4,
+ okay/4,
+ id/1, %% jitter callback
abuse/1,
abuse/2]).
@@ -48,7 +52,6 @@
-export([message/3]).
-include("diameter.hrl").
--include("diameter_ct.hrl").
%% ===========================================================================
@@ -105,49 +108,72 @@
[])).
%% Log to make failures identifiable.
--define(LOG(T), ?LOG("~p", [T])).
--define(LOG(F,A), ct:pal("~p: " ++ F, [self() | A])).
--define(WARN(F,A), ct:pal(error, "~p: " ++ F, [self() | A])).
+-define(LOG(F,A), io:format("~p: " ++ F ++ "~n", [self() | A])).
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 90}}].
+ [{timetrap, {seconds, 315}}].
all() ->
- [reopen,
- suspect,
- okay].
+ [reopen, suspect, okay].
-init_per_suite(Config) ->
- ok = diameter:start(),
- Config.
+reopen(_Config) ->
+ run([reopen]).
+
+suspect(_Config) ->
+ run([suspect]).
+
+okay(_Config) ->
+ run([okay]).
+
+%% ===========================================================================
+
+%% run/0
-end_per_suite(_Config) ->
- ok = diameter:stop().
+run() ->
+ run(all()).
+
+%% run/1.
+
+run(reopen) ->
+ reopen(); %% 20 watchdogs @ 15 sec
+
+run(suspect) ->
+ suspect();
+
+run(okay) ->
+ okay();
+
+run(List) ->
+ ok = diameter:start(),
+ try
+ ?util:run([{[fun run/1, T], maps:get(T, #{reopen => 300000}, 90000)}
+ || T <- List])
+ after
+ ok = diameter:stop()
+ end.
%% ===========================================================================
-%% # reopen/1
+%% # reopen/0
%% ===========================================================================
%% Test the watchdog state machine for the required failover, failback
%% and reopen behaviour by examining watchdog events.
reopen() ->
- [{timetrap, {minutes, 5}}]. %% 20 watchdogs @ 15 sec
-
-reopen(_) ->
- [] = run([[reopen, T, W, N, M]
- || T <- [listen, connect], %% watchdog to test
- W <- ?WD_TIMERS, %% watchdog_timer value
- N <- [0,1,2], %% DWR's to answer before ignoring
- M <- ['DWR', 'DWA', 'RAA']]). %% how to induce failback
+ ?util:run([{?MODULE, reopen, [T, W, N, M]}
+ || T <- [listen, connect], %% watchdog to test
+ W <- ?WD_TIMERS, %% watchdog_timer value
+ N <- [0,1,2], %% DWR's to answer before ignoring
+ M <- ['DWR', 'DWA', 'RAA']]). %% how to induce failback
reopen(Test, Wd, N, M) ->
%% Publish a ref ensure the connecting transport is added only
%% once events from the listening transport are subscribed to.
Ref = make_ref(),
- [] = run([[reopen, T, Test, Ref, Wd, N, M] || T <- [listen, connect]]).
+ ?util:run([{?MODULE, reopen, [T, Test, Ref, Wd, N, M]}
+ || T <- [listen, connect]]).
%% reopen/6
@@ -377,14 +403,14 @@ tpid(Ref, [[{ref, Ref},
TPid.
%% ===========================================================================
-%% # suspect/1
+%% # suspect/0
%% ===========================================================================
%% Configure transports to require a set number of watchdog timeouts
%% before moving from OKAY to SUSPECT.
-suspect(_) ->
- [] = run([[abuse, [suspect, N]] || N <- [0,1,3]]).
+suspect() ->
+ ?util:run([{?MODULE, abuse, [[suspect, N]]} || N <- [0,1,3]]).
suspect(Type, Fake, Ref, N)
when is_reference(Ref) ->
@@ -417,7 +443,7 @@ suspect(TRef, false, SvcName, N) ->
%% abuse/1
abuse(F) ->
- [] = run([[abuse, F, T] || T <- [listen, connect]]).
+ ?util:run([{?MODULE, abuse, [F, T]} || T <- [listen, connect]]).
abuse(F, [_,_,_|_] = Args) ->
?LOG("~p", [Args]),
@@ -425,21 +451,21 @@ abuse(F, [_,_,_|_] = Args) ->
abuse([F|A], Test) ->
Ref = make_ref(),
- [] = run([[abuse, F, [T, T == Test, Ref] ++ A]
- || T <- [listen, connect]]);
+ ?util:run([{?MODULE, abuse, [F, [T, T == Test, Ref] ++ A]}
+ || T <- [listen, connect]]);
abuse(F, Test) ->
abuse([F], Test).
%% ===========================================================================
-%% # okay/1
+%% # okay/0
%% ===========================================================================
%% Configure the number of watchdog exchanges before moving from
%% REOPEN to OKAY.
-okay(_) ->
- [] = run([[abuse, [okay, N]] || N <- [0,2,3]]).
+okay() ->
+ ?util:run([{?MODULE, abuse, [[okay, N]]} || N <- [0,2,3]]).
okay(Type, Fake, Ref, N)
when is_reference(Ref) ->
@@ -626,23 +652,6 @@ choose(false, _, X) -> X.
id(T) ->
T.
-%% run/1
-%%
-%% A more useful badmatch in case of failure.
-
-run(Fs) ->
- ?util:run([{?MODULE, [run1, F]} || F <- Fs]).
-
-run1([F|A]) ->
- ok = try
- apply(?MODULE, F, A),
- ok
- catch
- E:R:Stack ->
- ?WARN("~p", [{A, E, R, Stack}]),
- Stack
- end.
-
%% jitter/2
jitter(?WD(T), _) ->
diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk
index b1717aff00..fb8cfc445c 100644
--- a/lib/diameter/test/modules.mk
+++ b/lib/diameter/test/modules.mk
@@ -50,9 +50,6 @@ MODULES = \
diameter_transport_SUITE \
diameter_watchdog_SUITE
-HRL_FILES = \
- diameter_ct.hrl
-
DATA = \
diameter_codec_SUITE_data/avps.dia \
diameter_codec_SUITE_data/send.dia \