1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22%% Test service and transport config. In particular, of the detection
23%% of config errors.
24%%
25
26-module(diameter_config_SUITE).
27
28-export([suite/0,
29         all/0]).
30
31%% testcases
32-export([start/1,
33         start_service/1,
34         add_transport/1,
35         stop/1]).
36
37-define(util, diameter_util).
38
39%% Lists of {Key, GoodConfigList, BadConfigList} with which to
40%% configure.
41
42-define(SERVICE_CONFIG,
43        [{application,
44          [[[{dictionary, diameter_gen_base_rfc6733},
45             {module, ?MODULE}]]
46           | [[[{dictionary, D},
47                {module, M},
48                {alias, A},
49                {state, S},
50                {answer_errors, AE},
51                {request_errors, RE},
52                {call_mutates_state, C}]]
53              || D <- [diameter_gen_base_rfc3588, diameter_gen_base_rfc6733],
54                 M <- [?MODULE, [?MODULE, diameter_lib:now()]],
55                 A <- [0, common, make_ref()],
56                 S <- [[], make_ref()],
57                 AE <- [report, callback, discard],
58                 RE <- [answer_3xxx, answer, callback],
59                 C <- [true, false]]],
60          [[x],
61           [[]],
62           [[{dictionary, diameter_gen_base_rfc3588}]],
63           [[{module, ?MODULE}]]
64           | [[[{dictionary, diameter_gen_base_rfc6733},
65                {module, ?MODULE},
66                {K,x}]]
67              || K <- [answer_errors,
68                       request_errors,
69                       call_mutates_state]]]},
70         {restrict_connections,
71          [[false], [node], [nodes], [[node(), node()]]],
72          []},
73         {sequence,
74          [[{0,32}], [{1,31}]],
75          [[{2,31}]]},
76         {share_peers,
77          [[true],
78           [false],
79           [[node()]]],
80          [[x]]},
81         {use_shared_peers,
82          [[true],
83           [false],
84           [[node(), node()]]],
85          [[x]]},
86         {string_decode,
87          [[true], [false]],
88          [[0], [x]]},
89         {incoming_maxlen,
90          [[0], [65536], [16#FFFFFF]],
91          [[-1], [1 bsl 24], [infinity], [false]]},
92         {spawn_opt,
93          [[[]], [[monitor, link]]],
94          [[false]]},
95         {invalid_option,  %% invalid service options are rejected
96          [],
97          [[x],
98           [x,x]]}]).
99
100-define(TRANSPORT_CONFIG,
101        [{transport_module,
102          [[?MODULE]],
103          [[[?MODULE]]]},
104         {transport_config,
105          [[{}, 3000],
106           [{}, infinity]],
107          [[{}, x]]},
108         {applications,
109          [[[1, a, [x]]]],
110          [[x]]},
111         {capabilities,
112          [[[{'Origin-Host', "diameter.erlang.org"}]],
113           [[{'Origin-Realm', "erlang.org"}]]]
114          ++ [[[{'Host-IP-Address', L}]]
115              || L <- [[{127,0,0,1}],
116                       ["127.0.0.1"],
117                       ["127.0.0.1", "FFFF::1", "::1", {1,2,3,4,5,6,7,8}]]]
118          ++ [[[{'Product-Name', N}]]
119              || N <- [["Product", $-, ["Name"]],
120                       "Norðurálfa",
121                       "ᚠᚢᚦᚨᚱᚲ"]]
122          ++ [[[{K,V}]]
123              || K <- ['Vendor-Id',
124                       'Origin-State-Id',
125                       'Firmware-Revision'],
126                 V <- [0, 256, 16#FFFF]]
127          ++ [[[{K,V}]]
128              || K <- ['Supported-Vendor-Id',
129                       'Auth-Application-Id',
130                       'Acct-Application-Id',
131                       'Inband-Security-Id'],
132                 V <- [[17], [0, 256, 16#FFFF]]]
133          ++ [[[{'Vendor-Specific-Application-Id',
134                 [[{'Vendor-Id', V},
135                   {'Auth-Application-Id', [0]},
136                   {'Acct-Application-Id', [4]}]]}]]
137              || V <- [1, [1]]],
138          [[x], [[{'Origin-Host', "ᚠᚢᚦᚨᚱᚲ"}]]]
139          ++ [[[{'Host-IP-Address', A}]]
140              || A <- [{127,0,0,1}]]
141          ++ [[[{'Product-Name', N}]]
142              || N <- [x, 1]]
143          ++ [[[{K,V}]]
144              || K <- ['Vendor-Id',
145                       'Origin-State-Id',
146                       'Firmware-Revision'],
147                 V <- [x, [0], -1, 1 bsl 32]]
148          ++ [[[{K,V}]]
149              || K <- ['Supported-Vendor-Id',
150                       'Auth-Application-Id',
151                       'Acct-Application-Id',
152                       'Inband-Security-Id'],
153                 V <- [x, 17, [-1], [1 bsl 32]]]
154          ++ [[[{'Vendor-Specific-Application-Id', V}]]
155              || V <- [x,
156                       [[{'Vendor-Id', 1 bsl 32}]],
157                       [[{'Auth-Application-Id', 1}]]]]},
158         {capabilities_cb,
159          [[x]],
160          []},
161         {capx_timeout,
162          [[3000]],
163          [[{?MODULE, tmo, []}]]},
164         {disconnect_cb,
165          [[x]],
166          []},
167         {length_errors,
168          [[exit], [handle], [discard]],
169          [[x]]},
170         {dpr_timeout,
171          [[0], [3000], [16#FFFFFFFF]],
172          [[infinity], [-1], [1 bsl 32], [x]]},
173         {dpa_timeout,
174          [[0], [3000], [16#FFFFFFFF]],
175          [[infinity], [-1], [1 bsl 32], [x]]},
176         {connect_timer,
177          [[3000]],
178          [[infinity]]},
179         {watchdog_timer,
180          [[3000],
181           [{?MODULE, tmo, []}]],
182          [[infinity],
183           [-1]]},
184         {watchdog_config,
185          [[[{okay, 0}, {suspect, 0}]],
186           [[{okay, 1}]],
187           [[{suspect, 2}]]],
188          [[x],
189           [[{open, 0}]]]},
190         {pool_size,
191          [[1], [100]],
192          [[0], [infinity], [-1], [x]]},
193         {private,
194          [[x]],
195          []},
196         {spawn_opt,
197          [[[]], [[monitor, link]]],
198          [[false]]},
199         {invalid_option,  %% invalid transport options are silently ignored
200          [[x],
201           [x,x]],
202          []}]).
203
204%% ===========================================================================
205
206suite() ->
207    [{timetrap, {seconds, 60}}].
208
209all() ->
210    [start,
211     start_service,
212     add_transport,
213     stop].
214
215%% ===========================================================================
216
217start(_) ->
218    ok = diameter:start().
219
220start_service(T)
221  when is_tuple(T) ->
222    do(fun start/3, T);
223
224start_service(_) ->
225    [] = ?util:run([{?MODULE, start_service, [T]}
226                    || T <- [lists:keyfind(capabilities, 1, ?TRANSPORT_CONFIG)
227                             | ?SERVICE_CONFIG]]).
228
229add_transport(T)
230  when is_tuple(T) ->
231    do(fun add/3, T);
232
233add_transport(_) ->
234    [] = ?util:run([{?MODULE, add_transport, [T]}
235                    || T <- ?TRANSPORT_CONFIG]).
236
237stop(_) ->
238    ok = diameter:stop().
239
240%% ===========================================================================
241
242%% do/2
243
244do(F, {Key, Good, Bad}) ->
245    F(Key, Good, Bad).
246
247%% add/3
248
249add(Key, Good, Bad) ->
250    {[],[]} = {[{Vs,T} || Vs <- Good,
251                          T <- [add(Key, Vs)],
252                          [T] /= [T || {ok,_} <- [T]]],
253               [{Vs,T} || Vs <- Bad,
254                          T <- [add(Key, Vs)],
255                          [T] /= [T || {error,_} <- [T]]]}.
256
257add(Key, Vs) ->
258    T = list_to_tuple([Key | Vs]),
259    diameter:add_transport(make_ref(), {connect, [T]}).
260
261%% start/3
262
263start(Key, Good, Bad) ->
264    {[],[]} = {[{Vs,T} || Vs <- Good,
265                          T <- [start(Key, Vs)],
266                          T /= ok],
267               [{Vs,T} || Vs <- Bad,
268                          T <- [start(Key, Vs)],
269                          [T] /= [T || {error,_} <- [T]]]}.
270
271start(capabilities = K, [Vs]) ->
272    if is_list(Vs) ->
273            start(make_ref(), Vs ++ apps(K));
274       true ->
275            {error, Vs}
276    end;
277
278start(Key, Vs)
279  when is_atom(Key) ->
280    start(make_ref(), [list_to_tuple([Key | Vs]) | apps(Key)]);
281
282start(SvcName, Opts) ->
283    try
284        diameter:start_service(SvcName, Opts)
285    after
286        diameter:stop_service(SvcName)
287    end.
288
289apps(application) ->
290    [];
291apps(_) ->
292    [{application, [{dictionary, diameter_gen_base_rfc6733},
293                    {module, ?MODULE}]}].
294