aboutsummaryrefslogblamecommitdiffstats
path: root/lib/diameter/test/diameter_codec_SUITE.erl
blob: c79b642c09ebd87d1e53a30dad8a1aa9a5c8b541 (plain) (tree)
1
2
3
4
5


                   
                                                        
  










                                                                           







                                                                    

                                                                    





                              
                  

                          

                          





                              
               



                          
 
                            
                         
 







                                                                              






                                               





                         





                                 

                                 
                                                                  






















                                                                              






















                                                                            






























































































































































                                                                              
                                                                              


                                              


                        
                              



                             
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2010-2017. 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%
%%

%%
%% Test encode/decode of dictionary-related modules. Each test case
%% runs multiple tests in parallel since many of the tests are just
%% the same code with different in-data: implementing each test as a
%% single testcase would make for much duplication with ct's current
%% requirement of one function per testcase.
%%

-module(diameter_codec_SUITE).

-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,
         gen/1,
         lib/1,
         unknown/1,
         success/1,
         grouped_error/1,
         failed_error/1]).

-include("diameter_ct.hrl").
-include("diameter.hrl").

-define(L, atom_to_list).

%% ===========================================================================

suite() ->
    [{timetrap, {seconds, 10}}].

all() ->
    [base, gen, lib, unknown, {group, recode}].

groups() ->
    [{recode, [], [success,
                   grouped_error,
                   failed_error]}].

init_per_suite(Config) ->
    Config.

end_per_suite(_Config) ->
    ok.

init_per_group(recode, Config) ->
    ok = diameter:start(),
    Config.

end_per_group(_, _) ->
    ok =  diameter:stop().

init_per_testcase(gen, Config) ->
    [{application, ?APP, App}] = diameter_util:consult(?APP, app),
    {modules, Ms} = lists:keyfind(modules, 1, App),
    [_|_] = Gs = lists:filter(fun(M) ->
                                      lists:prefix("diameter_gen_", ?L(M))
                              end,
                              Ms),
    [{dicts, Gs} | Config];

init_per_testcase(_Name, Config) ->
    Config.

end_per_testcase(_, _) ->
    ok.

%% ===========================================================================

base(_Config) ->
    diameter_codec_test:base().

gen([{dicts, Ms} | _]) ->
    lists:foreach(fun diameter_codec_test:gen/1, Ms).

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),
    ok = make(Data, "recv.dia"),
    ok = make(Data, "avps.dia"),
    {ok, _, _} = compile("diameter_test_avps.erl"),
    ok = make(Data, "send.dia"),
    {ok, _, _} = compile("diameter_test_send.erl"),
    {ok, _, _} = compile("diameter_test_recv.erl"),
    {ok, _, _} = compile(filename:join([Data, "diameter_test_unknown.erl"]),
                         [{i, Priv}]),
    diameter_test_unknown:run().

make(Dir, File) ->
    diameter_make:codec(filename:join([Dir, File])).

compile(File) ->
    compile(File, []).

compile(File, Opts) ->
    compile:file(File, [return | Opts]).

%% ===========================================================================

