1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2016. 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%%----------------------------------------------------------------------
23%% Purpose: Test application config
24%%----------------------------------------------------------------------
25
26-module(megaco_config_test).
27
28-compile(export_all).
29
30-include("megaco_test_lib.hrl").
31-include_lib("megaco/include/megaco.hrl").
32-include_lib("megaco/src/app/megaco_internal.hrl").
33
34t()     -> megaco_test_lib:t(?MODULE).
35t(Case) -> megaco_test_lib:t({?MODULE, Case}).
36
37min(M) -> timer:minutes(M).
38
39%% Test server callbacks
40init_per_testcase(Case, Config) ->
41    C = lists:keydelete(tc_timeout, 1, Config),
42    do_init_per_testcase(Case, [{tc_timeout, min(3)}|C]).
43
44do_init_per_testcase(Case, Config) ->
45    process_flag(trap_exit, true),
46    megaco_test_lib:init_per_testcase(Case, Config).
47
48end_per_testcase(Case, Config) ->
49    process_flag(trap_exit, false),
50    megaco_test_lib:end_per_testcase(Case, Config).
51
52
53-record(command, {id, desc, cmd, verify}).
54
55-define(TEST_VERBOSITY, debug).
56-define(NUM_CNT_PROCS,  100).
57
58
59%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60%% Top test case
61
62all() ->
63    [config, {group, transaction_id_counter},
64     {group, tickets}].
65
66groups() ->
67    [{transaction_id_counter, [],
68      [transaction_id_counter_mg,
69       transaction_id_counter_mgc]},
70     {tickets, [], [otp_7216, otp_8167, otp_8183]}].
71
72init_per_group(_GroupName, Config) ->
73    Config.
74
75end_per_group(_GroupName, Config) ->
76    Config.
77
78
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%% Config test case
81
82config(suite) ->
83    [];
84config(Config) when is_list(Config) ->
85    ?ACQUIRE_NODES(1, Config),
86    Mid = fake_mid,
87
88    %% Nice values
89    Int = 3,
90    IT  = #megaco_incr_timer{max_retries = Int},
91
92    %% Evil values
93    NonInt = non_int,
94    IT2 = #megaco_incr_timer{wait_for = NonInt},
95    IT3 = #megaco_incr_timer{factor = NonInt},
96    IT4 = #megaco_incr_timer{max_retries = NonInt},
97    IT5 = #megaco_incr_timer{max_retries = non_infinity},
98
99    %% Command range values
100    Initial = 100,
101    Verify  = 200,
102    Nice    = 300,
103    Evil    = 400,
104    End     = 500,
105
106    InitialCmd =
107	fun(No, Desc, Cmd, VerifyVal) ->
108		initial_command(Initial + No, Desc, Cmd, VerifyVal)
109	end,
110
111    VerifyCmd =
112	fun(M, No, Key, V) ->
113		verify_user_default_command(M, Verify + No, Key, V)
114	end,
115
116    NiceCmd =
117	fun(M, No, Key, Val) ->
118		nice_user_update_command(M, Nice + No, Key, Val)
119	end,
120
121    EvilCmd =
122	fun(M, No, Key, Val) ->
123		evil_user_update_command(M, Evil + No, Key, Val)
124	end,
125
126    %% End commands
127    ExitCmd =
128	fun(No, Desc, Cmd) ->
129		exit_command(End + No, Desc, Cmd)
130	end,
131    ErrorCmd =
132	fun(No, Desc, Cmd, MainReason, TS) ->
133		error_command(End + No, Desc, Cmd, MainReason, TS)
134	end,
135    PlainCmd =
136	fun(No, Desc, Cmd, V) ->
137		command(End + No, Desc, Cmd, V)
138	end,
139
140    Commands =
141	[
142	 %% Initial commands
143	 InitialCmd(0,
144		    "enable trace",
145		    fun() -> megaco:enable_trace(100, io) end,
146		    ok),
147	 InitialCmd(1,
148		    "start",
149		    fun() -> megaco:start() end,
150		    ok),
151	 InitialCmd(2,
152		    "Verify no active requests",
153		    fun() -> megaco:system_info(n_active_requests) end,
154		    0),
155	 InitialCmd(3,
156		    "Verify no active replies",
157		    fun() -> megaco:system_info(n_active_replies) end,
158		    0),
159	 InitialCmd(4,
160		    "Verify no active connections",
161		    fun() -> megaco:system_info(n_active_connections) end,
162		    0),
163	 InitialCmd(5,
164		    "Verify no connections",
165		    fun() -> megaco:system_info(connections) end,
166		    []),
167	 InitialCmd(6,
168		    "Verify no users",
169		    fun() -> megaco:system_info(users) end,
170		    []),
171	 InitialCmd(7,
172		    "Start user",
173		    fun() -> megaco:start_user(Mid, []) end,
174		    ok),
175
176
177	 %% Verify user defaults
178	 VerifyCmd(Mid,  1, connections, []),
179	 VerifyCmd(Mid,  2, min_trans_id, 1),
180	 VerifyCmd(Mid,  3, max_trans_id, infinity),
181	 VerifyCmd(Mid,  4, request_timer, #megaco_incr_timer{}),
182	 VerifyCmd(Mid,  5, long_request_timer, timer:seconds(60)),
183	 VerifyCmd(Mid,  6, auto_ack, false),
184	 VerifyCmd(Mid,  7, pending_timer, 30000),
185	 VerifyCmd(Mid,  8, reply_timer, 30000),
186	 VerifyCmd(Mid,  9, send_mod, megaco_tcp),
187	 VerifyCmd(Mid, 10, encoding_mod, megaco_pretty_text_encoder),
188	 VerifyCmd(Mid, 11, encoding_config, []),
189	 VerifyCmd(Mid, 12, protocol_version, 1),
190	 VerifyCmd(Mid, 13, reply_data, undefined),
191	 VerifyCmd(Mid, 14, receive_handle,
192		   fun(H) when is_record(H, megaco_receive_handle) ->
193			   {ok, H};
194		      (R)  ->
195			   {error, R}
196		   end),
197
198
199	 %% Nice update
200	 NiceCmd(Mid,  1, min_trans_id, Int),
201	 NiceCmd(Mid,  2, max_trans_id, Int),
202	 NiceCmd(Mid,  3, max_trans_id, infinity),
203	 NiceCmd(Mid,  4, request_timer, Int),
204	 NiceCmd(Mid,  5, request_timer, infinity),
205	 NiceCmd(Mid,  6, request_timer, IT),
206	 NiceCmd(Mid,  7, long_request_timer, Int),
207	 NiceCmd(Mid,  8, long_request_timer, infinity),
208	 NiceCmd(Mid,  9, long_request_timer, IT),
209	 NiceCmd(Mid, 10, auto_ack, true),
210	 NiceCmd(Mid, 11, auto_ack, false),
211	 NiceCmd(Mid, 12, pending_timer, Int),
212	 NiceCmd(Mid, 13, pending_timer, infinity),
213	 NiceCmd(Mid, 14, pending_timer, IT),
214	 NiceCmd(Mid, 15, reply_timer, Int),
215	 NiceCmd(Mid, 16, reply_timer, infinity),
216	 NiceCmd(Mid, 17, reply_timer, IT),
217	 NiceCmd(Mid, 18, send_mod, an_atom),
218	 NiceCmd(Mid, 19, encoding_mod, an_atom),
219	 NiceCmd(Mid, 20, encoding_config, []),
220	 NiceCmd(Mid, 21, protocol_version, Int),
221	 NiceCmd(Mid, 23, reply_data, IT),
222	 NiceCmd(Mid, 23, resend_indication, true),
223	 NiceCmd(Mid, 24, resend_indication, false),
224	 NiceCmd(Mid, 25, resend_indication, flag),
225
226
227	 %% Evil update
228	 EvilCmd(Mid,  1, min_trans_id, NonInt),
229	 EvilCmd(Mid,  2, max_trans_id, NonInt),
230	 EvilCmd(Mid,  3, max_trans_id, non_infinity),
231	 EvilCmd(Mid,  4, request_timer, NonInt),
232	 EvilCmd(Mid,  5, request_timer, non_infinity),
233	 EvilCmd(Mid,  6, request_timer, IT2),
234	 EvilCmd(Mid,  7, request_timer, IT3),
235	 EvilCmd(Mid,  8, request_timer, IT4),
236	 EvilCmd(Mid,  9, request_timer, IT5),
237	 EvilCmd(Mid, 10, long_request_timer, NonInt),
238	 EvilCmd(Mid, 11, long_request_timer, non_infinity),
239	 EvilCmd(Mid, 12, long_request_timer, IT2),
240	 EvilCmd(Mid, 13, long_request_timer, IT3),
241	 EvilCmd(Mid, 14, long_request_timer, IT4),
242	 EvilCmd(Mid, 15, long_request_timer, IT5),
243	 EvilCmd(Mid, 16, auto_ack, non_bool),
244	 EvilCmd(Mid, 17, pending_timer, NonInt),
245	 EvilCmd(Mid, 18, pending_timer, non_infinity),
246	 EvilCmd(Mid, 19, pending_timer, IT2),
247	 EvilCmd(Mid, 20, pending_timer, IT3),
248	 EvilCmd(Mid, 21, pending_timer, IT4),
249	 EvilCmd(Mid, 22, pending_timer, IT5),
250	 EvilCmd(Mid, 23, reply_timer, NonInt),
251	 EvilCmd(Mid, 24, reply_timer, non_infinity),
252	 EvilCmd(Mid, 25, reply_timer, IT2),
253	 EvilCmd(Mid, 26, reply_timer, IT3),
254	 EvilCmd(Mid, 27, reply_timer, IT4),
255	 EvilCmd(Mid, 28, reply_timer, IT5),
256	 EvilCmd(Mid, 29, send_mod, {non_atom}),
257	 EvilCmd(Mid, 30, encoding_mod, {non_atom}),
258	 EvilCmd(Mid, 31, encoding_config, non_list),
259	 EvilCmd(Mid, 32, protocol_version, NonInt),
260	 EvilCmd(Mid, 33, resend_indication, flagg),
261
262
263	 %% End
264	 ExitCmd(1, "Verify non-existing system info",
265		 fun() -> megaco:system_info(non_exist) end),
266	 ExitCmd(2, "Verify non-existing user user info",
267		 fun() -> megaco:user_info(non_exist, trans_id) end),
268	 ExitCmd(3, "Verify non-existing user info",
269		 fun() -> megaco:user_info(Mid, non_exist) end),
270
271	 ErrorCmd(4, "Try updating user info for non-existing user",
272		  fun() ->
273			  megaco:update_user_info(non_exist, trans_id, 1)
274		  end,
275		  no_such_user, 2),
276	 ErrorCmd(11, "Try updating non-existing user info",
277		  fun() ->
278			  megaco:update_user_info(Mid, trans_id, 4711)
279		  end,
280		  bad_user_val, 4),
281	 ErrorCmd(12, "Try start already started user",
282		  fun() -> megaco:start_user(Mid, []) end,
283		  user_already_exists, 2),
284
285	 PlainCmd(13, "Verify started users",
286		  fun() -> megaco:system_info(users) end, [Mid]),
287	 PlainCmd(14, "Stop user", fun() -> megaco:stop_user(Mid) end, ok),
288	 PlainCmd(15, "Verify started users",
289		  fun() -> megaco:system_info(users) end, []),
290	 ErrorCmd(16, "Try stop not started user",
291		  fun() -> megaco:stop_user(Mid) end, no_such_user, 2),
292	 ErrorCmd(17, "Try start megaco (it's already started)",
293		  fun() -> megaco:start() end, already_started, 2),
294	 PlainCmd(18, "Stop megaco", fun() -> megaco:stop() end, ok),
295	 ErrorCmd(19, "Try stop megaco (it's not running)",
296		  fun() -> megaco:stop() end, not_started, 2)
297	],
298
299
300    exec(Commands).
301
302
303
304exec([]) ->
305    ok;
306exec([#command{id     = No,
307	       desc   = Desc,
308	       cmd    = Cmd,
309	       verify = Verify}|Commands]) ->
310    io:format("Executing command ~3w: ~s: ", [No, Desc]),
311    case (catch Verify((catch Cmd()))) of
312	{ok, OK} ->
313	    io:format("ok => ~p~n", [OK]),
314	    exec(Commands);
315	{error, Reason} ->
316	    io:format("error => ~p~n", [Reason]),
317	    {error, {bad_result, No, Reason}};
318	Error ->
319	    io:format("exit => ~p~n", [Error]),
320	    {error, {unexpected_result, No, Error}}
321    end.
322
323initial_command(No, Desc0, Cmd, VerifyVal) when is_function(Cmd) ->
324    Desc = lists:flatten(io_lib:format("Initial - ~s", [Desc0])),
325    command(No, Desc, Cmd, VerifyVal).
326
327verify_user_default_command(Mid, No, Key, Verify) ->
328    Desc = lists:flatten(io_lib:format("Defaults - Verify ~w", [Key])),
329    Cmd = fun() -> megaco:user_info(Mid, Key) end,
330    command(No, Desc, Cmd, Verify).
331
332nice_user_update_command(Mid, No, Key, Val) ->
333    Desc = lists:flatten(io_lib:format("Nice - Update ~w", [Key])),
334    Cmd = fun() -> megaco:update_user_info(Mid, Key, Val) end,
335    Verify = fun(ok) ->
336		     case (catch megaco:user_info(Mid, Key)) of
337			 {'EXIT', R} ->
338			     {error, {value_retreival_failed, R}};
339			 Val ->
340			     {ok, Val};
341			 Invalid ->
342			     {error, {value_update_failed, Val, Invalid}}
343		     end;
344		(R)  ->
345		     {error, R}
346	     end,
347    command(No, Desc, Cmd, Verify).
348
349
350evil_user_update_command(Mid, No, Key, Val) ->
351    Desc = lists:flatten(io_lib:format("Evil - Update ~w", [Key])),
352    Cmd = fun() ->
353		  case (catch megaco:user_info(Mid, Key)) of
354		      {'EXIT', R} ->
355			  {{error, {old_value_retreival_failed, R}},
356			   ignore};
357		      OldVal ->
358			  {OldVal,
359			   (catch megaco:update_user_info(Mid, Key, Val))}
360		  end
361	  end,
362    Verify = fun({{error, _} = Error, ignore}) ->
363		     Error;
364		({OldVal, {error, {bad_user_val, _, _, _}}}) ->
365		     case (catch megaco:user_info(Mid, Key)) of
366			 {'EXIT', R} ->
367			     {error, {value_retreival_failed, R}};
368			 OldVal ->
369			     {ok, OldVal};
370			 Invalid ->
371			     {error, {value_update_failed, OldVal, Invalid}}
372		     end;
373		(R) ->
374		     {error, R}
375	     end,
376    command(No, Desc, Cmd, Verify).
377
378exit_command(No, Desc, Cmd) when is_function(Cmd) ->
379    Verify = fun({'EXIT', _} = E) ->
380		     {ok, E};
381		(R) ->
382		     {error, R}
383	     end,
384    command(No, Desc, Cmd, Verify).
385
386error_command(No, Desc, Cmd, MainReason, TS) when is_function(Cmd) ->
387    Verify = fun({error, Reason}) ->
388		     io:format("verify -> Reason: ~n~p~n", [Reason]),
389		     case Reason of
390			 {MainReason, _} when TS == 2 ->
391			     {ok, MainReason};
392			 {MainReason, _, _, _} when TS == 4 ->
393			     {ok, MainReason};
394			 _ ->
395			     {error, Reason}
396		     end;
397		(R) ->
398		     {error, R}
399	     end,
400    command(No, Desc, Cmd, Verify).
401
402command(No, Desc, Cmd, Verify)
403  when (is_integer(No) andalso
404	is_list(Desc) andalso
405	is_function(Cmd) andalso
406	is_function(Verify)) ->
407    #command{id     = No,
408	     desc   = Desc,
409	     cmd    = Cmd,
410	     verify = Verify};
411command(No, Desc, Cmd, VerifyVal)
412  when (is_integer(No) andalso
413	is_list(Desc) andalso
414	is_function(Cmd)) ->
415    Verify = fun(Val) ->
416		     case Val of
417			 VerifyVal ->
418			     {ok, Val};
419			 _ ->
420			     {error, Val}
421		     end
422	     end,
423    #command{id     = No,
424	     desc   = Desc,
425	     cmd    = Cmd,
426	     verify = Verify}.
427
428
429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430
431transaction_id_counter_mg(suite) ->
432    [];
433transaction_id_counter_mg(doc) ->
434    ["This test case is intended to test and verify the "
435     "transaction counter handling of the application "
436     "in with one connection (MG). "];
437transaction_id_counter_mg(Config) when is_list(Config) ->
438    put(verbosity, ?TEST_VERBOSITY),
439    put(sname,     "TEST"),
440    put(tc,        transaction_id_counter_mg),
441
442    process_flag(trap_exit, true),
443
444    i("starting"),
445
446    {ok, _ConfigPid} = megaco_config:start_link(),
447
448    %% Basic user data
449    UserMid = {deviceName, "mg"},
450    UserConfig = [
451		  {min_trans_id, 1}
452		 ],
453
454    %% Basic connection data
455    RemoteMid = {deviceName, "mgc"},
456    RecvHandle = #megaco_receive_handle{local_mid       = UserMid,
457					encoding_mod    = ?MODULE,
458					encoding_config = [],
459					send_mod        = ?MODULE},
460    SendHandle = dummy_send_handle,
461    ControlPid = self(),
462
463    %% Start user
464    i("start user"),
465    ok = megaco_config:start_user(UserMid, UserConfig),
466
467    %% Create connection
468    i("create connection"),
469    {ok, CD} =
470	megaco_config:connect(RecvHandle, RemoteMid, SendHandle, ControlPid),
471
472    %% Set counter limits
473    i("set counter max limit"),
474    CH = CD#conn_data.conn_handle,
475    megaco_config:update_conn_info(CH, max_trans_id, 1000),
476
477    %% Create the counter worker procs
478    i("create counter working procs"),
479    Pids = create_counter_working_procs(CH, ?NUM_CNT_PROCS, []),
480
481    %% Start the counter worker procs
482    i("release the counter working procs"),
483    start_counter_working_procs(Pids),
484
485    %% Await the counter worker procs termination
486    i("await the counter working procs completion"),
487    await_completion_counter_working_procs(Pids),
488
489    %% Verify result
490    i("verify counter result"),
491    TransId = megaco_config:conn_info(CH, trans_id),
492    1 = TransId,
493
494    %% Stop test
495    i("disconnect"),
496    {ok, _, _} = megaco_config:disconnect(CH),
497    i("stop user"),
498    ok = megaco_config:stop_user(UserMid),
499    i("stop megaco_config"),
500    ok = megaco_config:stop(),
501
502    i("done"),
503    ok.
504
505
506
507create_counter_working_procs(_CH, 0, Pids) ->
508    Pids;
509create_counter_working_procs(CH, N, Pids) ->
510    TC = get(tc),
511    Pid = erlang:spawn_link(fun() -> counter_init(CH, TC) end),
512    create_counter_working_procs(CH, N-1, [Pid | Pids]).
513
514counter_init(CH, TC) ->
515    put(verbosity, ?TEST_VERBOSITY),
516    put(sname,     lists:flatten(io_lib:format("CNT-~p", [self()]))),
517    put(tc,        TC),
518    UserMid = CH#megaco_conn_handle.local_mid,
519    Min = megaco_config:user_info(UserMid, min_trans_id),
520    Max = megaco_config:conn_info(CH, max_trans_id),
521    Num = Max - Min + 1,
522    receive
523	start ->
524	    %% i("received start command (~p)", [Num]),
525	    ok
526    end,
527    counter_loop(CH, Num).
528
529counter_loop(_CH, 0) ->
530    %% i("done"),
531    exit(normal);
532counter_loop(CH, Num) when (Num > 0) ->
533    megaco_config:incr_trans_id_counter(CH, 1),
534    counter_loop(CH, Num-1).
535
536start_counter_working_procs([]) ->
537    %% i("released"),
538    ok;
539start_counter_working_procs([Pid | Pids]) ->
540    Pid ! start,
541    start_counter_working_procs(Pids).
542
543await_completion_counter_working_procs([]) ->
544    ok;
545await_completion_counter_working_procs(Pids) ->
546    receive
547	{'EXIT', Pid, normal} ->
548	    Pids2 = lists:delete(Pid, Pids),
549	    await_completion_counter_working_procs(Pids2);
550	_Any ->
551	    await_completion_counter_working_procs(Pids)
552    end.
553
554
555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
556
557transaction_id_counter_mgc(suite) ->
558    [];
559transaction_id_counter_mgc(doc) ->
560    ["This test case is intended to test and verify the "
561     "transaction counter handling of the application "
562     "in with several connections (MGC). "];
563transaction_id_counter_mgc(Config) when is_list(Config) ->
564    put(verbosity, ?TEST_VERBOSITY),
565    put(sname,     "TEST"),
566    put(tc,        transaction_id_counter_mgc),
567    process_flag(trap_exit, true),
568
569    i("starting"),
570
571    {ok, _ConfigPid} = megaco_config:start_link(),
572
573    %% Basic user data
574    UserMid = {deviceName, "mgc"},
575    UserConfig = [
576		  {min_trans_id, 1}
577		 ],
578
579    %% Basic connection data
580    RemoteMids =
581	[
582	 {deviceName, "mg01"},
583	 {deviceName, "mg02"},
584	 {deviceName, "mg03"},
585	 {deviceName, "mg04"},
586	 {deviceName, "mg05"},
587	 {deviceName, "mg06"},
588	 {deviceName, "mg07"},
589	 {deviceName, "mg08"},
590	 {deviceName, "mg09"},
591	 {deviceName, "mg10"}
592	],
593    RecvHandles =
594	[
595	 #megaco_receive_handle{local_mid     = UserMid,
596	 			encoding_mod    = ?MODULE,
597	 			encoding_config = [],
598	 			send_mod        = ?MODULE},
599	 #megaco_receive_handle{local_mid     = UserMid,
600	 			encoding_mod    = ?MODULE,
601	 			encoding_config = [],
602	 			send_mod        = ?MODULE},
603	 #megaco_receive_handle{local_mid     = UserMid,
604	 			encoding_mod    = ?MODULE,
605	 			encoding_config = [],
606	 			send_mod        = ?MODULE},
607	 #megaco_receive_handle{local_mid     = UserMid,
608	 			encoding_mod    = ?MODULE,
609	 			encoding_config = [],
610	 			send_mod        = ?MODULE},
611	 #megaco_receive_handle{local_mid     = UserMid,
612	 			encoding_mod    = ?MODULE,
613	 			encoding_config = [],
614	 			send_mod        = ?MODULE},
615	 #megaco_receive_handle{local_mid     = UserMid,
616	 			encoding_mod    = ?MODULE,
617	 			encoding_config = [],
618	 			send_mod        = ?MODULE},
619	 #megaco_receive_handle{local_mid     = UserMid,
620	 			encoding_mod    = ?MODULE,
621	 			encoding_config = [],
622	 			send_mod        = ?MODULE},
623	 #megaco_receive_handle{local_mid     = UserMid,
624	 			encoding_mod    = ?MODULE,
625	 			encoding_config = [],
626	 			send_mod        = ?MODULE},
627	 #megaco_receive_handle{local_mid     = UserMid,
628	 			encoding_mod    = ?MODULE,
629	 			encoding_config = [],
630	 			send_mod        = ?MODULE},
631	 #megaco_receive_handle{local_mid     = UserMid,
632				encoding_mod    = ?MODULE,
633				encoding_config = [],
634				send_mod        = ?MODULE}
635	],
636    SendHandle = dummy_send_handle,
637    ControlPid = self(),
638
639    %% Start user
640    i("start user"),
641    ok = megaco_config:start_user(UserMid, UserConfig),
642
643    %% Create connection
644    i("create connection(s)"),
645    CDs = create_connections(RecvHandles, RemoteMids, SendHandle, ControlPid),
646
647    %% Set counter limits
648    i("set counter max limit(s)"),
649    set_counter_max_limits(CDs, 1000),
650
651    %% Create the counter worker procs
652    i("create counter working procs"),
653    Pids = create_counter_working_procs(CDs, ?NUM_CNT_PROCS),
654
655    %% Start the counter worker procs
656    i("release the counter working procs"),
657    start_counter_working_procs(Pids),
658
659    %% Await the counter worker procs termination
660    i("await the counter working procs completion"),
661    await_completion_counter_working_procs(Pids),
662
663    %% Verify result
664    i("verify counter result"),
665    verify_counter_results(CDs),
666
667    %% Stop test
668    i("disconnect"),
669    delete_connections(CDs),
670    i("stop user"),
671    ok = megaco_config:stop_user(UserMid),
672    i("stop megaco_config"),
673    ok = megaco_config:stop(),
674
675    i("done"),
676    ok.
677
678create_connections(RecvHandles, RemoteMids, SendHandle, ControlPid) ->
679    create_connections(RecvHandles, RemoteMids, SendHandle, ControlPid, []).
680
681create_connections([], [], _SendHandle, _ControlPid, Acc) ->
682    lists:reverse(Acc);
683create_connections([RecvHandle | RecvHandles],
684		   [RemoteMid  | RemoteMids],
685		   SendHandle, ControlPid, Acc) ->
686    {ok, CD} =
687	megaco_config:connect(RecvHandle, RemoteMid, SendHandle, ControlPid),
688    create_connections(RecvHandles, RemoteMids,
689		       SendHandle, ControlPid, [CD | Acc]).
690
691
692set_counter_max_limits([], _MaxTransId) ->
693    ok;
694set_counter_max_limits([#conn_data{conn_handle = CH} | CDs], MaxTransId) ->
695    megaco_config:update_conn_info(CH, max_trans_id, MaxTransId),
696    set_counter_max_limits(CDs, MaxTransId).
697
698
699create_counter_working_procs(CDs, NumCntProcs) ->
700    lists:flatten(create_counter_working_procs2(CDs, NumCntProcs)).
701
702create_counter_working_procs2([], _NumCntProcs) ->
703    [];
704create_counter_working_procs2([#conn_data{conn_handle = CH} | CDs],
705			      NumCntProcs) ->
706    [create_counter_working_procs(CH, NumCntProcs, []) |
707     create_counter_working_procs2(CDs, NumCntProcs)].
708
709
710verify_counter_results([]) ->
711    ok;
712verify_counter_results([#conn_data{conn_handle = CH} | CDs]) ->
713    TransId = megaco_config:conn_info(CH, trans_id),
714    if
715	(TransId =:= 1) ->
716	    ok;
717	true ->
718	    ?ERROR({trans_id_verification_failed, CH, TransId})
719    end,
720    verify_counter_results(CDs).
721
722
723delete_connections([]) ->
724    ok;
725delete_connections([#conn_data{conn_handle = CH} | CDs]) ->
726    {ok, _, _} = megaco_config:disconnect(CH),
727    delete_connections(CDs).
728
729
730
731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
732
733otp_7216(suite) ->
734    [];
735otp_7216(Config) when is_list(Config) ->
736    put(tc, otp_7216),
737    p("start"),
738
739    p("start the megaco config process"),
740    megaco_config:start_link(),
741
742    LocalMid1 = {deviceName, "local-mid-1"},
743    %% LocalMid2 = {deviceName, "local-mid-2"},
744    RemoteMid1 = {deviceName, "remote-mid-1"},
745    %% RemoteMid2 = {deviceName, "remote-mid-2"},
746    RH = #megaco_receive_handle{local_mid       = LocalMid1,
747				encoding_mod    = dummy_codec_module,
748				encoding_config = [],
749				send_mod        = dummy_transport_module},
750    MinTransId = 7216,
751    MaxTransId = MinTransId + 10,
752    User1Config = [{min_trans_id, MinTransId},
753		   {max_trans_id, MaxTransId}],
754
755    VerifySerial =
756	fun(Actual, Expected) ->
757		if
758		    Actual == Expected ->
759			ok;
760		    true ->
761			throw({error, {invalid_counter_value, Actual}})
762		end
763	end,
764
765    p("start local user: ~p", [LocalMid1]),
766    ok = megaco_config:start_user(LocalMid1, User1Config),
767
768    p("connect"),
769    {ok, CD} = megaco_config:connect(RH, RemoteMid1,
770				     dummy_send_handle, self()),
771    p("connect ok: CD = ~n~p", [CD]),
772    CH = CD#conn_data.conn_handle,
773
774
775    p("*** make the first counter increment ***"),
776    {ok, CD01} = megaco_config:incr_trans_id_counter(CH, 1),
777    Serial01   = CD01#conn_data.serial,
778    p("serial: ~p", [Serial01]),
779    VerifySerial(Serial01, MinTransId),
780    p("counter increment 1 ok"),
781
782
783    p("*** make two more counter increments ***"),
784    {ok, _} = megaco_config:incr_trans_id_counter(CH, 1),
785    {ok, CD02} = megaco_config:incr_trans_id_counter(CH, 1),
786    Serial02   = CD02#conn_data.serial,
787    p("serial: ~p", [Serial02]),
788    VerifySerial(Serial02, MinTransId+2),
789    p("counter increment 2 ok"),
790
791
792    p("*** make a big counter increment ***"),
793    {ok, CD03} = megaco_config:incr_trans_id_counter(CH, 8),
794    Serial03   = CD03#conn_data.serial,
795    p("serial: ~p", [Serial03]),
796    VerifySerial(Serial03, MinTransId+2+8),
797    p("counter increment 3 ok"),
798
799
800    p("*** make a wrap-around counter increment ***"),
801    {ok, CD04} = megaco_config:incr_trans_id_counter(CH, 1),
802    Serial04   = CD04#conn_data.serial,
803    p("serial: ~p", [Serial04]),
804    VerifySerial(Serial04, MinTransId),
805    p("counter increment 4 ok"),
806
807
808    p("*** make a big counter increment ***"),
809    {ok, CD05} = megaco_config:incr_trans_id_counter(CH, 10),
810    Serial05   = CD05#conn_data.serial,
811    p("serial: ~p", [Serial05]),
812    VerifySerial(Serial05, MinTransId+10),
813    p("counter increment 5 ok"),
814
815
816    p("*** make a big wrap-around counter increment ***"),
817    {ok, CD06} = megaco_config:incr_trans_id_counter(CH, 3),
818    Serial06   = CD06#conn_data.serial,
819    p("serial: ~p", [Serial06]),
820    VerifySerial(Serial06, MinTransId+(3-1)),
821    p("counter increment 6 ok"),
822
823
824    p("*** make a big counter increment ***"),
825    {ok, CD07} = megaco_config:incr_trans_id_counter(CH, 7),
826    Serial07   = CD07#conn_data.serial,
827    p("serial: ~p", [Serial07]),
828    VerifySerial(Serial07, MinTransId+(3-1)+7),
829    p("counter increment 7 ok"),
830
831
832    p("*** make a big wrap-around counter increment ***"),
833    {ok, CD08} = megaco_config:incr_trans_id_counter(CH, 5),
834    Serial08   = CD08#conn_data.serial,
835    p("serial: ~p", [Serial08]),
836    VerifySerial(Serial08, MinTransId+(5-1-1)),
837    p("counter increment 8 ok"),
838
839
840    p("disconnect"),
841    {ok, CD, RCD} = megaco_config:disconnect(CH),
842    p("disconnect ok: RCD = ~n~p", [RCD]),
843
844    p("stop user"),
845    ok = megaco_config:stop_user(LocalMid1),
846
847    p("stop megaco config process"),
848    megaco_config:stop(),
849
850    p("done"),
851    ok.
852
853
854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
855
856otp_8167(suite) ->
857    [];
858otp_8167(Config) when is_list(Config) ->
859    put(tc, otp8167),
860    p("start"),
861
862    p("start the megaco config process"),
863    megaco_config:start_link(),
864
865    LocalMid1  = {deviceName, "local-mid-1"},
866    LocalMid2  = {deviceName, "local-mid-2"},
867    RemoteMid1 = {deviceName, "remote-mid-1"},
868    %% RemoteMid2 = {deviceName, "remote-mid-2"},
869    RH1 = #megaco_receive_handle{local_mid       = LocalMid1,
870				 encoding_mod    = dummy_codec_module,
871				 encoding_config = [],
872				 send_mod        = dummy_transport_module},
873%%     RH2 = #megaco_receive_handle{local_mid       = LocalMid2,
874%% 				 encoding_mod    = dummy_codec_module,
875%% 				 encoding_config = [],
876%% 				 send_mod        = dummy_transport_module},
877
878    User1ConfigA = [{call_proxy_gc_timeout, 1}],
879    User1ConfigB = [{call_proxy_gc_timeout, 0}],
880    User2ConfigA = [{call_proxy_gc_timeout, -1}],
881    User2ConfigB = [{call_proxy_gc_timeout, infinity}],
882    User2ConfigC = [{call_proxy_gc_timeout, "1"}],
883    User2ConfigD = [{call_proxy_gc_timeout, 1.0}],
884
885    p("start local user (1A): ~p", [LocalMid1]),
886    ok = megaco_config:start_user(LocalMid1, User1ConfigA),
887    p("stop local user (1A): ~p", [LocalMid1]),
888    ok = megaco_config:stop_user(LocalMid1),
889
890    p("start local user (1B): ~p", [LocalMid1]),
891    ok = megaco_config:start_user(LocalMid1, User1ConfigB),
892    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
893      [LocalMid1, -1]),
894    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, -1}} =
895	megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, -1),
896    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
897      [LocalMid1, infinity]),
898    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, infinity}} =
899	megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, infinity),
900    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
901      [LocalMid1, "1"]),
902    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, "1"}} =
903	megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, "1"),
904    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
905      [LocalMid1, 1.0]),
906    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, 1.0}} =
907	megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, 1.0),
908    p("change value for item call_proxy_gc_timeout for local user: ~p", [LocalMid1]),
909    ok = megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, 10101),
910
911    p("connect"),
912    {ok, CD} = megaco_config:connect(RH1, RemoteMid1,
913				     dummy_send_handle, self()),
914    p("connect ok: CD = ~n~p", [CD]),
915    CH = CD#conn_data.conn_handle,
916
917    p("get value for item cancel from connection: ~p", [CH]),
918    false = megaco_config:conn_info(CH, cancel),
919
920    p("get value for item cancel from connection data", []),
921    false = megaco_config:conn_info(CD, cancel),
922
923    p("get value for item call_proxy_gc_timeout for connection: ~p", [CH]),
924    10101 = megaco_config:conn_info(CH, call_proxy_gc_timeout),
925
926    p("change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
927      [CH, 20202]),
928    ok = megaco_config:update_conn_info(CH, call_proxy_gc_timeout, 20202),
929
930    p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
931      [CH, -1]),
932    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, -1}} =
933	megaco_config:update_conn_info(CH, call_proxy_gc_timeout, -1),
934
935    p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
936      [CH, infinity]),
937    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, infinity}} =
938	megaco_config:update_conn_info(CH, call_proxy_gc_timeout, infinity),
939
940    p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
941      [CH, "1"]),
942    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, "1"}} =
943	megaco_config:update_conn_info(CH, call_proxy_gc_timeout, "1"),
944
945    p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
946      [CH, 1.0]),
947    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, 1.0}} =
948	megaco_config:update_conn_info(CH, call_proxy_gc_timeout, 1.0),
949
950    p("disconnect: ~p", [CH]),
951    {ok, _, _} = megaco_config:disconnect(CH),
952
953    p("stop local user (1B): ~p", [LocalMid1]),
954    ok = megaco_config:stop_user(LocalMid1),
955
956    p("try (and fail) start local user (2A): ~p", [LocalMid2]),
957    {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, -1}} =
958	megaco_config:start_user(LocalMid2, User2ConfigA),
959
960    p("try (and fail) start local user (2B): ~p", [LocalMid2]),
961    {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, infinity}} =
962	megaco_config:start_user(LocalMid2, User2ConfigB),
963
964    p("try (and fail) start local user (2C): ~p", [LocalMid2]),
965    {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, "1"}} =
966	megaco_config:start_user(LocalMid2, User2ConfigC),
967
968    p("try (and fail) start local user (2D): ~p", [LocalMid2]),
969    {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, 1.0}} =
970	megaco_config:start_user(LocalMid2, User2ConfigD),
971
972    p("done"),
973    ok.
974
975
976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
977
978otp_8183(suite) ->
979    [];
980otp_8183(Config) when is_list(Config) ->
981    put(tc, otp8183),
982    p("start"),
983
984    p("start the megaco config process"),
985    megaco_config:start_link(),
986
987    LocalMid1  = {deviceName, "local-mid-1"},
988    LocalMid2  = {deviceName, "local-mid-2"},
989    RemoteMid1 = {deviceName, "remote-mid-1"},
990%%     RemoteMid2 = {deviceName, "remote-mid-2"},
991    RH1 = #megaco_receive_handle{local_mid       = LocalMid1,
992				 encoding_mod    = dummy_codec_module,
993				 encoding_config = [],
994				 send_mod        = dummy_transport_module},
995%%     RH2 = #megaco_receive_handle{local_mid       = LocalMid2,
996%% 				 encoding_mod    = dummy_codec_module,
997%% 				 encoding_config = [],
998%% 				 send_mod        = dummy_transport_module},
999
1000    OkValA = 100,
1001    OkValB = 0,
1002    OkValC = plain,
1003    OkValD = 10101,
1004    OkValE = 20202,
1005    BadValA = -1,
1006    BadValB = pain,
1007    BadValC = "1",
1008    BadValD = 1.0,
1009    User1ConfigA = [{request_keep_alive_timeout, OkValA}],
1010    User1ConfigB = [{request_keep_alive_timeout, OkValB}],
1011    User1ConfigC = [{request_keep_alive_timeout, OkValC}],
1012    User2ConfigA = [{request_keep_alive_timeout, BadValA}],
1013    User2ConfigB = [{request_keep_alive_timeout, BadValB}],
1014    User2ConfigC = [{request_keep_alive_timeout, BadValC}],
1015    User2ConfigD = [{request_keep_alive_timeout, BadValD}],
1016
1017    p("start local user (1A): ~p", [LocalMid1]),
1018    ok = megaco_config:start_user(LocalMid1, User1ConfigA),
1019    p("stop local user (1A): ~p", [LocalMid1]),
1020    ok = megaco_config:stop_user(LocalMid1),
1021
1022    p("start local user (1B): ~p", [LocalMid1]),
1023    ok = megaco_config:start_user(LocalMid1, User1ConfigB),
1024    p("stop local user (1B): ~p", [LocalMid1]),
1025    ok = megaco_config:stop_user(LocalMid1),
1026
1027    p("start local user (1C): ~p", [LocalMid1]),
1028    ok = megaco_config:start_user(LocalMid1, User1ConfigC),
1029
1030    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
1031      [LocalMid1, BadValA]),
1032    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValA}} =
1033	megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValA),
1034
1035    p("try (and fail) change value for item request_keep_alive_timeout for local user: ~p -> ~p",
1036      [LocalMid1, BadValB]),
1037    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValB}} =
1038	megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValB),
1039
1040    p("try (and fail) change value for item request_keep_alive_timeout for local user: ~p -> ~p",
1041      [LocalMid1, BadValC]),
1042    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValC}} =
1043	megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValC),
1044
1045    p("try (and fail) change value for item request_keep_alive_timeout for local user: ~p -> ~p",
1046      [LocalMid1, BadValD]),
1047    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValD}} =
1048	megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValD),
1049
1050    p("change value for item request_keep_alive_timeout for local user: ~p", [LocalMid1]),
1051    ok = megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, OkValD),
1052
1053    p("connect"),
1054    {ok, CD} = megaco_config:connect(RH1, RemoteMid1,
1055				     dummy_send_handle, self()),
1056    p("connect ok: CD = ~n~p", [CD]),
1057    CH = CD#conn_data.conn_handle,
1058
1059    p("get value for item request_keep_alive_timeout for connection: ~p", [CH]),
1060    OkValD = megaco_config:conn_info(CH, request_keep_alive_timeout),
1061
1062    p("change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1063      [CH, OkValE]),
1064    ok = megaco_config:update_conn_info(CH, request_keep_alive_timeout, OkValE),
1065
1066    p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1067      [CH, BadValA]),
1068    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValA}} =
1069	megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValA),
1070
1071    p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1072      [CH, BadValB]),
1073    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValB}} =
1074	megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValB),
1075
1076    p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1077      [CH, BadValC]),
1078    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValC}} =
1079	megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValC),
1080
1081    p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1082      [CH, BadValD]),
1083    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValD}} =
1084	megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValD),
1085
1086    p("disconnect: ~p", [CH]),
1087    {ok, _, _} = megaco_config:disconnect(CH),
1088
1089    p("stop local user (1B): ~p", [LocalMid1]),
1090    ok = megaco_config:stop_user(LocalMid1),
1091
1092    p("try (and fail) start local user (2A): ~p", [LocalMid2]),
1093    {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValA}} =
1094	megaco_config:start_user(LocalMid2, User2ConfigA),
1095
1096    p("try (and fail) start local user (2B): ~p", [LocalMid2]),
1097    {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValB}} =
1098	megaco_config:start_user(LocalMid2, User2ConfigB),
1099
1100    p("try (and fail) start local user (2C): ~p", [LocalMid2]),
1101    {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValC}} =
1102	megaco_config:start_user(LocalMid2, User2ConfigC),
1103
1104    p("try (and fail) start local user (2D): ~p", [LocalMid2]),
1105    {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValD}} =
1106	megaco_config:start_user(LocalMid2, User2ConfigD),
1107
1108    p("done"),
1109    ok.
1110
1111
1112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1113
1114p(F) ->
1115    p(F, []).
1116
1117p(F, A) ->
1118    io:format("[~w] " ++ F ++ "~n", [get(tc)|A]).
1119
1120
1121i(F) ->
1122    i(F, []).
1123
1124i(F, A) ->
1125    print(info, get(verbosity), now(), get(tc), "INF", F, A).
1126
1127printable(_, debug)   -> true;
1128printable(info, info) -> true;
1129printable(_,_)        -> false.
1130
1131print(Severity, Verbosity, Ts, Tc, P, F, A) ->
1132    print(printable(Severity,Verbosity), Ts, Tc, P, F, A).
1133
1134print(true, Ts, Tc, P, F, A) ->
1135    io:format("*** [~s] ~s ~p ~s:~w ***"
1136              "~n   " ++ F ++ "~n",
1137              [format_timestamp(Ts), P, self(), get(sname), Tc | A]);
1138print(_, _, _, _, _, _) ->
1139    ok.
1140
1141format_timestamp({_N1, _N2, N3} = Now) ->
1142    {Date, Time}   = calendar:now_to_datetime(Now),
1143    {YYYY,MM,DD}   = Date,
1144    {Hour,Min,Sec} = Time,
1145    FormatDate =
1146        io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
1147                      [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
1148    lists:flatten(FormatDate).
1149
1150