aboutsummaryrefslogtreecommitdiffstats
path: root/lib/diameter/test/diameter_3xxx_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/diameter/test/diameter_3xxx_SUITE.erl')
-rw-r--r--lib/diameter/test/diameter_3xxx_SUITE.erl233
1 files changed, 203 insertions, 30 deletions
diff --git a/lib/diameter/test/diameter_3xxx_SUITE.erl b/lib/diameter/test/diameter_3xxx_SUITE.erl
index a87d5347db..c780fd9859 100644
--- a/lib/diameter/test/diameter_3xxx_SUITE.erl
+++ b/lib/diameter/test/diameter_3xxx_SUITE.erl
@@ -18,7 +18,9 @@
%%
%%
-%% Tests of application_opt() request_errors.
+%% Tests of application_opt() request_errors. There's some overlap
+%% between this suite and the traffic suite but latter exercises more
+%% config.
%%
-module(diameter_3xxx_SUITE).
@@ -35,16 +37,19 @@
%% testcases
-export([start/1,
- send/1,
+ send_unknown_command/1,
+ send_ok_override/1,
+ send_invalid_avp_bits/1,
+ send_double_error/1,
stop/1]).
%% diameter callbacks
-export([peer_up/3,
peer_down/3,
- pick_peer/4,
- prepare_request/3,
- handle_answer/4,
- handle_error/4,
+ pick_peer/5,
+ prepare_request/4,
+ handle_answer/5,
+ handle_error/5,
handle_request/3]).
-include("diameter.hrl").
@@ -73,13 +78,22 @@
{answer_errors, callback},
{request_errors, RequestErrors}]}]).
--define(SUCCESS, ?'DIAMETER_BASE_RESULT-CODE_SUCCESS').
--define(UNSUPPORTED, ?'DIAMETER_BASE_RESULT-CODE_COMMAND_UNSUPPORTED').
+-define(SUCCESS, 2001).
+-define(UNSUPPORTED_COMMAND, 3001).
+-define(INVALID_AVP_BITS, 3009).
+-define(UNKNOWN_SESSION_ID, 5002).
+-define(MISSING_AVP, 5005).
-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT').
-define(GROUPS, [answer_3xxx, callback]).
-define(L, atom_to_list).
+-define(A, list_to_atom).
+-define(v, proplists:get_value).
+
+-define(testcase(Config), put({?MODULE, testcase}, ?v(testcase, Config))).
+-define(testcase(), get({?MODULE, testcase})).
+-define(group(Config), ?v(group, Config)).
%% ===========================================================================
@@ -90,7 +104,8 @@ all() ->
[{group, G} || G <- ?GROUPS].
groups() ->
- [{G, [], [start, send, stop]} || G <- ?GROUPS].
+ Tc = tc(),
+ [{G, [], [start] ++ Tc ++ [stop]} || G <- ?GROUPS].
init_per_suite(Config) ->
ok = diameter:start(),
@@ -105,8 +120,8 @@ init_per_group(Group, Config) ->
end_per_group(_, _) ->
ok.
-init_per_testcase(_Name, Config) ->
- Config.
+init_per_testcase(Name, Config) ->
+ [{testcase, Name} | Config].
end_per_testcase(_, _) ->
ok.
@@ -117,6 +132,12 @@ origin(callback) -> 1;
origin(0) -> answer_3xxx;
origin(1) -> callback.
+tc() ->
+ [send_unknown_command,
+ send_ok_override,
+ send_invalid_avp_bits,
+ send_double_error].
+
%% ===========================================================================
%% start/1
@@ -139,30 +160,90 @@ stop(_Config) ->
ok = diameter:stop_service(?SERVER),
ok = diameter:stop_service(?CLIENT).
-%% send/1
+%% send_unknown_command/1
%%
%% Send a unknown command and expect a different result depending on
%% whether or not the server gets a handle_request callback.
%% Server handle_request discards the request.
-send(callback) ->
+send_unknown_command(callback) ->
{error, timeout} = call();
%% No handle_request, diameter answers.
-send(answer_3xxx) ->
- #'diameter_base_answer-message'{'Result-Code' = ?UNSUPPORTED} = call();
+send_unknown_command(answer_3xxx) ->
+ #'diameter_base_answer-message'{'Result-Code' = ?UNSUPPORTED_COMMAND}
+ = call();
+
+send_unknown_command(Config) ->
+ ?testcase(Config),
+ send_unknown_command(?group(Config)).
-send(Config) ->
- send(proplists:get_value(group, Config)).
+%% send_ok_override/1
+%%
+%% Send a correct STA and expect the same answer from handle_request
+%% in both cases.
+
+send_ok_override(A)
+ when is_atom(A) ->
+ #diameter_base_STA{'Result-Code' = ?UNKNOWN_SESSION_ID}
+ = call();
+
+send_ok_override(Config) ->
+ ?testcase(Config),
+ send_ok_override(?group(Config)).
+
+%% send_invalid_avp_bits/1
+%%
+%% Send a request with an incorrect length on the optional
+%% Origin-State-Id and expect a callback to ignore the error.
+
+send_invalid_avp_bits(callback) ->
+ #diameter_base_STA{'Result-Code' = ?SUCCESS,
+ 'Failed-AVP' = []}
+ = call();
+
+send_invalid_avp_bits(answer_3xxx) ->
+ #'diameter_base_answer-message'{'Result-Code' = ?INVALID_AVP_BITS,
+ 'Failed-AVP' = []}
+ = call();
+
+send_invalid_avp_bits(Config) ->
+ ?testcase(Config),
+ send_invalid_avp_bits(?group(Config)).
+
+%% send_double_error/1
+%%
+%% Send a request with both an incorrect length on the optional
+%% Origin-State-Id and a missing AVP and see that it's answered
+%% differently.
+
+%% diameter answers with the 3xxx error.
+send_double_error(answer_3xxx) ->
+ #'diameter_base_answer-message'{'Result-Code' = ?INVALID_AVP_BITS,
+ 'Failed-AVP' = [_]}
+ = call();
+
+%% handle_request answers with STA and diameter resets Result-Code.
+send_double_error(callback) ->
+ #diameter_base_STA{'Result-Code' = ?MISSING_AVP,
+ 'Failed-AVP' = [_]}
+ = call();
+
+send_double_error(Config) ->
+ ?testcase(Config),
+ send_double_error(?group(Config)).
%% ===========================================================================
call() ->
+ Name = ?testcase(),
diameter:call(?CLIENT,
?DICT,
#diameter_base_STR
{'Termination-Cause' = ?LOGOUT,
- 'Auth-Application-Id' = ?DIAMETER_APP_ID_COMMON}).
+ 'Auth-Application-Id' = ?DIAMETER_APP_ID_COMMON,
+ 'Class' = [?L(Name)]},
+ [{extra, [Name]}]).
%% ===========================================================================
%% diameter callbacks
@@ -177,14 +258,19 @@ peer_up(_SvcName, _Peer, State) ->
peer_down(_SvcName, _Peer, State) ->
State.
-%% pick_peer/4
+%% pick_peer/5
-pick_peer([Peer], _, ?CLIENT, _State) ->
+pick_peer([Peer], _, ?CLIENT, _State, _Name) ->
{ok, Peer}.
-%% prepare_request/3
+%% prepare_request/4
+
+prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, Name) ->
+ {send, prepare(Pkt, Caps, Name)}.
-prepare_request(#diameter_packet{msg = Req0} = Pkt0, ?CLIENT, {_Ref, Caps}) ->
+prepare(Pkt0, Caps, send_unknown_command) ->
+ #diameter_packet{msg = Req0}
+ = Pkt0,
#diameter_caps{origin_host = {OH, _},
origin_realm = {OR, DR}}
= Caps,
@@ -196,19 +282,106 @@ prepare_request(#diameter_packet{msg = Req0} = Pkt0, ?CLIENT, {_Ref, Caps}) ->
= Pkt
= diameter_codec:encode(?DICT, Pkt0#diameter_packet{msg = Req}),
- {send, Pkt#diameter_packet{bin = <<H/binary, 572:24, T/binary>>}}.
+ Pkt#diameter_packet{bin = <<H/binary, 572:24, T/binary>>};
-%% handle_answer/4
-
-handle_answer(Pkt, _Req, ?CLIENT, _Peer) ->
+prepare(Pkt, Caps, send_ok_override) ->
+ #diameter_packet{msg = Req}
+ = Pkt,
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, DR}}
+ = Caps,
+ Req#diameter_base_STR{'Session-Id' = diameter:session_id(OH),
+ 'Origin-Host' = OH,
+ 'Origin-Realm' = OR,
+ 'Destination-Realm' = DR};
+
+prepare(Pkt, Caps, send_invalid_avp_bits) ->
+ #diameter_packet{msg = Req0}
+ = Pkt,
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, DR}}
+ = Caps,
+ %% Append an Origin-State-Id with an incorrect AVP Length in order
+ %% to force 3009.
+ Req = Req0#diameter_base_STR{'Session-Id' = diameter:session_id(OH),
+ 'Origin-Host' = OH,
+ 'Origin-Realm' = OR,
+ 'Destination-Realm' = DR,
+ 'Origin-State-Id' = [7]},
+ #diameter_packet{bin = Bin}
+ = diameter_codec:encode(?DICT, Pkt#diameter_packet{msg = Req}),
+ Offset = size(Bin) - 12 + 5,
+ <<H:Offset/binary, Len:24, T/binary>> = Bin,
+ Pkt#diameter_packet{bin = <<H/binary, (Len + 2):24, T/binary>>};
+
+prepare(Pkt0, Caps, send_double_error) ->
+ #diameter_packet{bin = Bin}
+ = Pkt
+ = prepare(Pkt0, Caps, send_invalid_avp_bits),
+ %% Keep Session-Id but remove Origin-Host.
+ <<V, Len:24, H:16/binary, T0/binary>>
+ = Bin,
+ {SessionId, T1} = split_avp(T0),
+ {OriginHost, T} = split_avp(T1),
+ Delta = size(OriginHost),
+ Pkt#diameter_packet{bin = <<V, (Len - Delta):24, H/binary,
+ SessionId/binary,
+ T/binary>>}.
+
+%% handle_answer/5
+
+handle_answer(Pkt, _Req, ?CLIENT, _Peer, _Name) ->
Pkt#diameter_packet.msg.
-%% handle_error/4
+%% handle_error/5
-handle_error(Reason, _Req, ?CLIENT, _Peer) ->
+handle_error(Reason, _Req, ?CLIENT, _Peer, _Name) ->
{error, Reason}.
+split_avp(<<_:5/binary, Len:24, _/binary>> = Bin) ->
+ L = pad(Len),
+ <<Avp:L/binary, T/binary>> = Bin,
+ {Avp, T}.
+
+pad(N)
+ when 0 == N rem 4 ->
+ N;
+pad(N) ->
+ N - (N rem 4) + 4.
+
%% handle_request/3
-handle_request(_, ?SERVER, _) ->
- discard.
+%% send_unknown_command
+handle_request(#diameter_packet{msg = undefined}, ?SERVER, _) ->
+ discard;
+
+handle_request(#diameter_packet{msg = Req}, ?SERVER, {_, Caps}) ->
+ #diameter_base_STR{'Class' = [Name]}
+ = Req,
+ {reply, request(?A(Name), Req, Caps)}.
+
+request(send_ok_override, Req, Caps) ->
+ #diameter_packet{msg = answer(Req, Caps),
+ errors = [?UNKNOWN_SESSION_ID]}; %% override
+
+request(send_invalid_avp_bits, Req, Caps) ->
+ #diameter_base_STR{'Origin-State-Id' = []}
+ = Req,
+ %% Default errors field but a non-answer-message and only 3xxx
+ %% errors detected means diameter sets neither Result-Code nor
+ %% Failed-AVP.
+ #diameter_packet{msg = answer(Req, Caps)};
+
+request(send_double_error, Req, Caps) ->
+ answer(Req, Caps).
+
+answer(Req, Caps) ->
+ #diameter_base_STR{'Session-Id' = SId}
+ = Req,
+ #diameter_caps{origin_host = {OH,_},
+ origin_realm = {OR,_}}
+ = Caps,
+ #diameter_base_STA{'Session-Id' = SId,
+ 'Origin-Host' = OH,
+ 'Origin-Realm' = OR,
+ 'Result-Code' = ?SUCCESS}.