%% Ensure a Grouped AVP is represented by a list in the avps field.
success(_) ->
    Avps = [{295, <<1:32>>},  %% Termination-Cause
            {284, [{280, "Proxy-Host"}, %% Proxy-Info
                   {33, "Proxy-State"}, %%
                   {295, <<2:32>>}]}],  %% Termination-Cause
    #diameter_packet{avps = [#diameter_avp{code = 295,
                                           value = 1,
                                           data = <<1:32>>},
                             [#diameter_avp{code = 284},
                              #diameter_avp{code = 280},
                              #diameter_avp{code = 33},
                              #diameter_avp{code = 295,
                                            value = 2,
                                            data = <<2:32>>}]],
                     errors = []}
        = str(recode(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(_) ->
    Avps = [{295, <<1:32>>},  %% Termination-Cause
            {284, [{295, <<0:32>>},      %% Proxy-Info, Termination-Cause
                   {280, "Proxy-Host"},
                   {33, "Proxy-State"}]}],
    #diameter_packet{avps = [#diameter_avp{code = 295,
                                           value = 1,
                                           data = <<1:32>>},
                             [#diameter_avp{code = 284},
                              #diameter_avp{code = 295,
                                            value = undefined,
                                            data = <<0:32>>},
                              #diameter_avp{code = 280},
                              #diameter_avp{code = 33}]],
                     errors = [{5004, #diameter_avp{code = 284}}]}
        = str(recode(str(Avps))).

%% ===========================================================================

%% Ensure that a failed decode in Failed-AVP is acceptable, and that
%% the component AVPs are decoded if possible.
failed_error(_) ->
    Avps = [{279, [{295, <<0:32>>},    %% Failed-AVP, Termination-Cause
                   {258, <<1:32>>},             %% Auth-Application-Id
                   {284, [{280, "Proxy-Host"},  %% Proxy-Info
                          {33, "Proxy-State"},
                          {295, <<0:32>>},      %% Termination-Cause, invalid
                          {258, <<2:32>>}]}]}], %% Auth-Application-Id
    #diameter_packet{avps = [[#diameter_avp{code = 279},
                              #diameter_avp{code = 295,
                                            value = undefined,
                                            data = <<0:32>>},
                              #diameter_avp{code = 258,
                                            value = 1,
                                            data = <<1:32>>},
                              [#diameter_avp{code = 284},
                               #diameter_avp{code = 280},
                               #diameter_avp{code = 33},
                               #diameter_avp{code = 295,
                                             value = undefined},
                               #diameter_avp{code = 258,
                                             value = 2,
                                             data = <<2:32>>}]]],
                     errors = []}
        = sta(recode(sta(Avps))).

%% ===========================================================================

%% str/1

str(#diameter_packet{avps = [#diameter_avp{code = 263},
                             #diameter_avp{code = 264},
                             #diameter_avp{code = 296},
                             #diameter_avp{code = 283},
                             #diameter_avp{code = 258,
                                           value = 0}
                             | T]}
    = Pkt) ->
    Pkt#diameter_packet{avps = T};

str(Avps) ->
    OH = "diameter.erlang.org",
    OR = "erlang.org",
    DR = "example.com",
    Sid = "diameter.erlang.org;123;456",

    [#diameter_header{version = 1,
                      cmd_code = 275,  %% STR
                      is_request = true,
                      application_id = 0,
                      hop_by_hop_id = 17,
                      end_to_end_id = 42,
                      is_proxiable = false,
                      is_error = false,
                      is_retransmitted = false}
     | avp([{263, Sid},  %% Session-Id
            {264, OH},   %% Origin-Host
            {296, OR},   %% Origin-Realm
            {283, DR},   %% Destination-Realm
            {258, <<0:32>>}]  %% Auth-Application-Id
           ++ Avps)].

%% sta/1

sta(#diameter_packet{avps = [#diameter_avp{code = 263},
                             #diameter_avp{code = 268},
                             #diameter_avp{code = 264},
                             #diameter_avp{code = 296},
                             #diameter_avp{code = 278,
                                           value = 4}
                             | T]}
    = Pkt) ->
    Pkt#diameter_packet{avps = T};

sta(Avps) ->
    OH = "diameter.erlang.org",
    OR = "erlang.org",
    Sid = "diameter.erlang.org;123;456",

    [#diameter_header{version = 1,
                      cmd_code = 275,  %% STA
                      is_request = false,
                      application_id = 0,
                      hop_by_hop_id = 17,
                      end_to_end_id = 42,
                      is_proxiable = false,
                      is_error = false,
                      is_retransmitted = false}
     | avp([{263, Sid},         %% Session-Id
            {268, <<2002:32>>}, %% Result-Code
            {264, OH},          %% Origin-Host
            {296, OR},          %% Origin-Realm
            {278, <<4:32>>}]    %% Origin-State-Id
           ++ Avps)].

avp({Code, Data}) ->
    #diameter_avp{code = Code,
                  data = avp(Data)};

avp(#diameter_avp{} = A) ->
    A;

avp([{_,_} | _] = Avps) ->
    lists:map(fun avp/1, Avps);

avp(V) ->
    V.

%% recode/1

recode(Msg) ->
    recode(Msg, diameter_gen_base_rfc6733).

recode(#diameter_packet{} = Pkt, Dict) ->
    diameter_codec:decode(Dict, opts(Dict), diameter_codec:encode(Dict, Pkt));

recode(Msg, Dict) ->
    recode(#diameter_packet{msg = Msg}, Dict).

opts(Mod) ->
    #{dictionary => Mod,
      decode_format => record,
      string_decode => false,
      strict_mbit => true,
      rfc => 6733,
      failed_avp => false}.