aboutsummaryrefslogtreecommitdiffstats
path: root/lib/diameter/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/diameter/test')
-rw-r--r--lib/diameter/test/Makefile5
-rw-r--r--lib/diameter/test/diameter_codec_test.erl6
-rw-r--r--lib/diameter/test/diameter_compiler_SUITE.erl51
-rw-r--r--lib/diameter/test/diameter_config_SUITE.erl261
-rw-r--r--lib/diameter/test/diameter_ct.erl2
-rw-r--r--lib/diameter/test/diameter_examples_SUITE.erl334
-rw-r--r--lib/diameter/test/modules.mk2
7 files changed, 609 insertions, 52 deletions
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index 061f0bcbef..9719c67b32 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -93,6 +93,11 @@ info:
@$(call list,HRL_FILES)
@echo
@$(call list,SUITES)
+ @echo
+ @echo erl = $(shell which erl)
+ @erl -noinput \
+ -eval 'io:format("diameter = ~s~n", [code:lib_dir(diameter)])' \
+ -s init stop
@echo ========================================
help:
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index dc8cbffc83..0baac59c1a 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -65,7 +65,7 @@ lib(N, {_,_} = T) ->
lib(IP, B) ->
LA = tuple_to_list(IP),
{SA,Fun} = ip(LA),
- [] = run([[fun lib/4, IP, B, Fun, A] || A <- [IP, LA, SA]]).
+ [] = run([[fun lib/4, IP, B, Fun, A] || A <- [IP, SA]]).
lib(IP, B, Fun, A) ->
try Fun(A) of
@@ -78,10 +78,10 @@ lib(IP, B, Fun, A) ->
ip([_,_,_,_] = A) ->
[$.|S] = lists:append(["." ++ integer_to_list(N) || N <- A]),
- {S, fun diameter_lib:ip4address/1};
+ {S, fun diameter_lib:ipaddr/1};
ip([_,_,_,_,_,_,_,_] = A) ->
[$:|S] = lists:flatten([":" ++ io_lib:format("~.16B", [N]) || N <- A]),
- {S, fun diameter_lib:ip6address/1}.
+ {S, fun diameter_lib:ipaddr/1}.
%% ------------------------------------------------------------------------
%% base/1
diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl
index 79bf9d32db..81722c8dca 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-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,8 +31,7 @@
%% testcases
-export([format/1, format/2,
replace/1, replace/2,
- generate/1, generate/4,
- examples/1]).
+ generate/1, generate/4]).
-export([dict/0]). %% fake dictionary module
@@ -328,14 +327,6 @@
"@codecs mymod "
"Origin-Host Origin-Realm\n&"}]}]).
-%% Standard dictionaries in examples/dict.
--define(EXAMPLES, [rfc4004_mip,
- rfc4005_nas,
- rfc4006_cc,
- rfc4072_eap,
- rfc4590_digest,
- rfc4740_sip]).
-
%% ===========================================================================
suite() ->
@@ -344,8 +335,7 @@ suite() ->
all() ->
[format,
replace,
- generate,
- examples].
+ generate].
%% Error handling testcases will make an erroneous dictionary out of
%% the base dictionary and check that the expected error results.
@@ -429,41 +419,6 @@ generate(Mods, Bin, N, Mode) ->
andalso ({ok, _} = compile:file(File ++ ".erl", [return_errors])).
%% ===========================================================================
-%% examples/1
-%%
-%% Compile dictionaries extracted from various standards.
-
-examples(_Config) ->
- Dir = filename:join([code:lib_dir(diameter, examples), "dict"]),
- [D || D <- ?EXAMPLES, _ <- [examples(?S(D), Dir)]].
-
-examples(Dict, Dir) ->
- {Name, Pre} = make_name(Dict),
- ok = diameter_make:codec(filename:join([Dir, Dict ++ ".dia"]),
- [{name, Name},
- {prefix, Pre},
- inherits("rfc3588_base")
- | opts(Dict)]),
- {ok, _, _} = compile:file(Name ++ ".erl", [return]).
-
-opts(M)
- when M == "rfc4006_cc";
- M == "rfc4072_eap" ->
- [inherits("rfc4005_nas")];
-opts("rfc4740_sip") ->
- [inherits("rfc4590_digest")];
-opts(_) ->
- [].
-
-inherits(File) ->
- {Name, _} = make_name(File),
- {inherits, File ++ "/" ++ Name}.
-
-make_name(File) ->
- {R, [$_|N]} = lists:splitwith(fun(C) -> C /= $_ end, File),
- {string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}.
-
-%% ===========================================================================
modify(Bin, Mods) ->
lists:foldl(fun re/2, Bin, Mods).
diff --git a/lib/diameter/test/diameter_config_SUITE.erl b/lib/diameter/test/diameter_config_SUITE.erl
new file mode 100644
index 0000000000..47def9c8c9
--- /dev/null
+++ b/lib/diameter/test/diameter_config_SUITE.erl
@@ -0,0 +1,261 @@
+%% coding: utf-8
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Test service and transport config. In particular, of the detection
+%% of config errors.
+%%
+
+-module(diameter_config_SUITE).
+
+-export([suite/0,
+ all/0]).
+
+%% testcases
+-export([start/1,
+ start_service/1,
+ add_transport/1,
+ stop/1]).
+
+-define(util, diameter_util).
+
+%% Lists of {Key, GoodConfigList, BadConfigList} with which to
+%% configure.
+
+-define(SERVICE_CONFIG,
+ [{application,
+ [[[{dictionary, diameter_gen_base_rfc6733},
+ {module, ?MODULE}]]
+ | [[[{dictionary, D},
+ {module, M},
+ {alias, A},
+ {state, S},
+ {answer_errors, AE},
+ {request_errors, RE},
+ {call_mutates_state, C}]]
+ || D <- [diameter_gen_base_rfc3588, diameter_gen_base_rfc6733],
+ M <- [?MODULE, [?MODULE, now()]],
+ A <- [0, common, make_ref()],
+ S <- [[], make_ref()],
+ AE <- [report, callback, discard],
+ RE <- [answer_3xxx, answer, callback],
+ C <- [true, false]]],
+ [[x],
+ [[]],
+ [[{dictionary, diameter_gen_base_rfc3588}]],
+ [[{module, ?MODULE}]]
+ | [[[{dictionary, diameter_gen_base_rfc6733},
+ {module, ?MODULE},
+ {K,x}]]
+ || K <- [answer_errors,
+ request_errors,
+ call_mutates_state]]]},
+ {restrict_connections,
+ [[false], [node], [nodes], [[node(), node()]]],
+ []},
+ {sequence,
+ [[{0,32}], [{1,31}]],
+ [[{2,31}]]},
+ {share_peers,
+ [[true],
+ [false],
+ [[node()]]],
+ [[x]]},
+ {use_shared_peers,
+ [[true],
+ [false],
+ [[node(), node()]]],
+ [[x]]}]).
+
+-define(TRANSPORT_CONFIG,
+ [{transport_module,
+ [[?MODULE]],
+ [[[?MODULE]]]},
+ {transport_config,
+ [[{}, 3000],
+ [{}, infinity]],
+ [[{}, x]]},
+ {applications,
+ [[[1, a, [x]]]],
+ [[x]]},
+ {capabilities,
+ [[[{'Origin-Host', "diameter.erlang.org"}]],
+ [[{'Origin-Realm', "erlang.org"}]]]
+ ++ [[[{'Host-IP-Address', L}]]
+ || L <- [[{127,0,0,1}],
+ ["127.0.0.1"],
+ ["127.0.0.1", "FFFF::1", "::1", {1,2,3,4,5,6,7,8}]]]
+ ++ [[[{'Product-Name', N}]]
+ || N <- [["Product", $-, ["Name"]],
+ "Norðurálfa",
+ "ᚠᚢᚦᚨᚱᚲ"]]
+ ++ [[[{K,V}]]
+ || K <- ['Vendor-Id',
+ 'Origin-State-Id',
+ 'Firmware-Revision'],
+ V <- [0, 256, 16#FFFF]]
+ ++ [[[{K,V}]]
+ || K <- ['Supported-Vendor-Id',
+ 'Auth-Application-Id',
+ 'Acct-Application-Id',
+ 'Inband-Security-Id'],
+ V <- [[17], [0, 256, 16#FFFF]]]
+ ++ [[[{'Vendor-Specific-Application-Id',
+ [[{'Vendor-Id', V},
+ {'Auth-Application-Id', [0]},
+ {'Acct-Application-Id', [4]}]]}]]
+ || V <- [1, [1]]],
+ [[x], [[{'Origin-Host', "ᚠᚢᚦᚨᚱᚲ"}]]]
+ ++ [[[{'Host-IP-Address', A}]]
+ || A <- [{127,0,0,1}]]
+ ++ [[[{'Product-Name', N}]]
+ || N <- [x, 1]]
+ ++ [[[{K,V}]]
+ || K <- ['Vendor-Id',
+ 'Origin-State-Id',
+ 'Firmware-Revision'],
+ V <- [x, [0], -1, 1 bsl 32]]
+ ++ [[[{K,V}]]
+ || K <- ['Supported-Vendor-Id',
+ 'Auth-Application-Id',
+ 'Acct-Application-Id',
+ 'Inband-Security-Id'],
+ V <- [x, 17, [-1], [1 bsl 32]]]
+ ++ [[[{'Vendor-Specific-Application-Id', V}]]
+ || V <- [x,
+ [[{'Vendor-Id', 1 bsl 32}]],
+ [[{'Auth-Application-Id', 1}]]]]},
+ {capabilities_cb,
+ [[x]],
+ []},
+ {capx_timeout,
+ [[3000]],
+ [[{?MODULE, tmo, []}]]},
+ {disconnect_cb,
+ [[x]],
+ []},
+ {length_errors,
+ [[exit], [handle], [discard]],
+ [[x]]},
+ {reconnect_timer,
+ [[3000]],
+ [[infinity]]},
+ {watchdog_timer,
+ [[3000],
+ [{?MODULE, tmo, []}]],
+ [[infinity],
+ [-1]]},
+ {watchdog_config,
+ [[[{okay, 0}, {suspect, 0}]],
+ [[{okay, 1}]],
+ [[{suspect, 2}]]],
+ [[x],
+ [[{open, 0}]]]}]).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 60}}].
+
+all() ->
+ [start,
+ start_service,
+ add_transport,
+ stop].
+
+%% ===========================================================================
+
+start(_) ->
+ ok = diameter:start().
+
+start_service(T)
+ when is_tuple(T) ->
+ do(fun start/3, T);
+
+start_service(_) ->
+ [] = ?util:run([{?MODULE, start_service, [T]}
+ || T <- [lists:keyfind(capabilities, 1, ?TRANSPORT_CONFIG)
+ | ?SERVICE_CONFIG]]).
+
+add_transport(T)
+ when is_tuple(T) ->
+ do(fun add/3, T);
+
+add_transport(_) ->
+ [] = ?util:run([{?MODULE, add_transport, [T]}
+ || T <- ?TRANSPORT_CONFIG]).
+
+stop(_) ->
+ ok = diameter:stop().
+
+%% ===========================================================================
+
+%% do/2
+
+do(F, {Key, Good, Bad}) ->
+ F(Key, Good, Bad).
+
+%% add/3
+
+add(Key, Good, Bad) ->
+ {[],[]} = {[{Vs,T} || Vs <- Good,
+ T <- [add(Key, Vs)],
+ [T] /= [T || {ok,_} <- [T]]],
+ [{Vs,T} || Vs <- Bad,
+ T <- [add(Key, Vs)],
+ [T] /= [T || {error,_} <- [T]]]}.
+
+add(Key, Vs) ->
+ T = list_to_tuple([Key | Vs]),
+ diameter:add_transport(make_ref(), {connect, [T]}).
+
+%% start/3
+
+start(Key, Good, Bad) ->
+ {[],[]} = {[{Vs,T} || Vs <- Good,
+ T <- [start(Key, Vs)],
+ T /= ok],
+ [{Vs,T} || Vs <- Bad,
+ T <- [start(Key, Vs)],
+ [T] /= [T || {error,_} <- [T]]]}.
+
+start(capabilities = K, [Vs]) ->
+ if is_list(Vs) ->
+ start(make_ref(), Vs ++ apps(K));
+ true ->
+ {error, Vs}
+ end;
+
+start(Key, Vs)
+ when is_atom(Key) ->
+ start(make_ref(), [list_to_tuple([Key | Vs]) | apps(Key)]);
+
+start(SvcName, Opts) ->
+ try
+ diameter:start_service(SvcName, Opts)
+ after
+ diameter:stop_service(SvcName)
+ end.
+
+apps(application) ->
+ [];
+apps(_) ->
+ [{application, [{dictionary, diameter_gen_base_rfc6733},
+ {module, ?MODULE}]}].
diff --git a/lib/diameter/test/diameter_ct.erl b/lib/diameter/test/diameter_ct.erl
index 1697287a22..ed2f884681 100644
--- a/lib/diameter/test/diameter_ct.erl
+++ b/lib/diameter/test/diameter_ct.erl
@@ -53,7 +53,7 @@ info(L0, L1) ->
L0,
L1),
Diff = [T, C, {memory, M}],
- ct:pal("INFO: ~p~n", [Diff]).
+ io:format("INFO: ~p~n", [Diff]).
diff(time, T0, T1) ->
timer:now_diff(T1, T0);
diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl
new file mode 100644
index 0000000000..6d797f6911
--- /dev/null
+++ b/lib/diameter/test/diameter_examples_SUITE.erl
@@ -0,0 +1,334 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Test example code under ../examples/code.
+%%
+
+-module(diameter_examples_SUITE).
+
+-export([suite/0,
+ all/0]).
+
+%% testcases
+-export([dict/1, dict/0,
+ code/1,
+ enslave/1,
+ start/1,
+ traffic/1,
+ stop/1]).
+
+-export([install/1,
+ call/1]).
+
+-include("diameter.hrl").
+
+%% ===========================================================================
+
+-define(util, diameter_util).
+
+%% The order here is significant and causes the server to listen
+%% before the clients connect.
+-define(NODES, [compile, server, client]).
+
+%% Options to ct_slave:start/2.
+-define(TIMEOUTS, [{T, 15000} || T <- [boot_timeout,
+ init_timeout,
+ start_timeout]]).
+
+%% @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.
+-define(INHERITS, [{rfc4006_cc, [rfc4005_nas]},
+ {rfc4072_eap, [rfc4005_nas]},
+ {rfc4740_sip, [rfc4590_digest]}]).
+
+%% Common dictionaries to inherit from examples.
+-define(DICT0, [rfc3588_base, rfc6733_base]).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 45}}].
+
+all() ->
+ [dict,
+ code,
+ enslave,
+ start,
+ traffic,
+ stop].
+
+%% ===========================================================================
+%% dict/1
+%%
+%% Compile example dictionaries in examples/dict.
+
+dict() ->
+ [{timetrap, {minutes, 10}}].
+
+dict(_Config) ->
+ Dirs = [filename:join(H ++ ["examples", "dict"])
+ || H <- [[code:lib_dir(diameter)], [here(), ".."]]],
+ [] = [{F,D,RC} || {_,F} <- sort(find_files(Dirs, ".*\\.dia")),
+ D <- ?DICT0,
+ RC <- [make(F,D)],
+ RC /= ok].
+
+sort([{_,_} | _] = Files) ->
+ lists:sort(fun({A,_},{B,_}) ->
+ sort([filename:rootname(F) || F <- [A,B]])
+ end,
+ Files);
+
+sort([A,B] = L) ->
+ [DA,DB] = [dep([D],[]) || D <- L],
+ case {[A] -- DB, [B] -- DA} of
+ {[], [_]} -> %% B depends on A
+ true;
+ {[_], []} -> %% A depends on B
+ false;
+ {[_],[_]} -> %% or not
+ length(DA) < length(DB)
+ end.
+
+%% Recursively accumulate inherited dictionaries.
+dep([D|Rest], Acc) ->
+ dep(dep(D), Rest, Acc);
+dep([], Acc) ->
+ Acc.
+
+dep([{Dict, _} | T], Rest, Acc) ->
+ dep(T, [Dict | Rest], [Dict | Acc]);
+dep([], Rest, Acc) ->
+ dep(Rest, Acc).
+
+make(Path, Dict0)
+ when is_atom(Dict0) ->
+ make(Path, atom_to_list(Dict0));
+
+make(Path, Dict0) ->
+ Dict = filename:rootname(filename:basename(Path)),
+ {Mod, Pre} = make_name(Dict),
+ {"diameter_gen_base" ++ Suf = Mod0, _} = make_name(Dict0),
+ Name = Mod ++ Suf,
+ try
+ ok = to_erl(Path, [{name, Name},
+ {prefix, Pre},
+ {inherits, "rfc3588_base/" ++ Mod0}
+ | [{inherits, D ++ "/" ++ M ++ Suf}
+ || {D,M} <- dep(Dict)]]),
+ ok = to_beam(Name)
+ catch
+ throw: {_,_} = E ->
+ E
+ end.
+
+to_erl(File, Opts) ->
+ case diameter_make:codec(File, Opts) of
+ ok ->
+ ok;
+ No ->
+ throw({make, No})
+ end.
+
+to_beam(Name) ->
+ case compile:file(Name ++ ".erl", [return]) of
+ {ok, _, _} ->
+ ok;
+ No ->
+ throw({compile, No})
+ end.
+
+dep(Dict) ->
+ case lists:keyfind(list_to_atom(Dict), 1, ?INHERITS) of
+ {_, Is} ->
+ lists:map(fun inherits/1, Is);
+ false ->
+ []
+ end.
+
+inherits(Dict)
+ when is_atom(Dict) ->
+ inherits(atom_to_list(Dict));
+
+inherits(Dict) ->
+ {Name, _} = make_name(Dict),
+ {Dict, Name}.
+
+make_name(Dict) ->
+ {R, [$_|N]} = lists:splitwith(fun(C) -> C /= $_ end, Dict),
+ {string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}.
+
+%% ===========================================================================
+%% code/1
+%%
+%% Compile example code under examples/code.
+
+code(Config) ->
+ Node = slave(hd(?NODES), here()),
+ [] = rpc:call(Node,
+ ?MODULE,
+ install,
+ [proplists:get_value(priv_dir, Config)]).
+
+%% Compile on another node since the code path may be modified.
+install(PrivDir) ->
+ Top = install(here(), PrivDir),
+ 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])]].
+
+%% Copy include files into a temporary directory and adjust the code
+%% path in order for example code to be able to include them with
+%% include_lib. This is really only required when running in the reop
+%% since generated includes, that the example code wants to
+%% include_lib, are under src/gen and there's no way to get get the
+%% 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 by slave/1 (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),
+ 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"]),
+ [] = [{T,E} || T <- [Tmp, TmpInc, TmpEbin],
+ {error, E} <- [file:make_dir(T)]],
+
+ Inc = filename:join([Top, "include"]),
+ Gen = filename:join([Top, "src", "gen"]),
+ Files = find_files([Inc, Gen], ".*\\.hrl"),
+ [] = [{F,E} || {_,F} <- Files,
+ 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.
+
+find_files(Dirs, RE) ->
+ lists:foldl(fun(D,A) -> fold_files(D, RE, A) end,
+ orddict:new(),
+ Dirs).
+
+fold_files(Dir, RE, Acc) ->
+ filelib:fold_files(Dir, RE, false, fun store/2, Acc).
+
+store(Path, Dict) ->
+ orddict:store(filename:basename(Path), Path, Dict).
+
+%% ===========================================================================
+
+%% enslave/1
+%%
+%% Start two nodes: one for the server, one for the client.
+
+enslave(Config) ->
+ Dir = here(),
+ Nodes = [{N, slave(N, Dir)} || N <- tl(?NODES)],
+ ?util:write_priv(Config, nodes, Nodes).
+
+slave(Name, Dir) ->
+ {ok, Node} = ct_slave:start(Name, ?TIMEOUTS),
+ ok = rpc:call(Node,
+ code,
+ add_pathsa,
+ [[Dir, filename:join([Dir, "..", "ebin"])]]),
+ Node.
+
+here() ->
+ filename:dirname(code:which(?MODULE)).
+
+top(Dir, LibDir) ->
+ File = filename:join([Dir, "depend.sed"]), %% only in the repo
+ case filelib:is_regular(File) of
+ true -> filename:join([Dir, ".."]);
+ false -> LibDir
+ end.
+
+%% start/1
+
+start(server) ->
+ ok = diameter:start(),
+ ok = server:start(),
+ {ok, Ref} = server:listen(tcp),
+ [_] = ?util:lport(tcp, Ref, 20),
+ ok;
+
+start(client) ->
+ ok = diameter:start(),
+ true = diameter:subscribe(client),
+ ok = client:start(),
+ {ok, Ref} = client:connect(tcp),
+ receive #diameter_event{info = {up, Ref, _, _, _}} -> ok end;
+
+start(Config) ->
+ Nodes = ?util:read_priv(Config, nodes),
+ [] = [RC || {T,N} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, start, [T])],
+ RC /= ok].
+
+%% traffic/1
+%%
+%% Send successful messages from client to server.
+
+traffic(server) ->
+ ok;
+
+traffic(client) ->
+ {_, MRef} = spawn_monitor(fun() -> call(100) end),
+ receive {'DOWN', MRef, process, _, Reason} -> Reason end;
+
+traffic(Config) ->
+ Nodes = ?util:read_priv(Config, nodes),
+ [] = [RC || {T,N} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, traffic, [T])],
+ RC /= ok].
+
+call(0) ->
+ exit(ok);
+
+call(N) ->
+ {ok, _} = client:call(),
+ call(N-1).
+
+%% stop/1
+
+stop(Name)
+ when is_atom(Name) ->
+ {ok, _Node} = ct_slave:stop(Name),
+ ok;
+
+stop(_Config) ->
+ [] = [RC || N <- ?NODES, RC <- [stop(N)], RC /= ok].
diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk
index beff588a02..1a829f8031 100644
--- a/lib/diameter/test/modules.mk
+++ b/lib/diameter/test/modules.mk
@@ -29,11 +29,13 @@ MODULES = \
diameter_capx_SUITE \
diameter_codec_SUITE \
diameter_codec_test \
+ diameter_config_SUITE \
diameter_compiler_SUITE \
diameter_dict_SUITE \
diameter_distribution_SUITE \
diameter_dpr_SUITE \
diameter_event_SUITE \
+ diameter_examples_SUITE \
diameter_failover_SUITE \
diameter_gen_sctp_SUITE \
diameter_length_SUITE \