1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2003-2019. 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: Verify the application specifics of the Megaco application
24%%          Testing the xxxOriginatingPendingLimit property of the
25%%          root package
26%%----------------------------------------------------------------------
27-module(megaco_pending_limit_SUITE).
28
29-export([
30 	 suite/0, all/0, groups/0,
31         init_per_suite/1, end_per_suite/1,
32         init_per_group/2, end_per_group/2,
33         init_per_testcase/2, end_per_testcase/2,
34
35	 sent_timer_late_reply/1,
36	 sent_timer_exceeded/1,
37	 sent_timer_exceeded_long/1,
38	 sent_resend_late_reply/1,
39	 sent_resend_exceeded/1,
40	 sent_resend_exceeded_long/1,
41	 recv_limit_exceeded1/1,
42	 recv_limit_exceeded2/1,
43	 otp_4956/1,
44	 otp_5310/1,
45	 otp_5619/1
46
47	]).
48
49-ifdef(megaco_hipe_special).
50-export([
51	 %% Case: recv_limit_exceeded1
52	 rle1_mgc_verify_service_change_req_msg/2,
53	 rle1_mgc_verify_notify_req_msg/1,
54	 rle1_mg_verify_handle_connect/1,
55	 rle1_mg_verify_service_change_rep/1,
56	 rle1_mg_verify_trans_rep/1,
57
58	 %% Case: otp_4956
59	 otp_4956_mgc_verify_handle_connect/1,
60	 otp_4956_mgc_verify_service_change_req/2,
61	 otp_4956_mgc_verify_notify_req1/1,
62	 otp_4956_mgc_verify_notify_req2/1,
63	 otp_4956_mgc_verify_handle_trans_req_abort/1,
64	 otp_4956_mgc_verify_handle_disconnect/1,
65	 otp_4956_mg_verify_service_change_rep_msg/1,
66	 otp_4956_mg_verify_pending_msg/1,
67	 otp_4956_mg_verify_pending_limit_msg/1,
68
69	 %% Utility
70	 encode_msg/3,
71	 decode_msg/3
72	]).
73-endif.
74
75-include_lib("megaco/include/megaco.hrl").
76-include_lib("megaco/include/megaco_message_v1.hrl").
77-include("megaco_test_lib.hrl").
78
79-define(TEST_VERBOSITY, debug).
80-define(MGC_VERBOSITY,  debug).
81-define(MG_VERBOSITY,   debug).
82
83-define(VERSION, 1).
84
85-define(A4444, ["11111111", "00000000", "00000000"]).
86-define(A4445, ["11111111", "00000000", "11111111"]).
87-define(A5555, ["11111111", "11111111", "00000000"]).
88-define(A5556, ["11111111", "11111111", "11111111"]).
89
90-define(MGC_START(Pid, Mid, ET, Conf, Verb),
91	megaco_test_mgc:start(Pid, Mid, ET, Conf, Verb)).
92-define(MGC_STOP(Pid), megaco_test_mgc:stop(Pid)).
93-define(MGC_GET_STATS(Pid, No), megaco_test_mgc:get_stats(Pid, No)).
94-define(MGC_RESET_STATS(Pid),   megaco_test_mgc:reset_stats(Pid)).
95-define(MGC_REQ_IGNORE(Pid),    megaco_test_mgc:request_ignore(Pid)).
96-define(MGC_REQ_PIGNORE(Pid),   megaco_test_mgc:request_pending_ignore(Pid)).
97-define(MGC_REQ_DISC(Pid,To),   megaco_test_mgc:request_discard(Pid,To)).
98-define(MGC_REQ_PEND(Pid,To),   megaco_test_mgc:request_pending(Pid,To)).
99-define(MGC_REQ_HAND(Pid, To),  megaco_test_mgc:request_handle(Pid, To)).
100-define(MGC_REQ_HANDS(Pid),     megaco_test_mgc:request_handle_sloppy(Pid)).
101-define(MGC_UPDATE_UI(Pid,Tag,Val),
102	megaco_test_mgc:update_user_info(Pid,Tag,Val)).
103-define(MGC_UPDATE_CI(Pid,Tag,Val),
104	megaco_test_mgc:update_conn_info(Pid,Tag,Val)).
105-define(MGC_USER_INFO(Pid,Tag), megaco_test_mgc:user_info(Pid,Tag)).
106-define(MGC_CONN_INFO(Pid,Tag), megaco_test_mgc:conn_info(Pid,Tag)).
107-define(MGC_ACK_INFO(Pid,To),   megaco_test_mgc:ack_info(Pid,To)).
108-define(MGC_ABORT_INFO(Pid,To), megaco_test_mgc:abort_info(Pid,To)).
109-define(MGC_DISCO(Pid,Reason),  megaco_test_mgc:disconnect(Pid,Reason)).
110
111-define(MG_START(Pid, Mid, Enc, Transp, Conf, Verb),
112	megaco_test_mg:start(Pid, Mid, Enc, Transp, Conf, Verb)).
113-define(MG_STOP(Pid), megaco_test_mg:stop(Pid)).
114-define(MG_GET_STATS(Pid, No), megaco_test_mg:get_stats(Pid, No)).
115-define(MG_RESET_STATS(Pid), megaco_test_mg:reset_stats(Pid)).
116-define(MG_SERV_CHANGE(Pid), megaco_test_mg:service_change(Pid)).
117-define(MG_NOTIF_RAR(Pid), megaco_test_mg:notify_request_and_reply(Pid)).
118-define(MG_NOTIF_REQ(Pid), megaco_test_mg:notify_request(Pid)).
119-define(MG_NOTIF_AR(Pid),  megaco_test_mg:await_notify_reply(Pid)).
120-define(MG_CANCEL(Pid,R),  megaco_test_mg:cancel_request(Pid,R)).
121-define(MG_APPLY_LOAD(Pid,CntStart), megaco_test_mg:apply_load(Pid,CntStart)).
122-define(MG_UPDATE_UI(Pid,Tag,Val),
123	megaco_test_mg:update_user_info(Pid,Tag,Val)).
124-define(MG_UPDATE_CI(Pid,Tag,Val),
125	megaco_test_mg:update_conn_info(Pid,Tag,Val)).
126-define(MG_USER_INFO(Pid,Tag), megaco_test_mg:user_info(Pid,Tag)).
127-define(MG_CONN_INFO(Pid,Tag), megaco_test_mg:conn_info(Pid,Tag)).
128-define(MG_GRP_REQ(Pid,N),     megaco_test_mg:group_requests(Pid,N)).
129-define(MG_ECC(Pid, M, T, F),  megaco_test_mg:enable_test_code(Pid,M,T,F)).
130
131
132%%======================================================================
133%% Common Test interface functions
134%%======================================================================
135
136suite() ->
137    [{ct_hooks, [ts_install_cth]}].
138
139all() ->
140    [
141     {group, sent},
142     {group, recv},
143     {group, tickets}
144    ].
145
146groups() ->
147    [
148     {sent,    [], sent_cases()},
149     {recv,    [], recv_cases()},
150     {tickets, [], tickets_cases()}
151    ].
152
153sent_cases() ->
154    [
155     sent_timer_late_reply,
156     sent_timer_exceeded,
157     sent_timer_exceeded_long,
158     sent_resend_late_reply,
159     sent_resend_exceeded,
160     sent_resend_exceeded_long
161    ].
162
163recv_cases() ->
164    [
165     recv_limit_exceeded1,
166     recv_limit_exceeded2
167    ].
168
169tickets_cases() ->
170    [
171     otp_4956,
172     otp_5310,
173     otp_5619
174    ].
175
176
177
178%%
179%% -----
180%%
181
182init_per_suite(suite) ->
183    [];
184init_per_suite(doc) ->
185    [];
186init_per_suite(Config0) when is_list(Config0) ->
187
188    ?ANNOUNCE_SUITE_INIT(),
189
190    p("init_per_suite -> entry with"
191      "~n      Config: ~p"
192      "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
193
194    case ?LIB:init_per_suite(Config0) of
195        {skip, _} = SKIP ->
196            SKIP;
197
198        Config1 when is_list(Config1) ->
199
200            %% We need a (local) monitor on this node also
201            megaco_test_sys_monitor:start(),
202
203            p("init_per_suite -> end when"
204              "~n      Config: ~p"
205              "~n      Nodes:  ~p", [Config1, erlang:nodes()]),
206
207            Config1
208    end.
209
210end_per_suite(suite) -> [];
211end_per_suite(doc) -> [];
212end_per_suite(Config0) when is_list(Config0) ->
213
214    p("end_per_suite -> entry with"
215      "~n      Config: ~p"
216      "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
217
218    megaco_test_sys_monitor:stop(),
219    Config1 = ?LIB:end_per_suite(Config0),
220
221    p("end_per_suite -> end when"
222      "~n      Nodes:  ~p", [erlang:nodes()]),
223
224    Config1.
225
226
227%%
228%% -----
229%%
230
231init_per_group(Group, Config) ->
232    ?ANNOUNCE_GROUP_INIT(Group),
233    Config.
234
235end_per_group(_Group, Config) ->
236    Config.
237
238
239
240%%
241%% -----
242%%
243
244init_per_testcase(Case, Config) ->
245    process_flag(trap_exit, true),
246
247    ?ANNOUNCE_CASE_INIT(Case),
248
249    p("init_per_testcase -> entry with"
250      "~n      Config: ~p"
251      "~n      Nodes:  ~p", [Config, erlang:nodes()]),
252
253    megaco_test_global_sys_monitor:reset_events(),
254    megaco_test_lib:init_per_testcase(Case, Config).
255
256end_per_testcase(Case, Config) ->
257    process_flag(trap_exit, false),
258
259    p("end_per_suite -> entry with"
260      "~n      Config: ~p"
261      "~n      Nodes:  ~p", [Config, erlang:nodes()]),
262
263    p("system events during test: "
264      "~n   ~p", [megaco_test_global_sys_monitor:events()]),
265
266    megaco_test_lib:end_per_testcase(Case, Config).
267
268
269
270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271%%%                                                                   %%%
272%%%                    Sent pending test cases                        %%%
273%%%                                                                   %%%
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275
276sent_timer_late_reply(suite) ->
277    [];
278sent_timer_late_reply(doc) ->
279    "...";
280sent_timer_late_reply(Config) when is_list(Config) ->
281    put(verbosity, ?TEST_VERBOSITY),
282    put(sname,     "TEST"),
283    put(tc,        sent_timer_late_reply),
284    i("starting"),
285
286    MgcNode = make_node_name(mgc),
287    MgNode  = make_node_name(mg),
288    d("start nodes: "
289      "~n      MgcNode: ~p"
290      "~n      MgNode:  ~p",
291      [MgcNode, MgNode]),
292    ok = ?START_NODES([MgcNode, MgNode], true),
293
294    %% Start the MGC and MGs
295    i("[MGC] start"),
296    ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
297    MgcConf = [{megaco_trace, false}],
298    {ok, Mgc} =
299	?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, MgcConf, ?MGC_VERBOSITY),
300
301    i("[MG] start"),
302    MgMid = {deviceName, "mg"},
303    MgConf = [{megaco_trace, io}],
304    {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConf, ?MG_VERBOSITY),
305
306    d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
307
308    i("[MG] connect to the MGC (service change)"),
309    ServChRes = ?MG_SERV_CHANGE(Mg),
310    d("service change result: ~p", [ServChRes]),
311
312    d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
313
314    d("[MGC] update connection info pending timer"),
315    PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
316				      factor   = 1},
317    ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
318
319    d("[MGC] update connection info sent pending limit"),
320    PendingLimit = 5,
321    ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
322
323    d("[MGC] late reply to requests "
324      "(simulate that the request takes a long time)"),
325    {ok, _} = ?MGC_REQ_DISC(Mgc, 11000),
326
327    d("[MG] send the notify"),
328    {ok, Reply} = ?MG_NOTIF_RAR(Mg),
329    d("[MG] Reply: ~p", [Reply]),
330    case Reply of
331	{_Version, {ok, [_ActionReply]}} ->
332	    ok;
333	_ ->
334	    ?ERROR({unexpected_reply, Reply})
335    end,
336
337    %% Tell MG to stop
338    i("[MG] stop"),
339    ?MG_STOP(Mg),
340
341    %% Tell Mgc to stop
342    i("[MGC] stop"),
343    ?MGC_STOP(Mgc),
344
345    %% Cleanup
346    d("stop nodes"),
347    ?STOP_NODES([MgcNode, MgNode]),
348
349    i("done", []),
350    ok.
351
352
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354
355sent_timer_exceeded(suite) ->
356    [];
357sent_timer_exceeded(doc) ->
358    "...";
359sent_timer_exceeded(Config) when is_list(Config) ->
360    put(verbosity, ?TEST_VERBOSITY),
361    put(sname,     "TEST"),
362    put(tc,        sent_timer_exceeded),
363    i("starting"),
364
365    MgcNode = make_node_name(mgc),
366    MgNode  = make_node_name(mg),
367    d("start nodes: "
368      "~n      MgcNode: ~p"
369      "~n      MgNode:  ~p",
370      [MgcNode, MgNode]),
371    ok = ?START_NODES([MgcNode, MgNode], true),
372
373    %% Start the MGC and MGs
374    i("[MGC] start"),
375    ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
376    {ok, Mgc} =
377	?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
378
379    i("[MG] start"),
380    MgMid = {deviceName, "mg"},
381    MgConfig = [],
382    {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
383
384    d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
385
386    i("[MG] connect to the MGC (service change)"),
387    ServChRes = ?MG_SERV_CHANGE(Mg),
388    d("service change result: ~p", [ServChRes]),
389
390    d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
391
392    d("[MGC] update connection info pending timer"),
393    PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
394				      factor   = 1},
395    ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
396
397    d("[MGC] update connection info sent pending limit"),
398    PendingLimit = 5,
399    ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
400
401    d("[MGC] no reply to requests "
402      "(simulate that the request takes a __long__ time)"),
403    ?MGC_REQ_IGNORE(Mgc),
404
405    d("sleep 5 seconds to align trace output"),
406    sleep(5000),
407
408    d("[MG] send the notify"),
409    {ok, {_ProtocolVersion, {error, ED}}} = ?MG_NOTIF_RAR(Mg),
410    d("[MG] ED: ~p", [ED]),
411    ErrorCode = ?megaco_number_of_transactionpending_exceeded,
412    ErrorCode = ED#'ErrorDescriptor'.errorCode,
413
414    %% Tell MG to stop
415    i("[MG] stop"),
416    ?MG_STOP(Mg),
417
418    %% Tell Mgc to stop
419    i("[MGC] stop"),
420    ?MGC_STOP(Mgc),
421
422    %% Cleanup
423    d("stop nodes"),
424    ?STOP_NODES([MgcNode, MgNode]),
425
426    i("done", []),
427    ok.
428
429
430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431
432sent_timer_exceeded_long(suite) ->
433    [];
434sent_timer_exceeded_long(doc) ->
435    "...";
436sent_timer_exceeded_long(Config) when is_list(Config) ->
437    put(verbosity, ?TEST_VERBOSITY),
438    put(sname,     "TEST"),
439    put(tc,        sent_timer_exceeded_long),
440    i("starting"),
441
442    MgcNode = make_node_name(mgc),
443    MgNode  = make_node_name(mg),
444    d("start nodes: "
445      "~n      MgcNode: ~p"
446      "~n      MgNode:  ~p",
447      [MgcNode, MgNode]),
448    ok = ?START_NODES([MgcNode, MgNode], true),
449
450    %% Start the MGC and MGs
451    i("[MGC] start"),
452    ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
453    {ok, Mgc} =
454	?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
455
456    i("[MG] start"),
457    MgMid = {deviceName, "mg"},
458    MgConfig = [],
459    {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
460
461    d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
462
463    i("[MG] connect to the MGC (service change)"),
464    ServChRes = ?MG_SERV_CHANGE(Mg),
465    d("service change result: ~p", [ServChRes]),
466
467    d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
468
469    d("[MGC] update connection info pending timer"),
470    PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
471				      factor   = 1},
472    ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
473
474    d("[MGC] update connection info sent pending limit"),
475    PendingLimit = 5,
476    ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
477
478    d("[MGC] long request with no reply ~n"
479      "   (simulate that we know that this will "
480      "take a while, but takes even longer...)"),
481    ?MGC_REQ_PIGNORE(Mgc),
482
483    d("[MG] send the notify"),
484    {ok, {_ProtocolVersion, {error, ED}}} = ?MG_NOTIF_RAR(Mg),
485    d("[MG] ED: ~p", [ED]),
486    ErrorCode = ?megaco_number_of_transactionpending_exceeded,
487    ErrorCode = ED#'ErrorDescriptor'.errorCode,
488
489    %% Tell MG to stop
490    i("[MG] stop"),
491    ?MG_STOP(Mg),
492
493    %% Tell Mgc to stop
494    i("[MGC] stop"),
495    ?MGC_STOP(Mgc),
496
497    %% Cleanup
498    d("stop nodes"),
499    ?STOP_NODES([MgcNode, MgNode]),
500
501    i("done", []),
502    ok.
503
504
505
506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507
508%% This test case can only be run with the stack compiled with
509%% the MEGACO_TEST_CODE flag. Therefor there is no point in
510%% including this test case in the usual test suite
511-ifdef(MEGACO_TEST_CODE).
512sent_resend_late_reply(suite) ->
513    [];
514sent_resend_late_reply(doc) ->
515    "...";
516sent_resend_late_reply(Config) when is_list(Config) ->
517    put(verbosity, ?TEST_VERBOSITY),
518    put(sname,     "TEST"),
519    put(tc,        sent_resend_late_reply),
520    i("starting"),
521
522    MgcNode = make_node_name(mgc),
523    MgNode  = make_node_name(mg),
524    d("start nodes: "
525      "~n      MgcNode: ~p"
526      "~n      MgNode:  ~p",
527      [MgcNode, MgNode]),
528    ok = ?START_NODES([MgcNode, MgNode], true),
529
530    %% Start the MGC and MGs
531    i("[MGC] start"),
532    ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
533    {ok, Mgc} =
534	?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
535
536    i("[MG] start"),
537    MgMid = {deviceName, "mg"},
538    MgConfig = [],
539    {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
540
541    d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
542
543    i("[MG] connect to the MGC (service change)"),
544    ServChRes = ?MG_SERV_CHANGE(Mg),
545    d("service change result: ~p", [ServChRes]),
546
547    d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
548
549    d("[MGC] update connection info pending timer"),
550    PendingTimer = infinity,
551    %%     PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
552    %% 				      factor    = 1},
553    ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
554
555    d("[MGC] update connection info sent pending limit"),
556    PendingLimit = 5,
557    ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
558
559    d("[MG] update connection info request timer"),
560    RequestTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
561				      factor   = 1},
562    ?MG_UPDATE_CI(Mg, request_timer, RequestTimer),
563
564    d("[MGC] no reply to requests "
565      "(simulate that the request takes a __long__ time)"),
566    ?MGC_REQ_IGNORE(Mgc),
567
568    d("[MG] set the 'init_request_timer' tag"),
569    EccRes = (catch ?MG_ECC(Mg, megaco_messenger,
570			    init_request_timer, fun init_request_timer/1)),
571    d("[MG] EccRes: ~p", [EccRes]),
572
573    d("[MGC] late reply to requests "
574      "(simulate that the request takes a long time)"),
575    ?MGC_REQ_DISC(Mgc, 11000),
576
577    d("[MG] send the notify"),
578    {ok, Reply} = (catch ?MG_NOTIF_RAR(Mg)),
579    d("[MG] Reply: ~p", [Reply]),
580    {_Version, {ok, [_ActionReply]}} = Reply,
581
582    %% Tell MG to stop
583    i("[MG] stop"),
584    ?MG_STOP(Mg),
585
586    %% Tell Mgc to stop
587    i("[MGC] stop"),
588    ?MGC_STOP(Mgc),
589
590    %% Cleanup
591    d("stop nodes"),
592    ?STOP_NODES([MgcNode, MgNode]),
593
594    i("done", []),
595    ok.
596
597-else.
598
599sent_resend_late_reply(suite) ->
600    [];
601sent_resend_late_reply(doc) ->
602    "...";
603sent_resend_late_reply(Config) when is_list(Config) ->
604    ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true").
605
606-endif.
607
608
609
610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
611
612%% This test case can only be run with the stack compiled with
613%% the MEGACO_TEST_CODE flag. Therefor there is no point in
614%% including this test case in the usual test suite
615-ifdef(MEGACO_TEST_CODE).
616sent_resend_exceeded(suite) ->
617    [];
618sent_resend_exceeded(doc) ->
619    "...";
620sent_resend_exceeded(Config) when is_list(Config) ->
621    put(verbosity, ?TEST_VERBOSITY),
622    put(sname,     "TEST"),
623    put(tc,        sent_resend_exceeded),
624    i("starting"),
625
626    MgcNode = make_node_name(mgc),
627    MgNode  = make_node_name(mg),
628    d("start nodes: "
629      "~n      MgcNode: ~p"
630      "~n      MgNode:  ~p",
631      [MgcNode, MgNode]),
632    ok = ?START_NODES([MgcNode, MgNode], true),
633
634    %% Start the MGC and MGs
635    i("[MGC] start"),
636    ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
637    {ok, Mgc} =
638	?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
639
640    i("[MG] start"),
641    MgMid = {deviceName, "mg"},
642    MgConfig = [],
643    {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
644
645    d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
646
647    i("[MG] connect to the MGC (service change)"),
648    ServChRes = ?MG_SERV_CHANGE(Mg),
649    d("service change result: ~p", [ServChRes]),
650
651    d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
652
653    d("[MGC] update connection info pending timer"),
654    PendingTimer = infinity,
655    ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
656
657    d("[MGC] update connection info sent pending limit"),
658    PendingLimit = 5,
659    ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
660
661    d("[MG] update connection info request timer"),
662    RequestTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
663				      factor   = 1},
664    ?MG_UPDATE_CI(Mg, request_timer, RequestTimer),
665
666    d("[MGC] no reply to requests "
667      "(simulate that the request takes a __long__ time)"),
668    ?MGC_REQ_IGNORE(Mgc),
669
670    d("[MG] set the 'init_request_timer' tag"),
671    EccRes = (catch ?MG_ECC(Mg, megaco_messenger,
672			    init_request_timer, fun init_request_timer/1)),
673    d("[MG] EccRes: ~p", [EccRes]),
674
675    d("[MG] send the notify"),
676    ED = (catch ?MG_NOTIF_RAR(Mg)),
677    d("[MG] ED: ~p", [ED]),
678    ErrorCode = ?megaco_number_of_transactionpending_exceeded,
679    #'ErrorDescriptor'{errorCode = ErrorCode} = ED,
680
681    %% Tell MG to stop
682    i("[MG] stop"),
683    ?MG_STOP(Mg),
684
685    %% Tell Mgc to stop
686    i("[MGC] stop"),
687    ?MGC_STOP(Mgc),
688
689    %% Cleanup
690    d("stop nodes"),
691    ?STOP_NODES([MgcNode, MgNode]),
692
693    i("done", []),
694    ok.
695
696
697-else.
698
699sent_resend_exceeded(suite) ->
700    [];
701sent_resend_exceeded(doc) ->
702    "...";
703sent_resend_exceeded(Config) when is_list(Config) ->
704    ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true").
705
706-endif.
707
708
709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710
711%% This test case can only be run with the stack compiled with
712%% the MEGACO_TEST_CODE flag. Therefor there is no point in
713%% including this test case in the usual test suite
714-ifdef(MEGACO_TEST_CODE).
715sent_resend_exceeded_long(suite) ->
716    [];
717sent_resend_exceeded_long(doc) ->
718    "...";
719sent_resend_exceeded_long(Config) when is_list(Config) ->
720    put(verbosity, ?TEST_VERBOSITY),
721    put(sname,     "TEST"),
722    put(tc,        sent_resend_exceeded_long),
723    i("starting"),
724
725    MgcNode = make_node_name(mgc),
726    MgNode  = make_node_name(mg),
727    d("start nodes: "
728      "~n      MgcNode: ~p"
729      "~n      MgNode:  ~p",
730      [MgcNode, MgNode]),
731    ok = ?START_NODES([MgcNode, MgNode], true),
732
733    %% Start the MGC and MGs
734    i("[MGC] start"),
735    ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
736    {ok, Mgc} =
737	?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
738
739    i("[MG] start"),
740    MgMid = {deviceName, "mg"},
741    MgConfig = [],
742    {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
743
744    d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
745
746    i("[MG] connect to the MGC (service change)"),
747    ServChRes = ?MG_SERV_CHANGE(Mg),
748    d("service change result: ~p", [ServChRes]),
749
750    d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
751
752    d("[MGC] update connection info pending timer"),
753    PendingTimer = infinity,
754    ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
755
756    d("[MGC] update connection info sent pending limit"),
757    PendingLimit = 5,
758    ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
759
760    d("[MG] update connection info request timer"),
761    RequestTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
762				      factor   = 1},
763    ?MG_UPDATE_CI(Mg, request_timer, RequestTimer),
764
765    d("[MGC] long request with no reply ~n"
766      "   (simulate that we know that this will "
767      "take a while, but takes even longer...)"),
768    ?MGC_REQ_PIGNORE(Mgc),
769
770    d("[MG] set the 'init_request_timer' tag"),
771    EccRes = (catch ?MG_ECC(Mg, megaco_messenger,
772			    init_request_timer, fun init_request_timer/1)),
773    d("[MG] EccRes: ~p", [EccRes]),
774
775    d("[MG] send the notify"),
776    ED = (catch ?MG_NOTIF_RAR(Mg)),
777    d("[MG] ED: ~p", [ED]),
778    ErrorCode = ?megaco_number_of_transactionpending_exceeded,
779    #'ErrorDescriptor'{errorCode = ErrorCode} = ED,
780
781    %% Tell MG to stop
782    i("[MG] stop"),
783    ?MG_STOP(Mg),
784
785    %% Tell Mgc to stop
786    i("[MGC] stop"),
787    ?MGC_STOP(Mgc),
788
789    %% Cleanup
790    d("stop nodes"),
791    ?STOP_NODES([MgcNode, MgNode]),
792
793    i("done", []),
794    ok.
795
796
797-else.
798
799sent_resend_exceeded_long(suite) ->
800    [];
801sent_resend_exceeded_long(doc) ->
802    "...";
803sent_resend_exceeded_long(Config) when is_list(Config) ->
804    ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true").
805
806-endif.
807
808
809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
810%%%                                                                   %%%
811%%%                 Received peinding test cases                      %%%
812%%%                                                                   %%%
813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
814
815recv_limit_exceeded1(suite) ->
816    [];
817recv_limit_exceeded1(doc) ->
818    "Received pending limit exceeded (exactly)";
819recv_limit_exceeded1(Config) when is_list(Config) ->
820    put(verbosity, ?TEST_VERBOSITY),
821    put(sname,     "TEST"),
822    put(tc,        rle1),
823    i("starting"),
824
825    MgcNode = make_node_name(mgc),
826    MgNode  = make_node_name(mg),
827    d("start nodes: "
828      "~n      MgcNode: ~p"
829      "~n      MgNode:  ~p",
830      [MgcNode, MgNode]),
831    ok = ?START_NODES([MgcNode, MgNode], true),
832
833    d("[MGC] start the simulator "),
834    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
835
836    d("[MGC] create the event sequence"),
837    MgcEvSeq = rle1_mgc_event_sequence(text, tcp),
838
839    i("wait some time before starting the MGC simulation"),
840    sleep(1000),
841
842    d("[MGC] start the simulation"),
843    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
844
845    i("wait some time before starting the MG simulator"),
846    sleep(1000),
847
848    d("[MG] start the simulator (generator)"),
849    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
850
851    d("[MG] create the event sequence"),
852    MgEvSeq = rle1_mg_event_sequence(text, tcp),
853
854    i("wait some time before starting the MG simulation"),
855    sleep(1000),
856
857    d("[MG] start the simulation"),
858    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
859
860    d("await the generator reply(s)"),
861    await_completion([MgcId, MgId]),
862
863    %% Tell Mgc to stop
864    i("[MGC] stop generator"),
865    megaco_test_tcp_generator:stop(Mgc),
866
867    %% Tell Mg to stop
868    i("[MG] stop generator"),
869    megaco_test_megaco_generator:stop(Mg),
870
871    %% Cleanup
872    d("stop nodes"),
873    ?STOP_NODES([MgcNode, MgNode]),
874
875    i("done", []),
876    ok.
877
878
879%%
880%% MGC generator stuff
881%%
882-ifdef(megaco_hipe_special).
883-define(rle1_mgc_decode_msg_fun(Mod, Conf),
884	{?MODULE, decode_msg, [Mod, Conf]}).
885-define(rle1_mgc_encode_msg_fun(Mod, Conf),
886	{?MODULE, encode_msg, [Mod, Conf]}).
887-define(rle1_mgc_verify_service_change_req_msg_fun(Mid),
888	{?MODULE, rle1_mgc_verify_service_change_req_msg, [Mid]}).
889-define(rle1_mgc_verify_notify_req_msg_fun(),
890	{?MODULE, rle1_mgc_verify_notify_req_msg, []}).
891-else.
892-define(rle1_mgc_decode_msg_fun(Mod, Conf),
893	rle1_mgc_decode_msg_fun(Mod, Conf)).
894-define(rle1_mgc_encode_msg_fun(Mod, Conf),
895	rle1_mgc_encode_msg_fun(Mod, Conf)).
896-define(rle1_mgc_verify_service_change_req_msg_fun(Mid),
897	rle1_mgc_verify_service_change_req_msg_fun(Mid)).
898-define(rle1_mgc_verify_notify_req_msg_fun(),
899	rle1_mgc_verify_notify_req_msg_fun()).
900-endif.
901
902rle1_mgc_event_sequence(text, tcp) ->
903    Mid = {deviceName,"ctrl"},
904    EM  = megaco_pretty_text_encoder,
905    EC  = [],
906    rle1_mgc_event_sequence2(Mid, EM, EC).
907
908rle1_mgc_event_sequence2(Mid, EM, EC) ->
909    DecodeFun = ?rle1_mgc_decode_msg_fun(EM, EC),
910    EncodeFun = ?rle1_mgc_encode_msg_fun(EM, EC),
911    ServiceChangeReply =
912	rle1_mgc_service_change_reply_msg(Mid, 1, 0),
913    Pending = rle1_mgc_pending_msg(Mid,2),
914    ServiceChangeReqVerify =
915	?rle1_mgc_verify_service_change_req_msg_fun(Mid),
916    NotifyReqVerify = ?rle1_mgc_verify_notify_req_msg_fun(),
917%%     ServiceChangeReqVerify =
918%% 	rle1_mgc_verify_service_change_req_fun(Mid),
919%%     NotifyReqVerify = rle1_mgc_verify_notify_request_fun(),
920    EvSeq =
921	[{debug,  true},
922	 {decode, DecodeFun},
923	 {encode, EncodeFun},
924	 {listen, 2944},
925	 {expect_accept, any},
926	 {expect_receive, "service-change-req",
927	  {ServiceChangeReqVerify, 10000}},
928	 {send, "service-change-reply", ServiceChangeReply},
929	 {expect_receive, "notify-request", {NotifyReqVerify, 5000}},
930	 {sleep, 100},
931	 {send, "pending 1", Pending},
932	 {sleep, 100},
933	 {send, "pending 2", Pending},
934	 {sleep, 100},
935	 {send, "pending 3", Pending},
936	 {sleep, 100},
937	 {send, "pending 4", Pending},
938	 {sleep, 100},
939	 {send, "pending 5", Pending},
940	 {sleep, 1000},
941	 disconnect
942	 ],
943    EvSeq.
944
945-ifndef(megaco_hipe_special).
946rle1_mgc_encode_msg_fun(Mod, Conf) ->
947    fun(M) ->
948            encode_msg(M, Mod, Conf)
949    end.
950
951rle1_mgc_decode_msg_fun(Mod, Conf) ->
952    fun(M) ->
953            decode_msg(M, Mod, Conf)
954    end.
955-endif.
956
957rle1_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
958    SCRP  = #'ServiceChangeResParm'{serviceChangeMgcId = Mid},
959    SCRPs = {serviceChangeResParms,SCRP},
960    Root  = #megaco_term_id{id = ["root"]},
961    SCR   = #'ServiceChangeReply'{terminationID       = [Root],
962                                  serviceChangeResult = SCRPs},
963    CR    = {serviceChangeReply, SCR},
964    rle1_mgc_msg(Mid, TransId, CR, Cid).
965
966rle1_mgc_msg(Mid, TransId, CR, Cid) ->
967    AR  = #'ActionReply'{contextId    = Cid,
968                         commandReply = [CR]},
969    ARs  = {actionReplies, [AR]},
970    TR   = #'TransactionReply'{transactionId     = TransId,
971                               transactionResult = ARs},
972    Body = {transactions, [{transactionReply, TR}]},
973    Mess = #'Message'{version     = 1,
974                      mId         = Mid,
975                      messageBody = Body},
976    #'MegacoMessage'{mess = Mess}.
977
978rle1_mgc_pending_msg(Mid, TransId) ->
979    TP   = #'TransactionPending'{transactionId = TransId},
980    Body = {transactions, [{transactionPending, TP}]},
981    Mess = #'Message'{version     = 1,
982                      mId         = Mid,
983                      messageBody = Body},
984    #'MegacoMessage'{mess = Mess}.
985
986-ifndef(megaco_hipe_special).
987rle1_mgc_verify_service_change_req_msg_fun(Mid) ->
988    fun(M) ->
989	    rle1_mgc_verify_service_change_req_msg(M, Mid)
990    end.
991-endif.
992
993rle1_mgc_verify_service_change_req_msg(#'MegacoMessage'{mess = Mess} = M,
994				       _Mid1) ->
995    io:format("rle1_mgc_verify_service_change_req_msg -> entry with"
996	      "~n   M: ~p"
997	      "~n", [M]),
998    #'Message'{version     = _V,
999	       mId         = _Mid2,
1000	       messageBody = Body} = Mess,
1001    {transactions, [Trans]} = Body,
1002    {transactionRequest, TR} = Trans,
1003    #'TransactionRequest'{transactionId = _Tid,
1004			  actions = [AR]} = TR,
1005    #'ActionRequest'{contextId = _Cid,
1006		     contextRequest = _CtxReq,
1007		     contextAttrAuditReq = _CtxAar,
1008		     commandRequests = [CR]} = AR,
1009    #'CommandRequest'{command = Cmd,
1010		      optional = _Opt,
1011		      wildcardReturn = _WR} = CR,
1012    {serviceChangeReq, SCR} = Cmd,
1013    #'ServiceChangeRequest'{terminationID = _TermID,
1014			    serviceChangeParms = SCP} = SCR,
1015    #'ServiceChangeParm'{serviceChangeMethod = restart,
1016			 serviceChangeReason = [[$9,$0,$1|_]]} = SCP,
1017    {ok, M};
1018rle1_mgc_verify_service_change_req_msg(M, _Mid) ->
1019    {error, {invalid_message, M}}.
1020
1021-ifndef(megaco_hipe_special).
1022rle1_mgc_verify_notify_req_msg_fun() ->
1023    fun(M) ->
1024	    rle1_mgc_verify_notify_req_msg(M)
1025    end.
1026-endif.
1027
1028rle1_mgc_verify_notify_req_msg(#'MegacoMessage'{mess = Mess} = M) ->
1029    io:format("rle1_mgc_verify_notify_req_msg -> entry with"
1030	      "~n   M: ~p"
1031	      "~n", [M]),
1032    #'Message'{messageBody = Body} = Mess,
1033    {transactions, [Trans]} = Body,
1034    {transactionRequest, TR} = Trans,
1035    #'TransactionRequest'{actions = [AR]} = TR,
1036    io:format("rle1_mgc_verify_notify_request_fun -> AR: "
1037	      "~n~p~n", [AR]),
1038    #'ActionRequest'{commandRequests = [CR]} = AR,
1039    #'CommandRequest'{command = Cmd} = CR,
1040    {notifyReq, NR} = Cmd,
1041    #'NotifyRequest'{observedEventsDescriptor = OED} = NR,
1042    #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
1043    #'ObservedEvent'{eventName = "al/of"} = OE,
1044    {ok, M};
1045rle1_mgc_verify_notify_req_msg(M) ->
1046    {error, {invalid_message, M}}.
1047
1048% rle1_err_desc(T) ->
1049%     EC = ?megaco_internal_gateway_error,
1050%     ET = lists:flatten(io_lib:format("~w",[T])),
1051%     #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
1052
1053
1054%%
1055%% MG generator stuff
1056%%
1057-ifdef(megaco_hipe_special).
1058-define(rle1_mg_verify_handle_connect_fun(),
1059	{?MODULE, rle1_mg_verify_handle_connect, []}).
1060-define(rle1_mg_verify_service_change_rep_fun(),
1061	{?MODULE, rle1_mg_verify_service_change_rep, []}).
1062-define(rle1_mg_verify_trans_rep_fun(),
1063	{?MODULE, rle1_mg_verify_trans_rep, []}).
1064-else.
1065-define(rle1_mg_verify_handle_connect_fun(),
1066	fun rle1_mg_verify_handle_connect/1).
1067-define(rle1_mg_verify_service_change_rep_fun(),
1068	fun rle1_mg_verify_service_change_rep/1).
1069-define(rle1_mg_verify_trans_rep_fun(),
1070	fun rle1_mg_verify_trans_rep/1).
1071-endif.
1072
1073rle1_mg_event_sequence(text, tcp) ->
1074    Mid = {deviceName,"mg"},
1075    RI = [
1076          {port,             2944},
1077          {encoding_module,  megaco_pretty_text_encoder},
1078          {encoding_config,  []},
1079          {transport_module, megaco_tcp}
1080         ],
1081    rle1_mg_event_sequence2(Mid, RI).
1082
1083rle1_mg_event_sequence2(Mid, RI) ->
1084    ServiceChangeReq = [rle1_mg_service_change_request_ar(Mid, 1)],
1085    Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
1086    NotifyReq = [rle1_mg_notify_request_ar(1, Tid, 1)],
1087    ConnectVerify            = ?rle1_mg_verify_handle_connect_fun(),
1088    ServiceChangeReplyVerify = ?rle1_mg_verify_service_change_rep_fun(),
1089    TransReplyVerify         = ?rle1_mg_verify_trans_rep_fun(),
1090%%     ConnectVerify            = fun rle1_mg_verify_handle_connect/1,
1091%%     ServiceChangeReplyVerify = fun rle1_mg_verify_service_change_reply/1,
1092%%     TransReplyVerify         = fun rle1_mg_verify_trans_reply/1,
1093    EvSeq = [
1094             {debug, true},
1095             megaco_start,
1096             {megaco_start_user, Mid, RI, []},
1097	     {megaco_update_user_info, recv_pending_limit, 4},
1098             start_transport,
1099             {megaco_trace, disable}, %%100},
1100             {megaco_system_info, users},
1101             {megaco_system_info, connections},
1102             connect,
1103             {megaco_callback, handle_connect, ConnectVerify},
1104             megaco_connect,
1105             {megaco_cast, ServiceChangeReq, []},
1106             {megaco_callback, handle_connect, ConnectVerify},
1107             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
1108             {sleep, 1000},
1109             {megaco_cast, NotifyReq, []},
1110             {megaco_callback, handle_trans_reply, TransReplyVerify},
1111             {sleep, 1000},
1112             megaco_stop_user,
1113             megaco_stop,
1114             {sleep, 1000}
1115            ],
1116    EvSeq.
1117
1118
1119rle1_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
1120    io:format("rle1_mg_verify_handle_connect -> ok"
1121	      "~n   CH: ~p~n", [CH]),
1122    {ok, CH, ok};
1123rle1_mg_verify_handle_connect(Else) ->
1124    io:format("rle1_mg_verify_handle_connect -> unknown"
1125	      "~n   Else: ~p~n", [Else]),
1126    {error, Else, ok}.
1127
1128rle1_mg_verify_service_change_rep(
1129  {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
1130    io:format("rle1_mg_verify_service_change_rep -> ok"
1131	      "~n   AR: ~p~n", [AR]),
1132    case AR of
1133	#'ActionReply'{commandReply = [SCR]} ->
1134	    case SCR of
1135		{serviceChangeReply,
1136		 #'ServiceChangeReply'{terminationID = [Tid],
1137				       serviceChangeResult = Res}} ->
1138		    case Tid of
1139			#megaco_term_id{contains_wildcards = false,
1140					id = ["root"]} ->
1141			    case Res of
1142				{serviceChangeResParms,
1143				 #'ServiceChangeResParm'{
1144				   serviceChangeMgcId = _RemoteMid}} ->
1145				    {ok, AR, ok};
1146				{Tag, Val} ->
1147				    Err = {invalid_service_change_result,
1148					   Tag, Val},
1149				    {error, Err, ok}
1150			    end;
1151			_ ->
1152			    Err = {invalid_termination_id, Tid},
1153			    {error, Err, ok}
1154		    end;
1155		{Tag, Val} ->
1156		    Err = {invalid_command_reply, Tag, Val},
1157		    {error, Err, ok}
1158	    end;
1159	_ ->
1160	    Err = {invalid_action_reply, AR},
1161	    {error, Err, ok}
1162    end;
1163rle1_mg_verify_service_change_rep(Else) ->
1164    io:format("rle1_mg_verify_service_change_rep -> unknown"
1165	      "~n   Else: ~p~n", [Else]),
1166    {error, Else, ok}.
1167
1168rle1_mg_verify_trans_rep(
1169  {handle_trans_reply, _CH, ?VERSION,
1170   {error, exceeded_recv_pending_limit} = E, _}) ->
1171    io:format("rle1_mg_verify_trans_rep -> expected error~n", []),
1172    {ok, E    , error};
1173rle1_mg_verify_trans_rep(Else) ->
1174    io:format("rle1_mg_verify_trans_rep -> unknown"
1175	      "~n   Else: ~p~n", [Else]),
1176    {error, Else, error}.
1177
1178rle1_mg_service_change_request_ar(_Mid, Cid) ->
1179    Prof  = cre_serviceChangeProf("resgw", 1),
1180    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
1181    Root  = #megaco_term_id{id = ["root"]},
1182    SCR   = cre_serviceChangeReq([Root], SCP),
1183    CMD   = cre_command(SCR),
1184    CR    = cre_cmdReq(CMD),
1185    cre_actionReq(Cid, [CR]).
1186
1187rle1_mg_notify_request_ar(Rid, Tid, Cid) ->
1188    TT      = cre_timeNotation("19990729", "22000000"),
1189    Ev      = cre_obsEvent("al/of", TT),
1190    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
1191    NR      = cre_notifyReq([Tid], EvsDesc),
1192    CMD     = cre_command(NR),
1193    CR      = cre_cmdReq(CMD),
1194    cre_actionReq(Cid, [CR]).
1195
1196
1197%% ---
1198
1199recv_limit_exceeded2(suite) ->
1200    [];
1201recv_limit_exceeded2(doc) ->
1202    "Received pending limit exceeded";
1203recv_limit_exceeded2(Config) when is_list(Config) ->
1204    put(verbosity, ?TEST_VERBOSITY),
1205    put(sname,     "TEST"),
1206    put(tc,        rle2),
1207    i("starting"),
1208
1209    _MgcNode = make_node_name(mgc),
1210    _MgNode  = make_node_name(mg),
1211
1212    ?SKIP(not_yet_implemented).
1213
1214
1215
1216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1217%%%                                                                   %%%
1218%%%                       Ticket test cases                           %%%
1219%%%                                                                   %%%
1220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1221
1222otp_4956(suite) ->
1223    [];
1224otp_4956(Config) when is_list(Config) ->
1225    put(verbosity, ?TEST_VERBOSITY),
1226    put(sname,     "TEST"),
1227    put(tc,        otp_4956),
1228    i("starting"),
1229
1230    MgcNode = make_node_name(mgc),
1231    MgNode  = make_node_name(mg),
1232    d("start nodes: "
1233      "~n      MgcNode: ~p"
1234      "~n      MgNode:  ~p",
1235      [MgcNode, MgNode]),
1236    ok = ?START_NODES([MgcNode, MgNode], true),
1237
1238    d("[MGC] start the simulator "),
1239    {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
1240
1241    d("[MGC] create the event sequence"),
1242    MgcEvSeq = otp_4956_mgc_event_sequence(text, tcp),
1243
1244    i("wait some time before starting the MGC simulation"),
1245    sleep(1000),
1246
1247    d("[MGC] start the simulation"),
1248    {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
1249
1250    i("wait some time before starting the MG simulator"),
1251    sleep(1000),
1252
1253    d("[MG] start the simulator (generator)"),
1254    {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
1255
1256    d("[MG] create the event sequence"),
1257    MgEvSeq = otp_4956_mg_event_sequence(text, tcp),
1258
1259    i("wait some time before starting the MG simulation"),
1260    sleep(1000),
1261
1262    d("[MG] start the simulation"),
1263    {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
1264
1265    d("await the generator reply(s)"),
1266    await_completion([MgcId, MgId]),
1267
1268    %% Tell Mgc to stop
1269    i("[MGC] stop generator"),
1270    megaco_test_megaco_generator:stop(Mgc),
1271
1272    %% Tell Mg to stop
1273    i("[MG] stop generator"),
1274    megaco_test_tcp_generator:stop(Mg),
1275
1276    %% Cleanup
1277    d("stop nodes"),
1278    ?STOP_NODES([MgcNode, MgNode]),
1279
1280    i("done", []),
1281    ok.
1282
1283
1284%%
1285%% MGC generator stuff
1286%%
1287-ifdef(megaco_hipe_special).
1288-define(otp_4956_mgc_verify_handle_connect_fun(),
1289        {?MODULE, otp_4956_mgc_verify_handle_connect, []}).
1290-define(otp_4956_mgc_verify_service_change_req_fun(Mid),
1291        {?MODULE, otp_4956_mgc_verify_service_change_req, [Mid]}).
1292-define(otp_4956_mgc_verify_notify_req1_fun(),
1293        {?MODULE, otp_4956_mgc_verify_notify_req1, []}).
1294-define(otp_4956_mgc_verify_notify_req2_fun(),
1295        {?MODULE, otp_4956_mgc_verify_notify_req2, []}).
1296-define(otp_4956_mgc_verify_handle_trans_req_abort_fun(),
1297        {?MODULE, otp_4956_mgc_verify_handle_trans_req_abort, []}).
1298-define(otp_4956_mgc_verify_handle_disconnect_fun(),
1299        {?MODULE, otp_4956_mgc_verify_handle_disconnect, []}).
1300-else.
1301-define(otp_4956_mgc_verify_handle_connect_fun(),
1302        otp_4956_mgc_verify_handle_connect_fun()).
1303-define(otp_4956_mgc_verify_service_change_req_fun(Mid),
1304        otp_4956_mgc_verify_service_change_req_fun(Mid)).
1305-define(otp_4956_mgc_verify_notify_req1_fun(),
1306        otp_4956_mgc_verify_notify_req1_fun()).
1307-define(otp_4956_mgc_verify_notify_req2_fun(),
1308        otp_4956_mgc_verify_notify_req2_fun()).
1309-define(otp_4956_mgc_verify_handle_trans_req_abort_fun(),
1310	otp_4956_mgc_verify_handle_trans_req_abort_fun()).
1311-define(otp_4956_mgc_verify_handle_disconnect_fun(),
1312	fun otp_4956_mgc_verify_handle_disconnect/1).
1313-endif.
1314
1315otp_4956_mgc_event_sequence(text, tcp) ->
1316    Mid = {deviceName,"ctrl"},
1317    RI = [
1318          {port,             2944},
1319          {encoding_module,  megaco_pretty_text_encoder},
1320          {encoding_config,  []},
1321          {transport_module, megaco_tcp}
1322         ],
1323    ConnectVerify          = ?otp_4956_mgc_verify_handle_connect_fun(),
1324    ServiceChangeReqVerify = ?otp_4956_mgc_verify_service_change_req_fun(Mid),
1325    NotifyReqVerify1       = ?otp_4956_mgc_verify_notify_req1_fun(),
1326    NotifyReqVerify2       = ?otp_4956_mgc_verify_notify_req2_fun(),
1327    ReqAbortVerify         = ?otp_4956_mgc_verify_handle_trans_req_abort_fun(),
1328    DiscoVerify            = ?otp_4956_mgc_verify_handle_disconnect_fun(),
1329%%     ConnectVerify          = otp_4956_mgc_verify_handle_connect_fun(),
1330%%     ServiceChangeReqVerify = otp_4956_mgc_verify_service_change_req_fun(Mid),
1331%%     NotifyReqVerify1       = otp_4956_mgc_verify_notify_request_fun1(),
1332%%     NotifyReqVerify2       = otp_4956_mgc_verify_notify_request_fun2(),
1333%%     ReqAbortVerify = otp_4956_mgc_verify_handle_trans_request_abort_fun(),
1334%%     DiscoVerify            = fun otp_4956_mgc_verify_handle_disconnect/1,
1335    EvSeq = [
1336             {debug, true},
1337	     {megaco_trace, disable},
1338	     {megaco_trace, max},
1339             megaco_start,
1340             {megaco_start_user, Mid, RI, []},
1341	     {megaco_update_user_info, sent_pending_limit, 4},
1342             start_transport,
1343             listen,
1344             {megaco_callback, handle_connect, ConnectVerify},
1345	     {megaco_conn_info, all},
1346             {megaco_callback, handle_trans_request_sc, ServiceChangeReqVerify},
1347             {megaco_callback, handle_trans_request_1, NotifyReqVerify1},
1348             {megaco_callback, handle_trans_request_abort, ReqAbortVerify},
1349             {megaco_callback, nocall, 1000},
1350             {megaco_callback, handle_trans_request_6, NotifyReqVerify2},
1351             {megaco_callback, handle_disconnect, DiscoVerify},
1352             megaco_stop_user,
1353             megaco_stop
1354            ],
1355    EvSeq.
1356
1357
1358-ifndef(megaco_hipe_special).
1359otp_4956_mgc_verify_handle_connect_fun() ->
1360    fun(M) ->
1361	    otp_4956_mgc_verify_handle_connect(M)
1362    end.
1363-endif.
1364
1365otp_4956_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
1366    {ok, CH, ok};
1367otp_4956_mgc_verify_handle_connect(Else) ->
1368    {error, Else, ok}.
1369
1370-ifndef(megaco_hipe_special).
1371otp_4956_mgc_verify_service_change_req_fun(Mid) ->
1372    fun(Req) ->
1373	    otp_4956_mgc_verify_service_change_req(Req, Mid)
1374    end.
1375-endif.
1376
1377otp_4956_mgc_verify_service_change_req(
1378  {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
1379    io:format("otp_4956_mgc_verify_service_change_req -> ok"
1380	      "~n   AR: ~p"
1381	      "~n", [AR]),
1382    case AR of
1383	#'ActionRequest'{commandRequests = [CR]} ->
1384	    case CR of
1385		#'CommandRequest'{command = Cmd} ->
1386		    case Cmd of
1387			{serviceChangeReq,
1388			 #'ServiceChangeRequest'{terminationID = [Tid],
1389						 serviceChangeParms = Parms}} ->
1390			    case Tid of
1391				#megaco_term_id{contains_wildcards = false,
1392						id = ["root"]} ->
1393				    case Parms of
1394					#'ServiceChangeParm'{
1395						 serviceChangeMethod = restart,
1396						 serviceChangeReason = [[$9,$0,$1|_]]} ->
1397					    Reply =
1398						{discard_ack,
1399						 [otp_4956_mgc_service_change_reply_ar(Mid, 1)]},
1400					    {ok, AR, Reply};
1401					_ ->
1402					    Err = {invalid_SCP, Parms},
1403					    ED = otp_4956_err_desc(Parms),
1404					    ErrReply = {discard_ack,
1405							ED},
1406					    {error, Err, ErrReply}
1407				    end;
1408				_ ->
1409				    Err = {invalid_termination_id, Tid},
1410				    ED = otp_4956_err_desc(Tid),
1411				    ErrReply = {discard_ack, ED},
1412				    {error, Err, ErrReply}
1413			    end;
1414			_ ->
1415			    Err = {invalid_command, Cmd},
1416			    ED = otp_4956_err_desc(Cmd),
1417			    ErrReply = {discard_ack, ED},
1418			    {error, Err, ErrReply}
1419		    end;
1420		_ ->
1421		    Err = {invalid_command_request, CR},
1422		    ED = otp_4956_err_desc(CR),
1423		    ErrReply = {discard_ack, ED},
1424		    {error, Err, ErrReply}
1425	    end;
1426	_ ->
1427	    Err = {invalid_action_request, AR},
1428	    ED = otp_4956_err_desc(AR),
1429	    ErrReply = {discard_ack, ED},
1430	    {error, Err, ErrReply}
1431    end;
1432otp_4956_mgc_verify_service_change_req(Else, _Mid) ->
1433    ED       = otp_4956_err_desc(Else),
1434    ErrReply = {discard_ack, ED},
1435    {error, Else, ErrReply}.
1436
1437-ifndef(megaco_hipe_special).
1438otp_4956_mgc_verify_notify_req1_fun() ->
1439    fun(Req) ->
1440	    otp_4956_mgc_verify_notify_req1(Req)
1441    end.
1442-endif.
1443
1444otp_4956_mgc_verify_notify_req1({handle_trans_request, _, ?VERSION, [AR]}) ->
1445    io:format("otp_4956_mgc_verify_notify_req1 -> entry with"
1446	      "~n   AR: ~p"
1447	      "~n", [AR]),
1448    case AR of
1449	#'ActionRequest'{contextId = Cid,
1450			 commandRequests = [CR]} ->
1451	    #'CommandRequest'{command = Cmd} = CR,
1452	    {notifyReq, NR} = Cmd,
1453	    #'NotifyRequest'{terminationID = [Tid],
1454			     observedEventsDescriptor = OED,
1455			     errorDescriptor = asn1_NOVALUE} = NR,
1456	    #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
1457	    #'ObservedEvent'{eventName = "al/of"} = OE,
1458	    Reply = {discard_ack, [otp_4956_mgc_notify_reply_ar(Cid, Tid)]},
1459	    {ok, 6500, AR, Reply};
1460	_ ->
1461                    ED = otp_4956_err_desc(AR),
1462	    ErrReply = {discard_ack, ED},
1463	    {error, AR, ErrReply}
1464    end;
1465otp_4956_mgc_verify_notify_req1(Else) ->
1466    io:format("otp_4956_mgc_verify_notify_req1 -> entry with"
1467	      "~n   Else: ~p"
1468	      "~n", [Else]),
1469    ED       = otp_4956_err_desc(Else),
1470    ErrReply = {discard_ack, ED},
1471    {error, Else, ErrReply}.
1472
1473-ifndef(megaco_hipe_special).
1474otp_4956_mgc_verify_notify_req2_fun() ->
1475    fun(Ev) ->
1476	    otp_4956_mgc_verify_notify_req2(Ev)
1477    end.
1478-endif.
1479
1480otp_4956_mgc_verify_notify_req2({handle_trans_request, _, ?VERSION, [AR]}) ->
1481    case AR of
1482	#'ActionRequest'{contextId = _Cid,
1483			 commandRequests = [CR]} ->
1484	    #'CommandRequest'{command = Cmd} = CR,
1485	    {notifyReq, NR} = Cmd,
1486	    #'NotifyRequest'{terminationID = [_Tid],
1487			     observedEventsDescriptor = OED,
1488			     errorDescriptor = asn1_NOVALUE} = NR,
1489	    #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
1490	    #'ObservedEvent'{eventName = "al/of"} = OE,
1491	    Reply = ignore,
1492	    {ok, 100, AR, Reply};
1493	_ ->
1494	    ED = otp_4956_err_desc(AR),
1495	    ErrReply = {discard_ack, ED},
1496	    {error, AR, ErrReply}
1497    end;
1498otp_4956_mgc_verify_notify_req2(Else) ->
1499    ED       = otp_4956_err_desc(Else),
1500    ErrReply = {discard_ack, ED},
1501    {error, Else, ErrReply}.
1502
1503-ifndef(megaco_hipe_special).
1504otp_4956_mgc_verify_handle_trans_req_abort_fun() ->
1505    fun(Req) ->
1506	    otp_4956_mgc_verify_handle_trans_req_abort(Req)
1507    end.
1508-endif.
1509
1510otp_4956_mgc_verify_handle_trans_req_abort({handle_trans_request_abort,
1511					    CH, ?VERSION, 2, Pid}) ->
1512    io:format("otp_4956_mgc_verify_handle_trans_req_abort -> ok"
1513	      "~n   CH:  ~p"
1514	      "~n   Pid: ~p"
1515	      "~n", [CH, Pid]),
1516    {ok, {CH, Pid}, ok};
1517otp_4956_mgc_verify_handle_trans_req_abort({handle_trans_request_abort,
1518					    CH, Version, TransId, Pid}) ->
1519    io:format("otp_4956_mgc_verify_handle_trans_req_abort -> error"
1520	      "~n   CH:      ~p"
1521	      "~n   Version: ~p"
1522	      "~n   TransId: ~p"
1523	      "~n   Pid:     ~p"
1524	      "~n", [CH, Version, TransId, Pid]),
1525    {error, {error, {invalid_version_trans_id, Version, TransId}}, ok};
1526otp_4956_mgc_verify_handle_trans_req_abort(Else) ->
1527    io:format("otp_4956_mgc_verify_handle_trans_req_abort -> error"
1528	      "~n   Else: ~p"
1529	      "~n", [Else]),
1530    {error, Else, ok}.
1531
1532otp_4956_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, _R}) ->
1533    io:format("otp_4956_mgc_verify_handle_disconnect -> ok"
1534	      "~n   CH: ~p"
1535	      "~n   _R:  ~p"
1536	      "~n", [CH, _R]),
1537    {ok, CH, ok};
1538otp_4956_mgc_verify_handle_disconnect(Else) ->
1539    io:format("otp_4956_mgc_verify_handle_disconnect -> unknown"
1540	      "~n   Else: ~p~n", [Else]),
1541    {error, Else, ok}.
1542
1543otp_4956_mgc_service_change_reply_ar(Mid, Cid) ->
1544    SCRP  = cre_serviceChangeResParm(Mid),
1545    SCRes = cre_serviceChangeResult(SCRP),
1546    Root  = #megaco_term_id{id = ["root"]},
1547    SCR   = cre_serviceChangeReply([Root], SCRes),
1548    CR    = cre_cmdReply(SCR),
1549    AR    = cre_actionReply(Cid, [CR]),
1550    AR.
1551
1552%% otp_4956_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
1553%%     AR    = otp_4956_mgc_service_change_reply_ar(Mid, Cid),
1554%%     TRes  = cre_transResult([AR]),
1555%%     TR    = cre_transReply(TransId, TRes),
1556%%     Trans = cre_transaction(TR),
1557%%     Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1558%%     cre_megacoMessage(Mess).
1559
1560otp_4956_mgc_notify_reply_ar(Cid, TermId) ->
1561    NR    = cre_notifyReply([TermId]),
1562    CR    = cre_cmdReply(NR),
1563    cre_actionReply(Cid, [CR]).
1564
1565%% otp_4956_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
1566%%     AR    = otp_4956_mgc_notify_reply_ar(Cid, TermId),
1567%%     TRes  = cre_transResult([AR]),
1568%%     TR    = cre_transReply(TransId, TRes),
1569%%     Trans = cre_transaction(TR),
1570%%     Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1571%%     cre_megacoMessage(Mess).
1572
1573
1574%%
1575%% MG generator stuff
1576%%
1577-ifdef(megaco_hipe_special).
1578-define(otp_4956_mg_decode_msg_fun(Mod, Conf),
1579	{?MODULE, decode_msg, [Mod, Conf]}).
1580-define(otp_4956_mg_encode_msg_fun(Mod, Conf),
1581	{?MODULE, encode_msg, [Mod, Conf]}).
1582-define(otp_4956_mg_verify_service_change_rep_msg_fun(),
1583	{?MODULE, otp_4956_mg_verify_service_change_rep_msg, []}).
1584-define(otp_4956_mg_verify_pending_msg_fun(),
1585	{?MODULE, otp_4956_mg_verify_pending_msg, []}).
1586-define(otp_4956_mg_verify_pending_limit_msg_fun(),
1587	{?MODULE, otp_4956_mg_verify_pending_limit_msg, []}).
1588-else.
1589-define(otp_4956_mg_decode_msg_fun(Mod, Conf),
1590	otp_4956_mg_decode_msg_fun(Mod, Conf)).
1591-define(otp_4956_mg_encode_msg_fun(Mod, Conf),
1592	otp_4956_mg_encode_msg_fun(Mod, Conf)).
1593-define(otp_4956_mg_verify_service_change_rep_msg_fun(),
1594	otp_4956_mg_verify_service_change_rep_msg_fun()).
1595-define(otp_4956_mg_verify_pending_msg_fun(),
1596	otp_4956_mg_verify_pending_msg_fun()).
1597-define(otp_4956_mg_verify_pending_limit_msg_fun(),
1598	otp_4956_mg_verify_pending_limit_msg_fun()).
1599-endif.
1600
1601otp_4956_mg_event_sequence(text, tcp) ->
1602    DecodeFun = ?otp_4956_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
1603    EncodeFun = ?otp_4956_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
1604    Mid = {deviceName,"mg"},
1605    ServiceChangeReq = otp_4956_mg_service_change_request_msg(Mid, 1, 0),
1606    TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
1607    NotifyReq = otp_4956_mg_notify_request_msg(Mid, 2, 1, TermId, 1),
1608    ServiceChangeReplyVerifyFun = ?otp_4956_mg_verify_service_change_rep_msg_fun(),
1609    PendingVerify               = ?otp_4956_mg_verify_pending_msg_fun(),
1610    PendingLimitVerify          = ?otp_4956_mg_verify_pending_limit_msg_fun(),
1611%%     ServiceChangeReplyVerifyFun =
1612%% 	otp_4956_mg_verify_service_change_rep_msg_fun(),
1613%%     PendingVerify = otp_4956_mg_verify_pending_msg_fun(),
1614%%     PendingLimitVerify = otp_4956_mg_verify_pending_limit_msg_fun(),
1615    EvSeq = [{debug,  true},
1616	     {decode, DecodeFun},
1617	     {encode, EncodeFun},
1618	     {connect, 2944},
1619	     {send, "service-change-request", ServiceChangeReq},
1620	     {expect_receive, "service-change-reply", {ServiceChangeReplyVerifyFun, 10000}},
1621	     {send, "notify request (first send)", NotifyReq},
1622	     {sleep, 100},
1623	     {send, "notify request (resend 1)", NotifyReq},
1624	     {expect_receive, "pending 1", {PendingVerify, 1000}},
1625	     {sleep, 1000},
1626	     {send, "notify request (resend 2)", NotifyReq},
1627	     {expect_receive, "pending 2", {PendingVerify, 1000}},
1628	     {sleep, 1000},
1629	     {send, "notify request (resend 3)", NotifyReq},
1630	     {expect_receive, "pending 3", {PendingVerify, 1000}},
1631	     {sleep, 1000},
1632	     {send, "notify request (resend 4)", NotifyReq},
1633	     {expect_receive, "pending 4", {PendingVerify, 1000}},
1634	     {sleep, 1000},
1635	     {send, "notify request (resend 5)", NotifyReq},
1636	     {expect_receive, "pending limit exceeded",
1637	      {PendingLimitVerify, 1000}},
1638	     {sleep, 4000},
1639	     {send, "notify request (resend 6)", NotifyReq},
1640	     {expect_nothing, 4000},
1641	     disconnect
1642	    ],
1643    EvSeq.
1644
1645-ifndef(megaco_hipe_special).
1646otp_4956_mg_encode_msg_fun(Mod, Conf) ->
1647    fun(M) ->
1648            encode_msg(M, Mod, Conf)
1649    end.
1650
1651otp_4956_mg_decode_msg_fun(Mod, Conf) ->
1652    fun(M) ->
1653            decode_msg(M, Mod, Conf)
1654    end.
1655-endif.
1656
1657-ifndef(megaco_hipe_special).
1658otp_4956_mg_verify_service_change_rep_msg_fun() ->
1659    fun(M) ->
1660	    otp_4956_mg_verify_service_change_rep_msg(M)
1661    end.
1662-endif.
1663
1664otp_4956_mg_verify_service_change_rep_msg(
1665  #'MegacoMessage'{mess = Mess} = M) ->
1666    io:format("otp_4956_mg_verify_service_change_rep_msg -> "
1667	      "ok so far~n",[]),
1668    #'Message'{version     = _V,
1669	       mId         = _MgMid,
1670	       messageBody = Body} = Mess,
1671    {transactions, [Trans]} = Body,
1672    {transactionReply, TR} = Trans,
1673    #'TransactionReply'{transactionId = _Tid,
1674			immAckRequired = asn1_NOVALUE,
1675			transactionResult = Res} = TR,
1676    {actionReplies, [AR]} = Res,
1677    #'ActionReply'{contextId = _Cid,
1678		   errorDescriptor = asn1_NOVALUE,
1679		   contextReply = _CtxReq,
1680		   commandReply = [CR]} = AR,
1681    {serviceChangeReply, SCR} = CR,
1682    #'ServiceChangeReply'{terminationID = _TermID,
1683			  serviceChangeResult = SCRes} = SCR,
1684    {serviceChangeResParms, SCRP} = SCRes,
1685    #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} = SCRP,
1686    {ok, M};
1687otp_4956_mg_verify_service_change_rep_msg(M) ->
1688    {error, {invalid_message, M}}.
1689
1690-ifndef(megaco_hipe_special).
1691otp_4956_mg_verify_pending_msg_fun() ->
1692    fun(M) ->
1693	    otp_4956_mg_verify_pending_msg(M)
1694    end.
1695-endif.
1696
1697otp_4956_mg_verify_pending_msg(#'MegacoMessage'{mess = Mess} = M) ->
1698    io:format("otp_4956_mg_verify_pending_msg -> entry with"
1699	      "~n   Mess. ~p"
1700	      "~n", [Mess]),
1701    #'Message'{messageBody = Body} = Mess,
1702    {transactions, [Trans]} = Body,
1703    {transactionPending, TP} = Trans,
1704    #'TransactionPending'{transactionId = _Id} = TP,
1705    io:format("otp_4956_mg_verify_pending_msg -> done~n", []),
1706    {ok, M};
1707otp_4956_mg_verify_pending_msg(M) ->
1708    io:format("otp_4956_mg_verify_pending_msg -> entry with"
1709	      "~n   M: ~p"
1710	      "~n", [M]),
1711    {error, {invalid_message, M}}.
1712
1713-ifndef(megaco_hipe_special).
1714otp_4956_mg_verify_pending_limit_msg_fun() ->
1715    fun(M) ->
1716	    otp_4956_mg_verify_pending_limit_msg(M)
1717    end.
1718-endif.
1719
1720otp_4956_mg_verify_pending_limit_msg(#'MegacoMessage'{mess = Mess} = M) ->
1721    io:format("otp_4956_mg_verify_pending_limit_msg -> entry with"
1722	      "~n   Mess: ~p"
1723	      "~n", [Mess]),
1724    #'Message'{messageBody = Body} = Mess,
1725    {transactions, [Trans]} = Body,
1726    {transactionReply, TR} = Trans,
1727    case element(4, TR) of
1728	{transactionError, ED} ->
1729	    EC = ?megaco_number_of_transactionpending_exceeded,
1730	    #'ErrorDescriptor'{errorCode = EC} = ED,
1731	    {ok, M};
1732	_ ->
1733	    {error, {invalid_transactionReply, TR}}
1734    end;
1735otp_4956_mg_verify_pending_limit_msg(M) ->
1736    io:format("otp_4956_mg_verify_pending_limit_msg -> entry with"
1737	      "~n   M: ~p"
1738	      "~n", [M]),
1739    {error, {invalid_message, M}}.
1740
1741otp_4956_mg_service_change_request_ar(_Mid, Cid) ->
1742    Prof  = cre_serviceChangeProf("resgw", 1),
1743    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
1744    Root  = #megaco_term_id{id = ["root"]},
1745    SCR   = cre_serviceChangeReq([Root], SCP),
1746    CMD   = cre_command(SCR),
1747    CR    = cre_cmdReq(CMD),
1748    cre_actionReq(Cid, [CR]).
1749
1750otp_4956_mg_service_change_request_msg(Mid, TransId, Cid) ->
1751    AR    = otp_4956_mg_service_change_request_ar(Mid, Cid),
1752    TR    = cre_transReq(TransId, [AR]),
1753    Trans = cre_transaction(TR),
1754    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1755    cre_megacoMessage(Mess).
1756
1757otp_4956_mg_notify_request_ar(Rid, Tid, Cid) ->
1758    TT      = cre_timeNotation("19990729", "22000000"),
1759    Ev      = cre_obsEvent("al/of", TT),
1760    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
1761    NR      = cre_notifyReq([Tid], EvsDesc),
1762    CMD     = cre_command(NR),
1763    CR      = cre_cmdReq(CMD),
1764    cre_actionReq(Cid, [CR]).
1765
1766otp_4956_mg_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
1767    AR      = otp_4956_mg_notify_request_ar(Rid, TermId, Cid),
1768    TR      = cre_transReq(TransId, [AR]),
1769    Trans   = cre_transaction(TR),
1770    Mess    = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1771    cre_megacoMessage(Mess).
1772
1773
1774otp_4956_err_desc(T) ->
1775    EC = ?megaco_internal_gateway_error,
1776    ET = lists:flatten(io_lib:format("~w",[T])),
1777    #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
1778
1779
1780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1781
1782otp_5310(suite) ->
1783    [];
1784otp_5310(doc) ->
1785    "...";
1786otp_5310(Config) when is_list(Config) ->
1787    put(verbosity, ?TEST_VERBOSITY),
1788    put(sname,     "TEST"),
1789    put(tc,        otp_5310),
1790    i("starting"),
1791
1792    MgcNode = make_node_name(mgc),
1793    MgNode  = make_node_name(mg),
1794    d("start nodes: "
1795      "~n      MgcNode: ~p"
1796      "~n      MgNode:  ~p",
1797      [MgcNode, MgNode]),
1798    ok = ?START_NODES([MgcNode, MgNode], true),
1799
1800    %% Start the MGC and MGs
1801    i("[MGC] start"),
1802    ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
1803    {ok, Mgc} =
1804	?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
1805
1806    i("[MG] start"),
1807    MgMid = {deviceName, "mg"},
1808    MgConfig = [],
1809    {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
1810
1811    d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
1812
1813    i("[MG] connect to the MGC (service change)"),
1814    ServChRes = ?MG_SERV_CHANGE(Mg),
1815    d("service change result: ~p", [ServChRes]),
1816
1817    d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
1818
1819    d("[MGC] update connection info pending timer"),
1820    PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(1),
1821				      factor   = 1},
1822    ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
1823
1824    d("[MGC] update connection info originating pending limit"),
1825    PendingLimit = 3,
1826    ?MGC_UPDATE_CI(Mgc, orig_pending_limit, PendingLimit),
1827
1828    ConnReps1 = ?MGC_CONN_INFO(Mgc, replies),
1829    d("[MGC] ConnReps1: ~p", [ConnReps1]),
1830    case filter_aborted1(ConnReps1, []) of
1831	[{_, []}] ->
1832	    ok;
1833	ConnFlt1 ->
1834	    ?ERROR({unexpected_reply_state, conn_info, ConnReps1, ConnFlt1})
1835    end,
1836    UserReps1 = ?MGC_USER_INFO(Mgc, replies),
1837    d("[MGC] UserReps1: ~p", [UserReps1]),
1838    case filter_aborted1(UserReps1, []) of
1839	[{_, []}] ->
1840	    ok;
1841	UserFlt1 ->
1842	    ?ERROR({unexpected_reply_state, user_info, UserReps1, UserFlt1})
1843    end,
1844
1845    %% Instruct the MGC to never reply to requests
1846    d("[MGC] don't reply to requests"),
1847    ?MGC_REQ_IGNORE(Mgc),
1848
1849    %% We want to know when the abort comes...
1850    d("[MGC] request abort inform"),
1851    ?MGC_ABORT_INFO(Mgc, self()),
1852
1853    %% Make MG send a request
1854    d("[MG] send the notify"),
1855    {ok, {_ProtocolVersion, {error, ED}}} = ?MG_NOTIF_RAR(Mg),
1856    d("[MG] ED: ~p", [ED]),
1857    ErrorCode = ?megaco_number_of_transactionpending_exceeded,
1858    ErrorCode = ED#'ErrorDescriptor'.errorCode,
1859
1860    %% Wait for the MGC to get aborted
1861    d("[MGC] await the abort callback"),
1862    {ok, TransId} = await_aborted(Mgc),
1863    d("[MGC] aborted transaction: ~p", [TransId]),
1864
1865    %% Make sure we have one in aborted state
1866    d("[MGC] how many is aborted (should be == 1)?"),
1867    ConnReps2 = ?MGC_CONN_INFO(Mgc, replies),
1868    case filter_aborted1(ConnReps2, []) of
1869	[{_, [TransId]}] ->
1870	    ok;
1871	[{_, []}] ->
1872	    ok; % has already been cleaned up...
1873	ConnFlt2 ->
1874	    ?ERROR({unexpected_reply_state, conn_info, ConnReps2, ConnFlt2})
1875    end,
1876    d("[MGC] ConnReps2: ~p", [ConnReps2]),
1877    UserReps2 = ?MGC_USER_INFO(Mgc, replies),
1878    d("[MGC] UserReps2: ~p", [UserReps2]),
1879    case filter_aborted1(UserReps2, []) of
1880	[{_, [TransId]}] ->
1881	    ok;
1882	[{_, []}] ->
1883	    ok; % has already been cleaned up...
1884	UserFlt2 ->
1885	    ?ERROR({unexpected_reply_state, user_info, UserReps2, UserFlt2})
1886    end,
1887
1888    %% do disconnect and the do cancel in the handle function
1889    d("[MGC] disconnect"),
1890    DiscoRes = ?MGC_DISCO(Mgc, cancel),
1891    d("[MGC] DiscoRes: ~p", [DiscoRes]),
1892
1893    %% check number of reply records (should be no in aborted).
1894    d("[MGC] check number of replies in aborted state (should be == 1)"),
1895    ConnReps3 = ?MGC_CONN_INFO(Mgc, replies),
1896    d("[MGC] ConnReps3: ~p", [ConnReps3]),
1897    UserReps3 = ?MGC_USER_INFO(Mgc, replies),
1898    d("[MGC] UserReps3: ~p", [UserReps3]),
1899
1900    %% Tell MG to stop
1901    i("[MG] stop"),
1902    ?MG_STOP(Mg),
1903
1904    %% Tell Mgc to stop
1905    i("[MGC] stop"),
1906    ?MGC_STOP(Mgc),
1907
1908    %% Cleanup
1909    d("stop nodes"),
1910    ?STOP_NODES([MgcNode, MgNode]),
1911
1912    i("done", []),
1913    ok.
1914
1915await_aborted(Mgc) ->
1916    d("await_aborted"),
1917    receive
1918	{abort_received, Mgc, TransId} ->
1919	    {ok, TransId}
1920    after 10000 ->
1921	    d("await_aborted - timeout"),
1922	    {error, timeout}
1923    end.
1924
1925filter_aborted1([], Acc) ->
1926    lists:reverse(Acc);
1927filter_aborted1([{CH, Ab}|T], Acc) ->
1928    filter_aborted1(T, [{CH, filter_aborted2(Ab, [])}|Acc]).
1929
1930filter_aborted2([], Aborted) ->
1931    lists:reverse(Aborted);
1932filter_aborted2([{TransId, aborted, _}|T], Aborted) ->
1933    filter_aborted2(T, [TransId|Aborted]);
1934filter_aborted2([{TransId, State, _}|T], Aborted) ->
1935    d("Transaction ~w actually in state ~w", [TransId, State]),
1936    filter_aborted2(T, Aborted);
1937filter_aborted2([_|T], Aborted) ->
1938    filter_aborted2(T, Aborted).
1939
1940
1941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942
1943%% The timeout times is a little odd in this test case. The (short)
1944%% request timer is longer then the (long) request timer. This is
1945%% simply to produce the effect that we want regarding max_retries =
1946%% infinity_restartable. Also the pending timeout has to be shorter
1947%% then "short" + "long" and longer then "long"
1948
1949otp_5619(suite) ->
1950    [];
1951otp_5619(doc) ->
1952    "...";
1953otp_5619(Config) when is_list(Config) ->
1954    put(verbosity, ?TEST_VERBOSITY),
1955    put(sname,     "TEST"),
1956    put(tc,        otp_5619),
1957    i("starting"),
1958
1959    MgcNode = make_node_name(mgc),
1960    MgNode  = make_node_name(mg),
1961    d("start nodes: "
1962      "~n      MgcNode: ~p"
1963      "~n      MgNode:  ~p",
1964      [MgcNode, MgNode]),
1965    ok = ?START_NODES([MgcNode, MgNode], true),
1966
1967    %% Start the MGC and MGs
1968    i("[MGC] start"),
1969    MgcMid = {deviceName, "ctrl"},
1970    ET = [{text, tcp}, {text, udp}, {binary, tcp}, {binary, udp}],
1971    {ok, Mgc} = ?MGC_START(MgcNode, MgcMid, ET, [], ?MGC_VERBOSITY),
1972
1973    i("[MG] start"),
1974    MgMid = {deviceName, "mg"},
1975    MgConfig = [],
1976    {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
1977
1978    d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
1979    d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
1980
1981    i("[MG] connect to the MGC (service change)"),
1982    ServChRes = ?MG_SERV_CHANGE(Mg),
1983    d("service change result: ~p", [ServChRes]),
1984
1985    d("[MG] update connection info long request timer"),
1986    LongReqTmr = #megaco_incr_timer{wait_for    = timer:seconds(1),
1987				    factor      = 1,
1988				    max_retries = infinity_restartable},
1989    ?MG_UPDATE_CI(Mg, long_request_timer, LongReqTmr),
1990
1991    d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
1992
1993    d("MGC conn info: ~p", [?MGC_CONN_INFO(Mgc, all)]),
1994
1995    d("[MGC] update connection info pending timer"),
1996    PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(3),
1997				      factor   = 1},
1998    ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
1999
2000    d("[MGC] update connection info sent pending limit"),
2001    PendingLimit = 5,
2002    ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
2003
2004    d("MGC conn info: ~p", [?MG_CONN_INFO(Mgc, all)]),
2005
2006
2007    d("[MGC] late reply to requests "
2008      "(simulate that the request takes a long time)"),
2009    {ok, _} = ?MGC_REQ_DISC(Mgc, 11000),
2010
2011
2012    d("[MG] send the notify and await the timeout"),
2013    {ok, Reply} = ?MG_NOTIF_RAR(Mg),
2014    case Reply of
2015	{_Version, {error, timeout}} ->
2016	    d("[MG] expected reply (timeout) received~n", []);
2017	_ ->
2018	    ?ERROR({unexpected_reply, Reply})
2019    end,
2020
2021
2022    %% Tell MG to stop
2023    i("[MG] stop~n"),
2024    ?MG_STOP(Mg),
2025
2026    %% Tell Mgc to stop
2027    i("[MGC] stop~n"),
2028    ?MGC_STOP(Mgc),
2029
2030    %% Cleanup
2031    d("stop nodes"),
2032    ?STOP_NODES([MgcNode, MgNode]),
2033
2034    i("done", []),
2035    ok.
2036
2037
2038%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2039
2040
2041%%
2042%% Common message creation functions
2043%%
2044
2045cre_serviceChangeParm(M,R,P) ->
2046    #'ServiceChangeParm'{serviceChangeMethod  = M,
2047                         serviceChangeReason  = R,
2048                         serviceChangeProfile = P}.
2049
2050cre_serviceChangeReq(Tid, Parms) ->
2051    #'ServiceChangeRequest'{terminationID      = Tid,
2052                            serviceChangeParms = Parms}.
2053
2054cre_timeNotation(D,T) ->
2055    #'TimeNotation'{date = D, time = T}.
2056
2057cre_obsEvent(Name, Not) ->
2058    #'ObservedEvent'{eventName    = Name,
2059                     timeNotation = Not}.
2060%% cre_obsEvent(Name, Not, Par) ->
2061%%     #'ObservedEvent'{eventName    = Name,
2062%%                      timeNotation = Not,
2063%%                      eventParList = Par}.
2064
2065cre_obsEvsDesc(Id, EvList) ->
2066    #'ObservedEventsDescriptor'{requestId        = Id,
2067                                observedEventLst = EvList}.
2068
2069cre_notifyReq(Tid, EvsDesc) ->
2070    #'NotifyRequest'{terminationID            = Tid,
2071                     observedEventsDescriptor = EvsDesc}.
2072
2073cre_command(R) when is_record(R, 'NotifyRequest') ->
2074    {notifyReq, R};
2075cre_command(R) when is_record(R, 'ServiceChangeRequest') ->
2076    {serviceChangeReq, R}.
2077
2078cre_cmdReq(Cmd) ->
2079    #'CommandRequest'{command = Cmd}.
2080
2081cre_actionReq(CtxId, CmdReqs) when is_list(CmdReqs) ->
2082    #'ActionRequest'{contextId       = CtxId,
2083                     commandRequests = CmdReqs}.
2084
2085cre_transReq(TransId, ARs) when is_list(ARs) ->
2086    #'TransactionRequest'{transactionId = TransId,
2087			  actions       = ARs}.
2088
2089%% --
2090
2091cre_serviceChangeResParm(Mid) ->
2092    cre_serviceChangeResParm(Mid, ?VERSION).
2093
2094cre_serviceChangeResParm(Mid, V) ->
2095    #'ServiceChangeResParm'{serviceChangeMgcId   = Mid,
2096			    serviceChangeVersion = V}.
2097
2098cre_serviceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
2099    {serviceChangeResParms, SCRP};
2100cre_serviceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
2101    {errorDescriptor, ED}.
2102
2103cre_serviceChangeReply(Tid, Res) ->
2104    #'ServiceChangeReply'{terminationID       = Tid,
2105                          serviceChangeResult = Res}.
2106
2107cre_cmdReply(R) when is_record(R, 'NotifyReply') ->
2108    {notifyReply, R};
2109cre_cmdReply(R) when is_record(R, 'ServiceChangeReply') ->
2110    {serviceChangeReply, R}.
2111
2112cre_notifyReply(Tid) ->
2113    #'NotifyReply'{terminationID = Tid}.
2114
2115cre_actionReply(CtxId, CmdRep) ->
2116    #'ActionReply'{contextId    = CtxId,
2117                   commandReply = CmdRep}.
2118
2119%% cre_transResult(ED) when record(ED, 'ErrorDescriptor') ->
2120%%     {transactionError, ED};
2121%% cre_transResult([AR|_] = ARs) when record(AR, 'ActionReply') ->
2122%%     {actionReplies, ARs}.
2123
2124%% cre_transReply(TransId, Res) ->
2125%%     #'TransactionReply'{transactionId     = TransId,
2126%%                         transactionResult = Res}.
2127
2128%% --
2129
2130cre_serviceChangeProf(Name, Ver) when is_list(Name) andalso is_integer(Ver) ->
2131    #'ServiceChangeProfile'{profileName = Name,
2132                            version     = Ver}.
2133
2134cre_transaction(Trans) when is_record(Trans, 'TransactionRequest') ->
2135    {transactionRequest, Trans};
2136cre_transaction(Trans) when is_record(Trans, 'TransactionPending') ->
2137    {transactionPending, Trans};
2138cre_transaction(Trans) when is_record(Trans, 'TransactionReply') ->
2139    {transactionReply, Trans};
2140cre_transaction(Trans) when is_record(Trans, 'TransactionAck') ->
2141    {transactionResponseAck, Trans}.
2142
2143cre_transactions(Trans) when is_list(Trans) ->
2144    {transactions, Trans}.
2145
2146cre_message(Version, Mid, Body) ->
2147    #'Message'{version     = Version,
2148               mId         = Mid,
2149               messageBody = Body}.
2150
2151cre_megacoMessage(Mess) ->
2152    #'MegacoMessage'{mess = Mess}.
2153
2154
2155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2156
2157%% Transform a short timer to a long one.
2158%% The purpose of this is to trick the stack
2159%% to keep re-sending the request, even after
2160%% having received the first pending (which
2161%% indicates that the other side _IS_
2162%% working on the request).
2163-ifdef(MEGACO_TEST_CODE).
2164
2165init_request_timer({short, Ref}) ->
2166    {long, Ref};
2167init_request_timer(O) ->
2168    O.
2169
2170-endif.
2171
2172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2173
2174encode_msg(M, Mod, Conf) ->
2175    Mod:encode_message(Conf, M).
2176
2177%% encode_msg(M, Mod, Conf, Ver) ->
2178%%     Mod:encode_message(Conf, Ver, M).
2179
2180decode_msg(M, Mod, Conf) ->
2181    Mod:decode_message(Conf, M).
2182
2183%% decode_msg(M, Mod, Conf, Ver) ->
2184%%     Mod:decode_message(Conf, Ver, M).
2185
2186
2187
2188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2189
2190
2191%% tim() ->
2192%%     {A,B,C} = erlang:now(),
2193%%     A*1000000000+B*1000+(C div 1000).
2194
2195
2196make_node_name(Name) ->
2197    case string:tokens(atom_to_list(node()), [$@]) of
2198	[_,Host] ->
2199	    list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
2200	_ ->
2201	    exit("Test node must be started with '-sname'")
2202     end.
2203
2204
2205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2206
2207await_completion(Ids) ->
2208    case megaco_test_generator_lib:await_completion(Ids) of
2209	{ok, Reply} ->
2210	    d("OK => Reply: ~n~p", [Reply]),
2211	    ok;
2212	{error, Reply} ->
2213	    d("ERROR => Reply: ~n~p", [Reply]),
2214	    ?ERROR({failed, Reply})
2215    end.
2216
2217
2218
2219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220
2221sleep(X) -> receive after X -> ok end.
2222
2223
2224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2225
2226p(F, A) ->
2227    io:format("*** [~s] ~p ***"
2228	      "~n   " ++ F ++ "~n",
2229	      [?FTS(), self() | A]).
2230
2231
2232i(F) ->
2233    i(F, []).
2234
2235i(F, A) ->
2236    print(info, get(verbosity), get(tc), "INF", F, A).
2237
2238
2239d(F) ->
2240    d(F, []).
2241
2242d(F, A) ->
2243    print(debug, get(verbosity), get(tc), "DBG", F, A).
2244
2245
2246printable(_, debug)   -> true;
2247printable(info, info) -> true;
2248printable(_,_)        -> false.
2249
2250print(Severity, Verbosity, Tc, P, F, A) ->
2251    print(printable(Severity,Verbosity), Tc, P, F, A).
2252
2253print(true, Tc, P, F, A) ->
2254    io:format("*** [~s] ~s ~p ~s:~w ***"
2255	      "~n   " ++ F ++ "~n",
2256	      [?FTS(), P, self(), get(sname), Tc | A]);
2257print(_, _, _, _, _) ->
2258    ok.
2259
2260
2261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2262
2263