1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2021. 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_SUITE).
27
28-export([
29         suite/0, all/0, groups/0,
30	 init_per_suite/1,    end_per_suite/1,
31	 init_per_group/2,    end_per_group/2,
32	 init_per_testcase/2, end_per_testcase/2,
33
34         config/1,
35         transaction_id_counter_mg/1,
36         transaction_id_counter_mgc/1,
37         otp_7216/1,
38         otp_8167/1,
39         otp_8183/1
40        ]).
41
42-include_lib("megaco/include/megaco.hrl").
43-include_lib("megaco/src/app/megaco_internal.hrl").
44-include("megaco_test_lib.hrl").
45
46-record(command, {id, desc, cmd, verify}).
47
48-define(TEST_VERBOSITY, debug).
49-define(NUM_CNT_PROCS,  100).
50
51
52%%======================================================================
53%% Common Test interface functions
54%%======================================================================
55
56suite() ->
57    [{ct_hooks, [ts_install_cth]}].
58
59all() ->
60    [
61     config,
62     {group, transaction_id_counter},
63     {group, tickets}
64    ].
65
66groups() ->
67    [
68     {transaction_id_counter, [], transaction_id_counter_cases()},
69     {tickets,                [], tickets_cases()}
70    ].
71
72
73
74transaction_id_counter_cases() ->
75    [
76     transaction_id_counter_mg,
77     transaction_id_counter_mgc
78    ].
79
80tickets_cases() ->
81    [
82     otp_7216,
83     otp_8167,
84     otp_8183
85    ].
86
87
88
89%%
90%% -----
91%%
92
93init_per_suite(Config0) when is_list(Config0) ->
94
95    p("init_per_suite -> entry with"
96      "~n      Config: ~p"
97      "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
98
99    case ?LIB:init_per_suite(Config0) of
100        {skip, _} = SKIP ->
101            SKIP;
102
103        Config1 when is_list(Config1) ->
104
105            %% We need a (local) monitor on this node also
106            megaco_test_sys_monitor:start(),
107
108            p("init_per_suite -> end when"
109              "~n      Config: ~p"
110              "~n      Nodes:  ~p", [Config1, erlang:nodes()]),
111
112            Config1
113    end.
114
115end_per_suite(Config0) when is_list(Config0) ->
116
117    p("end_per_suite -> entry with"
118      "~n      Config0: ~p"
119      "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
120
121    megaco_test_sys_monitor:stop(),
122    Config1 = ?LIB:end_per_suite(Config0),
123
124    p("end_per_suite -> end when"
125      "~n      Nodes:  ~p", [erlang:nodes()]),
126    Config1.
127
128
129
130%%
131%% -----
132%%
133
134init_per_group(_GroupName, Config) ->
135    Config.
136
137end_per_group(_GroupName, Config) ->
138    Config.
139
140
141%%
142%% -----
143%%
144
145%% Test server callbacks
146init_per_testcase(Case, Config) when (Case =:= otp_7216) orelse
147                                     (Case =:= otp_8167) orelse
148                                     (Case =:= otp_8183) ->
149    i("init_per_testcase -> entry with"
150      "~n   Config: ~p"
151      "~n   Nodes:  ~p", [Config, erlang:nodes()]),
152
153    megaco_test_global_sys_monitor:reset_events(),
154
155    i("try starting megaco_config"),
156    case megaco_config:start_link() of
157        {ok, _} ->
158            C = lists:keydelete(tc_timeout, 1, Config),
159            do_init_per_testcase(Case, [{tc_timeout, min(3)}|C]);
160        {error, Reason} ->
161            i("Failed starting megaco_config: "
162              "~n   ~p", [Reason]),
163            {skip, ?F("Failed starting config: ~p", [Reason])}
164    end;
165init_per_testcase(Case, Config) ->
166    C = lists:keydelete(tc_timeout, 1, Config),
167    do_init_per_testcase(Case, [{tc_timeout, min(3)}|C]).
168
169do_init_per_testcase(Case, Config) ->
170    process_flag(trap_exit, true),
171    megaco_test_lib:init_per_testcase(Case, Config).
172
173min(M) -> timer:minutes(M).
174
175
176end_per_testcase(Case, Config) when (Case =:= otp_7216) orelse
177                                    (Case =:= otp_8167) orelse
178                                    (Case =:= otp_8183) ->
179    p("end_per_testcase -> entry with"
180      "~n   Config: ~p"
181      "~n   Nodes:  ~p", [Config, erlang:nodes()]),
182
183    p("system events during test: "
184      "~n   ~p", [megaco_test_global_sys_monitor:events()]),
185
186    (catch megaco_config:stop()),
187    process_flag(trap_exit, false),
188    megaco_test_lib:end_per_testcase(Case, Config);
189end_per_testcase(Case, Config) ->
190    process_flag(trap_exit, false),
191    megaco_test_lib:end_per_testcase(Case, Config).
192
193
194
195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196%% Config test case
197
198config(suite) ->
199    [];
200config(Config) when is_list(Config) ->
201    ?ACQUIRE_NODES(1, Config),
202    Mid = fake_mid,
203
204    %% Nice values
205    Int = 3,
206    IT  = #megaco_incr_timer{max_retries = Int},
207
208    %% Evil values
209    NonInt = non_int,
210    IT2 = #megaco_incr_timer{wait_for = NonInt},
211    IT3 = #megaco_incr_timer{factor = NonInt},
212    IT4 = #megaco_incr_timer{max_retries = NonInt},
213    IT5 = #megaco_incr_timer{max_retries = non_infinity},
214
215    %% Command range values
216    Initial = 100,
217    Verify  = 200,
218    Nice    = 300,
219    Evil    = 400,
220    End     = 500,
221
222    InitialCmd =
223	fun(No, Desc, Cmd, VerifyVal) ->
224		initial_command(Initial + No, Desc, Cmd, VerifyVal)
225	end,
226
227    VerifyCmd =
228	fun(M, No, Key, V) ->
229		verify_user_default_command(M, Verify + No, Key, V)
230	end,
231
232    NiceCmd =
233	fun(M, No, Key, Val) ->
234		nice_user_update_command(M, Nice + No, Key, Val)
235	end,
236
237    EvilCmd =
238	fun(M, No, Key, Val) ->
239		evil_user_update_command(M, Evil + No, Key, Val)
240	end,
241
242    %% End commands
243    ExitCmd =
244	fun(No, Desc, Cmd) ->
245		exit_command(End + No, Desc, Cmd)
246	end,
247    ErrorCmd =
248	fun(No, Desc, Cmd, MainReason, TS) ->
249		error_command(End + No, Desc, Cmd, MainReason, TS)
250	end,
251    PlainCmd =
252	fun(No, Desc, Cmd, V) ->
253		command(End + No, Desc, Cmd, V)
254	end,
255
256    Commands =
257	[
258	 %% Initial commands
259	 InitialCmd(0,
260		    "enable trace",
261		    fun() -> megaco:enable_trace(100, io) end,
262		    ok),
263	 InitialCmd(1,
264		    "start",
265		    fun() -> megaco:start() end,
266		    ok),
267	 InitialCmd(2,
268		    "Verify no active requests",
269		    fun() -> megaco:system_info(n_active_requests) end,
270		    0),
271	 InitialCmd(3,
272		    "Verify no active replies",
273		    fun() -> megaco:system_info(n_active_replies) end,
274		    0),
275	 InitialCmd(4,
276		    "Verify no active connections",
277		    fun() -> megaco:system_info(n_active_connections) end,
278		    0),
279	 InitialCmd(5,
280		    "Verify no connections",
281		    fun() -> megaco:system_info(connections) end,
282		    []),
283	 InitialCmd(6,
284		    "Verify no users",
285		    fun() -> megaco:system_info(users) end,
286		    []),
287	 InitialCmd(7,
288		    "Start user",
289		    fun() -> megaco:start_user(Mid, []) end,
290		    ok),
291
292
293	 %% Verify user defaults
294	 VerifyCmd(Mid,  1, connections, []),
295	 VerifyCmd(Mid,  2, min_trans_id, 1),
296	 VerifyCmd(Mid,  3, max_trans_id, infinity),
297	 VerifyCmd(Mid,  4, request_timer, #megaco_incr_timer{}),
298	 VerifyCmd(Mid,  5, long_request_timer, timer:seconds(60)),
299	 VerifyCmd(Mid,  6, auto_ack, false),
300	 VerifyCmd(Mid,  7, pending_timer, 30000),
301	 VerifyCmd(Mid,  8, reply_timer, 30000),
302	 VerifyCmd(Mid,  9, send_mod, megaco_tcp),
303	 VerifyCmd(Mid, 10, encoding_mod, megaco_pretty_text_encoder),
304	 VerifyCmd(Mid, 11, encoding_config, []),
305	 VerifyCmd(Mid, 12, protocol_version, 1),
306	 VerifyCmd(Mid, 13, reply_data, undefined),
307	 VerifyCmd(Mid, 14, receive_handle,
308		   fun(H) when is_record(H, megaco_receive_handle) ->
309			   {ok, H};
310		      (R)  ->
311			   {error, R}
312		   end),
313
314
315	 %% Nice update
316	 NiceCmd(Mid,  1, min_trans_id, Int),
317	 NiceCmd(Mid,  2, max_trans_id, Int),
318	 NiceCmd(Mid,  3, max_trans_id, infinity),
319	 NiceCmd(Mid,  4, request_timer, Int),
320	 NiceCmd(Mid,  5, request_timer, infinity),
321	 NiceCmd(Mid,  6, request_timer, IT),
322	 NiceCmd(Mid,  7, long_request_timer, Int),
323	 NiceCmd(Mid,  8, long_request_timer, infinity),
324	 NiceCmd(Mid,  9, long_request_timer, IT),
325	 NiceCmd(Mid, 10, auto_ack, true),
326	 NiceCmd(Mid, 11, auto_ack, false),
327	 NiceCmd(Mid, 12, pending_timer, Int),
328	 NiceCmd(Mid, 13, pending_timer, infinity),
329	 NiceCmd(Mid, 14, pending_timer, IT),
330	 NiceCmd(Mid, 15, reply_timer, Int),
331	 NiceCmd(Mid, 16, reply_timer, infinity),
332	 NiceCmd(Mid, 17, reply_timer, IT),
333	 NiceCmd(Mid, 18, send_mod, an_atom),
334	 NiceCmd(Mid, 19, encoding_mod, an_atom),
335	 NiceCmd(Mid, 20, encoding_config, []),
336	 NiceCmd(Mid, 21, protocol_version, Int),
337	 NiceCmd(Mid, 23, reply_data, IT),
338	 NiceCmd(Mid, 23, resend_indication, true),
339	 NiceCmd(Mid, 24, resend_indication, false),
340	 NiceCmd(Mid, 25, resend_indication, flag),
341
342
343	 %% Evil update
344	 EvilCmd(Mid,  1, min_trans_id, NonInt),
345	 EvilCmd(Mid,  2, max_trans_id, NonInt),
346	 EvilCmd(Mid,  3, max_trans_id, non_infinity),
347	 EvilCmd(Mid,  4, request_timer, NonInt),
348	 EvilCmd(Mid,  5, request_timer, non_infinity),
349	 EvilCmd(Mid,  6, request_timer, IT2),
350	 EvilCmd(Mid,  7, request_timer, IT3),
351	 EvilCmd(Mid,  8, request_timer, IT4),
352	 EvilCmd(Mid,  9, request_timer, IT5),
353	 EvilCmd(Mid, 10, long_request_timer, NonInt),
354	 EvilCmd(Mid, 11, long_request_timer, non_infinity),
355	 EvilCmd(Mid, 12, long_request_timer, IT2),
356	 EvilCmd(Mid, 13, long_request_timer, IT3),
357	 EvilCmd(Mid, 14, long_request_timer, IT4),
358	 EvilCmd(Mid, 15, long_request_timer, IT5),
359	 EvilCmd(Mid, 16, auto_ack, non_bool),
360	 EvilCmd(Mid, 17, pending_timer, NonInt),
361	 EvilCmd(Mid, 18, pending_timer, non_infinity),
362	 EvilCmd(Mid, 19, pending_timer, IT2),
363	 EvilCmd(Mid, 20, pending_timer, IT3),
364	 EvilCmd(Mid, 21, pending_timer, IT4),
365	 EvilCmd(Mid, 22, pending_timer, IT5),
366	 EvilCmd(Mid, 23, reply_timer, NonInt),
367	 EvilCmd(Mid, 24, reply_timer, non_infinity),
368	 EvilCmd(Mid, 25, reply_timer, IT2),
369	 EvilCmd(Mid, 26, reply_timer, IT3),
370	 EvilCmd(Mid, 27, reply_timer, IT4),
371	 EvilCmd(Mid, 28, reply_timer, IT5),
372	 EvilCmd(Mid, 29, send_mod, {non_atom}),
373	 EvilCmd(Mid, 30, encoding_mod, {non_atom}),
374	 EvilCmd(Mid, 31, encoding_config, non_list),
375	 EvilCmd(Mid, 32, protocol_version, NonInt),
376	 EvilCmd(Mid, 33, resend_indication, flagg),
377
378
379	 %% End
380	 ExitCmd(1, "Verify non-existing system info",
381		 fun() -> megaco:system_info(non_exist) end),
382	 ExitCmd(2, "Verify non-existing user user info",
383		 fun() -> megaco:user_info(non_exist, trans_id) end),
384	 ExitCmd(3, "Verify non-existing user info",
385		 fun() -> megaco:user_info(Mid, non_exist) end),
386
387	 ErrorCmd(4, "Try updating user info for non-existing user",
388		  fun() ->
389			  megaco:update_user_info(non_exist, trans_id, 1)
390		  end,
391		  no_such_user, 2),
392	 ErrorCmd(11, "Try updating non-existing user info",
393		  fun() ->
394			  megaco:update_user_info(Mid, trans_id, 4711)
395		  end,
396		  bad_user_val, 4),
397	 ErrorCmd(12, "Try start already started user",
398		  fun() -> megaco:start_user(Mid, []) end,
399		  user_already_exists, 2),
400
401	 PlainCmd(13, "Verify started users",
402		  fun() -> megaco:system_info(users) end, [Mid]),
403	 PlainCmd(14, "Stop user", fun() -> megaco:stop_user(Mid) end, ok),
404	 PlainCmd(15, "Verify started users",
405		  fun() -> megaco:system_info(users) end, []),
406	 ErrorCmd(16, "Try stop not started user",
407		  fun() -> megaco:stop_user(Mid) end, no_such_user, 2),
408	 ErrorCmd(17, "Try start megaco (it's already started)",
409		  fun() -> megaco:start() end, already_started, 2),
410	 PlainCmd(18, "Stop megaco", fun() -> megaco:stop() end, ok),
411	 ErrorCmd(19, "Try stop megaco (it's not running)",
412		  fun() -> megaco:stop() end, not_started, 2)
413	],
414
415
416    exec(Commands).
417
418
419
420exec([]) ->
421    ok;
422exec([#command{id     = No,
423	       desc   = Desc,
424	       cmd    = Cmd,
425	       verify = Verify}|Commands]) ->
426    io:format("Executing command ~3w: ~s: ", [No, Desc]),
427    case (catch Verify((catch Cmd()))) of
428	{ok, OK} ->
429	    io:format("ok => ~p~n", [OK]),
430	    exec(Commands);
431	{error, Reason} ->
432	    io:format("error => ~p~n", [Reason]),
433	    {error, {bad_result, No, Reason}};
434	Error ->
435	    io:format("exit => ~p~n", [Error]),
436	    {error, {unexpected_result, No, Error}}
437    end.
438
439initial_command(No, Desc0, Cmd, VerifyVal) when is_function(Cmd) ->
440    Desc = lists:flatten(io_lib:format("Initial - ~s", [Desc0])),
441    command(No, Desc, Cmd, VerifyVal).
442
443verify_user_default_command(Mid, No, Key, Verify) ->
444    Desc = lists:flatten(io_lib:format("Defaults - Verify ~w", [Key])),
445    Cmd = fun() -> megaco:user_info(Mid, Key) end,
446    command(No, Desc, Cmd, Verify).
447
448nice_user_update_command(Mid, No, Key, Val) ->
449    Desc = lists:flatten(io_lib:format("Nice - Update ~w", [Key])),
450    Cmd = fun() -> megaco:update_user_info(Mid, Key, Val) end,
451    Verify = fun(ok) ->
452		     case (catch megaco:user_info(Mid, Key)) of
453			 {'EXIT', R} ->
454			     {error, {value_retreival_failed, R}};
455			 Val ->
456			     {ok, Val};
457			 Invalid ->
458			     {error, {value_update_failed, Val, Invalid}}
459		     end;
460		(R)  ->
461		     {error, R}
462	     end,
463    command(No, Desc, Cmd, Verify).
464
465
466evil_user_update_command(Mid, No, Key, Val) ->
467    Desc = lists:flatten(io_lib:format("Evil - Update ~w", [Key])),
468    Cmd = fun() ->
469		  case (catch megaco:user_info(Mid, Key)) of
470		      {'EXIT', R} ->
471			  {{error, {old_value_retreival_failed, R}},
472			   ignore};
473		      OldVal ->
474			  {OldVal,
475			   (catch megaco:update_user_info(Mid, Key, Val))}
476		  end
477	  end,
478    Verify = fun({{error, _} = Error, ignore}) ->
479		     Error;
480		({OldVal, {error, {bad_user_val, _, _, _}}}) ->
481		     case (catch megaco:user_info(Mid, Key)) of
482			 {'EXIT', R} ->
483			     {error, {value_retreival_failed, R}};
484			 OldVal ->
485			     {ok, OldVal};
486			 Invalid ->
487			     {error, {value_update_failed, OldVal, Invalid}}
488		     end;
489		(R) ->
490		     {error, R}
491	     end,
492    command(No, Desc, Cmd, Verify).
493
494exit_command(No, Desc, Cmd) when is_function(Cmd) ->
495    Verify = fun({'EXIT', _} = E) ->
496		     {ok, E};
497		(R) ->
498		     {error, R}
499	     end,
500    command(No, Desc, Cmd, Verify).
501
502error_command(No, Desc, Cmd, MainReason, TS) when is_function(Cmd) ->
503    Verify = fun({error, Reason}) ->
504		     io:format("verify -> Reason: ~n~p~n", [Reason]),
505		     case Reason of
506			 {MainReason, _} when TS == 2 ->
507			     {ok, MainReason};
508			 {MainReason, _, _, _} when TS == 4 ->
509			     {ok, MainReason};
510			 _ ->
511			     {error, Reason}
512		     end;
513		(R) ->
514		     {error, R}
515	     end,
516    command(No, Desc, Cmd, Verify).
517
518command(No, Desc, Cmd, Verify)
519  when (is_integer(No) andalso
520	is_list(Desc) andalso
521	is_function(Cmd) andalso
522	is_function(Verify)) ->
523    #command{id     = No,
524	     desc   = Desc,
525	     cmd    = Cmd,
526	     verify = Verify};
527command(No, Desc, Cmd, VerifyVal)
528  when (is_integer(No) andalso
529	is_list(Desc) andalso
530	is_function(Cmd)) ->
531    Verify = fun(Val) ->
532		     case Val of
533			 VerifyVal ->
534			     {ok, Val};
535			 _ ->
536			     {error, Val}
537		     end
538	     end,
539    #command{id     = No,
540	     desc   = Desc,
541	     cmd    = Cmd,
542	     verify = Verify}.
543
544
545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546
547transaction_id_counter_mg(suite) ->
548    [];
549transaction_id_counter_mg(doc) ->
550    ["This test case is intended to test and verify the "
551     "transaction counter handling of the application "
552     "in with one connection (MG). "];
553transaction_id_counter_mg(Config) when is_list(Config) ->
554    put(verbosity, ?TEST_VERBOSITY),
555    put(sname,     "TEST"),
556    put(tc,        transaction_id_counter_mg),
557
558    process_flag(trap_exit, true),
559
560    i("starting"),
561
562    {ok, _ConfigPid} = megaco_config:start_link(),
563
564    %% Basic user data
565    UserMid = {deviceName, "mg"},
566    UserConfig = [
567		  {min_trans_id, 1}
568		 ],
569
570    %% Basic connection data
571    RemoteMid = {deviceName, "mgc"},
572    RecvHandle = #megaco_receive_handle{local_mid       = UserMid,
573					encoding_mod    = ?MODULE,
574					encoding_config = [],
575					send_mod        = ?MODULE},
576    SendHandle = dummy_send_handle,
577    ControlPid = self(),
578
579    %% Start user
580    i("start user"),
581    ok = megaco_config:start_user(UserMid, UserConfig),
582
583    %% Create connection
584    i("create connection"),
585    {ok, CD} =
586	megaco_config:connect(RecvHandle, RemoteMid, SendHandle, ControlPid),
587
588    %% Set counter limits
589    i("set counter max limit"),
590    CH = CD#conn_data.conn_handle,
591    megaco_config:update_conn_info(CH, max_trans_id, 1000),
592
593    %% Create the counter worker procs
594    i("create counter working procs"),
595    Pids = create_counter_working_procs(CH, ?NUM_CNT_PROCS, []),
596
597    %% Start the counter worker procs
598    i("release the counter working procs"),
599    start_counter_working_procs(Pids),
600
601    %% Await the counter worker procs termination
602    i("await the counter working procs completion"),
603    ok = await_completion_counter_working_procs(Pids),
604
605    %% Verify result
606    i("verify counter result"),
607    TransId = megaco_config:conn_info(CH, trans_id),
608    1 = TransId,
609
610    %% Stop test
611    i("disconnect"),
612    {ok, _, _} = megaco_config:disconnect(CH),
613    i("stop user"),
614    ok = megaco_config:stop_user(UserMid),
615    i("stop megaco_config"),
616    ok = megaco_config:stop(),
617
618    i("done"),
619    ok.
620
621
622
623create_counter_working_procs(_CH, 0, Pids) ->
624    Pids;
625create_counter_working_procs(CH, N, Pids) ->
626    TC = get(tc),
627    Pid = erlang:spawn_link(fun() -> counter_init(CH, TC) end),
628    create_counter_working_procs(CH, N-1, [Pid | Pids]).
629
630counter_init(CH, TC) ->
631    put(verbosity, ?TEST_VERBOSITY),
632    put(sname,     lists:flatten(io_lib:format("CNT-~p", [self()]))),
633    put(tc,        TC),
634    UserMid = CH#megaco_conn_handle.local_mid,
635    Min = megaco_config:user_info(UserMid, min_trans_id),
636    Max = megaco_config:conn_info(CH, max_trans_id),
637    Num = Max - Min + 1,
638    receive
639	start ->
640	    %% i("received start command (~p)", [Num]),
641	    ok
642    end,
643    counter_loop(CH, Num).
644
645counter_loop(_CH, 0) ->
646    %% i("done"),
647    exit(normal);
648counter_loop(CH, Num) when (Num > 0) ->
649    megaco_config:incr_trans_id_counter(CH, 1),
650    counter_loop(CH, Num-1).
651
652start_counter_working_procs([]) ->
653    %% i("released"),
654    ok;
655start_counter_working_procs([Pid | Pids]) ->
656    Pid ! start,
657    start_counter_working_procs(Pids).
658
659await_completion_counter_working_procs(Pids) ->
660    await_completion_counter_working_procs(0, ts(), Pids, [], []).
661
662await_completion_counter_working_procs(MaxTSD, _TS, [], _OKs, [] = _ERRs) ->
663    i("done when ok with max TS-diff: ~p", [MaxTSD]),
664    ok;
665await_completion_counter_working_procs(MaxTSD, _TS, [], _OKs, ERRs) ->
666    i("done when error (~w) with max TS-diff: ~p", [length(ERRs), MaxTSD]),
667    {error, ERRs};
668await_completion_counter_working_procs(MaxTSD, TS, Pids, OKs, ERRs) ->
669    receive
670	{'EXIT', Pid, normal} ->
671            %% i("counter working process completion[~w, ~w, ~w] -> "
672            %%   "Expected exit from counter process: "
673            %%   "~n      Time since last event: ~s"
674            %%   "~n      Pid: ~p",
675            %%   [length(Pids), length(OKs), length(ERRs), tsd(TS), Pid]),
676            TSD = ts() - TS,
677            MaxTSD2 =
678                if (TSD > MaxTSD) ->
679                        i("counter working process completion[~w, ~w, ~w] -> "
680                          "Expected exit from counter process: "
681                          "~n      New max time since last event: ~s"
682                          "~n      Pid: ~p",
683                          [length(Pids),
684                           length(OKs),
685                           length(ERRs),
686                           tsd(TSD),
687                           Pid]),
688                        TSD;
689                   true ->
690                        MaxTSD
691                end,
692	    Pids2 = lists:delete(Pid, Pids),
693	    await_completion_counter_working_procs(MaxTSD2, ts(),
694                                                   Pids2, [Pid | OKs], ERRs);
695
696	{'EXIT', Pid, {timetrap_timeout, _Timeout, Stack} = _Reason} ->
697            TSD = ts() - TS,
698            MaxTSD2 =
699                if (TSD > MaxTSD) ->
700                        TSD;
701                   true ->
702                        MaxTSD
703                end,
704            e("counter working process completion[~w, ~w, ~w] -> "
705              "Test case timeout timetrap"
706              "~n      Time since last event: ~s (max ~s)"
707              "~n      Pid:                   ~p (~p)"
708              "~n      Stack:                 ~p",
709              [length(Pids), length(OKs), length(ERRs),
710               tsd(TSD), tsd(MaxTSD2),
711               Pid, lists:member(Pid, Pids),
712               Stack]),
713            %% The test case (timetrap) has timed out, which either means
714            %% we are running on very slow hw or some system functions
715            %% are slowing us down (this test case should never normally
716            %% time out).
717            case megaco_test_global_sys_monitor:events(?SECS(5)) of
718                {error, timeout} ->
719                    i("counter working process completion[~w, ~w, ~w] -> "
720                      "idle:sys-mon timeout",
721                      [length(Pids), length(OKs), length(ERRs)]),
722                    ?SKIP("TC idle; sys-monitor evs timeout");
723                [] ->
724                    i("counter working process completion[~w, ~w, ~w] -> idle",
725                      [length(Pids), length(OKs), length(ERRs)]),
726                    ?SKIP("TC idle");
727                SysEvs ->
728                    e("counter working process completion[~w, ~w, ~w] -> "
729                      "system event(s): "
730                      "~n      ~p",
731                      [length(Pids), length(OKs), length(ERRs), SysEvs]),
732                    ?SKIP("TC system events")
733            end;
734
735	{'EXIT', Pid, Reason} ->
736            TSD = ts() - TS,
737            MaxTSD2 =
738                if (TSD > MaxTSD) ->
739                        TSD;
740                   true ->
741                        MaxTSD
742                end,
743            e("counter working process completion[~w, ~w, ~w] -> "
744              "Unexpected exit from counter process: "
745              "~n      Time since last event: ~s (max ~s)"
746              "~n      Pid:                   ~p"
747              "~n      Reason:                ~p",
748              [length(Pids), length(OKs), length(ERRs),
749               tsd(TSD), tsd(MaxTSD2),
750               Pid, Reason]),
751	    Pids2 = lists:delete(Pid, Pids),
752	    await_completion_counter_working_procs(MaxTSD2, ts(),
753                                                   Pids2, OKs, [Pid | ERRs]);
754
755	Any ->
756            TSD = ts() - TS,
757            MaxTSD2 =
758                if (TSD > MaxTSD) ->
759                        TSD;
760                   true ->
761                        MaxTSD
762                end,
763            e("counter working process completion[~w, ~w, ~w] -> "
764              "Unexpected message: "
765              "~n      Time since last event: ~s (max ~s)"
766              "~n      ~p",
767              [length(Pids), length(OKs), length(ERRs),
768               tsd(TSD), tsd(MaxTSD2),
769               Any]),
770	    await_completion_counter_working_procs(MaxTSD2, TS,
771                                                   Pids, OKs, ERRs)
772
773    after 1000 ->
774            %% If nothing has happened for this long, something is wrong:
775            %% Check system events
776            TS2 = ts(),
777            TSD = TS2 - TS,
778            case megaco_test_global_sys_monitor:events() of
779                [] ->
780                    TS3 = ts(),
781                    i("counter working process completion[~w, ~w, ~w] -> idle"
782                      "~n      Time since last event:       ~s"
783                      "~n      (global) sys monitor events: ~s",
784                      [length(Pids), length(OKs), length(ERRs),
785                       tsd(TSD), tsd(TS3 - TS2)]),
786                    await_completion_counter_working_procs(MaxTSD, TS,
787                                                           Pids, OKs, ERRs);
788                SysEvs ->
789                    TS3 = ts(),
790                    e("counter working process completion[~w, ~w, ~w] -> "
791                      "system event(s): "
792                      "~n      Time since last event:       ~s"
793                      "~n      (global) sys monitor events: ~s"
794                      "~n      ~p",
795                      [length(Pids), length(OKs), length(ERRs),
796                       tsd(TSD), tsd(TS3 - TS2),
797                       SysEvs]),
798                    ?SKIP("TC idle with system events")
799            end
800    end.
801
802
803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
804
805transaction_id_counter_mgc(suite) ->
806    [];
807transaction_id_counter_mgc(doc) ->
808    ["This test case is intended to test and verify the "
809     "transaction counter handling of the application "
810     "in with several connections (MGC). "];
811transaction_id_counter_mgc(Config) when is_list(Config) ->
812    Name = transaction_id_counter_mgc,
813    Pre = fun() ->
814                  i("starting config server"),
815                  {ok, _ConfigPid} = megaco_config:start_link(),
816
817                  %% Basic user data
818                  UserMid = {deviceName, "mgc"},
819                  UserConfig = [
820                                {min_trans_id, 1}
821                               ],
822
823                  %% Basic connection data
824                  RemoteMids =
825                      [
826                       {deviceName, "mg01"},
827                       {deviceName, "mg02"},
828                       {deviceName, "mg03"},
829                       {deviceName, "mg04"},
830                       {deviceName, "mg05"},
831                       {deviceName, "mg06"},
832                       {deviceName, "mg07"},
833                       {deviceName, "mg08"},
834                       {deviceName, "mg09"},
835                       {deviceName, "mg10"}
836                      ],
837                  RecvHandles =
838                      [
839                       #megaco_receive_handle{local_mid     = UserMid,
840                                              encoding_mod    = ?MODULE,
841                                              encoding_config = [],
842                                              send_mod        = ?MODULE},
843                       #megaco_receive_handle{local_mid     = UserMid,
844                                              encoding_mod    = ?MODULE,
845                                              encoding_config = [],
846                                              send_mod        = ?MODULE},
847                       #megaco_receive_handle{local_mid     = UserMid,
848                                              encoding_mod    = ?MODULE,
849                                              encoding_config = [],
850                                              send_mod        = ?MODULE},
851                       #megaco_receive_handle{local_mid     = UserMid,
852                                              encoding_mod    = ?MODULE,
853                                              encoding_config = [],
854                                              send_mod        = ?MODULE},
855                       #megaco_receive_handle{local_mid     = UserMid,
856                                              encoding_mod    = ?MODULE,
857                                              encoding_config = [],
858                                              send_mod        = ?MODULE},
859                       #megaco_receive_handle{local_mid     = UserMid,
860                                              encoding_mod    = ?MODULE,
861                                              encoding_config = [],
862                                              send_mod        = ?MODULE},
863                       #megaco_receive_handle{local_mid     = UserMid,
864                                              encoding_mod    = ?MODULE,
865                                              encoding_config = [],
866                                              send_mod        = ?MODULE},
867                       #megaco_receive_handle{local_mid     = UserMid,
868                                              encoding_mod    = ?MODULE,
869                                              encoding_config = [],
870                                              send_mod        = ?MODULE},
871                       #megaco_receive_handle{local_mid     = UserMid,
872                                              encoding_mod    = ?MODULE,
873                                              encoding_config = [],
874                                              send_mod        = ?MODULE},
875                       #megaco_receive_handle{local_mid     = UserMid,
876                                              encoding_mod    = ?MODULE,
877                                              encoding_config = [],
878                                              send_mod        = ?MODULE}
879                      ],
880                  SendHandle = dummy_send_handle,
881                  ControlPid = self(),
882
883                  %% Start user
884                  i("start user"),
885                  ok = megaco_config:start_user(UserMid, UserConfig),
886
887                  %% Create connection
888                  i("create connection(s)"),
889                  CDs = create_connections(RecvHandles,
890                                           RemoteMids,
891                                           SendHandle,
892                                           ControlPid),
893
894                  %% Set counter limits
895                  i("set counter max limit(s)"),
896                  set_counter_max_limits(CDs, 1000),
897
898                  {UserMid, CDs}
899          end,
900    Case = fun({_, CDs}) ->
901                   %% Create the counter worker procs
902                   i("create counter working procs"),
903                   Pids = create_counter_working_procs(CDs, ?NUM_CNT_PROCS),
904
905                   %% Start the counter worker procs
906                   i("release the counter working procs"),
907                   start_counter_working_procs(Pids),
908
909                   %% Await the counter worker procs termination
910                   i("await the counter working procs completion"),
911                   ok = await_completion_counter_working_procs(Pids),
912
913                   %% Verify result
914                   i("verify counter result"),
915                   verify_counter_results(CDs)
916           end,
917
918    Post = fun({UserMid, CDs}) ->
919                   %% Stop test
920                   i("disconnect"),
921                   delete_connections(CDs),
922                   i("stop user"),
923                   ok = megaco_config:stop_user(UserMid),
924                   i("stop megaco_config"),
925                   ok = megaco_config:stop()
926           end,
927    try_tc(Name, Pre, Case, Post).
928
929
930create_connections(RecvHandles, RemoteMids, SendHandle, ControlPid) ->
931    create_connections(RecvHandles, RemoteMids, SendHandle, ControlPid, []).
932
933create_connections([], [], _SendHandle, _ControlPid, Acc) ->
934    lists:reverse(Acc);
935create_connections([RecvHandle | RecvHandles],
936		   [RemoteMid  | RemoteMids],
937		   SendHandle, ControlPid, Acc) ->
938    {ok, CD} =
939	megaco_config:connect(RecvHandle, RemoteMid, SendHandle, ControlPid),
940    create_connections(RecvHandles, RemoteMids,
941		       SendHandle, ControlPid, [CD | Acc]).
942
943
944set_counter_max_limits([], _MaxTransId) ->
945    ok;
946set_counter_max_limits([#conn_data{conn_handle = CH} | CDs], MaxTransId) ->
947    megaco_config:update_conn_info(CH, max_trans_id, MaxTransId),
948    set_counter_max_limits(CDs, MaxTransId).
949
950
951create_counter_working_procs(CDs, NumCntProcs) ->
952    lists:flatten(create_counter_working_procs2(CDs, NumCntProcs)).
953
954create_counter_working_procs2([], _NumCntProcs) ->
955    [];
956create_counter_working_procs2([#conn_data{conn_handle = CH} | CDs],
957			      NumCntProcs) ->
958    [create_counter_working_procs(CH, NumCntProcs, []) |
959     create_counter_working_procs2(CDs, NumCntProcs)].
960
961
962verify_counter_results(CDs) ->
963    verify_counter_results(CDs, [], []).
964
965verify_counter_results([], _OKs, [] = _Errors) ->
966    i("counter verification success"),
967    ok;
968verify_counter_results([], OKs, Errors) ->
969    e("counter verification failed: "
970      "~n      Num OKs:    ~p"
971      "~n      Num Errors: ~p", [length(OKs), length(Errors)]),
972    error;
973verify_counter_results([#conn_data{conn_handle = CH} = CD| CDs], OKs, Errors) ->
974    TransId = megaco_config:conn_info(CH, trans_id),
975    if
976	(TransId =:= 1) ->
977	    verify_counter_results(CDs, [CD|OKs], Errors);
978	true ->
979            e("invalid transaction is for connection: "
980              "~n      CD:      ~p"
981              "~n      TransId: ~p", [CD, TransId]),
982            verify_counter_results(CDs, OKs, [{CD, TransId}|Errors])
983    end.
984
985
986delete_connections([]) ->
987    ok;
988delete_connections([#conn_data{conn_handle = CH} | CDs]) ->
989    {ok, _, _} = megaco_config:disconnect(CH),
990    delete_connections(CDs).
991
992
993
994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
995
996otp_7216(suite) ->
997    [];
998otp_7216(Config) when is_list(Config) ->
999    put(tc, otp_7216),
1000    p("start"),
1001
1002    LocalMid1 = {deviceName, "local-mid-1"},
1003    %% LocalMid2 = {deviceName, "local-mid-2"},
1004    RemoteMid1 = {deviceName, "remote-mid-1"},
1005    %% RemoteMid2 = {deviceName, "remote-mid-2"},
1006    RH = #megaco_receive_handle{local_mid       = LocalMid1,
1007				encoding_mod    = dummy_codec_module,
1008				encoding_config = [],
1009				send_mod        = dummy_transport_module},
1010    MinTransId = 7216,
1011    MaxTransId = MinTransId + 10,
1012    User1Config = [{min_trans_id, MinTransId},
1013		   {max_trans_id, MaxTransId}],
1014
1015    VerifySerial =
1016	fun(Actual, Expected) ->
1017		if
1018		    Actual == Expected ->
1019			ok;
1020		    true ->
1021			throw({error, {invalid_counter_value, Actual}})
1022		end
1023	end,
1024
1025    p("start local user: ~p", [LocalMid1]),
1026    ok = megaco_config:start_user(LocalMid1, User1Config),
1027
1028    p("connect"),
1029    {ok, CD} = megaco_config:connect(RH, RemoteMid1,
1030				     dummy_send_handle, self()),
1031    p("connect ok: CD = ~n~p", [CD]),
1032    CH = CD#conn_data.conn_handle,
1033
1034
1035    p("*** make the first counter increment ***"),
1036    {ok, CD01} = megaco_config:incr_trans_id_counter(CH, 1),
1037    Serial01   = CD01#conn_data.serial,
1038    p("serial: ~p", [Serial01]),
1039    VerifySerial(Serial01, MinTransId),
1040    p("counter increment 1 ok"),
1041
1042
1043    p("*** make two more counter increments ***"),
1044    {ok, _} = megaco_config:incr_trans_id_counter(CH, 1),
1045    {ok, CD02} = megaco_config:incr_trans_id_counter(CH, 1),
1046    Serial02   = CD02#conn_data.serial,
1047    p("serial: ~p", [Serial02]),
1048    VerifySerial(Serial02, MinTransId+2),
1049    p("counter increment 2 ok"),
1050
1051
1052    p("*** make a big counter increment ***"),
1053    {ok, CD03} = megaco_config:incr_trans_id_counter(CH, 8),
1054    Serial03   = CD03#conn_data.serial,
1055    p("serial: ~p", [Serial03]),
1056    VerifySerial(Serial03, MinTransId+2+8),
1057    p("counter increment 3 ok"),
1058
1059
1060    p("*** make a wrap-around counter increment ***"),
1061    {ok, CD04} = megaco_config:incr_trans_id_counter(CH, 1),
1062    Serial04   = CD04#conn_data.serial,
1063    p("serial: ~p", [Serial04]),
1064    VerifySerial(Serial04, MinTransId),
1065    p("counter increment 4 ok"),
1066
1067
1068    p("*** make a big counter increment ***"),
1069    {ok, CD05} = megaco_config:incr_trans_id_counter(CH, 10),
1070    Serial05   = CD05#conn_data.serial,
1071    p("serial: ~p", [Serial05]),
1072    VerifySerial(Serial05, MinTransId+10),
1073    p("counter increment 5 ok"),
1074
1075
1076    p("*** make a big wrap-around counter increment ***"),
1077    {ok, CD06} = megaco_config:incr_trans_id_counter(CH, 3),
1078    Serial06   = CD06#conn_data.serial,
1079    p("serial: ~p", [Serial06]),
1080    VerifySerial(Serial06, MinTransId+(3-1)),
1081    p("counter increment 6 ok"),
1082
1083
1084    p("*** make a big counter increment ***"),
1085    {ok, CD07} = megaco_config:incr_trans_id_counter(CH, 7),
1086    Serial07   = CD07#conn_data.serial,
1087    p("serial: ~p", [Serial07]),
1088    VerifySerial(Serial07, MinTransId+(3-1)+7),
1089    p("counter increment 7 ok"),
1090
1091
1092    p("*** make a big wrap-around counter increment ***"),
1093    {ok, CD08} = megaco_config:incr_trans_id_counter(CH, 5),
1094    Serial08   = CD08#conn_data.serial,
1095    p("serial: ~p", [Serial08]),
1096    VerifySerial(Serial08, MinTransId+(5-1-1)),
1097    p("counter increment 8 ok"),
1098
1099
1100    p("disconnect"),
1101    {ok, CD, RCD} = megaco_config:disconnect(CH),
1102    p("disconnect ok: RCD = ~n~p", [RCD]),
1103
1104    p("stop user"),
1105    ok = megaco_config:stop_user(LocalMid1),
1106
1107    p("stop megaco config process"),
1108    megaco_config:stop(),
1109
1110    p("done"),
1111    ok.
1112
1113
1114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115
1116otp_8167(suite) ->
1117    [];
1118otp_8167(Config) when is_list(Config) ->
1119    put(tc, otp8167),
1120    p("start"),
1121
1122    LocalMid1  = {deviceName, "local-mid-1"},
1123    LocalMid2  = {deviceName, "local-mid-2"},
1124    RemoteMid1 = {deviceName, "remote-mid-1"},
1125    %% RemoteMid2 = {deviceName, "remote-mid-2"},
1126    RH1 = #megaco_receive_handle{local_mid       = LocalMid1,
1127				 encoding_mod    = dummy_codec_module,
1128				 encoding_config = [],
1129				 send_mod        = dummy_transport_module},
1130%%     RH2 = #megaco_receive_handle{local_mid       = LocalMid2,
1131%% 				 encoding_mod    = dummy_codec_module,
1132%% 				 encoding_config = [],
1133%% 				 send_mod        = dummy_transport_module},
1134
1135    User1ConfigA = [{call_proxy_gc_timeout, 1}],
1136    User1ConfigB = [{call_proxy_gc_timeout, 0}],
1137    User2ConfigA = [{call_proxy_gc_timeout, -1}],
1138    User2ConfigB = [{call_proxy_gc_timeout, infinity}],
1139    User2ConfigC = [{call_proxy_gc_timeout, "1"}],
1140    User2ConfigD = [{call_proxy_gc_timeout, 1.0}],
1141
1142    p("start local user (1A): ~p", [LocalMid1]),
1143    ok = megaco_config:start_user(LocalMid1, User1ConfigA),
1144    p("stop local user (1A): ~p", [LocalMid1]),
1145    ok = megaco_config:stop_user(LocalMid1),
1146
1147    p("start local user (1B): ~p", [LocalMid1]),
1148    ok = megaco_config:start_user(LocalMid1, User1ConfigB),
1149    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
1150      [LocalMid1, -1]),
1151    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, -1}} =
1152	megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, -1),
1153    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
1154      [LocalMid1, infinity]),
1155    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, infinity}} =
1156	megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, infinity),
1157    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
1158      [LocalMid1, "1"]),
1159    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, "1"}} =
1160	megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, "1"),
1161    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
1162      [LocalMid1, 1.0]),
1163    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, 1.0}} =
1164	megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, 1.0),
1165    p("change value for item call_proxy_gc_timeout for local user: ~p", [LocalMid1]),
1166    ok = megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, 10101),
1167
1168    p("connect"),
1169    {ok, CD} = megaco_config:connect(RH1, RemoteMid1,
1170				     dummy_send_handle, self()),
1171    p("connect ok: CD = ~n~p", [CD]),
1172    CH = CD#conn_data.conn_handle,
1173
1174    p("get value for item cancel from connection: ~p", [CH]),
1175    false = megaco_config:conn_info(CH, cancel),
1176
1177    p("get value for item cancel from connection data", []),
1178    false = megaco_config:conn_info(CD, cancel),
1179
1180    p("get value for item call_proxy_gc_timeout for connection: ~p", [CH]),
1181    10101 = megaco_config:conn_info(CH, call_proxy_gc_timeout),
1182
1183    p("change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
1184      [CH, 20202]),
1185    ok = megaco_config:update_conn_info(CH, call_proxy_gc_timeout, 20202),
1186
1187    p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
1188      [CH, -1]),
1189    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, -1}} =
1190	megaco_config:update_conn_info(CH, call_proxy_gc_timeout, -1),
1191
1192    p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
1193      [CH, infinity]),
1194    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, infinity}} =
1195	megaco_config:update_conn_info(CH, call_proxy_gc_timeout, infinity),
1196
1197    p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
1198      [CH, "1"]),
1199    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, "1"}} =
1200	megaco_config:update_conn_info(CH, call_proxy_gc_timeout, "1"),
1201
1202    p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
1203      [CH, 1.0]),
1204    {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, 1.0}} =
1205	megaco_config:update_conn_info(CH, call_proxy_gc_timeout, 1.0),
1206
1207    p("disconnect: ~p", [CH]),
1208    {ok, _, _} = megaco_config:disconnect(CH),
1209
1210    p("stop local user (1B): ~p", [LocalMid1]),
1211    ok = megaco_config:stop_user(LocalMid1),
1212
1213    p("try (and fail) start local user (2A): ~p", [LocalMid2]),
1214    {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, -1}} =
1215	megaco_config:start_user(LocalMid2, User2ConfigA),
1216
1217    p("try (and fail) start local user (2B): ~p", [LocalMid2]),
1218    {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, infinity}} =
1219	megaco_config:start_user(LocalMid2, User2ConfigB),
1220
1221    p("try (and fail) start local user (2C): ~p", [LocalMid2]),
1222    {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, "1"}} =
1223	megaco_config:start_user(LocalMid2, User2ConfigC),
1224
1225    p("try (and fail) start local user (2D): ~p", [LocalMid2]),
1226    {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, 1.0}} =
1227	megaco_config:start_user(LocalMid2, User2ConfigD),
1228
1229    p("done"),
1230    ok.
1231
1232
1233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1234
1235otp_8183(suite) ->
1236    [];
1237otp_8183(Config) when is_list(Config) ->
1238    put(tc, otp8183),
1239    p("start"),
1240
1241    LocalMid1  = {deviceName, "local-mid-1"},
1242    LocalMid2  = {deviceName, "local-mid-2"},
1243    RemoteMid1 = {deviceName, "remote-mid-1"},
1244%%     RemoteMid2 = {deviceName, "remote-mid-2"},
1245    RH1 = #megaco_receive_handle{local_mid       = LocalMid1,
1246				 encoding_mod    = dummy_codec_module,
1247				 encoding_config = [],
1248				 send_mod        = dummy_transport_module},
1249%%     RH2 = #megaco_receive_handle{local_mid       = LocalMid2,
1250%% 				 encoding_mod    = dummy_codec_module,
1251%% 				 encoding_config = [],
1252%% 				 send_mod        = dummy_transport_module},
1253
1254    OkValA = 100,
1255    OkValB = 0,
1256    OkValC = plain,
1257    OkValD = 10101,
1258    OkValE = 20202,
1259    BadValA = -1,
1260    BadValB = pain,
1261    BadValC = "1",
1262    BadValD = 1.0,
1263    User1ConfigA = [{request_keep_alive_timeout, OkValA}],
1264    User1ConfigB = [{request_keep_alive_timeout, OkValB}],
1265    User1ConfigC = [{request_keep_alive_timeout, OkValC}],
1266    User2ConfigA = [{request_keep_alive_timeout, BadValA}],
1267    User2ConfigB = [{request_keep_alive_timeout, BadValB}],
1268    User2ConfigC = [{request_keep_alive_timeout, BadValC}],
1269    User2ConfigD = [{request_keep_alive_timeout, BadValD}],
1270
1271    p("start local user (1A): ~p", [LocalMid1]),
1272    ok = megaco_config:start_user(LocalMid1, User1ConfigA),
1273    p("stop local user (1A): ~p", [LocalMid1]),
1274    ok = megaco_config:stop_user(LocalMid1),
1275
1276    p("start local user (1B): ~p", [LocalMid1]),
1277    ok = megaco_config:start_user(LocalMid1, User1ConfigB),
1278    p("stop local user (1B): ~p", [LocalMid1]),
1279    ok = megaco_config:stop_user(LocalMid1),
1280
1281    p("start local user (1C): ~p", [LocalMid1]),
1282    ok = megaco_config:start_user(LocalMid1, User1ConfigC),
1283
1284    p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
1285      [LocalMid1, BadValA]),
1286    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValA}} =
1287	megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValA),
1288
1289    p("try (and fail) change value for item request_keep_alive_timeout for local user: ~p -> ~p",
1290      [LocalMid1, BadValB]),
1291    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValB}} =
1292	megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValB),
1293
1294    p("try (and fail) change value for item request_keep_alive_timeout for local user: ~p -> ~p",
1295      [LocalMid1, BadValC]),
1296    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValC}} =
1297	megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValC),
1298
1299    p("try (and fail) change value for item request_keep_alive_timeout for local user: ~p -> ~p",
1300      [LocalMid1, BadValD]),
1301    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValD}} =
1302	megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValD),
1303
1304    p("change value for item request_keep_alive_timeout for local user: ~p", [LocalMid1]),
1305    ok = megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, OkValD),
1306
1307    p("connect"),
1308    {ok, CD} = megaco_config:connect(RH1, RemoteMid1,
1309				     dummy_send_handle, self()),
1310    p("connect ok: CD = ~n~p", [CD]),
1311    CH = CD#conn_data.conn_handle,
1312
1313    p("get value for item request_keep_alive_timeout for connection: ~p", [CH]),
1314    OkValD = megaco_config:conn_info(CH, request_keep_alive_timeout),
1315
1316    p("change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1317      [CH, OkValE]),
1318    ok = megaco_config:update_conn_info(CH, request_keep_alive_timeout, OkValE),
1319
1320    p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1321      [CH, BadValA]),
1322    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValA}} =
1323	megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValA),
1324
1325    p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1326      [CH, BadValB]),
1327    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValB}} =
1328	megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValB),
1329
1330    p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1331      [CH, BadValC]),
1332    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValC}} =
1333	megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValC),
1334
1335    p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
1336      [CH, BadValD]),
1337    {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValD}} =
1338	megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValD),
1339
1340    p("disconnect: ~p", [CH]),
1341    {ok, _, _} = megaco_config:disconnect(CH),
1342
1343    p("stop local user (1B): ~p", [LocalMid1]),
1344    ok = megaco_config:stop_user(LocalMid1),
1345
1346    p("try (and fail) start local user (2A): ~p", [LocalMid2]),
1347    {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValA}} =
1348	megaco_config:start_user(LocalMid2, User2ConfigA),
1349
1350    p("try (and fail) start local user (2B): ~p", [LocalMid2]),
1351    {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValB}} =
1352	megaco_config:start_user(LocalMid2, User2ConfigB),
1353
1354    p("try (and fail) start local user (2C): ~p", [LocalMid2]),
1355    {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValC}} =
1356	megaco_config:start_user(LocalMid2, User2ConfigC),
1357
1358    p("try (and fail) start local user (2D): ~p", [LocalMid2]),
1359    {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValD}} =
1360	megaco_config:start_user(LocalMid2, User2ConfigD),
1361
1362    p("done"),
1363    ok.
1364
1365
1366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1367
1368try_tc(TCName, Pre, Case, Post) ->
1369    try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
1370
1371try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
1372    ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
1373
1374
1375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1376
1377ts() ->
1378    erlang:monotonic_time(milli_seconds).
1379
1380tsd(TSD) ->
1381    if (TSD < 1000) ->
1382            ?F("~w ms", [TSD]);
1383       (TSD < 60000) ->
1384            ?F("~w secs", [TSD div 1000]);
1385       true ->
1386            ?F("~w mins", [TSD div 60000])
1387    end.
1388
1389
1390
1391
1392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1393
1394p(F) ->
1395    p(F, []).
1396
1397p(F, A) ->
1398    case get(tc) of
1399        undefined ->
1400            io:format(F ++ "~n", A);
1401        TC ->
1402            io:format("[~w] " ++ F ++ "~n", [TC|A])
1403    end.
1404
1405
1406i(F) ->
1407    i(F, []).
1408
1409i(F, A) ->
1410    print(info, get(verbosity), get(tc), "INFO", F, A).
1411
1412e(F, A) ->
1413    print(info, get(verbosity), get(tc), "ERROR", F, A).
1414
1415printable(_, debug)   -> true;
1416printable(info, info) -> true;
1417printable(_,_)        -> false.
1418
1419print(Severity, Verbosity, Tc, P, F, A) ->
1420    print(printable(Severity,Verbosity), Tc, P, F, A).
1421
1422print(true, Tc, P, F, A) ->
1423    io:format("*** [~s] ~s ~p ~s:~w ***"
1424              "~n   " ++ F ++ "~n",
1425              [?FTS(), P, self(), get(sname), Tc | A]);
1426print(_, _, _, _, _) ->
1427    ok.
1428