1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2006-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 the segment package introduced in v3 of the megaco std.
24%%----------------------------------------------------------------------
25
26-module(megaco_segment_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	 send_segmented_msg_plain1/1,
35	 send_segmented_msg_plain2/1,
36	 send_segmented_msg_plain3/1,
37	 send_segmented_msg_plain4/1,
38	 send_segmented_msg_ooo1/1,
39	 send_segmented_msg_missing_seg_reply1/1,
40	 send_segmented_msg_missing_seg_reply2/1,
41
42
43	 recv_segmented_msg_plain/1,
44	 recv_segmented_msg_ooo_seg/1,
45	 recv_segmented_msg_missing_seg1/1,
46	 recv_segmented_msg_missing_seg2/1
47
48	]).
49
50-include_lib("common_test/include/ct.hrl").
51-include("megaco_test_lib.hrl").
52-include_lib("megaco/include/megaco.hrl").
53-include_lib("megaco/include/megaco_message_v3.hrl").
54
55-define(TEST_VERBOSITY, debug).
56
57-define(VERSION, 3).
58
59
60%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61
62%%======================================================================
63%% Common Test interface functions
64%%======================================================================
65
66suite() ->
67    [{ct_hooks, [ts_install_cth]}].
68
69all() ->
70    [
71     {group, send},
72     {group, recv}
73    ].
74
75groups() ->
76    [
77     {send, [], send_cases()},
78     {recv, [], recv_cases()}
79    ].
80
81send_cases() ->
82    [
83     send_segmented_msg_plain1,
84     send_segmented_msg_plain2,
85     send_segmented_msg_plain3,
86     send_segmented_msg_plain4,
87     send_segmented_msg_ooo1,
88     send_segmented_msg_missing_seg_reply1,
89     send_segmented_msg_missing_seg_reply2
90    ].
91
92recv_cases() ->
93    [
94     recv_segmented_msg_plain,
95     recv_segmented_msg_ooo_seg,
96     recv_segmented_msg_missing_seg1,
97     recv_segmented_msg_missing_seg2
98    ].
99
100
101
102%%
103%% -----
104%%
105
106init_per_suite(suite) ->
107    [];
108init_per_suite(doc) ->
109    [];
110init_per_suite(Config0) when is_list(Config0) ->
111
112    ?ANNOUNCE_SUITE_INIT(),
113
114    p("init_per_suite -> entry with"
115      "~n      Config: ~p"
116      "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
117
118    case ?LIB:init_per_suite(Config0) of
119        {skip, _} = SKIP ->
120            SKIP;
121
122        Config1 when is_list(Config1) ->
123
124            %% We need a (local) monitor on this node also
125            megaco_test_sys_monitor:start(),
126
127            p("init_per_suite -> end when"
128              "~n      Config: ~p"
129              "~n      Nodes:  ~p", [Config1, erlang:nodes()]),
130
131            Config1
132    end.
133
134end_per_suite(suite) -> [];
135end_per_suite(doc) -> [];
136end_per_suite(Config0) when is_list(Config0) ->
137
138    p("end_per_suite -> entry with"
139      "~n      Config: ~p"
140      "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
141
142    megaco_test_sys_monitor:stop(),
143    Config1 = ?LIB:end_per_suite(Config0),
144
145    p("end_per_suite -> end when"
146      "~n      Nodes:  ~p", [erlang:nodes()]),
147
148    Config1.
149
150
151
152%%
153%% -----
154%%
155
156init_per_group(Group, Config) ->
157    ?ANNOUNCE_GROUP_INIT(Group),
158    Config.
159
160end_per_group(_Group, Config) ->
161    Config.
162
163
164
165init_per_testcase(Case, Config) ->
166    process_flag(trap_exit, true),
167
168    p("init_per_testcase -> entry with"
169      "~n      Config: ~p"
170      "~n      Nodes:  ~p", [Config, erlang:nodes()]),
171
172    megaco_test_global_sys_monitor:reset_events(),
173    megaco_test_lib:init_per_testcase(Case, Config).
174
175end_per_testcase(Case, Config) ->
176    process_flag(trap_exit, false),
177
178    p("end_per_testcase -> entry with"
179      "~n      Config: ~p"
180      "~n      Nodes:  ~p", [Config, erlang:nodes()]),
181
182    p("system events during test: "
183      "~n   ~p", [megaco_test_global_sys_monitor:events()]),
184
185    megaco_test_lib:end_per_testcase(Case, Config).
186
187
188
189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190%%%                                                                   %%%
191%%%                 Segmented reply send test cases                   %%%
192%%%                                                                   %%%
193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194
195send_segmented_msg_plain1(suite) ->
196    [];
197send_segmented_msg_plain1(doc) ->
198    "First plain test that it is possible to send segmented messages. "
199	"Send window = infinity. ";
200send_segmented_msg_plain1(Config) when is_list(Config) ->
201    Pre = fun() ->
202                  MgcNode = make_node_name(mgc),
203                  MgNode  = make_node_name(mg),
204                  d("start nodes: "
205                    "~n   MgcNode: ~p"
206                    "~n   MgNode:  ~p",
207                    [MgcNode, MgNode]),
208                  Nodes = [MgcNode, MgNode],
209                  ok = ?START_NODES(Nodes),
210                  Nodes
211          end,
212    Case = fun do_send_segmented_msg_plain1/1,
213    Post = fun(Nodes) ->
214                   d("stop nodes"),
215                   ?STOP_NODES(lists:reverse(Nodes))
216           end,
217    try_tc(ssmp1, Pre, Case, Post).
218
219do_send_segmented_msg_plain1([MgcNode, MgNode]) ->
220
221    d("[MGC] start the simulator "),
222    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
223
224    d("[MGC] create the event sequence"),
225    MgcEvSeq = ssmp1_mgc_event_sequence(text, tcp),
226
227    i("wait some time before starting the MGC simulation"),
228    sleep(1000),
229
230    d("[MGC] start the simulation"),
231    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
232
233    i("wait some time before starting the MG simulator"),
234    sleep(1000),
235
236    d("[MG] start the simulator (generator)"),
237    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
238
239    d("[MG] create the event sequence"),
240    MgEvSeq = ssmp1_mg_event_sequence(text, tcp),
241
242    i("wait some time before starting the MG simulation"),
243    sleep(1000),
244
245    d("[MG] start the simulation"),
246    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
247
248    d("await the generator reply(s)"),
249    await_completion([MgcId, MgId]),
250
251    %% Tell Mgc to stop
252    i("[MGC] stop generator"),
253    megaco_test_tcp_generator:stop(Mgc),
254
255    %% Tell Mg to stop
256    i("[MG] stop generator"),
257    megaco_test_megaco_generator:stop(Mg),
258
259    i("done", []),
260    ok.
261
262
263
264%%
265%% MGC generator stuff
266%%
267
268ssmp1_mgc_event_sequence(text, tcp) ->
269    DecodeFun = ssmp1_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
270    EncodeFun = ssmp1_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
271    Mid       = {deviceName,"mgc"},
272    ScrVerifyFun     = ssmp1_mgc_verify_service_change_req_msg_fun(),
273    ServiceChangeRep = ssmp1_mgc_service_change_reply_msg(Mid, 1),
274    TermId1   =
275	#megaco_term_id{id = ["00000000","00000000","00000001"]},
276    CtxId1    = 1,
277    TermId2   =
278	#megaco_term_id{id = ["00000000","00000000","00000002"]},
279    CtxId2    = 2,
280    TransId   = 2,
281    NotifyReq = ssmp1_mgc_notify_request_msg(Mid, TransId,
282					    TermId1, CtxId1,
283					    TermId2, CtxId2),
284    NrVerifyFun1 =
285	ssmp1_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
286						     TermId1, CtxId1),
287    NrVerifyFun2 =
288	ssmp1_mgc_verify_notify_reply_segment_msg_fun(2, true, TransId,
289						     TermId2, CtxId2),
290    SegmentRep1 = ssmp1_mgc_segment_reply_msg(Mid, TransId, 1, false),
291    SegmentRep2 = ssmp1_mgc_segment_reply_msg(Mid, TransId, 2, true),
292    TransAck    = ssmp1_mgc_trans_ack_msg(Mid, TransId),
293    EvSeq = [{debug,  true},
294             {decode, DecodeFun},
295             {encode, EncodeFun},
296             {listen, 2944},
297	     {expect_accept, any},
298             {expect_receive, "service-change-request",  {ScrVerifyFun, 5000}},
299             {send, "service-change-reply",              ServiceChangeRep},
300	     {expect_nothing, timer:seconds(1)},
301             {send, "notify request",                    NotifyReq},
302             {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 2000}},
303             {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
304             {send, "segment reply 1",                   SegmentRep1},
305	     {sleep, 100},
306             {send, "segment reply 2",                   SegmentRep2},
307	     {sleep, 100}, % {expect_nothing, 500},
308	     {send, "transaction-ack",                   TransAck},
309             {expect_closed,  timer:seconds(5)},
310             disconnect
311            ],
312    EvSeq.
313
314ssmp1_mgc_encode_msg_fun(Mod, Conf) ->
315    fun(M) ->
316            Mod:encode_message(Conf, M)
317    end.
318
319ssmp1_mgc_decode_msg_fun(Mod, Conf) ->
320    fun(M) ->
321            Mod:decode_message(Conf, M)
322    end.
323
324ssmp1_mgc_verify_service_change_req_msg_fun() ->
325    fun(Msg) ->
326	    (catch ssmp1_mgc_verify_service_change_req(Msg))
327    end.
328
329ssmp1_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
330    io:format("ssmp1_mgc_verify_service_change_req -> entry with"
331	      "~n   M: ~p"
332	      "~n", [M]),
333    Body =
334	case Mess of
335	    #'Message'{version     = 1,
336                       mId         = _MgMid,
337                       messageBody = MsgBody} ->
338		MsgBody;
339	    _ ->
340		throw({error, {invalid_Message, Mess}})
341	end,
342    Trans =
343	case Body of
344            {transactions, [Transactions]} ->
345		Transactions;
346	    _ ->
347		throw({error, {invalid_messageBody, Body}})
348	end,
349    TR =
350	case Trans of
351            {transactionRequest, TransRequest} ->
352		TransRequest;
353	    _ ->
354		throw({error, {invalid_transactions, Trans}})
355	end,
356    AR =
357	case TR of
358            #'TransactionRequest'{transactionId = _TransId,
359				  actions       = [ActionReq]} ->
360		ActionReq;
361	    _ ->
362		throw({error, {invalid_transactionRequest, TR}})
363	end,
364    CR =
365	case AR of
366	    #'ActionRequest'{contextId       = _Cid,
367			     commandRequests = [CmdReq]} ->
368		CmdReq;
369	    _ ->
370		throw({error, {invalid_action, AR}})
371	end,
372    Cmd =
373	case CR of
374	    #'CommandRequest'{command = Command} ->
375		Command;
376	    _ ->
377		throw({error, {invalid_commandRequest, CR}})
378	end,
379    {Tid, Parms} =
380	case Cmd of
381	    {serviceChangeReq,
382	     #'ServiceChangeRequest'{terminationID      = [TermID],
383				     serviceChangeParms = ServChParms}} ->
384		{TermID, ServChParms};
385	    _ ->
386		throw({error, {invalid_command, Cmd}})
387	end,
388    case Tid of
389	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
390	    ok;
391	_ ->
392	    throw({error, {invalid_terminationID, Tid}})
393    end,
394    case Parms of
395	%% Version 1 'ServiceChangeParm'
396	{'ServiceChangeParm',
397	 restart,                            % serviceChangeMethod
398	 asn1_NOVALUE,                       % serviceChangeAddress
399	 ?VERSION,                           % serviceChangeVersion,
400	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
401	 [[$9,$0,$1|_]],                     % serviceChangeReason
402	 asn1_NOVALUE,                       % serviceChangeDelay
403	 asn1_NOVALUE,                       % serviceChangeMgcId
404	 asn1_NOVALUE,                       % timeStamp
405	 asn1_NOVALUE                        % nonStandardData
406	} ->
407	    {ok, M};
408	_ ->
409	    {error, {invalid_serviceChangeParms, Parms}}
410    end.
411
412ssmp1_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
413					     TransId, TermId, Cid) ->
414    fun(Msg) ->
415	    (catch ssmp1_mgc_verify_notify_reply_segment(Msg,
416							SN, Last,
417							TransId, TermId, Cid))
418    end.
419
420ssmp1_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
421				     SN, Last, TransId, TermId, Cid) ->
422    io:format("ssmp1_mgc_verify_notify_reply_segment -> entry with"
423	      "~n   M:       ~p"
424	      "~n   SN:      ~p"
425	      "~n   Last:    ~p"
426	      "~n   TransId: ~p"
427	      "~n   TermId:  ~p"
428	      "~n   Cid:     ~p"
429	      "~n", [M, SN, Last, TransId, TermId, Cid]),
430    Body =
431	case Mess of
432	    #'Message'{version     = ?VERSION,
433                       mId         = _Mid,
434                       messageBody = MsgBody} ->
435		MsgBody;
436	    _ ->
437		throw({error, {invalid_Message, Mess}})
438	end,
439    Trans =
440	case Body of
441            {transactions, [Transactions]} ->
442		Transactions;
443	    _ ->
444		throw({error, {invalid_messageBody, Body}})
445	end,
446    TR =
447	case Trans of
448            {transactionReply, TransReply} ->
449		TransReply;
450	    _ ->
451		throw({error, {invalid_transactions, Trans}})
452	end,
453    TRes =
454	case TR of
455            #'TransactionReply'{transactionId        = TransId,
456				transactionResult    = TransRes,
457				segmentNumber        = SN,
458				segmentationComplete = asn1_NOVALUE} when (Last == false) ->
459		TransRes;
460            #'TransactionReply'{transactionId        = TransId,
461				transactionResult    = TransRes,
462				segmentNumber        = SN,
463				segmentationComplete = 'NULL'} when (Last == true) ->
464		TransRes;
465	    _ ->
466		throw({error, {invalid_transactionReply, TR}})
467	end,
468    AR =
469	case TRes of
470	    {actionReplies, [ActionReply]} ->
471		ActionReply;
472	    {actionReplies, ActionReplies} ->
473		throw({error, {invalid_actionReplies, ActionReplies}});
474	    _ ->
475		throw({error, {invalid_transactionResult, TRes}})
476	end,
477    CR =
478	case AR of
479	    #'ActionReply'{contextId    = Cid,
480			   commandReply = [CommandReply]} ->
481		CommandReply;
482	    #'ActionReply'{contextId    = Cid,
483			   commandReply = CommandReplies} ->
484		throw({error, {invalid_commandReplies, CommandReplies}});
485	    _ ->
486		throw({error, {invalid_actionReply, AR}})
487	end,
488    NR =
489	case CR of
490	    {notifyReply, NotifyReply} ->
491		NotifyReply;
492	    _ ->
493		throw({error, {invalid_commandReply, CR}})
494	end,
495    case NR of
496	#'NotifyReply'{terminationID   = [TermId],
497		       errorDescriptor = asn1_NOVALUE} ->
498	    {ok, M};
499	_ ->
500	    {error, {invalid_NotifyReply, NR}}
501    end;
502ssmp1_mgc_verify_notify_reply_segment(Crap,
503				     _SN, _Last, _TransId, _TermId, _Cid) ->
504    {error, {invalid_MegacoMessage, Crap}}.
505
506
507ssmp1_mgc_service_change_reply_msg(Mid, Cid) ->
508    SCRP  = cre_serviceChangeResParm(Mid),
509    SCRes = cre_serviceChangeResult(SCRP),
510    Root  = #megaco_term_id{id = ["root"]},
511    SCR   = cre_serviceChangeReply([Root], SCRes),
512    CR    = cre_cmdReply(SCR),
513    AR    = cre_actionReply(Cid, [CR]),
514    TRes  = cre_transResult([AR]),
515    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
516    Trans = cre_transaction(TR),
517    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
518    cre_megacoMessage(Mess).
519
520ssmp1_mgc_notify_request_msg(Mid, TransId, TermId1, Cid1, TermId2, Cid2) ->
521    AR1     = ssmp1_mgc_notify_request_ar(1, TermId1, Cid1),
522    AR2     = ssmp1_mgc_notify_request_ar(2, TermId2, Cid2),
523    TR      = cre_transReq(TransId, [AR1, AR2]),
524    Trans   = cre_transaction(TR),
525    Mess    = cre_message(?VERSION, Mid, cre_transactions([Trans])),
526    cre_megacoMessage(Mess).
527
528ssmp1_mgc_notify_request_ar(Rid, Tid, Cid) ->
529    TT      = cre_timeNotation(integer_to_list(19990720+Rid),
530			       integer_to_list(22000000+Rid)),
531    Ev      = cre_obsEvent("al/of", TT),
532    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
533    NR      = cre_notifyReq([Tid], EvsDesc),
534    CMD     = cre_command(NR),
535    CR      = cre_cmdReq(CMD),
536    cre_actionReq(Cid, [CR]).
537
538ssmp1_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
539    SR    = ssmp1_mgc_segment_reply(TransId, SN, Last),
540    Trans = cre_transaction(SR),
541    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
542    cre_megacoMessage(Mess).
543
544ssmp1_mgc_segment_reply(TransId, SN, true) ->
545    cre_segReply(TransId, SN, 'NULL');
546ssmp1_mgc_segment_reply(TransId, SN, false) ->
547    cre_segReply(TransId, SN, asn1_NOVALUE).
548
549ssmp1_mgc_trans_ack_msg(Mid, TransId) ->
550    TA    = cre_transAck(TransId),
551    Trans = cre_transaction([TA]),
552    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
553    cre_megacoMessage(Mess).
554
555
556%%
557%% MG generator stuff
558%%
559ssmp1_mg_event_sequence(text, tcp) ->
560    Mid = {deviceName,"mg"},
561    RI = [
562          {port,             2944},
563          {encoding_module,  megaco_pretty_text_encoder},
564          {encoding_config,  []},
565          {transport_module, megaco_tcp}
566         ],
567    ConnectVerify = ssmp1_mg_verify_handle_connect_fun(),
568    ServiceChangeReq = ssmp1_mg_service_change_request_ar(Mid, 1),
569    ServiceChangeReplyVerify = ssmp1_mg_verify_service_change_reply_fun(),
570    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
571    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
572    NotifyReqVerify = ssmp1_mg_verify_notify_request_fun(Tid1, Tid2),
573    AckVerify = ssmp1_mg_verify_ack_fun(),
574    EvSeq = [
575             {debug, true},
576             {megaco_trace, disable},
577             %% {megaco_trace, max},
578             megaco_start,
579             {megaco_start_user, Mid, RI, []},
580             start_transport,
581             {megaco_system_info, users},
582             {megaco_system_info, connections},
583             connect,
584             {megaco_callback, handle_connect, ConnectVerify},
585             megaco_connect,
586             {megaco_cast,     [ServiceChangeReq], []},
587             {megaco_callback, handle_connect,     ConnectVerify},
588             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
589	     {megaco_update_conn_info, protocol_version, ?VERSION},
590	     {megaco_update_conn_info, segment_send,     infinity},
591	     {megaco_update_conn_info, max_pdu_size,     128},
592             {sleep, 1000},
593             {megaco_callback, handle_trans_request, NotifyReqVerify},
594             {megaco_callback, handle_trans_ack,     AckVerify, 5000},
595             megaco_stop_user,
596             megaco_stop,
597             {sleep, 1000}
598            ],
599    EvSeq.
600
601
602ssmp1_mg_verify_handle_connect_fun() ->
603    fun(Ev) -> ssmp1_mg_verify_handle_connect(Ev) end.
604
605ssmp1_mg_verify_handle_connect({handle_connect, CH, 1}) ->
606    io:format("ssmp1_mg_verify_handle_connect -> ok"
607	      "~n   CH: ~p~n", [CH]),
608    {ok, CH, ok};
609ssmp1_mg_verify_handle_connect(Else) ->
610    io:format("ssmp1_mg_verify_handle_connect -> unknown"
611	      "~n   Else: ~p~n", [Else]),
612    {error, Else, ok}.
613
614
615ssmp1_mg_verify_service_change_reply_fun() ->
616    fun(Rep) -> ssmp1_mg_verify_scr(Rep) end.
617
618ssmp1_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
619    (catch ssmp1_mg_do_verify_scr(AR));
620ssmp1_mg_verify_scr(Crap) ->
621    io:format("ssmp1_mg_verify_scr -> error: "
622	      "~n   Crap: ~p"
623	      "~n", [Crap]),
624    {error, Crap, ok}.
625
626ssmp1_mg_do_verify_scr(AR) ->
627    io:format("ssmp1_mg_do_verify_scr -> ok: "
628	      "~n   AR: ~p~n", [AR]),
629    CR =
630	case AR of
631	    #'ActionReply'{commandReply = [CmdRep]} ->
632		CmdRep;
633	    _ ->
634		Reason1 = {invalid_action_reply, AR},
635		throw({error, Reason1, ok})
636	end,
637    SCR =
638	case CR of
639	    {serviceChangeReply, ServChRep} ->
640		ServChRep;
641	    _ ->
642		Reason2 = {invalid_command_reply, CR},
643		throw({error, Reason2, ok})
644	end,
645    {Tid, SCRes} =
646	case SCR of
647	    #'ServiceChangeReply'{terminationID       = [TermID],
648				  serviceChangeResult = Res} ->
649		{TermID, Res};
650	    _ ->
651		Reason3 = {invalid_service_change_reply, SCR},
652		throw({error, Reason3, ok})
653	end,
654    case Tid of
655	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
656	    ok;
657	_ ->
658	    Reason4 = {invalid_termination_id, Tid},
659	    throw({error, Reason4, ok})
660    end,
661    SCRParm =
662	case SCRes of
663	    {serviceChangeResParms, ServChResParms} ->
664		ServChResParms;
665	    _ ->
666		Reason5 = {invalid_serviceChangeResult, SCRes},
667		throw({error, Reason5, ok})
668	end,
669    case SCRParm of
670	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
671	    {ok, AR, ok};
672	_ ->
673	    Reason6 = {invalid_service_change_result, SCRParm},
674	    {error, Reason6, ok}
675    end.
676
677ssmp1_mg_verify_notify_request_fun(Tid1, Tid2) ->
678    fun(Req) ->
679	    ssmp1_mg_verify_notify_request(Req, Tid1, Tid2)
680    end.
681
682ssmp1_mg_verify_notify_request(
683  {handle_trans_request, _CH, ?VERSION, [AR1, AR2]}, Tid1, Tid2) ->
684    (catch ssmp1_mg_do_verify_notify_request(Tid1, Tid2, AR1, AR2));
685ssmp1_mg_verify_notify_request(
686  {handle_trans_request, _CH, ?VERSION, ARs}, _Tid1, _Tid2) ->
687    {error, {invalid_action_requests, ARs}, ok};
688ssmp1_mg_verify_notify_request(
689  {handle_trans_request, CH, V, ARs}, _Tid1, _Tid2) ->
690    {error, {invalid_trans_request, {CH, V, ARs}}, ok};
691ssmp1_mg_verify_notify_request(Crap, _Tid1, _Tid2) ->
692    io:format("ssmp1_mg_verify_notify_request -> unknown request"
693	      "~n   Tid1: ~p"
694	      "~n   Tid2: ~p"
695	      "~n   Crap: ~p"
696	      "~n", [_Tid1, _Tid2, Crap]),
697    {error, {unexpected_event, Crap}, ok}.
698
699ssmp1_mg_do_verify_notify_request(Tid1, Tid2, AR1, AR2) ->
700    io:format("ssmp1_mg_do_verify_notify_request -> ok"
701	      "~n   Tid1: ~p"
702	      "~n   Tid2: ~p"
703	      "~n   AR1:  ~p"
704	      "~n   AR2:  ~p"
705	      "~n", [Tid1, Tid2, AR1, AR2]),
706    ActionReply1 = ssmp1_mg_do_verify_notify_request(Tid1, AR1),
707    ActionReply2 = ssmp1_mg_do_verify_notify_request(Tid2, AR2),
708    Reply = {{handle_ack, ssmp1}, [ActionReply1, ActionReply2]},
709    {ok, [AR1, AR2], Reply}.
710
711ssmp1_mg_do_verify_notify_request(Tid, AR) ->
712    io:format("ssmp1_mg_do_verify_notify_request -> ok"
713	      "~n   Tid: ~p"
714	      "~n   AR:  ~p"
715	      "~n", [Tid, AR]),
716    {Cid, CR} =
717	case AR of
718	    #'ActionRequest'{contextId       = CtxId,
719			     commandRequests = [CmdReq]} ->
720		{CtxId, CmdReq};
721	    _ ->
722		Reason1 = {invalid_actionRequest, AR},
723		throw({error, Reason1, ok})
724	end,
725    Cmd =
726	case CR of
727	    #'CommandRequest'{command = Command} ->
728		Command;
729	    _ ->
730		throw({error, {invalid_commandRequest, CR}, ok})
731	end,
732    OED =
733	case Cmd of
734	    {notifyReq,
735	     #'NotifyRequest'{terminationID            = [Tid],
736			      observedEventsDescriptor = ObsEvDesc,
737			      errorDescriptor          = asn1_NOVALUE}} ->
738		ObsEvDesc;
739	    _ ->
740		throw({error, {invalid_command, Cmd}, ok})
741	end,
742    OE =
743	case OED of
744	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
745		ObsEv;
746	    #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
747		throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
748	    _ ->
749		throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
750	end,
751    case OE of
752	#'ObservedEvent'{eventName = "al/of"} ->
753	    ssmp1_mg_notify_reply_ar(Cid, Tid);
754	_ ->
755	    throw({error, {invalid_ObservedEvent, OE}, ok})
756    end.
757
758
759ssmp1_mg_verify_ack_fun() ->
760    fun(Event) -> ssmp1_mg_verify_ack(Event) end.
761
762ssmp1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp1}) ->
763    io:format("ssmp1_mg_verify_ack -> ok"
764              "~n   CH: ~p"
765              "~n", [CH]),
766    {ok, CH, ok};
767ssmp1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
768    io:format("ssmp1_mg_verify_ack -> error"
769              "~n   CrapAckData: ~p"
770              "~n   CH:          ~p"
771              "~n", [CrapAckData, CH]),
772    {error, {unknown_ack_data, CrapAckData, CH}, ok};
773ssmp1_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
774		    BadAckStatus, BadAckData}) ->
775    io:format("ssmp1_mg_verify_ack -> error"
776              "~n   BadAckStatus: ~p"
777              "~n   BadAckData: ~p"
778              "~n   CH:          ~p"
779              "~n", [BadAckStatus, BadAckData, CH]),
780    {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
781ssmp1_mg_verify_ack(BadEvent) ->
782    {error, {unknown_event, BadEvent}, ok}.
783
784
785ssmp1_mg_service_change_request_ar(_Mid, Cid) ->
786    Prof  = cre_serviceChangeProf("resgw", 1),
787    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
788    Root  = #megaco_term_id{id = ["root"]},
789    SCR   = cre_serviceChangeReq([Root], SCP),
790    CMD   = cre_command(SCR),
791    CR    = cre_cmdReq(CMD),
792    cre_actionReq(Cid, [CR]).
793
794ssmp1_mg_notify_reply_ar(Cid, Tid) ->
795    NR = cre_notifyReply([Tid]),
796    CR = cre_cmdReply(NR),
797    cre_actionReply(Cid, [CR]).
798
799
800
801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802
803send_segmented_msg_plain2(suite) ->
804    [];
805send_segmented_msg_plain2(doc) ->
806    "Second plain test that it is possible to send segmented messages. "
807	"Send window = infinity. ";
808send_segmented_msg_plain2(Config) when is_list(Config) ->
809    Factor = ?config(megaco_factor, Config),
810    ct:timetrap(?MINS(1) + Factor * ?MINS(1)),
811    Pre = fun() ->
812                  MgcNode = make_node_name(mgc),
813                  MgNode  = make_node_name(mg),
814                  d("start nodes: "
815                    "~n   MgcNode: ~p"
816                    "~n   MgNode:  ~p",
817                    [MgcNode, MgNode]),
818                  Nodes = [MgcNode, MgNode],
819                  ok = ?START_NODES(Nodes),
820                  Nodes
821          end,
822    Case = fun(X) -> do_send_segmented_msg_plain2(Factor, X) end,
823    Post = fun(Nodes) ->
824                   d("stop nodes"),
825                   ?STOP_NODES(lists:reverse(Nodes))
826           end,
827    try_tc(ssmp2, Pre, Case, Post).
828
829do_send_segmented_msg_plain2(Factor, [MgcNode, MgNode]) ->
830
831    d("[MGC] start the simulator "),
832    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
833
834    d("[MGC] create the event sequence"),
835    MgcEvSeq = ssmp2_mgc_event_sequence(Factor, text, tcp),
836
837    i("wait some time before starting the MGC simulation"),
838    sleep(1000),
839
840    d("[MGC] start the simulation"),
841    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
842
843    i("wait some time before starting the MG simulator"),
844    sleep(1000),
845
846    d("[MG] start the simulator (generator)"),
847    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
848
849    d("[MG] create the event sequence"),
850    MgEvSeq = ssmp2_mg_event_sequence(Factor, text, tcp),
851
852    i("wait some time before starting the MG simulation"),
853    sleep(1000),
854
855    d("[MG] start the simulation"),
856    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
857
858    d("await the generator reply(s)"),
859    await_completion([MgcId, MgId]),
860
861    %% Tell Mgc to stop
862    i("[MGC] stop generator"),
863    megaco_test_tcp_generator:stop(Mgc),
864
865    %% Tell Mg to stop
866    i("[MG] stop generator"),
867    megaco_test_megaco_generator:stop(Mg),
868
869    i("done", []),
870    ok.
871
872
873
874%%
875%% MGC generator stuff
876%%
877
878ssmp2_mgc_event_sequence(Factor, text, tcp) ->
879    DecodeFun = ssmp2_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
880    EncodeFun = ssmp2_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
881    Mid       = {deviceName,"mgc"},
882    ScrVerifyFun     = ssmp2_mgc_verify_service_change_req_msg_fun(),
883    ServiceChangeRep = ssmp2_mgc_service_change_reply_msg(Mid, 1),
884    TermId1   =
885	#megaco_term_id{id = ["00000000","00000000","00000001"]},
886    CtxId1    = 1,
887    TermId2   =
888	#megaco_term_id{id = ["00000000","00000000","00000002"]},
889    CtxId2    = 2,
890    TransId   = 2,
891    NotifyReq = ssmp2_mgc_notify_request_msg(Mid, TransId,
892					    TermId1, CtxId1,
893					    TermId2, CtxId2),
894    NrVerifyFun1 =
895	ssmp2_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
896						     TermId1, CtxId1),
897    NrVerifyFun2 =
898	ssmp2_mgc_verify_notify_reply_segment_msg_fun(2, true, TransId,
899						     TermId2, CtxId2),
900    SegmentRep1 = ssmp2_mgc_segment_reply_msg(Mid, TransId, 1, false),
901    SegmentRep2 = ssmp2_mgc_segment_reply_msg(Mid, TransId, 2, true),
902    TransAck    = ssmp2_mgc_trans_ack_msg(Mid, TransId),
903    TO = fun(T) -> Factor * T end,
904    EvSeq = [{debug,  true},
905             {decode, DecodeFun},
906             {encode, EncodeFun},
907             {listen, 2944},
908	     {expect_accept, any},
909             {expect_receive, "service-change-request",  {ScrVerifyFun, 5000}},
910             {send, "service-change-reply",              ServiceChangeRep},
911	     {expect_nothing, ?SECS(1)},
912             {send, "notify request",                    NotifyReq},
913             {expect_receive, "notify reply: segment 1",
914              {NrVerifyFun1, TO(?SECS(2))}},
915             {send, "segment reply 1",                   SegmentRep1},
916             {expect_receive, "notify reply: segment 2",
917              {NrVerifyFun2, TO(?SECS(1))}},
918             {send, "segment reply 2",                   SegmentRep2},
919	     {sleep, 100}, % {expect_nothing, 500},
920	     {send, "transaction-ack",                   TransAck},
921             {expect_closed,  TO(?SECS(5))},
922             disconnect
923            ],
924    EvSeq.
925
926ssmp2_mgc_encode_msg_fun(Mod, Conf) ->
927    fun(M) ->
928            Mod:encode_message(Conf, M)
929    end.
930
931ssmp2_mgc_decode_msg_fun(Mod, Conf) ->
932    fun(M) ->
933            Mod:decode_message(Conf, M)
934    end.
935
936ssmp2_mgc_verify_service_change_req_msg_fun() ->
937    fun(Msg) ->
938	    (catch ssmp2_mgc_verify_service_change_req(Msg))
939    end.
940
941ssmp2_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
942    io:format("ssmp2_mgc_verify_service_change_req -> entry with"
943	      "~n   M: ~p"
944	      "~n", [M]),
945    Body =
946	case Mess of
947	    #'Message'{version     = 1,
948                       mId         = _MgMid,
949                       messageBody = MsgBody} ->
950		MsgBody;
951	    _ ->
952		throw({error, {invalid_Message, Mess}})
953	end,
954    Trans =
955	case Body of
956            {transactions, [Transactions]} ->
957		Transactions;
958	    _ ->
959		throw({error, {invalid_messageBody, Body}})
960	end,
961    TR =
962	case Trans of
963            {transactionRequest, TransRequest} ->
964		TransRequest;
965	    _ ->
966		throw({error, {invalid_transactions, Trans}})
967	end,
968    AR =
969	case TR of
970            #'TransactionRequest'{transactionId = _TransId,
971				  actions       = [ActionReq]} ->
972		ActionReq;
973	    _ ->
974		throw({error, {invalid_transactionRequest, TR}})
975	end,
976    CR =
977	case AR of
978	    #'ActionRequest'{contextId       = _Cid,
979			     commandRequests = [CmdReq]} ->
980		CmdReq;
981	    _ ->
982		throw({error, {invalid_action, AR}})
983	end,
984    Cmd =
985	case CR of
986	    #'CommandRequest'{command = Command} ->
987		Command;
988	    _ ->
989		throw({error, {invalid_commandRequest, CR}})
990	end,
991    {Tid, Parms} =
992	case Cmd of
993	    {serviceChangeReq,
994	     #'ServiceChangeRequest'{terminationID      = [TermID],
995				     serviceChangeParms = ServChParms}} ->
996		{TermID, ServChParms};
997	    _ ->
998		throw({error, {invalid_command, Cmd}})
999	end,
1000    case Tid of
1001	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
1002	    ok;
1003	_ ->
1004	    throw({error, {invalid_terminationID, Tid}})
1005    end,
1006    case Parms of
1007	%% Version 1 'ServiceChangeParm'
1008	{'ServiceChangeParm',
1009	 restart,                            % serviceChangeMethod
1010	 asn1_NOVALUE,                       % serviceChangeAddress
1011	 ?VERSION,                           % serviceChangeVersion,
1012	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
1013	 [[$9,$0,$1|_]],                     % serviceChangeReason
1014	 asn1_NOVALUE,                       % serviceChangeDelay
1015	 asn1_NOVALUE,                       % serviceChangeMgcId
1016	 asn1_NOVALUE,                       % timeStamp
1017	 asn1_NOVALUE                        % nonStandardData
1018	} ->
1019	    {ok, M};
1020	_ ->
1021	    {error, {invalid_serviceChangeParms, Parms}}
1022    end.
1023
1024ssmp2_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
1025					     TransId, TermId, Cid) ->
1026    fun(Msg) ->
1027	    (catch ssmp2_mgc_verify_notify_reply_segment(Msg,
1028							SN, Last,
1029							TransId, TermId, Cid))
1030    end.
1031
1032ssmp2_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
1033				     SN, Last, TransId, TermId, Cid) ->
1034    p("ssmp2_mgc_verify_notify_reply_segment -> entry with"
1035      "~n   M:       ~p"
1036      "~n   SN:      ~p"
1037      "~n   Last:    ~p"
1038      "~n   TransId: ~p"
1039      "~n   TermId:  ~p"
1040      "~n   Cid:     ~p", [M, SN, Last, TransId, TermId, Cid]),
1041    Body =
1042	case Mess of
1043	    #'Message'{version     = ?VERSION,
1044                       mId         = _Mid,
1045                       messageBody = MsgBody} ->
1046		MsgBody;
1047	    _ ->
1048		throw({error, {invalid_Message, Mess}})
1049	end,
1050    Trans =
1051	case Body of
1052            {transactions, [Transactions]} ->
1053		Transactions;
1054	    _ ->
1055		throw({error, {invalid_messageBody, Body}})
1056	end,
1057    TR =
1058	case Trans of
1059            {transactionReply, TransReply} ->
1060		TransReply;
1061	    _ ->
1062		throw({error, {invalid_transactions, Trans}})
1063	end,
1064    TRes =
1065	case TR of
1066            #'TransactionReply'{transactionId        = TransId,
1067				transactionResult    = TransRes,
1068				segmentNumber        = SN,
1069				segmentationComplete = asn1_NOVALUE} when (Last == false) ->
1070		TransRes;
1071            #'TransactionReply'{transactionId        = TransId,
1072				transactionResult    = TransRes,
1073				segmentNumber        = SN,
1074				segmentationComplete = 'NULL'} when (Last == true) ->
1075		TransRes;
1076	    _ ->
1077		throw({error, {invalid_transactionReply, TR}})
1078	end,
1079    AR =
1080	case TRes of
1081	    {actionReplies, [ActionReply]} ->
1082		ActionReply;
1083	    {actionReplies, ActionReplies} ->
1084		throw({error, {invalid_actionReplies, ActionReplies}});
1085	    _ ->
1086		throw({error, {invalid_transactionResult, TRes}})
1087	end,
1088    CR =
1089	case AR of
1090	    #'ActionReply'{contextId    = Cid,
1091			   commandReply = [CommandReply]} ->
1092		CommandReply;
1093	    #'ActionReply'{contextId    = Cid,
1094			   commandReply = CommandReplies} ->
1095		throw({error, {invalid_commandReplies, CommandReplies}});
1096	    _ ->
1097		throw({error, {invalid_actionReply, AR}})
1098	end,
1099    NR =
1100	case CR of
1101	    {notifyReply, NotifyReply} ->
1102		NotifyReply;
1103	    _ ->
1104		throw({error, {invalid_commandReply, CR}})
1105	end,
1106    case NR of
1107	#'NotifyReply'{terminationID   = [TermId],
1108		       errorDescriptor = asn1_NOVALUE} ->
1109	    {ok, M};
1110	_ ->
1111	    {error, {invalid_NotifyReply, NR}}
1112    end;
1113ssmp2_mgc_verify_notify_reply_segment(Crap,
1114				     _SN, _Last, _TransId, _TermId, _Cid) ->
1115    {error, {invalid_MegacoMessage, Crap}}.
1116
1117
1118ssmp2_mgc_service_change_reply_msg(Mid, Cid) ->
1119    SCRP  = cre_serviceChangeResParm(Mid),
1120    SCRes = cre_serviceChangeResult(SCRP),
1121    Root  = #megaco_term_id{id = ["root"]},
1122    SCR   = cre_serviceChangeReply([Root], SCRes),
1123    CR    = cre_cmdReply(SCR),
1124    AR    = cre_actionReply(Cid, [CR]),
1125    TRes  = cre_transResult([AR]),
1126    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
1127    Trans = cre_transaction(TR),
1128    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
1129    cre_megacoMessage(Mess).
1130
1131ssmp2_mgc_notify_request_msg(Mid, TransId, TermId1, Cid1, TermId2, Cid2) ->
1132    AR1     = ssmp2_mgc_notify_request_ar(1, TermId1, Cid1),
1133    AR2     = ssmp2_mgc_notify_request_ar(2, TermId2, Cid2),
1134    TR      = cre_transReq(TransId, [AR1, AR2]),
1135    Trans   = cre_transaction(TR),
1136    Mess    = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1137    cre_megacoMessage(Mess).
1138
1139ssmp2_mgc_notify_request_ar(Rid, Tid, Cid) ->
1140    TT      = cre_timeNotation(integer_to_list(19990720+Rid),
1141			       integer_to_list(22000000+Rid)),
1142    Ev      = cre_obsEvent("al/of", TT),
1143    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
1144    NR      = cre_notifyReq([Tid], EvsDesc),
1145    CMD     = cre_command(NR),
1146    CR      = cre_cmdReq(CMD),
1147    cre_actionReq(Cid, [CR]).
1148
1149ssmp2_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
1150    SR    = ssmp2_mgc_segment_reply(TransId, SN, Last),
1151    Trans = cre_transaction(SR),
1152    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1153    cre_megacoMessage(Mess).
1154
1155ssmp2_mgc_segment_reply(TransId, SN, true) ->
1156    cre_segReply(TransId, SN, 'NULL');
1157ssmp2_mgc_segment_reply(TransId, SN, false) ->
1158    cre_segReply(TransId, SN, asn1_NOVALUE).
1159
1160ssmp2_mgc_trans_ack_msg(Mid, TransId) ->
1161    TA    = cre_transAck(TransId),
1162    Trans = cre_transaction([TA]),
1163    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1164    cre_megacoMessage(Mess).
1165
1166
1167%%
1168%% MG generator stuff
1169%%
1170ssmp2_mg_event_sequence(Factor, text, tcp) ->
1171    Mid = {deviceName,"mg"},
1172    RI = [
1173          {port,             2944},
1174          {encoding_module,  megaco_pretty_text_encoder},
1175          {encoding_config,  []},
1176          {transport_module, megaco_tcp}
1177         ],
1178    ConnectVerify = ssmp2_mg_verify_handle_connect_fun(),
1179    ServiceChangeReq = ssmp2_mg_service_change_request_ar(Mid, 1),
1180    ServiceChangeReplyVerify = ssmp2_mg_verify_service_change_reply_fun(),
1181    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
1182    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
1183    NotifyReqVerify = ssmp2_mg_verify_notify_request_fun(Tid1, Tid2),
1184    AckVerify = ssmp2_mg_verify_ack_fun(),
1185    SECS = fun(T) -> ?SECS(Factor * T) end,
1186    EvSeq = [
1187             {debug, true},
1188             {megaco_trace, disable},
1189             %% {megaco_trace, max},
1190             megaco_start,
1191             {megaco_start_user, Mid, RI, []},
1192             start_transport,
1193             {megaco_system_info, users},
1194             {megaco_system_info, connections},
1195             connect,
1196             {megaco_callback, handle_connect, ConnectVerify},
1197             megaco_connect,
1198             {megaco_cast,     [ServiceChangeReq], []},
1199             {megaco_callback, handle_connect,     ConnectVerify},
1200             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
1201	     {megaco_update_conn_info, protocol_version, ?VERSION},
1202	     {megaco_update_conn_info, segment_send,     infinity},
1203	     {megaco_update_conn_info, max_pdu_size,     128},
1204             {sleep, ?SECS(1)},
1205             {megaco_callback, handle_trans_request, NotifyReqVerify},
1206             {megaco_callback, handle_trans_ack,     AckVerify, SECS(5)},
1207             megaco_stop_user,
1208             megaco_stop,
1209             {sleep, ?SECS(1)}
1210            ],
1211    EvSeq.
1212
1213
1214ssmp2_mg_verify_handle_connect_fun() ->
1215    fun(Ev) -> ssmp2_mg_verify_handle_connect(Ev) end.
1216
1217ssmp2_mg_verify_handle_connect({handle_connect, CH, 1}) ->
1218    p("ssmp2_mg_verify_handle_connect -> ok"
1219      "~n   CH: ~p", [CH]),
1220    {ok, CH, ok};
1221ssmp2_mg_verify_handle_connect(Else) ->
1222    p("ssmp2_mg_verify_handle_connect -> unknown"
1223      "~n   Else: ~p", [Else]),
1224    {error, Else, ok}.
1225
1226
1227ssmp2_mg_verify_service_change_reply_fun() ->
1228    fun(Rep) -> ssmp2_mg_verify_scr(Rep) end.
1229
1230ssmp2_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
1231    (catch ssmp2_mg_do_verify_scr(AR));
1232ssmp2_mg_verify_scr(Crap) ->
1233    p("ssmp2_mg_verify_scr -> error: "
1234      "~n   Crap: ~p", [Crap]),
1235    {error, Crap, ok}.
1236
1237ssmp2_mg_do_verify_scr(AR) ->
1238    p("ssmp2_mg_do_verify_scr -> ok: "
1239      "~n   AR: ~p", [AR]),
1240    CR =
1241	case AR of
1242	    #'ActionReply'{commandReply = [CmdRep]} ->
1243		CmdRep;
1244	    _ ->
1245		Reason1 = {invalid_action_reply, AR},
1246		throw({error, Reason1, ok})
1247	end,
1248    SCR =
1249	case CR of
1250	    {serviceChangeReply, ServChRep} ->
1251		ServChRep;
1252	    _ ->
1253		Reason2 = {invalid_command_reply, CR},
1254		throw({error, Reason2, ok})
1255	end,
1256    {Tid, SCRes} =
1257	case SCR of
1258	    #'ServiceChangeReply'{terminationID       = [TermID],
1259				  serviceChangeResult = Res} ->
1260		{TermID, Res};
1261	    _ ->
1262		Reason3 = {invalid_service_change_reply, SCR},
1263		throw({error, Reason3, ok})
1264	end,
1265    case Tid of
1266	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
1267	    ok;
1268	_ ->
1269	    Reason4 = {invalid_termination_id, Tid},
1270	    throw({error, Reason4, ok})
1271    end,
1272    SCRParm =
1273	case SCRes of
1274	    {serviceChangeResParms, ServChResParms} ->
1275		ServChResParms;
1276	    _ ->
1277		Reason5 = {invalid_serviceChangeResult, SCRes},
1278		throw({error, Reason5, ok})
1279	end,
1280    case SCRParm of
1281	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
1282	    {ok, AR, ok};
1283	_ ->
1284	    Reason6 = {invalid_service_change_result, SCRParm},
1285	    {error, Reason6, ok}
1286    end.
1287
1288ssmp2_mg_verify_notify_request_fun(Tid1, Tid2) ->
1289    fun(Req) -> ssmp2_mg_verify_notify_request(Req, Tid1, Tid2) end.
1290
1291ssmp2_mg_verify_notify_request(
1292  {handle_trans_request, _CH, ?VERSION, [AR1, AR2]}, Tid1, Tid2) ->
1293    (catch ssmp2_mg_do_verify_notify_request(Tid1, Tid2, AR1, AR2));
1294ssmp2_mg_verify_notify_request(
1295  {handle_trans_request, _CH, ?VERSION, ARs}, _Tid1, _Tid2) ->
1296    {error, {invalid_action_requests, ARs}, ok};
1297ssmp2_mg_verify_notify_request(
1298  {handle_trans_request, CH, V, ARs}, _Tid1, _Tid2) ->
1299    {error, {invalid_trans_request, {CH, V, ARs}}, ok};
1300ssmp2_mg_verify_notify_request(Crap, _Tid1, _Tid2) ->
1301    p("ssmp2_mg_verify_notify_request -> unknown request"
1302      "~n   Tid1: ~p"
1303      "~n   Tid2: ~p"
1304      "~n   Crap: ~p", [_Tid1, _Tid2, Crap]),
1305    {error, {unexpected_event, Crap}, ok}.
1306
1307ssmp2_mg_do_verify_notify_request(Tid1, Tid2, AR1, AR2) ->
1308    p("ssmp2_mg_do_verify_notify_request -> ok"
1309      "~n   Tid1: ~p"
1310      "~n   Tid2: ~p"
1311      "~n   AR1:  ~p"
1312      "~n   AR2:  ~p", [Tid1, Tid2, AR1, AR2]),
1313    ActionReply1 = ssmp2_mg_do_verify_notify_request(Tid1, AR1),
1314    ActionReply2 = ssmp2_mg_do_verify_notify_request(Tid2, AR2),
1315    Reply = {{handle_ack, ssmp2}, [ActionReply1, ActionReply2]},
1316    {ok, [AR1, AR2], Reply}.
1317
1318ssmp2_mg_do_verify_notify_request(Tid, AR) ->
1319    p("ssmp2_mg_do_verify_notify_request -> ok"
1320      "~n   Tid: ~p"
1321      "~n   AR:  ~p", [Tid, AR]),
1322    {Cid, CR} =
1323	case AR of
1324	    #'ActionRequest'{contextId       = CtxId,
1325			     commandRequests = [CmdReq]} ->
1326		{CtxId, CmdReq};
1327	    _ ->
1328		Reason1 = {invalid_actionRequest, AR},
1329		throw({error, Reason1, ok})
1330	end,
1331    Cmd =
1332	case CR of
1333	    #'CommandRequest'{command = Command} ->
1334		Command;
1335	    _ ->
1336		throw({error, {invalid_commandRequest, CR}, ok})
1337	end,
1338    OED =
1339	case Cmd of
1340	    {notifyReq,
1341	     #'NotifyRequest'{terminationID            = [Tid],
1342			      observedEventsDescriptor = ObsEvDesc,
1343			      errorDescriptor          = asn1_NOVALUE}} ->
1344		ObsEvDesc;
1345	    _ ->
1346		throw({error, {invalid_command, Cmd}, ok})
1347	end,
1348    OE =
1349	case OED of
1350	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
1351		ObsEv;
1352	    #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
1353		throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
1354	    _ ->
1355		throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
1356	end,
1357    case OE of
1358	#'ObservedEvent'{eventName = "al/of"} ->
1359	    ssmp2_mg_notify_reply_ar(Cid, Tid);
1360	_ ->
1361	    throw({error, {invalid_ObservedEvent, OE}, ok})
1362    end.
1363
1364
1365ssmp2_mg_verify_ack_fun() ->
1366    fun(Event) -> ssmp2_mg_verify_ack(Event) end.
1367
1368ssmp2_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp2}) ->
1369    p("ssmp2_mg_verify_ack -> ok"
1370      "~n   CH: ~p", [CH]),
1371    {ok, CH, ok};
1372ssmp2_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
1373    {error, {unknown_ack_data, CrapAckData, CH}, ok};
1374ssmp2_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
1375		    BadAckStatus, BadAckData}) ->
1376    {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
1377ssmp2_mg_verify_ack(BadEvent) ->
1378    {error, {unknown_event, BadEvent}, ok}.
1379
1380
1381ssmp2_mg_service_change_request_ar(_Mid, Cid) ->
1382    Prof  = cre_serviceChangeProf("resgw", 1),
1383    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
1384    Root  = #megaco_term_id{id = ["root"]},
1385    SCR   = cre_serviceChangeReq([Root], SCP),
1386    CMD   = cre_command(SCR),
1387    CR    = cre_cmdReq(CMD),
1388    cre_actionReq(Cid, [CR]).
1389
1390ssmp2_mg_notify_reply_ar(Cid, Tid) ->
1391    NR = cre_notifyReply([Tid]),
1392    CR = cre_cmdReply(NR),
1393    cre_actionReply(Cid, [CR]).
1394
1395
1396
1397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398
1399send_segmented_msg_plain3(suite) ->
1400    [];
1401send_segmented_msg_plain3(doc) ->
1402    "Third plain test that it is possible to send segmented messages. "
1403	"Send window = 1. ";
1404send_segmented_msg_plain3(Config) when is_list(Config) ->
1405    Factor = ?config(megaco_factor, Config),
1406    ct:timetrap(?MINS(1) + Factor * ?MINS(1)),
1407    Pre = fun() ->
1408                  MgcNode = make_node_name(mgc),
1409                  MgNode  = make_node_name(mg),
1410                  d("start nodes: "
1411                    "~n   MgcNode: ~p"
1412                    "~n   MgNode:  ~p",
1413                    [MgcNode, MgNode]),
1414                  Nodes = [MgcNode, MgNode],
1415                  ok = ?START_NODES(Nodes),
1416                  Nodes
1417          end,
1418    Case = fun do_send_segmented_msg_plain3/1,
1419    Post = fun(Nodes) ->
1420                   d("stop nodes"),
1421                   ?STOP_NODES(lists:reverse(Nodes))
1422           end,
1423    try_tc(ssmp3, Pre, Case, Post).
1424
1425do_send_segmented_msg_plain3([MgcNode, MgNode]) ->
1426
1427    d("[MGC] start the simulator "),
1428    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
1429
1430    d("[MGC] create the event sequence"),
1431    MgcEvSeq = ssmp3_mgc_event_sequence(text, tcp),
1432
1433    i("wait some time before starting the MGC simulation"),
1434    sleep(1000),
1435
1436    d("[MGC] start the simulation"),
1437    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
1438
1439    i("wait some time before starting the MG simulator"),
1440    sleep(1000),
1441
1442    d("[MG] start the simulator (generator)"),
1443    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
1444
1445    d("[MG] create the event sequence"),
1446    MgEvSeq = ssmp3_mg_event_sequence(text, tcp),
1447
1448    i("wait some time before starting the MG simulation"),
1449    sleep(1000),
1450
1451    d("[MG] start the simulation"),
1452    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
1453
1454    d("await the generator reply(s)"),
1455    await_completion([MgcId, MgId]),
1456
1457    %% Tell Mgc to stop
1458    i("[MGC] stop generator"),
1459    megaco_test_tcp_generator:stop(Mgc),
1460
1461    %% Tell Mg to stop
1462    i("[MG] stop generator"),
1463    megaco_test_megaco_generator:stop(Mg),
1464
1465    i("done", []),
1466    ok.
1467
1468
1469
1470%%
1471%% MGC generator stuff
1472%%
1473
1474ssmp3_mgc_event_sequence(text, tcp) ->
1475    DecodeFun = ssmp3_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
1476    EncodeFun = ssmp3_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
1477    Mid       = {deviceName,"mgc"},
1478    ScrVerifyFun     = ssmp3_mgc_verify_service_change_req_msg_fun(),
1479    ServiceChangeRep = ssmp3_mgc_service_change_reply_msg(Mid, 1),
1480    TermId1   =
1481	#megaco_term_id{id = ["00000000","00000000","00000001"]},
1482    CtxId1    = 1,
1483    TermId2   =
1484	#megaco_term_id{id = ["00000000","00000000","00000002"]},
1485    CtxId2    = 2,
1486    TermId3   =
1487	#megaco_term_id{id = ["00000000","00000000","00000003"]},
1488    CtxId3    = 3,
1489    TermId4   =
1490	#megaco_term_id{id = ["00000000","00000000","00000004"]},
1491    CtxId4    = 4,
1492    TermId5   =
1493	#megaco_term_id{id = ["00000000","00000000","00000005"]},
1494    CtxId5    = 5,
1495    TermId6   =
1496	#megaco_term_id{id = ["00000000","00000000","00000006"]},
1497    CtxId6    = 6,
1498    TermId7   =
1499	#megaco_term_id{id = ["00000000","00000000","00000007"]},
1500    CtxId7    = 7,
1501    TermId8   =
1502	#megaco_term_id{id = ["00000000","00000000","00000008"]},
1503    CtxId8    = 8,
1504    TransId   = 2,
1505    TermIDs = [TermId1, TermId2, TermId3, TermId4,
1506	       TermId5, TermId6, TermId7, TermId8],
1507    CIDs    = [CtxId1, CtxId2, CtxId3, CtxId4,
1508	       CtxId5, CtxId6, CtxId7, CtxId8],
1509    NotifyReq = ssmp3_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
1510    NrVerifyFun1 =
1511	ssmp3_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
1512						      TermId1, CtxId1),
1513    NrVerifyFun2 =
1514	ssmp3_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
1515						      TermId2, CtxId2),
1516    NrVerifyFun3 =
1517	ssmp3_mgc_verify_notify_reply_segment_msg_fun(3, false, TransId,
1518						      TermId3, CtxId3),
1519    NrVerifyFun4 =
1520	ssmp3_mgc_verify_notify_reply_segment_msg_fun(4, false, TransId,
1521						      TermId4, CtxId4),
1522    NrVerifyFun5 =
1523	ssmp3_mgc_verify_notify_reply_segment_msg_fun(5, false, TransId,
1524						      TermId5, CtxId5),
1525    NrVerifyFun6 =
1526	ssmp3_mgc_verify_notify_reply_segment_msg_fun(6, false, TransId,
1527						      TermId6, CtxId6),
1528    NrVerifyFun7 =
1529	ssmp3_mgc_verify_notify_reply_segment_msg_fun(7, false, TransId,
1530						      TermId7, CtxId7),
1531    NrVerifyFun8 =
1532	ssmp3_mgc_verify_notify_reply_segment_msg_fun(8, true, TransId,
1533						      TermId8, CtxId8),
1534    SegmentRep1 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 1, false),
1535    SegmentRep2 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 2, false),
1536    SegmentRep3 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 3, false),
1537    SegmentRep4 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 4, false),
1538    SegmentRep5 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 5, false),
1539    SegmentRep6 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 6, false),
1540    SegmentRep7 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 7, false),
1541    SegmentRep8 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 8, true),
1542    TransAck    = ssmp3_mgc_trans_ack_msg(Mid, TransId),
1543    EvSeq = [{debug,  true},
1544             {decode, DecodeFun},
1545             {encode, EncodeFun},
1546             {listen, 2944},
1547	     {expect_accept, any},
1548             {expect_receive, "service-change-request",  {ScrVerifyFun, 5000}},
1549             {send, "service-change-reply",              ServiceChangeRep},
1550	     {expect_nothing, 1000},
1551             {send, "notify request",                    NotifyReq},
1552             {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
1553	     {expect_nothing, 200},
1554             {send, "segment reply 1",                   SegmentRep1},
1555
1556             {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
1557	     {expect_nothing, 200},
1558             {send, "segment reply 2",                   SegmentRep2},
1559
1560             {expect_receive, "notify reply: segment 3", {NrVerifyFun3, 1000}},
1561	     {expect_nothing, 200},
1562             {send, "segment reply 3",                   SegmentRep3},
1563
1564             {expect_receive, "notify reply: segment 4", {NrVerifyFun4, 1000}},
1565	     {expect_nothing, 200},
1566             {send, "segment reply 4",                   SegmentRep4},
1567
1568             {expect_receive, "notify reply: segment 5", {NrVerifyFun5, 1000}},
1569	     {expect_nothing, 200},
1570             {send, "segment reply 5",                   SegmentRep5},
1571
1572             {expect_receive, "notify reply: segment 6", {NrVerifyFun6, 1000}},
1573	     {expect_nothing, 200},
1574             {send, "segment reply 6",                   SegmentRep6},
1575
1576             {expect_receive, "notify reply: segment 7", {NrVerifyFun7, 1000}},
1577	     {expect_nothing, 200},
1578             {send, "segment reply 7",                   SegmentRep7},
1579
1580             {expect_receive, "notify reply: segment 8", {NrVerifyFun8, 1000}},
1581	     {expect_nothing, 200},
1582             {send, "segment reply 8",                   SegmentRep8},
1583
1584	     {expect_nothing, 200},
1585	     {send, "transaction-ack",                   TransAck},
1586             {expect_closed,  5000},
1587             disconnect
1588            ],
1589    EvSeq.
1590
1591ssmp3_mgc_encode_msg_fun(Mod, Conf) ->
1592    fun(M) ->
1593            Mod:encode_message(Conf, M)
1594    end.
1595
1596ssmp3_mgc_decode_msg_fun(Mod, Conf) ->
1597    fun(M) ->
1598            Mod:decode_message(Conf, M)
1599    end.
1600
1601ssmp3_mgc_verify_service_change_req_msg_fun() ->
1602    fun(Msg) ->
1603	    (catch ssmp3_mgc_verify_service_change_req(Msg))
1604    end.
1605
1606ssmp3_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
1607    p("ssmp3_mgc_verify_service_change_req -> entry with"
1608      "~n   M: ~p", [M]),
1609    Body =
1610	case Mess of
1611	    #'Message'{version     = 1,
1612                       mId         = _MgMid,
1613                       messageBody = MsgBody} ->
1614		MsgBody;
1615	    _ ->
1616		throw({error, {invalid_Message, Mess}})
1617	end,
1618    Trans =
1619	case Body of
1620            {transactions, [Transactions]} ->
1621		Transactions;
1622	    _ ->
1623		throw({error, {invalid_messageBody, Body}})
1624	end,
1625    TR =
1626	case Trans of
1627            {transactionRequest, TransRequest} ->
1628		TransRequest;
1629	    _ ->
1630		throw({error, {invalid_transactions, Trans}})
1631	end,
1632    AR =
1633	case TR of
1634            #'TransactionRequest'{transactionId = _TransId,
1635				  actions       = [ActionReq]} ->
1636		ActionReq;
1637	    _ ->
1638		throw({error, {invalid_transactionRequest, TR}})
1639	end,
1640    CR =
1641	case AR of
1642	    #'ActionRequest'{contextId       = _Cid,
1643			     commandRequests = [CmdReq]} ->
1644		CmdReq;
1645	    _ ->
1646		throw({error, {invalid_action, AR}})
1647	end,
1648    Cmd =
1649	case CR of
1650	    #'CommandRequest'{command = Command} ->
1651		Command;
1652	    _ ->
1653		throw({error, {invalid_commandRequest, CR}})
1654	end,
1655    {Tid, Parms} =
1656	case Cmd of
1657	    {serviceChangeReq,
1658	     #'ServiceChangeRequest'{terminationID      = [TermID],
1659				     serviceChangeParms = ServChParms}} ->
1660		{TermID, ServChParms};
1661	    _ ->
1662		throw({error, {invalid_command, Cmd}})
1663	end,
1664    case Tid of
1665	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
1666	    ok;
1667	_ ->
1668	    throw({error, {invalid_terminationID, Tid}})
1669    end,
1670    case Parms of
1671	%% Version 1 'ServiceChangeParm'
1672	{'ServiceChangeParm',
1673	 restart,                            % serviceChangeMethod
1674	 asn1_NOVALUE,                       % serviceChangeAddress
1675	 ?VERSION,                           % serviceChangeVersion,
1676	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
1677	 [[$9,$0,$1|_]],                     % serviceChangeReason
1678	 asn1_NOVALUE,                       % serviceChangeDelay
1679	 asn1_NOVALUE,                       % serviceChangeMgcId
1680	 asn1_NOVALUE,                       % timeStamp
1681	 asn1_NOVALUE                        % nonStandardData
1682	} ->
1683	    {ok, M};
1684	_ ->
1685	    {error, {invalid_serviceChangeParms, Parms}}
1686    end.
1687
1688ssmp3_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
1689					     TransId, TermId, Cid) ->
1690    fun(Msg) ->
1691	    (catch ssmp3_mgc_verify_notify_reply_segment(Msg,
1692							SN, Last,
1693							TransId, TermId, Cid))
1694    end.
1695
1696ssmp3_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
1697				     SN, Last, TransId, TermId, Cid) ->
1698    p("ssmp3_mgc_verify_notify_reply_segment -> entry with"
1699      "~n   M:       ~p"
1700      "~n   SN:      ~p"
1701      "~n   Last:    ~p"
1702      "~n   TransId: ~p"
1703      "~n   TermId:  ~p"
1704      "~n   Cid:     ~p", [M, SN, Last, TransId, TermId, Cid]),
1705    Body =
1706	case Mess of
1707	    #'Message'{version     = ?VERSION,
1708                       mId         = _Mid,
1709                       messageBody = MsgBody} ->
1710		MsgBody;
1711	    _ ->
1712		throw({error, {invalid_Message, Mess}})
1713	end,
1714    Trans =
1715	case Body of
1716            {transactions, [Transactions]} ->
1717		Transactions;
1718	    _ ->
1719		throw({error, {invalid_messageBody, Body}})
1720	end,
1721    TR =
1722	case Trans of
1723            {transactionReply, TransReply} ->
1724		TransReply;
1725	    _ ->
1726		throw({error, {invalid_transactions, Trans}})
1727	end,
1728    TRes =
1729	case TR of
1730            #'TransactionReply'{transactionId        = TransId,
1731				transactionResult    = TransRes,
1732				segmentNumber        = SN,
1733				segmentationComplete = asn1_NOVALUE} when (Last == false) ->
1734		TransRes;
1735            #'TransactionReply'{transactionId        = TransId,
1736				transactionResult    = TransRes,
1737				segmentNumber        = SN,
1738				segmentationComplete = 'NULL'} when (Last == true) ->
1739		TransRes;
1740	    _ ->
1741		throw({error, {invalid_transactionReply, TR}})
1742	end,
1743    AR =
1744	case TRes of
1745	    {actionReplies, [ActionReply]} ->
1746		ActionReply;
1747	    {actionReplies, ActionReplies} ->
1748		throw({error, {invalid_actionReplies, ActionReplies}});
1749	    _ ->
1750		throw({error, {invalid_transactionResult, TRes}})
1751	end,
1752    CR =
1753	case AR of
1754	    #'ActionReply'{contextId    = Cid,
1755			   commandReply = [CommandReply]} ->
1756		CommandReply;
1757	    #'ActionReply'{contextId    = Cid,
1758			   commandReply = CommandReplies} ->
1759		throw({error, {invalid_commandReplies, CommandReplies}});
1760	    _ ->
1761		throw({error, {invalid_actionReply, AR}})
1762	end,
1763    NR =
1764	case CR of
1765	    {notifyReply, NotifyReply} ->
1766		NotifyReply;
1767	    _ ->
1768		throw({error, {invalid_commandReply, CR}})
1769	end,
1770    case NR of
1771	#'NotifyReply'{terminationID   = [TermId],
1772		       errorDescriptor = asn1_NOVALUE} ->
1773	    {ok, M};
1774	_ ->
1775	    {error, {invalid_NotifyReply, NR}}
1776    end;
1777ssmp3_mgc_verify_notify_reply_segment(Crap,
1778				     _SN, _Last, _TransId, _TermId, _Cid) ->
1779    {error, {invalid_MegacoMessage, Crap}}.
1780
1781
1782ssmp3_mgc_service_change_reply_msg(Mid, Cid) ->
1783    SCRP  = cre_serviceChangeResParm(Mid),
1784    SCRes = cre_serviceChangeResult(SCRP),
1785    Root  = #megaco_term_id{id = ["root"]},
1786    SCR   = cre_serviceChangeReply([Root], SCRes),
1787    CR    = cre_cmdReply(SCR),
1788    AR    = cre_actionReply(Cid, [CR]),
1789    TRes  = cre_transResult([AR]),
1790    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
1791    Trans = cre_transaction(TR),
1792    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
1793    cre_megacoMessage(Mess).
1794
1795ssmp3_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
1796    ARs     = ssmp3_mgc_notify_request_ars(TermIDs, CIDs),
1797    TR      = cre_transReq(TransId, ARs),
1798    Trans   = cre_transaction(TR),
1799    Mess    = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1800    cre_megacoMessage(Mess).
1801
1802ssmp3_mgc_notify_request_ars(TermIDs, CIDs) ->
1803    ssmp3_mgc_notify_request_ars(TermIDs, CIDs, []).
1804
1805ssmp3_mgc_notify_request_ars([], [], Acc) ->
1806    lists:reverse(Acc);
1807ssmp3_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
1808    AR = ssmp3_mgc_notify_request_ar(100+CID, TermID, CID),
1809    ssmp3_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
1810
1811ssmp3_mgc_notify_request_ar(Rid, Tid, Cid) ->
1812    TT      = cre_timeNotation(integer_to_list(19990720+Rid),
1813			       integer_to_list(22000000+Rid)),
1814    Ev      = cre_obsEvent("al/of", TT),
1815    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
1816    NR      = cre_notifyReq([Tid], EvsDesc),
1817    CMD     = cre_command(NR),
1818    CR      = cre_cmdReq(CMD),
1819    cre_actionReq(Cid, [CR]).
1820
1821ssmp3_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
1822    SR    = ssmp3_mgc_segment_reply(TransId, SN, Last),
1823    Trans = cre_transaction(SR),
1824    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1825    cre_megacoMessage(Mess).
1826
1827ssmp3_mgc_segment_reply(TransId, SN, true) ->
1828    cre_segReply(TransId, SN, 'NULL');
1829ssmp3_mgc_segment_reply(TransId, SN, false) ->
1830    cre_segReply(TransId, SN, asn1_NOVALUE).
1831
1832ssmp3_mgc_trans_ack_msg(Mid, TransId) ->
1833    TA    = cre_transAck(TransId),
1834    Trans = cre_transaction([TA]),
1835    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
1836    cre_megacoMessage(Mess).
1837
1838
1839%%
1840%% MG generator stuff
1841%%
1842ssmp3_mg_event_sequence(text, tcp) ->
1843    Mid = {deviceName,"mg"},
1844    RI = [
1845          {port,             2944},
1846          {encoding_module,  megaco_pretty_text_encoder},
1847          {encoding_config,  []},
1848          {transport_module, megaco_tcp}
1849         ],
1850    ConnectVerify = ssmp3_mg_verify_handle_connect_fun(),
1851    ServiceChangeReq = ssmp3_mg_service_change_request_ar(Mid, 1),
1852    ServiceChangeReplyVerify = ssmp3_mg_verify_service_change_reply_fun(),
1853    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
1854    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
1855    Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
1856    Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
1857    Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
1858    Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
1859    Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
1860    Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
1861    Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
1862    NotifyReqVerify = ssmp3_mg_verify_notify_request_fun(Tids),
1863    AckVerify = ssmp3_mg_verify_ack_fun(),
1864    EvSeq = [
1865             {debug, true},
1866             {megaco_trace, disable},
1867             %% {megaco_trace, max},
1868             megaco_start,
1869             {megaco_start_user, Mid, RI, []},
1870             start_transport,
1871             {megaco_system_info, users},
1872             {megaco_system_info, connections},
1873             connect,
1874             {megaco_callback, handle_connect, ConnectVerify},
1875             megaco_connect,
1876             {megaco_cast,     [ServiceChangeReq], []},
1877             {megaco_callback, handle_connect,     ConnectVerify},
1878             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
1879	     {megaco_update_conn_info, protocol_version, ?VERSION},
1880	     {megaco_update_conn_info, segment_send,     1},
1881	     {megaco_update_conn_info, max_pdu_size,     128},
1882             {sleep, 500},
1883             {megaco_callback, handle_trans_request, NotifyReqVerify},
1884             {megaco_callback, handle_trans_ack,     AckVerify, 5000},
1885             megaco_stop_user,
1886             megaco_stop,
1887             {sleep, 1000}
1888            ],
1889    EvSeq.
1890
1891
1892ssmp3_mg_verify_handle_connect_fun() ->
1893    fun(Ev) -> ssmp3_mg_verify_handle_connect(Ev) end.
1894
1895ssmp3_mg_verify_handle_connect({handle_connect, CH, 1}) ->
1896    p("ssmp3_mg_verify_handle_connect -> ok"
1897      "~n   CH: ~p", [CH]),
1898    {ok, CH, ok};
1899ssmp3_mg_verify_handle_connect(Else) ->
1900    p("ssmp3_mg_verify_handle_connect -> unknown"
1901      "~n   Else: ~p", [Else]),
1902    {error, Else, ok}.
1903
1904
1905ssmp3_mg_verify_service_change_reply_fun() ->
1906    fun(Rep) -> ssmp3_mg_verify_scr(Rep) end.
1907
1908ssmp3_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
1909    (catch ssmp3_mg_do_verify_scr(AR));
1910ssmp3_mg_verify_scr(Crap) ->
1911    p("ssmp3_mg_verify_scr -> error: "
1912      "~n   Crap: ~p", [Crap]),
1913    {error, Crap, ok}.
1914
1915ssmp3_mg_do_verify_scr(AR) ->
1916    p("ssmp3_mg_do_verify_scr -> ok: "
1917      "~n   AR: ~p", [AR]),
1918    CR =
1919	case AR of
1920	    #'ActionReply'{commandReply = [CmdRep]} ->
1921		CmdRep;
1922	    _ ->
1923		Reason1 = {invalid_action_reply, AR},
1924		throw({error, Reason1, ok})
1925	end,
1926    SCR =
1927	case CR of
1928	    {serviceChangeReply, ServChRep} ->
1929		ServChRep;
1930	    _ ->
1931		Reason2 = {invalid_command_reply, CR},
1932		throw({error, Reason2, ok})
1933	end,
1934    {Tid, SCRes} =
1935	case SCR of
1936	    #'ServiceChangeReply'{terminationID       = [TermID],
1937				  serviceChangeResult = Res} ->
1938		{TermID, Res};
1939	    _ ->
1940		Reason3 = {invalid_service_change_reply, SCR},
1941		throw({error, Reason3, ok})
1942	end,
1943    case Tid of
1944	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
1945	    ok;
1946	_ ->
1947	    Reason4 = {invalid_termination_id, Tid},
1948	    throw({error, Reason4, ok})
1949    end,
1950    SCRParm =
1951	case SCRes of
1952	    {serviceChangeResParms, ServChResParms} ->
1953		ServChResParms;
1954	    _ ->
1955		Reason5 = {invalid_serviceChangeResult, SCRes},
1956		throw({error, Reason5, ok})
1957	end,
1958    case SCRParm of
1959	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
1960	    {ok, AR, ok};
1961	_ ->
1962	    Reason6 = {invalid_service_change_result, SCRParm},
1963	    {error, Reason6, ok}
1964    end.
1965
1966ssmp3_mg_verify_notify_request_fun(Tids) ->
1967    fun(Req) -> ssmp3_mg_verify_notify_request(Req, Tids) end.
1968
1969ssmp3_mg_verify_notify_request(
1970  {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
1971  when length(ARs) == length(Tids) ->
1972    (catch ssmp3_mg_do_verify_notify_request(Tids, ARs));
1973ssmp3_mg_verify_notify_request(
1974  {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
1975    {error, {invalid_action_requests, ARs}, ok};
1976ssmp3_mg_verify_notify_request(
1977  {handle_trans_request, CH, V, ARs}, _Tids) ->
1978    {error, {invalid_trans_request, {CH, V, ARs}}, ok};
1979ssmp3_mg_verify_notify_request(Crap, _Tids) ->
1980    p("ssmp3_mg_verify_notify_request -> unknown request"
1981      "~n   Crap: ~p"
1982      "~n   Tids: ~p", [Crap, _Tids]),
1983    {error, {unexpected_event, Crap}, ok}.
1984
1985ssmp3_mg_do_verify_notify_request(Tids, ARs) ->
1986    p("ssmp3_mg_do_verify_notify_request -> ok"
1987      "~n   Tids: ~p"
1988      "~n   ARs:  ~p", [Tids, ARs]),
1989    ActionReplies = ssmp3_mg_do_verify_notify_request_ars(Tids, ARs),
1990    p("ssmp3_mg_do_verify_notify_request -> ok"
1991      "~n   ActionReplies:  ~p", [ActionReplies]),
1992    Reply = {{handle_ack, ssmp3}, ActionReplies},
1993    {ok, ARs, Reply}.
1994
1995ssmp3_mg_do_verify_notify_request_ars(Tids, ARs) ->
1996    ssmp3_mg_do_verify_notify_request_ars(Tids, ARs, []).
1997
1998ssmp3_mg_do_verify_notify_request_ars([], [], Acc) ->
1999    lists:reverse(Acc);
2000ssmp3_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
2001    ActionReply = ssmp3_mg_do_verify_notify_request_ar(Tid, AR),
2002    ssmp3_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
2003
2004ssmp3_mg_do_verify_notify_request_ar(Tid, AR) ->
2005    p("ssmp3_mg_do_verify_notify_request_ar -> ok"
2006      "~n   Tid: ~p"
2007      "~n   AR:  ~p", [Tid, AR]),
2008    {Cid, CR} =
2009	case AR of
2010	    #'ActionRequest'{contextId       = CtxId,
2011			     commandRequests = [CmdReq]} ->
2012		{CtxId, CmdReq};
2013	    _ ->
2014		Reason1 = {invalid_actionRequest, AR},
2015		throw({error, Reason1, ok})
2016	end,
2017    Cmd =
2018	case CR of
2019	    #'CommandRequest'{command = Command} ->
2020		Command;
2021	    _ ->
2022		throw({error, {invalid_commandRequest, CR}, ok})
2023	end,
2024    OED =
2025	case Cmd of
2026	    {notifyReq,
2027	     #'NotifyRequest'{terminationID            = [Tid],
2028			      observedEventsDescriptor = ObsEvDesc,
2029			      errorDescriptor          = asn1_NOVALUE}} ->
2030		ObsEvDesc;
2031	    _ ->
2032		throw({error, {invalid_command, Cmd}, ok})
2033	end,
2034    OE =
2035	case OED of
2036	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
2037		ObsEv;
2038	    #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
2039		throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
2040	    _ ->
2041		throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
2042	end,
2043    case OE of
2044	#'ObservedEvent'{eventName = "al/of"} ->
2045	    ssmp3_mg_notify_reply_ar(Cid, Tid);
2046	_ ->
2047	    throw({error, {invalid_ObservedEvent, OE}, ok})
2048    end.
2049
2050
2051ssmp3_mg_verify_ack_fun() ->
2052    fun(Event) -> ssmp3_mg_verify_ack(Event) end.
2053
2054ssmp3_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp3}) ->
2055    p("ssmp3_mg_verify_ack -> ok"
2056      "~n   CH: ~p", [CH]),
2057    {ok, CH, ok};
2058ssmp3_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
2059    {error, {unknown_ack_data, CrapAckData, CH}, ok};
2060ssmp3_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
2061		    BadAckStatus, BadAckData}) ->
2062    {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
2063ssmp3_mg_verify_ack(BadEvent) ->
2064    {error, {unknown_event, BadEvent}, ok}.
2065
2066
2067ssmp3_mg_service_change_request_ar(_Mid, Cid) ->
2068    Prof  = cre_serviceChangeProf("resgw", 1),
2069    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
2070    Root  = #megaco_term_id{id = ["root"]},
2071    SCR   = cre_serviceChangeReq([Root], SCP),
2072    CMD   = cre_command(SCR),
2073    CR    = cre_cmdReq(CMD),
2074    cre_actionReq(Cid, [CR]).
2075
2076ssmp3_mg_notify_reply_ar(Cid, Tid) ->
2077    NR = cre_notifyReply([Tid]),
2078    CR = cre_cmdReply(NR),
2079    cre_actionReply(Cid, [CR]).
2080
2081
2082
2083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2084
2085send_segmented_msg_plain4(suite) ->
2086    [];
2087send_segmented_msg_plain4(doc) ->
2088    "Forth plain test that it is possible to send segmented messages. "
2089	"Send window = 3. ";
2090send_segmented_msg_plain4(Config) when is_list(Config) ->
2091    Factor = ?config(megaco_factor, Config),
2092    ct:timetrap(Factor * ?MINS(1)),
2093    Pre = fun() ->
2094                  MgcNode = make_node_name(mgc),
2095                  MgNode  = make_node_name(mg),
2096                  d("start nodes: "
2097                    "~n   MgcNode: ~p"
2098                    "~n   MgNode:  ~p",
2099                    [MgcNode, MgNode]),
2100                  Nodes = [MgcNode, MgNode],
2101                  ok = ?START_NODES(Nodes),
2102                  Nodes
2103          end,
2104    Case = fun(X) -> do_send_segmented_msg_plain4(Factor, X) end,
2105    Post = fun(Nodes) ->
2106                   d("stop nodes"),
2107                   ?STOP_NODES(lists:reverse(Nodes))
2108           end,
2109    try_tc(ssmp4, Pre, Case, Post).
2110
2111do_send_segmented_msg_plain4(Factor, [MgcNode, MgNode]) ->
2112    d("[MGC] start the simulator "),
2113    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
2114
2115    d("[MGC] create the event sequence"),
2116    MgcEvSeq = ssmp4_mgc_event_sequence(Factor, text, tcp),
2117
2118    i("wait some time before starting the MGC simulation"),
2119    sleep(1000),
2120
2121    d("[MGC] start the simulation"),
2122    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
2123
2124    i("wait some time before starting the MG simulator"),
2125    sleep(1000),
2126
2127    d("[MG] start the simulator (generator)"),
2128    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
2129
2130    d("[MG] create the event sequence"),
2131    MgEvSeq = ssmp4_mg_event_sequence(Factor, text, tcp),
2132
2133    i("wait some time before starting the MG simulation"),
2134    sleep(1000),
2135
2136    d("[MG] start the simulation"),
2137    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
2138
2139    d("await the generator reply(s)"),
2140    await_completion([MgcId, MgId]),
2141
2142    %% Tell Mgc to stop
2143    i("[MGC] stop generator"),
2144    megaco_test_tcp_generator:stop(Mgc),
2145
2146    %% Tell Mg to stop
2147    i("[MG] stop generator"),
2148    megaco_test_megaco_generator:stop(Mg),
2149
2150    i("done", []),
2151    ok.
2152
2153
2154
2155%%
2156%% MGC generator stuff
2157%%
2158
2159ssmp4_mgc_event_sequence(Factor, text, tcp) ->
2160    DecodeFun = ssmp4_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
2161    EncodeFun = ssmp4_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
2162    Mid       = {deviceName,"mgc"},
2163    ScrVerifyFun     = ssmp4_mgc_verify_service_change_req_msg_fun(),
2164    ServiceChangeRep = ssmp4_mgc_service_change_reply_msg(Mid, 1),
2165    TermId1   =
2166	#megaco_term_id{id = ["00000000","00000000","00000001"]},
2167    CtxId1    = 1,
2168    TermId2   =
2169	#megaco_term_id{id = ["00000000","00000000","00000002"]},
2170    CtxId2    = 2,
2171    TermId3   =
2172	#megaco_term_id{id = ["00000000","00000000","00000003"]},
2173    CtxId3    = 3,
2174    TermId4   =
2175	#megaco_term_id{id = ["00000000","00000000","00000004"]},
2176    CtxId4    = 4,
2177    TermId5   =
2178	#megaco_term_id{id = ["00000000","00000000","00000005"]},
2179    CtxId5    = 5,
2180    TermId6   =
2181	#megaco_term_id{id = ["00000000","00000000","00000006"]},
2182    CtxId6    = 6,
2183    TermId7   =
2184	#megaco_term_id{id = ["00000000","00000000","00000007"]},
2185    CtxId7    = 7,
2186    TermId8   =
2187	#megaco_term_id{id = ["00000000","00000000","00000008"]},
2188    CtxId8    = 8,
2189    TransId   = 2,
2190    TermIDs = [TermId1, TermId2, TermId3, TermId4,
2191	       TermId5, TermId6, TermId7, TermId8],
2192    CIDs    = [CtxId1, CtxId2, CtxId3, CtxId4,
2193	       CtxId5, CtxId6, CtxId7, CtxId8],
2194    NotifyReq = ssmp4_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
2195    NrVerifyFun1 =
2196	ssmp4_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
2197						      TermId1, CtxId1),
2198    NrVerifyFun2 =
2199	ssmp4_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
2200						      TermId2, CtxId2),
2201    NrVerifyFun3 =
2202	ssmp4_mgc_verify_notify_reply_segment_msg_fun(3, false, TransId,
2203						      TermId3, CtxId3),
2204    NrVerifyFun4 =
2205	ssmp4_mgc_verify_notify_reply_segment_msg_fun(4, false, TransId,
2206						      TermId4, CtxId4),
2207    NrVerifyFun5 =
2208	ssmp4_mgc_verify_notify_reply_segment_msg_fun(5, false, TransId,
2209						      TermId5, CtxId5),
2210    NrVerifyFun6 =
2211	ssmp4_mgc_verify_notify_reply_segment_msg_fun(6, false, TransId,
2212						      TermId6, CtxId6),
2213    NrVerifyFun7 =
2214	ssmp4_mgc_verify_notify_reply_segment_msg_fun(7, false, TransId,
2215						      TermId7, CtxId7),
2216    NrVerifyFun8 =
2217	ssmp4_mgc_verify_notify_reply_segment_msg_fun(8, true, TransId,
2218						      TermId8, CtxId8),
2219    SegmentRep1 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 1, false),
2220    SegmentRep2 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 2, false),
2221    SegmentRep3 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 3, false),
2222    SegmentRep4 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 4, false),
2223    SegmentRep5 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 5, false),
2224    SegmentRep6 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 6, false),
2225    SegmentRep7 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 7, false),
2226    SegmentRep8 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 8, true),
2227    TransAck    = ssmp4_mgc_trans_ack_msg(Mid, TransId),
2228    TO = fun(T) -> Factor*T end,
2229    EvSeq = [{debug,  true},
2230             {trigger, "verbosity",
2231              fun() ->
2232                      put(verbosity, ?TEST_VERBOSITY)
2233              end},
2234             {decode, DecodeFun},
2235             {encode, EncodeFun},
2236             {listen, 2944},
2237	     {expect_accept, any},
2238             {expect_receive, "service-change-request",  {ScrVerifyFun, TO(5000)}},
2239             {send, "service-change-reply",              ServiceChangeRep},
2240	     {expect_nothing, 1000},
2241             {send, "notify request",                    NotifyReq},
2242             {expect_receive, "notify reply: segment 1", {NrVerifyFun1, TO(1000)}},
2243             {expect_receive, "notify reply: segment 2", {NrVerifyFun2, TO(1000)}},
2244             {expect_receive, "notify reply: segment 3", {NrVerifyFun3, TO(1000)}},
2245	     {expect_nothing, 1000},
2246             {send, "segment reply 1",                   SegmentRep1},
2247             {expect_receive, "notify reply: segment 4", {NrVerifyFun4, TO(1000)}},
2248	     {expect_nothing, 1000},
2249             {send, "segment reply 2",                   SegmentRep2},
2250             {expect_receive, "notify reply: segment 5", {NrVerifyFun5, TO(1000)}},
2251	     {expect_nothing, 1000},
2252             {send, "segment reply 3",                   SegmentRep3},
2253             {expect_receive, "notify reply: segment 6", {NrVerifyFun6, TO(1000)}},
2254	     {expect_nothing, 1000},
2255             {send, "segment reply 4",                   SegmentRep4},
2256             {expect_receive, "notify reply: segment 7", {NrVerifyFun7, TO(1000)}},
2257	     {expect_nothing, 1000},
2258             {send, "segment reply 5",                   SegmentRep5},
2259             {expect_receive, "notify reply: segment 8", {NrVerifyFun8, TO(1000)}},
2260	     {expect_nothing, 1000},
2261             {send, "segment reply 6",                   SegmentRep6},
2262	     {expect_nothing, 1000},
2263             {send, "segment reply 7",                   SegmentRep7},
2264	     {expect_nothing, 1000},
2265             {send, "segment reply 8",                   SegmentRep8},
2266	     {expect_nothing, 1000},
2267	     {send, "transaction-ack",                   TransAck},
2268             {expect_closed,  5000},
2269             disconnect
2270            ],
2271    EvSeq.
2272
2273ssmp4_mgc_encode_msg_fun(Mod, Conf) ->
2274    fun(M) ->
2275            Mod:encode_message(Conf, M)
2276    end.
2277
2278ssmp4_mgc_decode_msg_fun(Mod, Conf) ->
2279    fun(M) ->
2280            Mod:decode_message(Conf, M)
2281    end.
2282
2283ssmp4_mgc_verify_service_change_req_msg_fun() ->
2284    fun(Msg) ->
2285	    (catch ssmp4_mgc_verify_service_change_req(Msg))
2286    end.
2287
2288ssmp4_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
2289    p("ssmp4_mgc_verify_service_change_req -> entry with"
2290      "~n   M: ~p", [M]),
2291    Body =
2292	case Mess of
2293	    #'Message'{version     = 1,
2294                       mId         = _MgMid,
2295                       messageBody = MsgBody} ->
2296		MsgBody;
2297	    _ ->
2298		throw({error, {invalid_Message, Mess}})
2299	end,
2300    Trans =
2301	case Body of
2302            {transactions, [Transactions]} ->
2303		Transactions;
2304	    _ ->
2305		throw({error, {invalid_messageBody, Body}})
2306	end,
2307    TR =
2308	case Trans of
2309            {transactionRequest, TransRequest} ->
2310		TransRequest;
2311	    _ ->
2312		throw({error, {invalid_transactions, Trans}})
2313	end,
2314    AR =
2315	case TR of
2316            #'TransactionRequest'{transactionId = _TransId,
2317				  actions       = [ActionReq]} ->
2318		ActionReq;
2319	    _ ->
2320		throw({error, {invalid_transactionRequest, TR}})
2321	end,
2322    CR =
2323	case AR of
2324	    #'ActionRequest'{contextId       = _Cid,
2325			     commandRequests = [CmdReq]} ->
2326		CmdReq;
2327	    _ ->
2328		throw({error, {invalid_action, AR}})
2329	end,
2330    Cmd =
2331	case CR of
2332	    #'CommandRequest'{command = Command} ->
2333		Command;
2334	    _ ->
2335		throw({error, {invalid_commandRequest, CR}})
2336	end,
2337    {Tid, Parms} =
2338	case Cmd of
2339	    {serviceChangeReq,
2340	     #'ServiceChangeRequest'{terminationID      = [TermID],
2341				     serviceChangeParms = ServChParms}} ->
2342		{TermID, ServChParms};
2343	    _ ->
2344		throw({error, {invalid_command, Cmd}})
2345	end,
2346    case Tid of
2347	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
2348	    ok;
2349	_ ->
2350	    throw({error, {invalid_terminationID, Tid}})
2351    end,
2352    case Parms of
2353	%% Version 1 'ServiceChangeParm'
2354	{'ServiceChangeParm',
2355	 restart,                            % serviceChangeMethod
2356	 asn1_NOVALUE,                       % serviceChangeAddress
2357	 ?VERSION,                           % serviceChangeVersion,
2358	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
2359	 [[$9,$0,$1|_]],                     % serviceChangeReason
2360	 asn1_NOVALUE,                       % serviceChangeDelay
2361	 asn1_NOVALUE,                       % serviceChangeMgcId
2362	 asn1_NOVALUE,                       % timeStamp
2363	 asn1_NOVALUE                        % nonStandardData
2364	} ->
2365	    {ok, M};
2366	_ ->
2367	    {error, {invalid_serviceChangeParms, Parms}}
2368    end.
2369
2370ssmp4_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
2371					     TransId, TermId, Cid) ->
2372    fun(Msg) ->
2373	    (catch ssmp4_mgc_verify_notify_reply_segment(Msg,
2374							SN, Last,
2375							TransId, TermId, Cid))
2376    end.
2377
2378ssmp4_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
2379				     SN, Last, TransId, TermId, Cid) ->
2380    p("ssmp4_mgc_verify_notify_reply_segment -> entry with"
2381      "~n   M:       ~p"
2382      "~n   SN:      ~p"
2383      "~n   Last:    ~p"
2384      "~n   TransId: ~p"
2385      "~n   TermId:  ~p"
2386      "~n   Cid:     ~p", [M, SN, Last, TransId, TermId, Cid]),
2387    Body =
2388	case Mess of
2389	    #'Message'{version     = ?VERSION,
2390                       mId         = _Mid,
2391                       messageBody = MsgBody} ->
2392		MsgBody;
2393	    _ ->
2394		throw({error, {invalid_Message, Mess}})
2395	end,
2396    Trans =
2397	case Body of
2398            {transactions, [Transactions]} ->
2399		Transactions;
2400	    _ ->
2401		throw({error, {invalid_messageBody, Body}})
2402	end,
2403    TR =
2404	case Trans of
2405            {transactionReply, TransReply} ->
2406		TransReply;
2407	    _ ->
2408		throw({error, {invalid_transactions, Trans}})
2409	end,
2410    TRes =
2411	case TR of
2412            #'TransactionReply'{transactionId        = TransId,
2413				transactionResult    = TransRes,
2414				segmentNumber        = SN,
2415				segmentationComplete = asn1_NOVALUE} when (Last == false) ->
2416		TransRes;
2417            #'TransactionReply'{transactionId        = TransId,
2418				transactionResult    = TransRes,
2419				segmentNumber        = SN,
2420				segmentationComplete = 'NULL'} when (Last == true) ->
2421		TransRes;
2422	    _ ->
2423		throw({error, {invalid_transactionReply, TR}})
2424	end,
2425    AR =
2426	case TRes of
2427	    {actionReplies, [ActionReply]} ->
2428		ActionReply;
2429	    {actionReplies, ActionReplies} ->
2430		throw({error, {invalid_actionReplies, ActionReplies}});
2431	    _ ->
2432		throw({error, {invalid_transactionResult, TRes}})
2433	end,
2434    CR =
2435	case AR of
2436	    #'ActionReply'{contextId    = Cid,
2437			   commandReply = [CommandReply]} ->
2438		CommandReply;
2439	    #'ActionReply'{contextId    = Cid,
2440			   commandReply = CommandReplies} ->
2441		throw({error, {invalid_commandReplies, CommandReplies}});
2442	    _ ->
2443		throw({error, {invalid_actionReply, AR}})
2444	end,
2445    NR =
2446	case CR of
2447	    {notifyReply, NotifyReply} ->
2448		NotifyReply;
2449	    _ ->
2450		throw({error, {invalid_commandReply, CR}})
2451	end,
2452    case NR of
2453	#'NotifyReply'{terminationID   = [TermId],
2454		       errorDescriptor = asn1_NOVALUE} ->
2455	    {ok, M};
2456	_ ->
2457	    {error, {invalid_NotifyReply, NR}}
2458    end;
2459ssmp4_mgc_verify_notify_reply_segment(Crap,
2460				     _SN, _Last, _TransId, _TermId, _Cid) ->
2461    {error, {invalid_MegacoMessage, Crap}}.
2462
2463
2464ssmp4_mgc_service_change_reply_msg(Mid, Cid) ->
2465    SCRP  = cre_serviceChangeResParm(Mid),
2466    SCRes = cre_serviceChangeResult(SCRP),
2467    Root  = #megaco_term_id{id = ["root"]},
2468    SCR   = cre_serviceChangeReply([Root], SCRes),
2469    CR    = cre_cmdReply(SCR),
2470    AR    = cre_actionReply(Cid, [CR]),
2471    TRes  = cre_transResult([AR]),
2472    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
2473    Trans = cre_transaction(TR),
2474    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
2475    cre_megacoMessage(Mess).
2476
2477ssmp4_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
2478    ARs     = ssmp4_mgc_notify_request_ars(TermIDs, CIDs),
2479    TR      = cre_transReq(TransId, ARs),
2480    Trans   = cre_transaction(TR),
2481    Mess    = cre_message(?VERSION, Mid, cre_transactions([Trans])),
2482    cre_megacoMessage(Mess).
2483
2484ssmp4_mgc_notify_request_ars(TermIDs, CIDs) ->
2485    ssmp4_mgc_notify_request_ars(TermIDs, CIDs, []).
2486
2487ssmp4_mgc_notify_request_ars([], [], Acc) ->
2488    lists:reverse(Acc);
2489ssmp4_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
2490    AR = ssmp4_mgc_notify_request_ar(100+CID, TermID, CID),
2491    ssmp4_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
2492
2493ssmp4_mgc_notify_request_ar(Rid, Tid, Cid) ->
2494    TT      = cre_timeNotation(integer_to_list(19990720+Rid),
2495			       integer_to_list(22000000+Rid)),
2496    Ev      = cre_obsEvent("al/of", TT),
2497    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
2498    NR      = cre_notifyReq([Tid], EvsDesc),
2499    CMD     = cre_command(NR),
2500    CR      = cre_cmdReq(CMD),
2501    cre_actionReq(Cid, [CR]).
2502
2503ssmp4_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
2504    SR    = ssmp4_mgc_segment_reply(TransId, SN, Last),
2505    Trans = cre_transaction(SR),
2506    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
2507    cre_megacoMessage(Mess).
2508
2509ssmp4_mgc_segment_reply(TransId, SN, true) ->
2510    cre_segReply(TransId, SN, 'NULL');
2511ssmp4_mgc_segment_reply(TransId, SN, false) ->
2512    cre_segReply(TransId, SN, asn1_NOVALUE).
2513
2514ssmp4_mgc_trans_ack_msg(Mid, TransId) ->
2515    TA    = cre_transAck(TransId),
2516    Trans = cre_transaction([TA]),
2517    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
2518    cre_megacoMessage(Mess).
2519
2520
2521%%
2522%% MG generator stuff
2523%%
2524ssmp4_mg_event_sequence(Factor, text, tcp) ->
2525    Mid = {deviceName,"mg"},
2526    RI = [
2527          {port,             2944},
2528          {encoding_module,  megaco_pretty_text_encoder},
2529          {encoding_config,  []},
2530          {transport_module, megaco_tcp}
2531         ],
2532    ConnectVerify = ssmp4_mg_verify_handle_connect_fun(),
2533    ServiceChangeReq = ssmp4_mg_service_change_request_ar(Mid, 1),
2534    ServiceChangeReplyVerify = ssmp4_mg_verify_service_change_reply_fun(),
2535    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
2536    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
2537    Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
2538    Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
2539    Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
2540    Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
2541    Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
2542    Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
2543    Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
2544    NotifyReqVerify = ssmp4_mg_verify_notify_request_fun(Tids),
2545    AckVerify = ssmp4_mg_verify_ack_fun(),
2546    TO = fun(T) -> Factor*T end,
2547    EvSeq = [
2548             {debug, true},
2549	     {megaco_trace, disable},
2550             %% {megaco_trace, max},
2551             megaco_start,
2552             {megaco_start_user, Mid, RI, []},
2553             start_transport,
2554             {megaco_system_info, users},
2555             {megaco_system_info, connections},
2556             connect,
2557             {megaco_callback, handle_connect, ConnectVerify},
2558             megaco_connect,
2559             {megaco_cast,     [ServiceChangeReq], []},
2560             {megaco_callback, handle_connect,     ConnectVerify},
2561             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
2562	     {megaco_update_conn_info, protocol_version, ?VERSION},
2563	     {megaco_update_conn_info, segment_send,     3},
2564	     {megaco_update_conn_info, max_pdu_size,     128},
2565             {sleep, 1000},
2566             {megaco_callback, handle_trans_request, NotifyReqVerify},
2567             {megaco_callback, handle_trans_ack,     AckVerify, TO(?SECS(15))},
2568             megaco_stop_user,
2569             megaco_stop,
2570             {sleep, 1000}
2571            ],
2572    EvSeq.
2573
2574
2575ssmp4_mg_verify_handle_connect_fun() ->
2576    fun(Ev) -> ssmp4_mg_verify_handle_connect(Ev) end.
2577
2578ssmp4_mg_verify_handle_connect({handle_connect, CH, 1}) ->
2579    p("ssmp4_mg_verify_handle_connect -> ok"
2580      "~n   CH: ~p", [CH]),
2581    {ok, CH, ok};
2582ssmp4_mg_verify_handle_connect(Else) ->
2583    p("ssmp4_mg_verify_handle_connect -> unknown"
2584      "~n   Else: ~p", [Else]),
2585    {error, Else, ok}.
2586
2587
2588ssmp4_mg_verify_service_change_reply_fun() ->
2589    fun(Rep) -> ssmp4_mg_verify_scr(Rep) end.
2590
2591ssmp4_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
2592    (catch ssmp4_mg_do_verify_scr(AR));
2593ssmp4_mg_verify_scr(Crap) ->
2594    p("ssmp4_mg_verify_scr -> error: "
2595      "~n   Crap: ~p", [Crap]),
2596    {error, Crap, ok}.
2597
2598ssmp4_mg_do_verify_scr(AR) ->
2599    p("ssmp4_mg_do_verify_scr -> ok: "
2600      "~n   AR: ~p", [AR]),
2601    CR =
2602	case AR of
2603	    #'ActionReply'{commandReply = [CmdRep]} ->
2604		CmdRep;
2605	    _ ->
2606		Reason1 = {invalid_action_reply, AR},
2607		throw({error, Reason1, ok})
2608	end,
2609    SCR =
2610	case CR of
2611	    {serviceChangeReply, ServChRep} ->
2612		ServChRep;
2613	    _ ->
2614		Reason2 = {invalid_command_reply, CR},
2615		throw({error, Reason2, ok})
2616	end,
2617    {Tid, SCRes} =
2618	case SCR of
2619	    #'ServiceChangeReply'{terminationID       = [TermID],
2620				  serviceChangeResult = Res} ->
2621		{TermID, Res};
2622	    _ ->
2623		Reason3 = {invalid_service_change_reply, SCR},
2624		throw({error, Reason3, ok})
2625	end,
2626    case Tid of
2627	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
2628	    ok;
2629	_ ->
2630	    Reason4 = {invalid_termination_id, Tid},
2631	    throw({error, Reason4, ok})
2632    end,
2633    SCRParm =
2634	case SCRes of
2635	    {serviceChangeResParms, ServChResParms} ->
2636		ServChResParms;
2637	    _ ->
2638		Reason5 = {invalid_serviceChangeResult, SCRes},
2639		throw({error, Reason5, ok})
2640	end,
2641    case SCRParm of
2642	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
2643	    {ok, AR, ok};
2644	_ ->
2645	    Reason6 = {invalid_service_change_result, SCRParm},
2646	    {error, Reason6, ok}
2647    end.
2648
2649ssmp4_mg_verify_notify_request_fun(Tids) ->
2650    fun(Req) -> ssmp4_mg_verify_notify_request(Req, Tids) end.
2651
2652ssmp4_mg_verify_notify_request(
2653  {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
2654  when length(ARs) =:= length(Tids) ->
2655    (catch ssmp4_mg_do_verify_notify_request(Tids, ARs));
2656ssmp4_mg_verify_notify_request(
2657  {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
2658    e("MG Notify Request verification failed: invalid action requests"
2659      "~n   ARs: ~p", [ARs]),
2660    {error, {invalid_action_requests, ARs}, ok};
2661ssmp4_mg_verify_notify_request(
2662  {handle_trans_request, CH, V, ARs}, _Tids) ->
2663    e("MG Notify Request verification failed: invalid trans request"
2664      "~n   CH:  ~p"
2665      "~n   V:   ~p"
2666      "~n   ARs: ~p", [CH, V, ARs]),
2667    {error, {invalid_trans_request, {CH, V, ARs}}, ok};
2668ssmp4_mg_verify_notify_request(Crap, _Tids) ->
2669    e("MG Notify Request verification failed: unknown request"
2670      "~n   Crap: ~p"
2671      "~n   Tids: ~p", [Crap, _Tids]),
2672    {error, {unexpected_event, Crap}, ok}.
2673
2674ssmp4_mg_do_verify_notify_request(Tids, ARs) ->
2675    p("MG Notify Request verification - attempt verify action request(s):"
2676      "~n   Tids: ~p"
2677      "~n   ARs:  ~p", [Tids, ARs]),
2678    ActionReplies = ssmp4_mg_do_verify_notify_request_ars(Tids, ARs),
2679    p("MG Notify Request verification - ok"
2680      "~n   ActionReplies:  ~p"
2681      "~n", [ActionReplies]),
2682    Reply = {{handle_ack, ssmp4}, ActionReplies},
2683    {ok, ARs, Reply}.
2684
2685ssmp4_mg_do_verify_notify_request_ars(Tids, ARs) ->
2686    ssmp4_mg_do_verify_notify_request_ars(Tids, ARs, []).
2687
2688ssmp4_mg_do_verify_notify_request_ars([], [], Acc) ->
2689    lists:reverse(Acc);
2690ssmp4_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
2691    ActionReply = ssmp4_mg_do_verify_notify_request_ar(Tid, AR),
2692    ssmp4_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
2693
2694ssmp4_mg_do_verify_notify_request_ar(Tid, AR) ->
2695    p("ssmp4_mg_do_verify_notify_request_ar -> ok"
2696      "~n   Tid: ~p"
2697      "~n   AR:  ~p", [Tid, AR]),
2698    {Cid, CR} =
2699	case AR of
2700	    #'ActionRequest'{contextId       = CtxId,
2701			     commandRequests = [CmdReq]} ->
2702		{CtxId, CmdReq};
2703	    _ ->
2704		Reason1 = {invalid_actionRequest, AR},
2705		throw({error, Reason1, ok})
2706	end,
2707    Cmd =
2708	case CR of
2709	    #'CommandRequest'{command = Command} ->
2710		Command;
2711	    _ ->
2712		throw({error, {invalid_commandRequest, CR}, ok})
2713	end,
2714    OED =
2715	case Cmd of
2716	    {notifyReq,
2717	     #'NotifyRequest'{terminationID            = [Tid],
2718			      observedEventsDescriptor = ObsEvDesc,
2719			      errorDescriptor          = asn1_NOVALUE}} ->
2720		ObsEvDesc;
2721	    _ ->
2722		throw({error, {invalid_command, Cmd}, ok})
2723	end,
2724    OE =
2725	case OED of
2726	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
2727		ObsEv;
2728	    #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
2729		throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
2730	    _ ->
2731		throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
2732	end,
2733    case OE of
2734	#'ObservedEvent'{eventName = "al/of"} ->
2735	    ssmp4_mg_notify_reply_ar(Cid, Tid);
2736	_ ->
2737	    throw({error, {invalid_ObservedEvent, OE}, ok})
2738    end.
2739
2740
2741ssmp4_mg_verify_ack_fun() ->
2742    fun(Event) -> ssmp4_mg_verify_ack(Event) end.
2743
2744ssmp4_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp4}) ->
2745    p("ssmp4_mg_verify_ack -> ok"
2746      "~n   CH: ~p", [CH]),
2747    {ok, CH, ok};
2748ssmp4_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
2749    {error, {unknown_ack_data, CrapAckData, CH}, ok};
2750ssmp4_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
2751		    BadAckStatus, BadAckData}) ->
2752    {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
2753ssmp4_mg_verify_ack(BadEvent) ->
2754    {error, {unknown_event, BadEvent}, ok}.
2755
2756
2757ssmp4_mg_service_change_request_ar(_Mid, Cid) ->
2758    Prof  = cre_serviceChangeProf("resgw", 1),
2759    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
2760    Root  = #megaco_term_id{id = ["root"]},
2761    SCR   = cre_serviceChangeReq([Root], SCP),
2762    CMD   = cre_command(SCR),
2763    CR    = cre_cmdReq(CMD),
2764    cre_actionReq(Cid, [CR]).
2765
2766ssmp4_mg_notify_reply_ar(Cid, Tid) ->
2767    NR = cre_notifyReply([Tid]),
2768    CR = cre_cmdReply(NR),
2769    cre_actionReply(Cid, [CR]).
2770
2771
2772
2773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2774
2775send_segmented_msg_ooo1(suite) ->
2776    [];
2777send_segmented_msg_ooo1(doc) ->
2778    "First segment out of order test. "
2779	"Tests that it is possible to send segmented messages, when the "
2780	"segment reply is sent out-of-order. "
2781	"Send window = 3. ";
2782send_segmented_msg_ooo1(Config) when is_list(Config) ->
2783    Pre = fun() ->
2784                  MgcNode = make_node_name(mgc),
2785                  MgNode  = make_node_name(mg),
2786                  d("start nodes: "
2787                    "~n   MgcNode: ~p"
2788                    "~n   MgNode:  ~p",
2789                    [MgcNode, MgNode]),
2790                  Nodes = [MgcNode, MgNode],
2791                  ok = ?START_NODES(Nodes),
2792                  Nodes
2793          end,
2794    Case = fun do_send_segmented_msg_ooo1/1,
2795    Post = fun(Nodes) ->
2796                   d("stop nodes"),
2797                   ?STOP_NODES(lists:reverse(Nodes))
2798           end,
2799    try_tc(ssmo1, Pre, Case, Post).
2800
2801do_send_segmented_msg_ooo1([MgcNode, MgNode]) ->
2802
2803    d("[MGC] start the simulator"),
2804    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
2805
2806    d("[MGC] create the event sequence"),
2807    MgcEvSeq = ssmo1_mgc_event_sequence(text, tcp),
2808
2809    i("wait some time before starting the MGC simulation"),
2810    sleep(1000),
2811
2812    d("[MGC] start the simulation"),
2813    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
2814
2815    i("wait some time before starting the MG simulator"),
2816    sleep(1000),
2817
2818    d("[MG] start the simulator (generator)"),
2819    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
2820
2821    d("[MG] create the event sequence"),
2822    MgEvSeq = ssmo1_mg_event_sequence(text, tcp),
2823
2824    i("wait some time before starting the MG simulation"),
2825    sleep(1000),
2826
2827    d("[MG] start the simulation"),
2828    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
2829
2830    %% Await MGC ready for segments
2831    d("await MGC trigger event"),
2832    MgcPid =
2833	receive
2834	    {ready_for_segmented_msg, mgc, Pid1} ->
2835		d("received MGC trigger event"),
2836		Pid1
2837	after 5000 ->
2838		d("timeout waiting for MGC trigger event: ~p",
2839		  [megaco_test_lib:flush()]),
2840		?ERROR(timeout_MGC_trigger_event)
2841	end,
2842
2843    %% Await MG ready for segments
2844    d("await MG trigger event"),
2845    MgPid =
2846	receive
2847	    {ready_for_segmented_msg, mg, Pid2} ->
2848		d("received MG trigger event"),
2849		Pid2
2850	after 5000 ->
2851		d("timeout waiting for MG trigger event: ~p",
2852		  [megaco_test_lib:flush()]),
2853		?ERROR(timeout_MG_trigger_event)
2854	end,
2855
2856    %% Instruct the MG to continue
2857    d("send continue to MG"),
2858    MgPid ! {continue_with_segmented_msg, self()},
2859
2860    sleep(500),
2861
2862    %% Instruct the MGC to continue
2863    d("send continue to MGC"),
2864    MgcPid ! {continue_with_segmented_msg, self()},
2865
2866    d("await the generator reply(s)"),
2867    await_completion([MgcId, MgId]),
2868
2869    %% Tell Mgc to stop
2870    i("[MGC] stop generator"),
2871    megaco_test_tcp_generator:stop(Mgc),
2872
2873    %% Tell Mg to stop
2874    i("[MG] stop generator"),
2875    megaco_test_megaco_generator:stop(Mg),
2876
2877    i("done", []),
2878    ok.
2879
2880
2881
2882%%
2883%% MGC generator stuff
2884%%
2885
2886ssmo1_mgc_event_sequence(text, tcp) ->
2887    DecodeFun = ssmo1_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
2888    EncodeFun = ssmo1_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
2889    Mid       = {deviceName,"mgc"},
2890    ScrVerifyFun     = ssmo1_mgc_verify_service_change_req_msg_fun(),
2891    ServiceChangeRep = ssmo1_mgc_service_change_reply_msg(Mid, 1),
2892    AnnounceReadySegs = ssmo1_mgc_announce_ready_for_segmented_msg_fun(),
2893    AwaitContinueSegs = ssmo1_mgc_continue_with_segmented_msg_fun(),
2894    TermId1   =
2895	#megaco_term_id{id = ["00000000","00000000","00000001"]},
2896    CtxId1    = 1,
2897    TermId2   =
2898	#megaco_term_id{id = ["00000000","00000000","00000002"]},
2899    CtxId2    = 2,
2900    TermId3   =
2901	#megaco_term_id{id = ["00000000","00000000","00000003"]},
2902    CtxId3    = 3,
2903    TermId4   =
2904	#megaco_term_id{id = ["00000000","00000000","00000004"]},
2905    CtxId4    = 4,
2906    TermId5   =
2907	#megaco_term_id{id = ["00000000","00000000","00000005"]},
2908    CtxId5    = 5,
2909    TermId6   =
2910	#megaco_term_id{id = ["00000000","00000000","00000006"]},
2911    CtxId6    = 6,
2912    TermId7   =
2913	#megaco_term_id{id = ["00000000","00000000","00000007"]},
2914    CtxId7    = 7,
2915    TermId8   =
2916	#megaco_term_id{id = ["00000000","00000000","00000008"]},
2917    CtxId8    = 8,
2918    TransId   = 2,
2919    TermIDs = [TermId1, TermId2, TermId3, TermId4,
2920	       TermId5, TermId6, TermId7, TermId8],
2921    CIDs    = [CtxId1, CtxId2, CtxId3, CtxId4,
2922	       CtxId5, CtxId6, CtxId7, CtxId8],
2923    NotifyReq = ssmo1_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
2924    NrVerifyFun1 =
2925	ssmo1_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
2926						      TermId1, CtxId1),
2927    NrVerifyFun2 =
2928	ssmo1_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
2929						      TermId2, CtxId2),
2930    NrVerifyFun3 =
2931	ssmo1_mgc_verify_notify_reply_segment_msg_fun(3, false, TransId,
2932						      TermId3, CtxId3),
2933    NrVerifyFun4 =
2934	ssmo1_mgc_verify_notify_reply_segment_msg_fun(4, false, TransId,
2935						      TermId4, CtxId4),
2936    NrVerifyFun5 =
2937	ssmo1_mgc_verify_notify_reply_segment_msg_fun(5, false, TransId,
2938						      TermId5, CtxId5),
2939    NrVerifyFun6 =
2940	ssmo1_mgc_verify_notify_reply_segment_msg_fun(6, false, TransId,
2941						      TermId6, CtxId6),
2942    NrVerifyFun7 =
2943	ssmo1_mgc_verify_notify_reply_segment_msg_fun(7, false, TransId,
2944						      TermId7, CtxId7),
2945    NrVerifyFun8 =
2946	ssmo1_mgc_verify_notify_reply_segment_msg_fun(8, true, TransId,
2947						      TermId8, CtxId8),
2948    SegmentRep1 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 1, false),
2949    SegmentRep2 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 2, false),
2950    SegmentRep3 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 3, false),
2951    SegmentRep4 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 4, false),
2952    SegmentRep5 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 5, false),
2953    SegmentRep6 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 6, false),
2954    SegmentRep7 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 7, false),
2955    SegmentRep8 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 8, true),
2956    TransAck    = ssmo1_mgc_trans_ack_msg(Mid, TransId),
2957    EvSeq = [{debug,  true},
2958             {decode, DecodeFun},
2959             {encode, EncodeFun},
2960             {listen, 2944},
2961	     {expect_accept, any},
2962             {expect_receive, "service-change-request",  {ScrVerifyFun, 5000}},
2963             {send, "service-change-reply",              ServiceChangeRep},
2964
2965             {trigger, "announce ready for segmented message",
2966              AnnounceReadySegs},
2967             {trigger, "await continue for segmented message",
2968              AwaitContinueSegs},
2969
2970	     %% {expect_nothing, 1000},
2971             {send, "notify request",                    NotifyReq},
2972             {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
2973             {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
2974             {expect_receive, "notify reply: segment 3", {NrVerifyFun3, 1000}},
2975	     {expect_nothing, 1000},
2976             {send, "segment reply 2 [1]",               SegmentRep2},
2977             {expect_receive, "notify reply: segment 4", {NrVerifyFun4, 1000}},
2978	     {expect_nothing, 1000},
2979             {send, "segment reply 1 [2]",               SegmentRep1},
2980             {expect_receive, "notify reply: segment 5", {NrVerifyFun5, 1000}},
2981	     {expect_nothing, 1000},
2982             {send, "segment reply 3 [3]",               SegmentRep3},
2983             {expect_receive, "notify reply: segment 6", {NrVerifyFun6, 1000}},
2984	     {expect_nothing, 1000},
2985             {send, "segment reply 5 [4]",               SegmentRep5},
2986             {expect_receive, "notify reply: segment 7", {NrVerifyFun7, 1000}},
2987	     {expect_nothing, 1000},
2988             {send, "segment reply 4 [5]",               SegmentRep4},
2989             {expect_receive, "notify reply: segment 8", {NrVerifyFun8, 1000}},
2990	     {expect_nothing, 1000},
2991             {send, "segment reply 6",                   SegmentRep6},
2992	     {expect_nothing, 1000},
2993             {send, "segment reply 7",                   SegmentRep7},
2994	     {expect_nothing, 1000},
2995             {send, "segment reply 8",                   SegmentRep8},
2996	     {expect_nothing, 1000},
2997	     {send, "transaction-ack",                   TransAck},
2998             {expect_closed,  5000},
2999             disconnect
3000            ],
3001    EvSeq.
3002
3003ssmo1_mgc_encode_msg_fun(Mod, Conf) ->
3004    fun(M) ->
3005            Mod:encode_message(Conf, M)
3006    end.
3007
3008ssmo1_mgc_decode_msg_fun(Mod, Conf) ->
3009    fun(M) ->
3010            Mod:decode_message(Conf, M)
3011    end.
3012
3013ssmo1_mgc_verify_service_change_req_msg_fun() ->
3014    fun(Msg) ->
3015	    (catch ssmo1_mgc_verify_service_change_req(Msg))
3016    end.
3017
3018ssmo1_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
3019    p("ssmo1_mgc_verify_service_change_req -> entry with"
3020      "~n   M: ~p", [M]),
3021    Body =
3022	case Mess of
3023	    #'Message'{version     = 1,
3024                       mId         = _MgMid,
3025                       messageBody = MsgBody} ->
3026		MsgBody;
3027	    _ ->
3028		throw({error, {invalid_Message, Mess}})
3029	end,
3030    Trans =
3031	case Body of
3032            {transactions, [Transactions]} ->
3033		Transactions;
3034	    _ ->
3035		throw({error, {invalid_messageBody, Body}})
3036	end,
3037    TR =
3038	case Trans of
3039            {transactionRequest, TransRequest} ->
3040		TransRequest;
3041	    _ ->
3042		throw({error, {invalid_transactions, Trans}})
3043	end,
3044    AR =
3045	case TR of
3046            #'TransactionRequest'{transactionId = _TransId,
3047				  actions       = [ActionReq]} ->
3048		ActionReq;
3049	    _ ->
3050		throw({error, {invalid_transactionRequest, TR}})
3051	end,
3052    CR =
3053	case AR of
3054	    #'ActionRequest'{contextId       = _Cid,
3055			     commandRequests = [CmdReq]} ->
3056		CmdReq;
3057	    _ ->
3058		throw({error, {invalid_action, AR}})
3059	end,
3060    Cmd =
3061	case CR of
3062	    #'CommandRequest'{command = Command} ->
3063		Command;
3064	    _ ->
3065		throw({error, {invalid_commandRequest, CR}})
3066	end,
3067    {Tid, Parms} =
3068	case Cmd of
3069	    {serviceChangeReq,
3070	     #'ServiceChangeRequest'{terminationID      = [TermID],
3071				     serviceChangeParms = ServChParms}} ->
3072		{TermID, ServChParms};
3073	    _ ->
3074		throw({error, {invalid_command, Cmd}})
3075	end,
3076    case Tid of
3077	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
3078	    ok;
3079	_ ->
3080	    throw({error, {invalid_terminationID, Tid}})
3081    end,
3082    case Parms of
3083	%% Version 1 'ServiceChangeParm'
3084	{'ServiceChangeParm',
3085	 restart,                            % serviceChangeMethod
3086	 asn1_NOVALUE,                       % serviceChangeAddress
3087	 ?VERSION,                           % serviceChangeVersion,
3088	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
3089	 [[$9,$0,$1|_]],                     % serviceChangeReason
3090	 asn1_NOVALUE,                       % serviceChangeDelay
3091	 asn1_NOVALUE,                       % serviceChangeMgcId
3092	 asn1_NOVALUE,                       % timeStamp
3093	 asn1_NOVALUE                        % nonStandardData
3094	} ->
3095	    {ok, M};
3096	_ ->
3097	    {error, {invalid_serviceChangeParms, Parms}}
3098    end.
3099
3100ssmo1_mgc_announce_ready_for_segmented_msg_fun() ->
3101    TC = self(),
3102    fun() ->
3103            TC ! {ready_for_segmented_msg, mgc, self()}
3104    end.
3105
3106ssmo1_mgc_continue_with_segmented_msg_fun() ->
3107    TC = self(),
3108    fun() ->
3109            p("[MGC] await continue with segmented message"),
3110            receive
3111                {continue_with_segmented_msg, TC} ->
3112                    p("[MGC] received continue with segmented message"),
3113                    ok
3114            end
3115    end.
3116
3117ssmo1_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
3118					     TransId, TermId, Cid) ->
3119    fun(Msg) ->
3120	    (catch ssmo1_mgc_verify_notify_reply_segment(Msg,
3121							SN, Last,
3122							TransId, TermId, Cid))
3123    end.
3124
3125ssmo1_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
3126				     SN, Last, TransId, TermId, Cid) ->
3127    io:format("ssmo1_mgc_verify_notify_reply_segment -> entry with"
3128	      "~n   M:       ~p"
3129	      "~n   SN:      ~p"
3130	      "~n   Last:    ~p"
3131	      "~n   TransId: ~p"
3132	      "~n   TermId:  ~p"
3133	      "~n   Cid:     ~p"
3134	      "~n", [M, SN, Last, TransId, TermId, Cid]),
3135    Body =
3136	case Mess of
3137	    #'Message'{version     = ?VERSION,
3138                       mId         = _Mid,
3139                       messageBody = MsgBody} ->
3140		MsgBody;
3141	    _ ->
3142		throw({error, {invalid_Message, Mess}})
3143	end,
3144    Trans =
3145	case Body of
3146            {transactions, [Transactions]} ->
3147		Transactions;
3148	    _ ->
3149		throw({error, {invalid_messageBody, Body}})
3150	end,
3151    TR =
3152	case Trans of
3153            {transactionReply, TransReply} ->
3154		TransReply;
3155	    _ ->
3156		throw({error, {invalid_transactions, Trans}})
3157	end,
3158    TRes =
3159	case TR of
3160            #'TransactionReply'{transactionId        = TransId,
3161				transactionResult    = TransRes,
3162				segmentNumber        = SN,
3163				segmentationComplete = asn1_NOVALUE} when (Last == false) ->
3164		TransRes;
3165            #'TransactionReply'{transactionId        = TransId,
3166				transactionResult    = TransRes,
3167				segmentNumber        = SN,
3168				segmentationComplete = 'NULL'} when (Last == true) ->
3169		TransRes;
3170	    _ ->
3171		throw({error, {invalid_transactionReply, TR}})
3172	end,
3173    AR =
3174	case TRes of
3175	    {actionReplies, [ActionReply]} ->
3176		ActionReply;
3177	    {actionReplies, ActionReplies} ->
3178		throw({error, {invalid_actionReplies, ActionReplies}});
3179	    _ ->
3180		throw({error, {invalid_transactionResult, TRes}})
3181	end,
3182    CR =
3183	case AR of
3184	    #'ActionReply'{contextId    = Cid,
3185			   commandReply = [CommandReply]} ->
3186		CommandReply;
3187	    #'ActionReply'{contextId    = Cid,
3188			   commandReply = CommandReplies} ->
3189		throw({error, {invalid_commandReplies, CommandReplies}});
3190	    _ ->
3191		throw({error, {invalid_actionReply, AR}})
3192	end,
3193    NR =
3194	case CR of
3195	    {notifyReply, NotifyReply} ->
3196		NotifyReply;
3197	    _ ->
3198		throw({error, {invalid_commandReply, CR}})
3199	end,
3200    case NR of
3201	#'NotifyReply'{terminationID   = [TermId],
3202		       errorDescriptor = asn1_NOVALUE} ->
3203	    {ok, M};
3204	_ ->
3205	    {error, {invalid_NotifyReply, NR}}
3206    end;
3207ssmo1_mgc_verify_notify_reply_segment(Crap,
3208				     _SN, _Last, _TransId, _TermId, _Cid) ->
3209    {error, {invalid_MegacoMessage, Crap}}.
3210
3211
3212ssmo1_mgc_service_change_reply_msg(Mid, Cid) ->
3213    SCRP  = cre_serviceChangeResParm(Mid),
3214    SCRes = cre_serviceChangeResult(SCRP),
3215    Root  = #megaco_term_id{id = ["root"]},
3216    SCR   = cre_serviceChangeReply([Root], SCRes),
3217    CR    = cre_cmdReply(SCR),
3218    AR    = cre_actionReply(Cid, [CR]),
3219    TRes  = cre_transResult([AR]),
3220    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
3221    Trans = cre_transaction(TR),
3222    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
3223    cre_megacoMessage(Mess).
3224
3225ssmo1_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
3226    ARs     = ssmo1_mgc_notify_request_ars(TermIDs, CIDs),
3227    TR      = cre_transReq(TransId, ARs),
3228    Trans   = cre_transaction(TR),
3229    Mess    = cre_message(?VERSION, Mid, cre_transactions([Trans])),
3230    cre_megacoMessage(Mess).
3231
3232ssmo1_mgc_notify_request_ars(TermIDs, CIDs) ->
3233    ssmo1_mgc_notify_request_ars(TermIDs, CIDs, []).
3234
3235ssmo1_mgc_notify_request_ars([], [], Acc) ->
3236    lists:reverse(Acc);
3237ssmo1_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
3238    AR = ssmo1_mgc_notify_request_ar(100+CID, TermID, CID),
3239    ssmo1_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
3240
3241ssmo1_mgc_notify_request_ar(Rid, Tid, Cid) ->
3242    TT      = cre_timeNotation(integer_to_list(19990720+Rid),
3243			       integer_to_list(22000000+Rid)),
3244    Ev      = cre_obsEvent("al/of", TT),
3245    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
3246    NR      = cre_notifyReq([Tid], EvsDesc),
3247    CMD     = cre_command(NR),
3248    CR      = cre_cmdReq(CMD),
3249    cre_actionReq(Cid, [CR]).
3250
3251ssmo1_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
3252    SR    = ssmo1_mgc_segment_reply(TransId, SN, Last),
3253    Trans = cre_transaction(SR),
3254    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
3255    cre_megacoMessage(Mess).
3256
3257ssmo1_mgc_segment_reply(TransId, SN, true) ->
3258    cre_segReply(TransId, SN, 'NULL');
3259ssmo1_mgc_segment_reply(TransId, SN, false) ->
3260    cre_segReply(TransId, SN, asn1_NOVALUE).
3261
3262ssmo1_mgc_trans_ack_msg(Mid, TransId) ->
3263    TA    = cre_transAck(TransId),
3264    Trans = cre_transaction([TA]),
3265    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
3266    cre_megacoMessage(Mess).
3267
3268
3269%%
3270%% MG generator stuff
3271%%
3272ssmo1_mg_event_sequence(text, tcp) ->
3273    Mid = {deviceName,"mg"},
3274    RI = [
3275          {port,             2944},
3276          {encoding_module,  megaco_pretty_text_encoder},
3277          {encoding_config,  []},
3278          {transport_module, megaco_tcp}
3279         ],
3280    ConnectVerify = ssmo1_mg_verify_handle_connect_fun(),
3281    ServiceChangeReq = ssmo1_mg_service_change_request_ar(Mid, 1),
3282    ServiceChangeReplyVerify = ssmo1_mg_verify_service_change_reply_fun(),
3283    AnnounceReadySegs = ssmo1_mg_announce_ready_for_segmented_msg_fun(),
3284    AwaitContinueSegs = ssmo1_mg_continue_with_segmented_msg_fun(),
3285    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
3286    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
3287    Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
3288    Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
3289    Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
3290    Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
3291    Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
3292    Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
3293    Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
3294    NotifyReqVerify = ssmo1_mg_verify_notify_request_fun(Tids),
3295    AckVerify = ssmo1_mg_verify_ack_fun(),
3296    EvSeq = [
3297             {debug, true},
3298	     {megaco_trace, disable},
3299             %% {megaco_trace, max},
3300             megaco_start,
3301             {megaco_start_user, Mid, RI, []},
3302             start_transport,
3303             {megaco_system_info, users},
3304             {megaco_system_info, connections},
3305             connect,
3306             {megaco_callback, handle_connect, ConnectVerify},
3307             megaco_connect,
3308             {megaco_cast,     [ServiceChangeReq], []},
3309             {megaco_callback, handle_connect,     ConnectVerify},
3310             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
3311	     {megaco_update_conn_info, protocol_version, ?VERSION},
3312	     {megaco_update_conn_info, segment_send,     3},
3313	     {megaco_update_conn_info, max_pdu_size,     128},
3314
3315             {trigger, "announce ready for segmented message",
3316              AnnounceReadySegs},
3317             {trigger, "await continue for segmented message",
3318              AwaitContinueSegs},
3319
3320             {megaco_callback, handle_trans_request, NotifyReqVerify},
3321             {megaco_callback, handle_trans_ack,     AckVerify, 15000},
3322             megaco_stop_user,
3323             megaco_stop,
3324             {sleep, 1000}
3325            ],
3326    EvSeq.
3327
3328ssmo1_mg_verify_handle_connect_fun() ->
3329    fun(Ev) -> ssmo1_mg_verify_handle_connect(Ev) end.
3330
3331ssmo1_mg_verify_handle_connect({handle_connect, CH, 1}) ->
3332    io:format("ssmo1_mg_verify_handle_connect -> ok"
3333	      "~n   CH: ~p~n", [CH]),
3334    {ok, CH, ok};
3335ssmo1_mg_verify_handle_connect(Else) ->
3336    io:format("ssmo1_mg_verify_handle_connect -> unknown"
3337	      "~n   Else: ~p~n", [Else]),
3338    {error, Else, ok}.
3339
3340
3341ssmo1_mg_verify_service_change_reply_fun() ->
3342    fun(Rep) -> ssmo1_mg_verify_scr(Rep) end.
3343
3344ssmo1_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
3345    (catch ssmo1_mg_do_verify_scr(AR));
3346ssmo1_mg_verify_scr(Crap) ->
3347    io:format("ssmo1_mg_verify_scr -> error: "
3348	      "~n   Crap: ~p"
3349	      "~n", [Crap]),
3350    {error, Crap, ok}.
3351
3352ssmo1_mg_do_verify_scr(AR) ->
3353    io:format("ssmo1_mg_do_verify_scr -> ok: "
3354	      "~n   AR: ~p~n", [AR]),
3355    CR =
3356	case AR of
3357	    #'ActionReply'{commandReply = [CmdRep]} ->
3358		CmdRep;
3359	    _ ->
3360		Reason1 = {invalid_action_reply, AR},
3361		throw({error, Reason1, ok})
3362	end,
3363    SCR =
3364	case CR of
3365	    {serviceChangeReply, ServChRep} ->
3366		ServChRep;
3367	    _ ->
3368		Reason2 = {invalid_command_reply, CR},
3369		throw({error, Reason2, ok})
3370	end,
3371    {Tid, SCRes} =
3372	case SCR of
3373	    #'ServiceChangeReply'{terminationID       = [TermID],
3374				  serviceChangeResult = Res} ->
3375		{TermID, Res};
3376	    _ ->
3377		Reason3 = {invalid_service_change_reply, SCR},
3378		throw({error, Reason3, ok})
3379	end,
3380    case Tid of
3381	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
3382	    ok;
3383	_ ->
3384	    Reason4 = {invalid_termination_id, Tid},
3385	    throw({error, Reason4, ok})
3386    end,
3387    SCRParm =
3388	case SCRes of
3389	    {serviceChangeResParms, ServChResParms} ->
3390		ServChResParms;
3391	    _ ->
3392		Reason5 = {invalid_serviceChangeResult, SCRes},
3393		throw({error, Reason5, ok})
3394	end,
3395    case SCRParm of
3396	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
3397	    {ok, AR, ok};
3398	_ ->
3399	    Reason6 = {invalid_service_change_result, SCRParm},
3400	    {error, Reason6, ok}
3401    end.
3402
3403ssmo1_mg_announce_ready_for_segmented_msg_fun() ->
3404    TC = self(),
3405    fun() ->
3406            TC ! {ready_for_segmented_msg, mg, self()}
3407    end.
3408
3409ssmo1_mg_continue_with_segmented_msg_fun() ->
3410    TC = self(),
3411    fun() ->
3412            p("[MG] await continue with segmented message"),
3413            receive
3414                {continue_with_segmented_msg, TC} ->
3415                    p("[MG] received continue with segmented message"),
3416                    ok
3417            end
3418    end.
3419
3420ssmo1_mg_verify_notify_request_fun(Tids) ->
3421    fun(Req) -> ssmo1_mg_verify_notify_request(Req, Tids) end.
3422
3423ssmo1_mg_verify_notify_request(
3424  {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
3425  when length(ARs) == length(Tids) ->
3426    (catch ssmo1_mg_do_verify_notify_request(Tids, ARs));
3427ssmo1_mg_verify_notify_request(
3428  {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
3429    {error, {invalid_action_requests, ARs}, ok};
3430ssmo1_mg_verify_notify_request(
3431  {handle_trans_request, CH, V, ARs}, _Tids) ->
3432    {error, {invalid_trans_request, {CH, V, ARs}}, ok};
3433ssmo1_mg_verify_notify_request(Crap, _Tids) ->
3434    io:format("ssmo1_mg_verify_notify_request -> unknown request"
3435	      "~n   Crap: ~p"
3436	      "~n   Tids: ~p"
3437	      "~n", [Crap, _Tids]),
3438    {error, {unexpected_event, Crap}, ok}.
3439
3440ssmo1_mg_do_verify_notify_request(Tids, ARs) ->
3441    io:format("ssmo1_mg_do_verify_notify_request -> ok"
3442	      "~n   Tids: ~p"
3443	      "~n   ARs:  ~p"
3444	      "~n", [Tids, ARs]),
3445    ActionReplies = ssmo1_mg_do_verify_notify_request_ars(Tids, ARs),
3446    io:format("ssmo1_mg_do_verify_notify_request -> ok"
3447	      "~n   ActionReplies:  ~p"
3448	      "~n", [ActionReplies]),
3449    Reply = {{handle_ack, ssmp4}, ActionReplies},
3450    {ok, ARs, Reply}.
3451
3452ssmo1_mg_do_verify_notify_request_ars(Tids, ARs) ->
3453    ssmo1_mg_do_verify_notify_request_ars(Tids, ARs, []).
3454
3455ssmo1_mg_do_verify_notify_request_ars([], [], Acc) ->
3456    lists:reverse(Acc);
3457ssmo1_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
3458    ActionReply = ssmo1_mg_do_verify_notify_request_ar(Tid, AR),
3459    ssmo1_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
3460
3461ssmo1_mg_do_verify_notify_request_ar(Tid, AR) ->
3462    io:format("ssmo1_mg_do_verify_notify_request_ar -> ok"
3463	      "~n   Tid: ~p"
3464	      "~n   AR:  ~p"
3465	      "~n", [Tid, AR]),
3466    {Cid, CR} =
3467	case AR of
3468	    #'ActionRequest'{contextId       = CtxId,
3469			     commandRequests = [CmdReq]} ->
3470		{CtxId, CmdReq};
3471	    _ ->
3472		Reason1 = {invalid_actionRequest, AR},
3473		throw({error, Reason1, ok})
3474	end,
3475    Cmd =
3476	case CR of
3477	    #'CommandRequest'{command = Command} ->
3478		Command;
3479	    _ ->
3480		throw({error, {invalid_commandRequest, CR}, ok})
3481	end,
3482    OED =
3483	case Cmd of
3484	    {notifyReq,
3485	     #'NotifyRequest'{terminationID            = [Tid],
3486			      observedEventsDescriptor = ObsEvDesc,
3487			      errorDescriptor          = asn1_NOVALUE}} ->
3488		ObsEvDesc;
3489	    _ ->
3490		throw({error, {invalid_command, Cmd}, ok})
3491	end,
3492    OE =
3493	case OED of
3494	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
3495		ObsEv;
3496	    #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
3497		throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
3498	    _ ->
3499		throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
3500	end,
3501    case OE of
3502	#'ObservedEvent'{eventName = "al/of"} ->
3503	    ssmo1_mg_notify_reply_ar(Cid, Tid);
3504	_ ->
3505	    throw({error, {invalid_ObservedEvent, OE}, ok})
3506    end.
3507
3508
3509ssmo1_mg_verify_ack_fun() ->
3510    fun(Event) -> ssmo1_mg_verify_ack(Event) end.
3511
3512ssmo1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp4}) ->
3513    io:format("ssmo1_mg_verify_ack -> ok"
3514              "~n   CH: ~p"
3515              "~n", [CH]),
3516    {ok, CH, ok};
3517ssmo1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
3518    {error, {unknown_ack_data, CrapAckData, CH}, ok};
3519ssmo1_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
3520		    BadAckStatus, BadAckData}) ->
3521    {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
3522ssmo1_mg_verify_ack(BadEvent) ->
3523    {error, {unknown_event, BadEvent}, ok}.
3524
3525
3526ssmo1_mg_service_change_request_ar(_Mid, Cid) ->
3527    Prof  = cre_serviceChangeProf("resgw", 1),
3528    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
3529    Root  = #megaco_term_id{id = ["root"]},
3530    SCR   = cre_serviceChangeReq([Root], SCP),
3531    CMD   = cre_command(SCR),
3532    CR    = cre_cmdReq(CMD),
3533    cre_actionReq(Cid, [CR]).
3534
3535ssmo1_mg_notify_reply_ar(Cid, Tid) ->
3536    NR = cre_notifyReply([Tid]),
3537    CR = cre_cmdReply(NR),
3538    cre_actionReply(Cid, [CR]).
3539
3540
3541
3542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3543
3544send_segmented_msg_missing_seg_reply1(suite) ->
3545    [];
3546send_segmented_msg_missing_seg_reply1(doc) ->
3547    "First missing segment test. "
3548	"Tests that the callbacks and error messages are delivered "
3549	"when a segment reply goes missing. Ack expected. "
3550	"Send window = 3. ";
3551send_segmented_msg_missing_seg_reply1(Config) when is_list(Config) ->
3552    Pre = fun() ->
3553                  MgcNode = make_node_name(mgc),
3554                  MgNode  = make_node_name(mg),
3555                  d("start nodes: "
3556                    "~n      MgcNode: ~p"
3557                    "~n      MgNode:  ~p",
3558                    [MgcNode, MgNode]),
3559                  Nodes = [MgcNode, MgNode],
3560                  ok = ?START_NODES(Nodes),
3561                  Nodes
3562          end,
3563    Case = fun do_send_segmented_msg_missing_seg_reply1/1,
3564    Post = fun(Nodes) ->
3565                   d("stop nodes"),
3566                   ?STOP_NODES(lists:reverse(Nodes))
3567           end,
3568    try_tc(ssmmsr1, Pre, Case, Post).
3569
3570do_send_segmented_msg_missing_seg_reply1([MgcNode, MgNode]) ->
3571
3572    d("[MGC] start the simulator "),
3573    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
3574
3575    d("[MGC] create the event sequence"),
3576    MgcEvSeq = ssmmsr1_mgc_event_sequence(text, tcp),
3577
3578    i("wait some time before starting the MGC simulation"),
3579    sleep(1000),
3580
3581    d("[MGC] start the simulation"),
3582    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
3583
3584    i("wait some time before starting the MG simulator"),
3585    sleep(1000),
3586
3587    d("[MG] start the simulator (generator)"),
3588    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
3589
3590    d("[MG] create the event sequence"),
3591    MgEvSeq = ssmmsr1_mg_event_sequence(text, tcp),
3592
3593    i("wait some time before starting the MG simulation"),
3594    sleep(1000),
3595
3596    d("[MG] start the simulation"),
3597    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
3598
3599    %% Await MGC ready for segments
3600    d("await MGC trigger event"),
3601    MgcPid =
3602	receive
3603	    {ready_for_segments, mgc, Pid1} ->
3604		d("received MGC trigger event"),
3605		Pid1
3606	after 5000 ->
3607		d("timeout waiting for MGC trigger event: ~p",
3608		  [megaco_test_lib:flush()]),
3609		?ERROR(timeout_MGC_trigger_event)
3610	end,
3611
3612    %% Await MG ready for segments
3613    d("await MG trigger event"),
3614    MgPid =
3615	receive
3616	    {ready_for_segments, mg, Pid2} ->
3617		d("received MG trigger event"),
3618		Pid2
3619	after 5000 ->
3620		d("timeout waiting for MG trigger event: ~p",
3621		  [megaco_test_lib:flush()]),
3622		?ERROR(timeout_MG_trigger_event)
3623	end,
3624
3625    %% Instruct the MG to continue
3626    d("send continue to MG"),
3627    MgPid ! {continue_with_segments, self()},
3628
3629    sleep(500),
3630
3631    %% Instruct the MGC to continue
3632    d("send continue to MGC"),
3633    MgcPid ! {continue_with_segments, self()},
3634
3635    d("await the generator reply(s)"),
3636    await_completion([MgcId, MgId]),
3637
3638    %% Tell Mgc to stop
3639    i("[MGC] stop generator"),
3640    megaco_test_tcp_generator:stop(Mgc),
3641
3642    %% Tell Mg to stop
3643    i("[MG] stop generator"),
3644    megaco_test_megaco_generator:stop(Mg),
3645
3646    i("done", []),
3647    ok.
3648
3649
3650
3651%%
3652%% MGC generator stuff
3653%%
3654
3655ssmmsr1_mgc_event_sequence(text, tcp) ->
3656    DecodeFun = ssmmsr1_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
3657    EncodeFun = ssmmsr1_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
3658    Mid       = {deviceName,"mgc"},
3659    ScrVerifyFun     = ssmmsr1_mgc_verify_service_change_req_msg_fun(),
3660    ServiceChangeRep = ssmmsr1_mgc_service_change_reply_msg(Mid, 1),
3661    TermId1   =
3662	#megaco_term_id{id = ["00000000","00000000","00000001"]},
3663    CtxId1    = 1,
3664    TermId2   =
3665	#megaco_term_id{id = ["00000000","00000000","00000002"]},
3666    CtxId2    = 2,
3667    TermId3   =
3668	#megaco_term_id{id = ["00000000","00000000","00000003"]},
3669    CtxId3    = 3,
3670    TermId4   =
3671	#megaco_term_id{id = ["00000000","00000000","00000004"]},
3672    CtxId4    = 4,
3673    TermId5   =
3674	#megaco_term_id{id = ["00000000","00000000","00000005"]},
3675    CtxId5    = 5,
3676    TermId6   =
3677	#megaco_term_id{id = ["00000000","00000000","00000006"]},
3678    CtxId6    = 6,
3679    TermId7   =
3680	#megaco_term_id{id = ["00000000","00000000","00000007"]},
3681    CtxId7    = 7,
3682    TermId8   =
3683	#megaco_term_id{id = ["00000000","00000000","00000008"]},
3684    CtxId8    = 8,
3685    TransId   = 2,
3686    TermIDs = [TermId1, TermId2, TermId3, TermId4,
3687	       TermId5, TermId6, TermId7, TermId8],
3688    CIDs    = [CtxId1, CtxId2, CtxId3, CtxId4,
3689	       CtxId5, CtxId6, CtxId7, CtxId8],
3690    NotifyReq = ssmmsr1_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
3691    NrVerifyFun1 =
3692	ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
3693						      TermId1, CtxId1),
3694    NrVerifyFun2 =
3695	ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
3696						      TermId2, CtxId2),
3697    NrVerifyFun3 =
3698	ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(3, false, TransId,
3699						      TermId3, CtxId3),
3700    NrVerifyFun4 =
3701	ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(4, false, TransId,
3702						      TermId4, CtxId4),
3703    NrVerifyFun5 =
3704	ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(5, false, TransId,
3705						      TermId5, CtxId5),
3706    NrVerifyFun6 =
3707	ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(6, false, TransId,
3708						      TermId6, CtxId6),
3709    NrVerifyFun7 =
3710	ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(7, false, TransId,
3711						      TermId7, CtxId7),
3712    NrVerifyFun8 =
3713	ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(8, true, TransId,
3714						      TermId8, CtxId8),
3715    SegmentRep1 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 1, false),
3716    SegmentRep2 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 2, false),
3717    %% SegmentRep3 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 3, false),
3718    SegmentRep4 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 4, false),
3719    SegmentRep5 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 5, false),
3720    SegmentRep6 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 6, false),
3721    SegmentRep7 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 7, false),
3722    SegmentRep8 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 8, true),
3723    TransAck    = ssmmsr1_mgc_trans_ack_msg(Mid, TransId),
3724    ReadyForSegments = ssmmsr1_mgc_ready_for_segments_fun(),
3725    EvSeq = [{debug,  true},
3726             {trigger, "verbosity",
3727              fun() ->
3728                      put(verbosity, ?TEST_VERBOSITY)
3729              end},
3730             {decode, DecodeFun},
3731             {encode, EncodeFun},
3732             {listen, 2944},
3733	     {expect_accept, any},
3734             {expect_receive, "service-change-request",  {ScrVerifyFun, 5000}},
3735             {send, "service-change-reply",              ServiceChangeRep},
3736	     %% {expect_nothing, 1000},
3737	     {trigger, "segment send sync trigger", ReadyForSegments},
3738             {send, "notify request",                    NotifyReq},
3739             {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
3740             {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
3741             {expect_receive, "notify reply: segment 3", {NrVerifyFun3, 1000}},
3742	     {expect_nothing, 1000},
3743             {send, "segment reply 1 [1]",               SegmentRep1},
3744             {expect_receive, "notify reply: segment 4", {NrVerifyFun4, 1000}},
3745	     {expect_nothing, 1000},
3746             {send, "segment reply 2 [2]",               SegmentRep2},
3747             {expect_receive, "notify reply: segment 5", {NrVerifyFun5, 1000}},
3748	     {expect_nothing, 1000},
3749             {send, "segment reply 4 [3]",               SegmentRep4},
3750             {expect_receive, "notify reply: segment 6", {NrVerifyFun6, 1000}},
3751	     {expect_nothing, 1000},
3752             {send, "segment reply 5 [4]",               SegmentRep5},
3753             {expect_receive, "notify reply: segment 7", {NrVerifyFun7, 1000}},
3754	     {expect_nothing, 1000},
3755             {send, "segment reply 6 [5]",               SegmentRep6},
3756             {expect_receive, "notify reply: segment 8", {NrVerifyFun8, 1000}},
3757	     {expect_nothing, 1000},
3758             {send, "segment reply 7 [6]",               SegmentRep7},
3759	     {expect_nothing, 1000},
3760             {send, "segment reply 8 [7]",               SegmentRep8},
3761	     {expect_nothing, 1000},
3762	     {send, "transaction-ack",                   TransAck},
3763             {expect_closed,  5000},
3764             disconnect
3765            ],
3766    EvSeq.
3767
3768ssmmsr1_mgc_ready_for_segments_fun() ->
3769    TC = self(),
3770    fun() ->
3771	    io:format("ssmmsr1_mgc_ready_for_segments_fun -> entry~n", []),
3772	    TC ! {ready_for_segments, mgc, self()},
3773	    receive
3774		{continue_with_segments, TC} ->
3775		    io:format("ssmmsr1_mgc_ready_for_segments_fun -> "
3776			      "received continue~n", []),
3777		    ok
3778	    end
3779    end.
3780
3781ssmmsr1_mgc_encode_msg_fun(Mod, Conf) ->
3782    fun(M) ->
3783            Mod:encode_message(Conf, M)
3784    end.
3785
3786ssmmsr1_mgc_decode_msg_fun(Mod, Conf) ->
3787    fun(M) ->
3788            Mod:decode_message(Conf, M)
3789    end.
3790
3791ssmmsr1_mgc_verify_service_change_req_msg_fun() ->
3792    fun(Msg) ->
3793	    (catch ssmmsr1_mgc_verify_service_change_req(Msg))
3794    end.
3795
3796ssmmsr1_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
3797    io:format("ssmmsr1_mgc_verify_service_change_req -> entry with"
3798	      "~n   M: ~p"
3799	      "~n", [M]),
3800    Body =
3801	case Mess of
3802	    #'Message'{version     = 1,
3803                       mId         = _MgMid,
3804                       messageBody = MsgBody} ->
3805		MsgBody;
3806	    _ ->
3807		throw({error, {invalid_Message, Mess}})
3808	end,
3809    Trans =
3810	case Body of
3811            {transactions, [Transactions]} ->
3812		Transactions;
3813	    _ ->
3814		throw({error, {invalid_messageBody, Body}})
3815	end,
3816    TR =
3817	case Trans of
3818            {transactionRequest, TransRequest} ->
3819		TransRequest;
3820	    _ ->
3821		throw({error, {invalid_transactions, Trans}})
3822	end,
3823    AR =
3824	case TR of
3825            #'TransactionRequest'{transactionId = _TransId,
3826				  actions       = [ActionReq]} ->
3827		ActionReq;
3828	    _ ->
3829		throw({error, {invalid_transactionRequest, TR}})
3830	end,
3831    CR =
3832	case AR of
3833	    #'ActionRequest'{contextId       = _Cid,
3834			     commandRequests = [CmdReq]} ->
3835		CmdReq;
3836	    _ ->
3837		throw({error, {invalid_action, AR}})
3838	end,
3839    Cmd =
3840	case CR of
3841	    #'CommandRequest'{command = Command} ->
3842		Command;
3843	    _ ->
3844		throw({error, {invalid_commandRequest, CR}})
3845	end,
3846    {Tid, Parms} =
3847	case Cmd of
3848	    {serviceChangeReq,
3849	     #'ServiceChangeRequest'{terminationID      = [TermID],
3850				     serviceChangeParms = ServChParms}} ->
3851		{TermID, ServChParms};
3852	    _ ->
3853		throw({error, {invalid_command, Cmd}})
3854	end,
3855    case Tid of
3856	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
3857	    ok;
3858	_ ->
3859	    throw({error, {invalid_terminationID, Tid}})
3860    end,
3861    case Parms of
3862	%% Version 1 'ServiceChangeParm'
3863	{'ServiceChangeParm',
3864	 restart,                            % serviceChangeMethod
3865	 asn1_NOVALUE,                       % serviceChangeAddress
3866	 ?VERSION,                           % serviceChangeVersion,
3867	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
3868	 [[$9,$0,$1|_]],                     % serviceChangeReason
3869	 asn1_NOVALUE,                       % serviceChangeDelay
3870	 asn1_NOVALUE,                       % serviceChangeMgcId
3871	 asn1_NOVALUE,                       % timeStamp
3872	 asn1_NOVALUE                        % nonStandardData
3873	} ->
3874	    {ok, M};
3875	_ ->
3876	    {error, {invalid_serviceChangeParms, Parms}}
3877    end.
3878
3879ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
3880					     TransId, TermId, Cid) ->
3881    fun(Msg) ->
3882	    (catch ssmmsr1_mgc_verify_notify_reply_segment(Msg,
3883							SN, Last,
3884							TransId, TermId, Cid))
3885    end.
3886
3887ssmmsr1_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
3888				     SN, Last, TransId, TermId, Cid) ->
3889    io:format("ssmmsr1_mgc_verify_notify_reply_segment -> entry with"
3890	      "~n   M:       ~p"
3891	      "~n   SN:      ~p"
3892	      "~n   Last:    ~p"
3893	      "~n   TransId: ~p"
3894	      "~n   TermId:  ~p"
3895	      "~n   Cid:     ~p"
3896	      "~n", [M, SN, Last, TransId, TermId, Cid]),
3897    Body =
3898	case Mess of
3899	    #'Message'{version     = ?VERSION,
3900                       mId         = _Mid,
3901                       messageBody = MsgBody} ->
3902		MsgBody;
3903	    _ ->
3904		throw({error, {invalid_Message, Mess}})
3905	end,
3906    Trans =
3907	case Body of
3908            {transactions, [Transactions]} ->
3909		Transactions;
3910	    _ ->
3911		throw({error, {invalid_messageBody, Body}})
3912	end,
3913    TR =
3914	case Trans of
3915            {transactionReply, TransReply} ->
3916		TransReply;
3917	    _ ->
3918		throw({error, {invalid_transactions, Trans}})
3919	end,
3920    TRes =
3921	case TR of
3922            #'TransactionReply'{transactionId        = TransId,
3923				transactionResult    = TransRes,
3924				segmentNumber        = SN,
3925				segmentationComplete = asn1_NOVALUE} when (Last == false) ->
3926		TransRes;
3927            #'TransactionReply'{transactionId        = TransId,
3928				transactionResult    = TransRes,
3929				segmentNumber        = SN,
3930				segmentationComplete = 'NULL'} when (Last == true) ->
3931		TransRes;
3932	    _ ->
3933		throw({error, {invalid_transactionReply, TR}})
3934	end,
3935    AR =
3936	case TRes of
3937	    {actionReplies, [ActionReply]} ->
3938		ActionReply;
3939	    {actionReplies, ActionReplies} ->
3940		throw({error, {invalid_actionReplies, ActionReplies}});
3941	    _ ->
3942		throw({error, {invalid_transactionResult, TRes}})
3943	end,
3944    CR =
3945	case AR of
3946	    #'ActionReply'{contextId    = Cid,
3947			   commandReply = [CommandReply]} ->
3948		CommandReply;
3949	    #'ActionReply'{contextId    = Cid,
3950			   commandReply = CommandReplies} ->
3951		throw({error, {invalid_commandReplies, CommandReplies}});
3952	    _ ->
3953		throw({error, {invalid_actionReply, AR}})
3954	end,
3955    NR =
3956	case CR of
3957	    {notifyReply, NotifyReply} ->
3958		NotifyReply;
3959	    _ ->
3960		throw({error, {invalid_commandReply, CR}})
3961	end,
3962    case NR of
3963	#'NotifyReply'{terminationID   = [TermId],
3964		       errorDescriptor = asn1_NOVALUE} ->
3965	    {ok, M};
3966	_ ->
3967	    {error, {invalid_NotifyReply, NR}}
3968    end;
3969ssmmsr1_mgc_verify_notify_reply_segment(Crap,
3970				     _SN, _Last, _TransId, _TermId, _Cid) ->
3971    {error, {invalid_MegacoMessage, Crap}}.
3972
3973
3974ssmmsr1_mgc_service_change_reply_msg(Mid, Cid) ->
3975    SCRP  = cre_serviceChangeResParm(Mid),
3976    SCRes = cre_serviceChangeResult(SCRP),
3977    Root  = #megaco_term_id{id = ["root"]},
3978    SCR   = cre_serviceChangeReply([Root], SCRes),
3979    CR    = cre_cmdReply(SCR),
3980    AR    = cre_actionReply(Cid, [CR]),
3981    TRes  = cre_transResult([AR]),
3982    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
3983    Trans = cre_transaction(TR),
3984    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
3985    cre_megacoMessage(Mess).
3986
3987ssmmsr1_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
3988    ARs     = ssmmsr1_mgc_notify_request_ars(TermIDs, CIDs),
3989    TR      = cre_transReq(TransId, ARs),
3990    Trans   = cre_transaction(TR),
3991    Mess    = cre_message(?VERSION, Mid, cre_transactions([Trans])),
3992    cre_megacoMessage(Mess).
3993
3994ssmmsr1_mgc_notify_request_ars(TermIDs, CIDs) ->
3995    ssmmsr1_mgc_notify_request_ars(TermIDs, CIDs, []).
3996
3997ssmmsr1_mgc_notify_request_ars([], [], Acc) ->
3998    lists:reverse(Acc);
3999ssmmsr1_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
4000    AR = ssmmsr1_mgc_notify_request_ar(100+CID, TermID, CID),
4001    ssmmsr1_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
4002
4003ssmmsr1_mgc_notify_request_ar(Rid, Tid, Cid) ->
4004    TT      = cre_timeNotation(integer_to_list(19990720+Rid),
4005			       integer_to_list(22000000+Rid)),
4006    Ev      = cre_obsEvent("al/of", TT),
4007    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
4008    NR      = cre_notifyReq([Tid], EvsDesc),
4009    CMD     = cre_command(NR),
4010    CR      = cre_cmdReq(CMD),
4011    cre_actionReq(Cid, [CR]).
4012
4013ssmmsr1_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
4014    SR    = ssmmsr1_mgc_segment_reply(TransId, SN, Last),
4015    Trans = cre_transaction(SR),
4016    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
4017    cre_megacoMessage(Mess).
4018
4019ssmmsr1_mgc_segment_reply(TransId, SN, true) ->
4020    cre_segReply(TransId, SN, 'NULL');
4021ssmmsr1_mgc_segment_reply(TransId, SN, false) ->
4022    cre_segReply(TransId, SN, asn1_NOVALUE).
4023
4024ssmmsr1_mgc_trans_ack_msg(Mid, TransId) ->
4025    TA    = cre_transAck(TransId),
4026    Trans = cre_transaction([TA]),
4027    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
4028    cre_megacoMessage(Mess).
4029
4030
4031%%
4032%% MG generator stuff
4033%%
4034ssmmsr1_mg_event_sequence(text, tcp) ->
4035    Mid = {deviceName,"mg"},
4036    RI = [
4037          {port,             2944},
4038          {encoding_module,  megaco_pretty_text_encoder},
4039          {encoding_config,  []},
4040          {transport_module, megaco_tcp}
4041         ],
4042    ConnectVerify = ssmmsr1_mg_verify_handle_connect_fun(),
4043    ServiceChangeReq = ssmmsr1_mg_service_change_request_ar(Mid, 1),
4044    ServiceChangeReplyVerify = ssmmsr1_mg_verify_service_change_reply_fun(),
4045    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
4046    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
4047    Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
4048    Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
4049    Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
4050    Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
4051    Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
4052    Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
4053    Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
4054    NotifyReqVerify = ssmmsr1_mg_verify_notify_request_fun(Tids),
4055    AckVerify = ssmmsr1_mg_verify_ack_fun(),
4056    ReadyForSegments = ssmmsr1_mg_ready_for_segments_fun(),
4057    EvSeq = [
4058             {debug, true},
4059             {trigger,
4060              fun() ->
4061                      put(verbosity, ?TEST_VERBOSITY)
4062              end},
4063	     {megaco_trace, disable},
4064             %% {megaco_trace, max},
4065             megaco_start,
4066             {megaco_start_user, Mid, RI, []},
4067             start_transport,
4068             {megaco_system_info, users},
4069             {megaco_system_info, connections},
4070             connect,
4071             {megaco_callback, handle_connect, ConnectVerify},
4072             megaco_connect,
4073             {megaco_cast,     [ServiceChangeReq], []},
4074             {megaco_callback, handle_connect,     ConnectVerify},
4075             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
4076	     {megaco_update_conn_info, protocol_version, ?VERSION},
4077	     {megaco_update_conn_info, reply_timer,      20000},
4078	     {megaco_update_conn_info, segment_send,     3},
4079	     {megaco_update_conn_info, max_pdu_size,     128},
4080	     %% {sleep, 1000},
4081             {trigger, ReadyForSegments},
4082             {megaco_callback, handle_trans_request, NotifyReqVerify},
4083             {megaco_callback, handle_trans_ack,     AckVerify, 15000},
4084             megaco_stop_user,
4085             megaco_stop,
4086             {sleep, 1000}
4087            ],
4088    EvSeq.
4089
4090
4091ssmmsr1_mg_ready_for_segments_fun() ->
4092    TC = self(),
4093    fun() ->
4094	    io:format("ssmmsr1_mg_ready_for_segments_fun -> entry~n", []),
4095	    TC ! {ready_for_segments, mg, self()},
4096	    receive
4097		{continue_with_segments, TC} ->
4098		    io:format("ssmmsr1_mg_ready_for_segments_fun -> "
4099			      "received continue~n", []),
4100		    ok
4101	    end
4102    end.
4103
4104ssmmsr1_mg_verify_handle_connect_fun() ->
4105    fun(Ev) -> ssmmsr1_mg_verify_handle_connect(Ev) end.
4106
4107ssmmsr1_mg_verify_handle_connect({handle_connect, CH, 1}) ->
4108    io:format("ssmmsr1_mg_verify_handle_connect -> ok"
4109	      "~n   CH: ~p~n", [CH]),
4110    {ok, CH, ok};
4111ssmmsr1_mg_verify_handle_connect(Else) ->
4112    io:format("ssmmsr1_mg_verify_handle_connect -> unknown"
4113	      "~n   Else: ~p~n", [Else]),
4114    {error, Else, ok}.
4115
4116
4117ssmmsr1_mg_verify_service_change_reply_fun() ->
4118    fun(Rep) -> ssmmsr1_mg_verify_scr(Rep) end.
4119
4120ssmmsr1_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
4121    (catch ssmmsr1_mg_do_verify_scr(AR));
4122ssmmsr1_mg_verify_scr(Crap) ->
4123    io:format("ssmmsr1_mg_verify_scr -> error: "
4124	      "~n   Crap: ~p"
4125	      "~n", [Crap]),
4126    {error, Crap, ok}.
4127
4128ssmmsr1_mg_do_verify_scr(AR) ->
4129    io:format("ssmmsr1_mg_do_verify_scr -> ok: "
4130	      "~n   AR: ~p~n", [AR]),
4131    CR =
4132	case AR of
4133	    #'ActionReply'{commandReply = [CmdRep]} ->
4134		CmdRep;
4135	    _ ->
4136		Reason1 = {invalid_action_reply, AR},
4137		throw({error, Reason1, ok})
4138	end,
4139    SCR =
4140	case CR of
4141	    {serviceChangeReply, ServChRep} ->
4142		ServChRep;
4143	    _ ->
4144		Reason2 = {invalid_command_reply, CR},
4145		throw({error, Reason2, ok})
4146	end,
4147    {Tid, SCRes} =
4148	case SCR of
4149	    #'ServiceChangeReply'{terminationID       = [TermID],
4150				  serviceChangeResult = Res} ->
4151		{TermID, Res};
4152	    _ ->
4153		Reason3 = {invalid_service_change_reply, SCR},
4154		throw({error, Reason3, ok})
4155	end,
4156    case Tid of
4157	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
4158	    ok;
4159	_ ->
4160	    Reason4 = {invalid_termination_id, Tid},
4161	    throw({error, Reason4, ok})
4162    end,
4163    SCRParm =
4164	case SCRes of
4165	    {serviceChangeResParms, ServChResParms} ->
4166		ServChResParms;
4167	    _ ->
4168		Reason5 = {invalid_serviceChangeResult, SCRes},
4169		throw({error, Reason5, ok})
4170	end,
4171    case SCRParm of
4172	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
4173	    {ok, AR, ok};
4174	_ ->
4175	    Reason6 = {invalid_service_change_result, SCRParm},
4176	    {error, Reason6, ok}
4177    end.
4178
4179ssmmsr1_mg_verify_notify_request_fun(Tids) ->
4180    fun(Req) -> ssmmsr1_mg_verify_notify_request(Req, Tids) end.
4181
4182ssmmsr1_mg_verify_notify_request(
4183  {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
4184  when length(ARs) == length(Tids) ->
4185    (catch ssmmsr1_mg_do_verify_notify_request(Tids, ARs));
4186ssmmsr1_mg_verify_notify_request(
4187  {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
4188    {error, {invalid_action_requests, ARs}, ok};
4189ssmmsr1_mg_verify_notify_request(
4190  {handle_trans_request, CH, V, ARs}, _Tids) ->
4191    {error, {invalid_trans_request, {CH, V, ARs}}, ok};
4192ssmmsr1_mg_verify_notify_request(Crap, _Tids) ->
4193    io:format("ssmmsr1_mg_verify_notify_request -> unknown request"
4194	      "~n   Crap: ~p"
4195	      "~n   Tids: ~p"
4196	      "~n", [Crap, _Tids]),
4197    {error, {unexpected_event, Crap}, ok}.
4198
4199ssmmsr1_mg_do_verify_notify_request(Tids, ARs) ->
4200    io:format("ssmmsr1_mg_do_verify_notify_request -> ok"
4201	      "~n   Tids: ~p"
4202	      "~n   ARs:  ~p"
4203	      "~n", [Tids, ARs]),
4204    ActionReplies = ssmmsr1_mg_do_verify_notify_request_ars(Tids, ARs),
4205    io:format("ssmmsr1_mg_do_verify_notify_request -> ok"
4206	      "~n   ActionReplies:  ~p"
4207	      "~n", [ActionReplies]),
4208    Reply = {{handle_ack, ssmmsr1}, ActionReplies},
4209    {ok, ARs, Reply}.
4210
4211ssmmsr1_mg_do_verify_notify_request_ars(Tids, ARs) ->
4212    ssmmsr1_mg_do_verify_notify_request_ars(Tids, ARs, []).
4213
4214ssmmsr1_mg_do_verify_notify_request_ars([], [], Acc) ->
4215    lists:reverse(Acc);
4216ssmmsr1_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
4217    ActionReply = ssmmsr1_mg_do_verify_notify_request_ar(Tid, AR),
4218    ssmmsr1_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
4219
4220ssmmsr1_mg_do_verify_notify_request_ar(Tid, AR) ->
4221    io:format("ssmmsr1_mg_do_verify_notify_request_ar -> ok"
4222	      "~n   Tid: ~p"
4223	      "~n   AR:  ~p"
4224	      "~n", [Tid, AR]),
4225    {Cid, CR} =
4226	case AR of
4227	    #'ActionRequest'{contextId       = CtxId,
4228			     commandRequests = [CmdReq]} ->
4229		{CtxId, CmdReq};
4230	    _ ->
4231		Reason1 = {invalid_actionRequest, AR},
4232		throw({error, Reason1, ok})
4233	end,
4234    Cmd =
4235	case CR of
4236	    #'CommandRequest'{command = Command} ->
4237		Command;
4238	    _ ->
4239		throw({error, {invalid_commandRequest, CR}, ok})
4240	end,
4241    OED =
4242	case Cmd of
4243	    {notifyReq,
4244	     #'NotifyRequest'{terminationID            = [Tid],
4245			      observedEventsDescriptor = ObsEvDesc,
4246			      errorDescriptor          = asn1_NOVALUE}} ->
4247		ObsEvDesc;
4248	    _ ->
4249		throw({error, {invalid_command, Cmd}, ok})
4250	end,
4251    OE =
4252	case OED of
4253	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
4254		ObsEv;
4255	    #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
4256		throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
4257	    _ ->
4258		throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
4259	end,
4260    case OE of
4261	#'ObservedEvent'{eventName = "al/of"} ->
4262	    ssmmsr1_mg_notify_reply_ar(Cid, Tid);
4263	_ ->
4264	    throw({error, {invalid_ObservedEvent, OE}, ok})
4265    end.
4266
4267
4268ssmmsr1_mg_verify_ack_fun() ->
4269    fun(Event) -> ssmmsr1_mg_verify_ack(Event) end.
4270
4271ssmmsr1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, AckStatus, ssmmsr1}) ->
4272    io:format("ssmmsr1_mg_verify_ack -> "
4273              "~n   AckStatus: ~p"
4274              "~n   CH:        ~p"
4275              "~n", [AckStatus, CH]),
4276    case AckStatus of
4277	{error, Reason} ->
4278	    case Reason of
4279		{segment_failure, SegInfo} when is_list(SegInfo) ->
4280		    case lists:keysearch(segments_not_acked, 1, SegInfo) of
4281			{value, {segments_not_acked, [3]}} ->
4282			    {ok, CH, ok};
4283			{value, {segments_not_acked, SNs}} ->
4284			    X = {unexpected_not_acked_segments, SNs},
4285			    {error, X, ok};
4286			false ->
4287			    X = {unexpected_seg_info, SegInfo},
4288			    {error, X, ok}
4289		    end;
4290		_ ->
4291		    X = {unexpected_reason, Reason},
4292		    {error, X, ok}
4293	    end;
4294	_ ->
4295	    X = {unexpected_ack_status, AckStatus},
4296	    {error, X, ok}
4297    end;
4298ssmmsr1_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
4299		       BadAckStatus, BadAckData}) ->
4300    {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
4301ssmmsr1_mg_verify_ack(BadEvent) ->
4302    {error, {unknown_event, BadEvent}, ok}.
4303
4304
4305ssmmsr1_mg_service_change_request_ar(_Mid, Cid) ->
4306    Prof  = cre_serviceChangeProf("resgw", 1),
4307    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
4308    Root  = #megaco_term_id{id = ["root"]},
4309    SCR   = cre_serviceChangeReq([Root], SCP),
4310    CMD   = cre_command(SCR),
4311    CR    = cre_cmdReq(CMD),
4312    cre_actionReq(Cid, [CR]).
4313
4314ssmmsr1_mg_notify_reply_ar(Cid, Tid) ->
4315    NR = cre_notifyReply([Tid]),
4316    CR = cre_cmdReply(NR),
4317    cre_actionReply(Cid, [CR]).
4318
4319
4320
4321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4322
4323send_segmented_msg_missing_seg_reply2(suite) ->
4324    [];
4325send_segmented_msg_missing_seg_reply2(doc) ->
4326    "First missing segment test. "
4327	"Tests that the callbacks and error messages are delivered "
4328	"when a segment reply goes missing. Ack expected. "
4329	"Send window = 1. ";
4330send_segmented_msg_missing_seg_reply2(Config) when is_list(Config) ->
4331    Pre = fun() ->
4332                  MgcNode = make_node_name(mgc),
4333                  MgNode  = make_node_name(mg),
4334                  d("start nodes: "
4335                    "~n      MgcNode: ~p"
4336                    "~n      MgNode:  ~p",
4337                    [MgcNode, MgNode]),
4338                  Nodes = [MgcNode, MgNode],
4339                  ok = ?START_NODES(Nodes),
4340                  Nodes
4341          end,
4342    Case = fun do_send_segmented_msg_missing_seg_reply2/1,
4343    Post = fun(Nodes) ->
4344                   d("stop nodes"),
4345                   ?STOP_NODES(lists:reverse(Nodes))
4346           end,
4347    try_tc(ssmmsr2, Pre, Case, Post).
4348
4349do_send_segmented_msg_missing_seg_reply2([MgcNode, MgNode]) ->
4350
4351    d("[MGC] start the simulator "),
4352    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
4353
4354    d("[MGC] create the event sequence"),
4355    MgcEvSeq = ssmmsr2_mgc_event_sequence(text, tcp),
4356
4357    i("wait some time before starting the MGC simulation"),
4358    sleep(1000),
4359
4360    d("[MGC] start the simulation"),
4361    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
4362
4363    i("wait some time before starting the MG simulator"),
4364    sleep(1000),
4365
4366    d("[MG] start the simulator (generator)"),
4367    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
4368
4369    d("[MG] create the event sequence"),
4370    MgEvSeq = ssmmsr2_mg_event_sequence(text, tcp),
4371
4372    i("wait some time before starting the MG simulation"),
4373    sleep(1000),
4374
4375    d("[MG] start the simulation"),
4376    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
4377
4378    %% Await MGC ready for segments
4379    d("await MGC trigger event"),
4380    MgcPid =
4381	receive
4382	    {ready_for_segments, mgc, Pid1} ->
4383		d("received MGC trigger event"),
4384		Pid1
4385	after 5000 ->
4386		d("timeout waiting for MGC trigger event: ~p",
4387		  [megaco_test_lib:flush()]),
4388		?ERROR(timeout_MGC_trigger_event)
4389	end,
4390
4391    %% Await MG ready for segments
4392    d("await MG trigger event"),
4393    MgPid =
4394	receive
4395	    {ready_for_segments, mg, Pid2} ->
4396		d("received MG trigger event"),
4397		Pid2
4398	after 5000 ->
4399		d("timeout waiting for MG trigger event: ~p",
4400		  [megaco_test_lib:flush()]),
4401		?ERROR(timeout_MG_trigger_event)
4402	end,
4403
4404    %% Instruct the MG to continue
4405    d("send continue to MG"),
4406    MgPid ! {continue_with_segments, self()},
4407
4408    sleep(500),
4409
4410    %% Instruct the MGC to continue
4411    d("send continue to MGC"),
4412    MgcPid ! {continue_with_segments, self()},
4413
4414    d("await the generator reply(s)"),
4415    await_completion([MgcId, MgId]),
4416
4417    %% Tell Mgc to stop
4418    i("[MGC] stop generator"),
4419    megaco_test_tcp_generator:stop(Mgc),
4420
4421    %% Tell Mg to stop
4422    i("[MG] stop generator"),
4423    megaco_test_megaco_generator:stop(Mg),
4424
4425    i("done", []),
4426    ok.
4427
4428
4429
4430%%
4431%% MGC generator stuff
4432%%
4433
4434ssmmsr2_mgc_event_sequence(text, tcp) ->
4435    DecodeFun = ssmmsr2_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
4436    EncodeFun = ssmmsr2_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
4437    Mid       = {deviceName,"mgc"},
4438    ScrVerifyFun     = ssmmsr2_mgc_verify_service_change_req_msg_fun(),
4439    ServiceChangeRep = ssmmsr2_mgc_service_change_reply_msg(Mid, 1),
4440    TermId1   =
4441	#megaco_term_id{id = ["00000000","00000000","00000001"]},
4442    CtxId1    = 1,
4443    TermId2   =
4444	#megaco_term_id{id = ["00000000","00000000","00000002"]},
4445    CtxId2    = 2,
4446    TermId3   =
4447	#megaco_term_id{id = ["00000000","00000000","00000003"]},
4448    CtxId3    = 3,
4449    TermId4   =
4450	#megaco_term_id{id = ["00000000","00000000","00000004"]},
4451    CtxId4    = 4,
4452    TermId5   =
4453	#megaco_term_id{id = ["00000000","00000000","00000005"]},
4454    CtxId5    = 5,
4455    TermId6   =
4456	#megaco_term_id{id = ["00000000","00000000","00000006"]},
4457    CtxId6    = 6,
4458    TermId7   =
4459	#megaco_term_id{id = ["00000000","00000000","00000007"]},
4460    CtxId7    = 7,
4461    TermId8   =
4462	#megaco_term_id{id = ["00000000","00000000","00000008"]},
4463    CtxId8    = 8,
4464    TransId   = 2,
4465    TermIDs = [TermId1, TermId2, TermId3, TermId4,
4466	       TermId5, TermId6, TermId7, TermId8],
4467    CIDs    = [CtxId1, CtxId2, CtxId3, CtxId4,
4468	       CtxId5, CtxId6, CtxId7, CtxId8],
4469    NotifyReq = ssmmsr2_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
4470    NrVerifyFun1 =
4471	ssmmsr2_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
4472						      TermId1, CtxId1),
4473    NrVerifyFun2 =
4474    	ssmmsr2_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
4475							TermId2, CtxId2),
4476    SegmentRep1 = ssmmsr2_mgc_segment_reply_msg(Mid, TransId, 1, false),
4477    ReadyForSegments = ssmmsr2_mgc_ready_for_segments_fun(),
4478    EvSeq = [{debug,  true},
4479             {trigger, "verbosity",
4480              fun() ->
4481                      put(verbosity, ?TEST_VERBOSITY)
4482              end},
4483             {decode, DecodeFun},
4484             {encode, EncodeFun},
4485             {listen, 2944},
4486	     {expect_accept, any},
4487             {expect_receive, "service-change-request",  {ScrVerifyFun, 5000}},
4488             {send, "service-change-reply",              ServiceChangeRep},
4489	     %% {expect_nothing, 1000},
4490	     {trigger, "segment send sync trigger", ReadyForSegments},
4491             {send, "notify request",                    NotifyReq},
4492             {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
4493             {send, "segment reply 1",               SegmentRep1},
4494             {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
4495             {expect_closed,  20000},
4496             disconnect
4497            ],
4498    EvSeq.
4499
4500ssmmsr2_mgc_ready_for_segments_fun() ->
4501    TC = self(),
4502    fun() ->
4503	    io:format("ssmmsr2_mgc_ready_for_segments_fun -> entry~n", []),
4504	    TC ! {ready_for_segments, mgc, self()},
4505	    receive
4506		{continue_with_segments, TC} ->
4507		    io:format("ssmmsr2_mgc_ready_for_segments_fun -> "
4508			      "received continue~n", []),
4509		    ok
4510	    end
4511    end.
4512
4513ssmmsr2_mgc_encode_msg_fun(Mod, Conf) ->
4514    fun(M) ->
4515            Mod:encode_message(Conf, M)
4516    end.
4517
4518ssmmsr2_mgc_decode_msg_fun(Mod, Conf) ->
4519    fun(M) ->
4520            Mod:decode_message(Conf, M)
4521    end.
4522
4523ssmmsr2_mgc_verify_service_change_req_msg_fun() ->
4524    fun(Msg) ->
4525	    (catch ssmmsr2_mgc_verify_service_change_req(Msg))
4526    end.
4527
4528ssmmsr2_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
4529    io:format("ssmmsr2_mgc_verify_service_change_req -> entry with"
4530	      "~n   M: ~p"
4531	      "~n", [M]),
4532    Body =
4533	case Mess of
4534	    #'Message'{version     = 1,
4535                       mId         = _MgMid,
4536                       messageBody = MsgBody} ->
4537		MsgBody;
4538	    _ ->
4539		throw({error, {invalid_Message, Mess}})
4540	end,
4541    Trans =
4542	case Body of
4543            {transactions, [Transactions]} ->
4544		Transactions;
4545	    _ ->
4546		throw({error, {invalid_messageBody, Body}})
4547	end,
4548    TR =
4549	case Trans of
4550            {transactionRequest, TransRequest} ->
4551		TransRequest;
4552	    _ ->
4553		throw({error, {invalid_transactions, Trans}})
4554	end,
4555    AR =
4556	case TR of
4557            #'TransactionRequest'{transactionId = _TransId,
4558				  actions       = [ActionReq]} ->
4559		ActionReq;
4560	    _ ->
4561		throw({error, {invalid_transactionRequest, TR}})
4562	end,
4563    CR =
4564	case AR of
4565	    #'ActionRequest'{contextId       = _Cid,
4566			     commandRequests = [CmdReq]} ->
4567		CmdReq;
4568	    _ ->
4569		throw({error, {invalid_action, AR}})
4570	end,
4571    Cmd =
4572	case CR of
4573	    #'CommandRequest'{command = Command} ->
4574		Command;
4575	    _ ->
4576		throw({error, {invalid_commandRequest, CR}})
4577	end,
4578    {Tid, Parms} =
4579	case Cmd of
4580	    {serviceChangeReq,
4581	     #'ServiceChangeRequest'{terminationID      = [TermID],
4582				     serviceChangeParms = ServChParms}} ->
4583		{TermID, ServChParms};
4584	    _ ->
4585		throw({error, {invalid_command, Cmd}})
4586	end,
4587    case Tid of
4588	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
4589	    ok;
4590	_ ->
4591	    throw({error, {invalid_terminationID, Tid}})
4592    end,
4593    case Parms of
4594	%% Version 1 'ServiceChangeParm'
4595	{'ServiceChangeParm',
4596	 restart,                            % serviceChangeMethod
4597	 asn1_NOVALUE,                       % serviceChangeAddress
4598	 ?VERSION,                           % serviceChangeVersion,
4599	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
4600	 [[$9,$0,$1|_]],                     % serviceChangeReason
4601	 asn1_NOVALUE,                       % serviceChangeDelay
4602	 asn1_NOVALUE,                       % serviceChangeMgcId
4603	 asn1_NOVALUE,                       % timeStamp
4604	 asn1_NOVALUE                        % nonStandardData
4605	} ->
4606	    {ok, M};
4607	_ ->
4608	    {error, {invalid_serviceChangeParms, Parms}}
4609    end.
4610
4611ssmmsr2_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
4612					     TransId, TermId, Cid) ->
4613    fun(Msg) ->
4614	    (catch ssmmsr2_mgc_verify_notify_reply_segment(Msg,
4615							SN, Last,
4616							TransId, TermId, Cid))
4617    end.
4618
4619ssmmsr2_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
4620				     SN, Last, TransId, TermId, Cid) ->
4621    io:format("ssmmsr2_mgc_verify_notify_reply_segment -> entry with"
4622	      "~n   M:       ~p"
4623	      "~n   SN:      ~p"
4624	      "~n   Last:    ~p"
4625	      "~n   TransId: ~p"
4626	      "~n   TermId:  ~p"
4627	      "~n   Cid:     ~p"
4628	      "~n", [M, SN, Last, TransId, TermId, Cid]),
4629    Body =
4630	case Mess of
4631	    #'Message'{version     = ?VERSION,
4632                       mId         = _Mid,
4633                       messageBody = MsgBody} ->
4634		MsgBody;
4635	    _ ->
4636		throw({error, {invalid_Message, Mess}})
4637	end,
4638    Trans =
4639	case Body of
4640            {transactions, [Transactions]} ->
4641		Transactions;
4642	    _ ->
4643		throw({error, {invalid_messageBody, Body}})
4644	end,
4645    TR =
4646	case Trans of
4647            {transactionReply, TransReply} ->
4648		TransReply;
4649	    _ ->
4650		throw({error, {invalid_transactions, Trans}})
4651	end,
4652    TRes =
4653	case TR of
4654            #'TransactionReply'{transactionId        = TransId,
4655				transactionResult    = TransRes,
4656				segmentNumber        = SN,
4657				segmentationComplete = asn1_NOVALUE} when (Last == false) ->
4658		TransRes;
4659            #'TransactionReply'{transactionId        = TransId,
4660				transactionResult    = TransRes,
4661				segmentNumber        = SN,
4662				segmentationComplete = 'NULL'} when (Last == true) ->
4663		TransRes;
4664	    _ ->
4665		throw({error, {invalid_transactionReply, TR}})
4666	end,
4667    AR =
4668	case TRes of
4669	    {actionReplies, [ActionReply]} ->
4670		ActionReply;
4671	    {actionReplies, ActionReplies} ->
4672		throw({error, {invalid_actionReplies, ActionReplies}});
4673	    _ ->
4674		throw({error, {invalid_transactionResult, TRes}})
4675	end,
4676    CR =
4677	case AR of
4678	    #'ActionReply'{contextId    = Cid,
4679			   commandReply = [CommandReply]} ->
4680		CommandReply;
4681	    #'ActionReply'{contextId    = Cid,
4682			   commandReply = CommandReplies} ->
4683		throw({error, {invalid_commandReplies, CommandReplies}});
4684	    _ ->
4685		throw({error, {invalid_actionReply, AR}})
4686	end,
4687    NR =
4688	case CR of
4689	    {notifyReply, NotifyReply} ->
4690		NotifyReply;
4691	    _ ->
4692		throw({error, {invalid_commandReply, CR}})
4693	end,
4694    case NR of
4695	#'NotifyReply'{terminationID   = [TermId],
4696		       errorDescriptor = asn1_NOVALUE} ->
4697	    {ok, M};
4698	_ ->
4699	    {error, {invalid_NotifyReply, NR}}
4700    end;
4701ssmmsr2_mgc_verify_notify_reply_segment(Crap,
4702				     _SN, _Last, _TransId, _TermId, _Cid) ->
4703    {error, {invalid_MegacoMessage, Crap}}.
4704
4705
4706ssmmsr2_mgc_service_change_reply_msg(Mid, Cid) ->
4707    SCRP  = cre_serviceChangeResParm(Mid),
4708    SCRes = cre_serviceChangeResult(SCRP),
4709    Root  = #megaco_term_id{id = ["root"]},
4710    SCR   = cre_serviceChangeReply([Root], SCRes),
4711    CR    = cre_cmdReply(SCR),
4712    AR    = cre_actionReply(Cid, [CR]),
4713    TRes  = cre_transResult([AR]),
4714    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
4715    Trans = cre_transaction(TR),
4716    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
4717    cre_megacoMessage(Mess).
4718
4719ssmmsr2_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
4720    ARs     = ssmmsr2_mgc_notify_request_ars(TermIDs, CIDs),
4721    TR      = cre_transReq(TransId, ARs),
4722    Trans   = cre_transaction(TR),
4723    Mess    = cre_message(?VERSION, Mid, cre_transactions([Trans])),
4724    cre_megacoMessage(Mess).
4725
4726ssmmsr2_mgc_notify_request_ars(TermIDs, CIDs) ->
4727    ssmmsr2_mgc_notify_request_ars(TermIDs, CIDs, []).
4728
4729ssmmsr2_mgc_notify_request_ars([], [], Acc) ->
4730    lists:reverse(Acc);
4731ssmmsr2_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
4732    AR = ssmmsr2_mgc_notify_request_ar(100+CID, TermID, CID),
4733    ssmmsr2_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
4734
4735ssmmsr2_mgc_notify_request_ar(Rid, Tid, Cid) ->
4736    TT      = cre_timeNotation(integer_to_list(19990720+Rid),
4737			       integer_to_list(22000000+Rid)),
4738    Ev      = cre_obsEvent("al/of", TT),
4739    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
4740    NR      = cre_notifyReq([Tid], EvsDesc),
4741    CMD     = cre_command(NR),
4742    CR      = cre_cmdReq(CMD),
4743    cre_actionReq(Cid, [CR]).
4744
4745ssmmsr2_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
4746    SR    = ssmmsr2_mgc_segment_reply(TransId, SN, Last),
4747    Trans = cre_transaction(SR),
4748    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
4749    cre_megacoMessage(Mess).
4750
4751ssmmsr2_mgc_segment_reply(TransId, SN, true) ->
4752    cre_segReply(TransId, SN, 'NULL');
4753ssmmsr2_mgc_segment_reply(TransId, SN, false) ->
4754    cre_segReply(TransId, SN, asn1_NOVALUE).
4755
4756%% ssmmsr2_mgc_trans_ack_msg(Mid, TransId) ->
4757%%     TA    = cre_transAck(TransId),
4758%%     Trans = cre_transaction([TA]),
4759%%     Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
4760%%     cre_megacoMessage(Mess).
4761
4762
4763%%
4764%% MG generator stuff
4765%%
4766ssmmsr2_mg_event_sequence(text, tcp) ->
4767    Mid = {deviceName,"mg"},
4768    RI = [
4769          {port,             2944},
4770          {encoding_module,  megaco_pretty_text_encoder},
4771          {encoding_config,  []},
4772          {transport_module, megaco_tcp}
4773         ],
4774    ConnectVerify = ssmmsr2_mg_verify_handle_connect_fun(),
4775    ServiceChangeReq = ssmmsr2_mg_service_change_request_ar(Mid, 1),
4776    ServiceChangeReplyVerify = ssmmsr2_mg_verify_service_change_reply_fun(),
4777    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
4778    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
4779    Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
4780    Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
4781    Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
4782    Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
4783    Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
4784    Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
4785    Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
4786    NotifyReqVerify = ssmmsr2_mg_verify_notify_request_fun(Tids),
4787    AckVerify = ssmmsr2_mg_verify_ack_fun(),
4788    ReadyForSegments = ssmmsr2_mg_ready_for_segments_fun(),
4789    EvSeq = [
4790             {debug, true},
4791             {trigger,
4792              fun() ->
4793                      put(verbosity, ?TEST_VERBOSITY)
4794              end},
4795	     {megaco_trace, disable},
4796             %% {megaco_trace, max},
4797             megaco_start,
4798             {megaco_start_user, Mid, RI, []},
4799             start_transport,
4800             {megaco_system_info, users},
4801             {megaco_system_info, connections},
4802             connect,
4803             {megaco_callback, handle_connect, ConnectVerify},
4804             megaco_connect,
4805             {megaco_cast,     [ServiceChangeReq], []},
4806             {megaco_callback, handle_connect,     ConnectVerify},
4807             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
4808	     {megaco_update_conn_info, protocol_version, ?VERSION},
4809	     {megaco_update_conn_info, reply_timer,      12000},
4810	     {megaco_update_conn_info, segment_send,     1},
4811	     {megaco_update_conn_info, max_pdu_size,     128},
4812             %% {sleep, 1000},
4813             {trigger, ReadyForSegments},
4814             {megaco_callback, handle_trans_request, NotifyReqVerify},
4815             {megaco_callback, handle_trans_ack,     AckVerify, 15000},
4816             megaco_stop_user,
4817             megaco_stop,
4818             {sleep, 1000}
4819            ],
4820    EvSeq.
4821
4822
4823ssmmsr2_mg_ready_for_segments_fun() ->
4824    TC = self(),
4825    fun() ->
4826	    io:format("ssmmsr2_mg_ready_for_segments_fun -> entry~n", []),
4827	    TC ! {ready_for_segments, mg, self()},
4828	    receive
4829		{continue_with_segments, TC} ->
4830		    io:format("ssmmsr2_mg_ready_for_segments_fun -> "
4831			      "received continue~n", []),
4832		    ok
4833	    end
4834    end.
4835
4836ssmmsr2_mg_verify_handle_connect_fun() ->
4837    fun(Ev) -> ssmmsr2_mg_verify_handle_connect(Ev) end.
4838
4839ssmmsr2_mg_verify_handle_connect({handle_connect, CH, 1}) ->
4840    io:format("ssmmsr2_mg_verify_handle_connect -> ok"
4841	      "~n   CH: ~p~n", [CH]),
4842    {ok, CH, ok};
4843ssmmsr2_mg_verify_handle_connect(Else) ->
4844    io:format("ssmmsr2_mg_verify_handle_connect -> unknown"
4845	      "~n   Else: ~p~n", [Else]),
4846    {error, Else, ok}.
4847
4848
4849ssmmsr2_mg_verify_service_change_reply_fun() ->
4850    fun(Rep) -> ssmmsr2_mg_verify_scr(Rep) end.
4851
4852ssmmsr2_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
4853    (catch ssmmsr2_mg_do_verify_scr(AR));
4854ssmmsr2_mg_verify_scr(Crap) ->
4855    io:format("ssmmsr2_mg_verify_scr -> error: "
4856	      "~n   Crap: ~p"
4857	      "~n", [Crap]),
4858    {error, Crap, ok}.
4859
4860ssmmsr2_mg_do_verify_scr(AR) ->
4861    io:format("ssmmsr2_mg_do_verify_scr -> ok: "
4862	      "~n   AR: ~p~n", [AR]),
4863    CR =
4864	case AR of
4865	    #'ActionReply'{commandReply = [CmdRep]} ->
4866		CmdRep;
4867	    _ ->
4868		Reason1 = {invalid_action_reply, AR},
4869		throw({error, Reason1, ok})
4870	end,
4871    SCR =
4872	case CR of
4873	    {serviceChangeReply, ServChRep} ->
4874		ServChRep;
4875	    _ ->
4876		Reason2 = {invalid_command_reply, CR},
4877		throw({error, Reason2, ok})
4878	end,
4879    {Tid, SCRes} =
4880	case SCR of
4881	    #'ServiceChangeReply'{terminationID       = [TermID],
4882				  serviceChangeResult = Res} ->
4883		{TermID, Res};
4884	    _ ->
4885		Reason3 = {invalid_service_change_reply, SCR},
4886		throw({error, Reason3, ok})
4887	end,
4888    case Tid of
4889	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
4890	    ok;
4891	_ ->
4892	    Reason4 = {invalid_termination_id, Tid},
4893	    throw({error, Reason4, ok})
4894    end,
4895    SCRParm =
4896	case SCRes of
4897	    {serviceChangeResParms, ServChResParms} ->
4898		ServChResParms;
4899	    _ ->
4900		Reason5 = {invalid_serviceChangeResult, SCRes},
4901		throw({error, Reason5, ok})
4902	end,
4903    case SCRParm of
4904	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
4905	    {ok, AR, ok};
4906	_ ->
4907	    Reason6 = {invalid_service_change_result, SCRParm},
4908	    {error, Reason6, ok}
4909    end.
4910
4911ssmmsr2_mg_verify_notify_request_fun(Tids) ->
4912    fun(Req) -> ssmmsr2_mg_verify_notify_request(Req, Tids) end.
4913
4914ssmmsr2_mg_verify_notify_request(
4915  {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
4916  when length(ARs) == length(Tids) ->
4917    (catch ssmmsr2_mg_do_verify_notify_request(Tids, ARs));
4918ssmmsr2_mg_verify_notify_request(
4919  {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
4920    {error, {invalid_action_requests, ARs}, ok};
4921ssmmsr2_mg_verify_notify_request(
4922  {handle_trans_request, CH, V, ARs}, _Tids) ->
4923    {error, {invalid_trans_request, {CH, V, ARs}}, ok};
4924ssmmsr2_mg_verify_notify_request(Crap, _Tids) ->
4925    io:format("ssmmsr2_mg_verify_notify_request -> unknown request"
4926	      "~n   Crap: ~p"
4927	      "~n   Tids: ~p"
4928	      "~n", [Crap, _Tids]),
4929    {error, {unexpected_event, Crap}, ok}.
4930
4931ssmmsr2_mg_do_verify_notify_request(Tids, ARs) ->
4932    io:format("ssmmsr2_mg_do_verify_notify_request -> ok"
4933	      "~n   Tids: ~p"
4934	      "~n   ARs:  ~p"
4935	      "~n", [Tids, ARs]),
4936    ActionReplies = ssmmsr2_mg_do_verify_notify_request_ars(Tids, ARs),
4937    io:format("ssmmsr2_mg_do_verify_notify_request -> ok"
4938	      "~n   ActionReplies:  ~p"
4939	      "~n", [ActionReplies]),
4940    Reply = {{handle_ack, ssmmsr2}, ActionReplies},
4941    {ok, ARs, Reply}.
4942
4943ssmmsr2_mg_do_verify_notify_request_ars(Tids, ARs) ->
4944    ssmmsr2_mg_do_verify_notify_request_ars(Tids, ARs, []).
4945
4946ssmmsr2_mg_do_verify_notify_request_ars([], [], Acc) ->
4947    lists:reverse(Acc);
4948ssmmsr2_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
4949    ActionReply = ssmmsr2_mg_do_verify_notify_request_ar(Tid, AR),
4950    ssmmsr2_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
4951
4952ssmmsr2_mg_do_verify_notify_request_ar(Tid, AR) ->
4953    io:format("ssmmsr2_mg_do_verify_notify_request_ar -> ok"
4954	      "~n   Tid: ~p"
4955	      "~n   AR:  ~p"
4956	      "~n", [Tid, AR]),
4957    {Cid, CR} =
4958	case AR of
4959	    #'ActionRequest'{contextId       = CtxId,
4960			     commandRequests = [CmdReq]} ->
4961		{CtxId, CmdReq};
4962	    _ ->
4963		Reason1 = {invalid_actionRequest, AR},
4964		throw({error, Reason1, ok})
4965	end,
4966    Cmd =
4967	case CR of
4968	    #'CommandRequest'{command = Command} ->
4969		Command;
4970	    _ ->
4971		throw({error, {invalid_commandRequest, CR}, ok})
4972	end,
4973    OED =
4974	case Cmd of
4975	    {notifyReq,
4976	     #'NotifyRequest'{terminationID            = [Tid],
4977			      observedEventsDescriptor = ObsEvDesc,
4978			      errorDescriptor          = asn1_NOVALUE}} ->
4979		ObsEvDesc;
4980	    _ ->
4981		throw({error, {invalid_command, Cmd}, ok})
4982	end,
4983    OE =
4984	case OED of
4985	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
4986		ObsEv;
4987	    #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
4988		throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
4989	    _ ->
4990		throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
4991	end,
4992    case OE of
4993	#'ObservedEvent'{eventName = "al/of"} ->
4994	    ssmmsr2_mg_notify_reply_ar(Cid, Tid);
4995	_ ->
4996	    throw({error, {invalid_ObservedEvent, OE}, ok})
4997    end.
4998
4999
5000ssmmsr2_mg_verify_ack_fun() ->
5001    fun(Event) -> (catch ssmmsr2_mg_verify_ack(Event)) end.
5002
5003ssmmsr2_mg_verify_ack({handle_trans_ack, CH, ?VERSION, AckStatus, ssmmsr2}) ->
5004    io:format("ssmmsr2_mg_verify_ack -> "
5005              "~n   AckStatus: ~p"
5006              "~n   CH:        ~p"
5007              "~n", [AckStatus, CH]),
5008    case AckStatus of
5009	{error, Reason} ->
5010	    case Reason of
5011		{segment_failure, SegInfo} when is_list(SegInfo) ->
5012		    io:format("ssmmsr2_mg_verify_ack -> verify not acked"
5013			      "~n", []),
5014		    case lists:keysearch(segments_not_acked, 1, SegInfo) of
5015			{value, {segments_not_acked, [2]}} ->
5016			    ok;
5017			{value, {segments_not_acked, SNs}} ->
5018			    X = {unexpected_not_acked_segments, SNs},
5019			    throw({error, X, ok});
5020			false ->
5021			    X = {unexpected_seg_info, SegInfo},
5022			    throw({error, X, ok})
5023		    end,
5024		    io:format("ssmmsr2_mg_verify_ack -> verify not sent"
5025			      "~n", []),
5026		    case lists:keysearch(segments_not_sent, 1, SegInfo) of
5027			{value, {segments_not_sent, NotSent}} ->
5028			    case [3,4,5,6,7,8] -- NotSent of
5029				[] ->
5030				    {ok, CH, ok};
5031				_ ->
5032				    Y = {unexpected_not_sent_segments,
5033					 NotSent},
5034				    throw({error, Y, ok})
5035			    end;
5036			false ->
5037			    Y = {unexpected_seg_info, SegInfo},
5038			    throw({error, Y, ok})
5039		    end;
5040		_ ->
5041		    X = {unexpected_reason, Reason},
5042		    {error, X, ok}
5043	    end;
5044	_ ->
5045	    X = {unexpected_ack_status, AckStatus},
5046	    {error, X, ok}
5047    end;
5048ssmmsr2_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
5049		       BadAckStatus, BadAckData}) ->
5050    {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
5051ssmmsr2_mg_verify_ack(BadEvent) ->
5052    {error, {unknown_event, BadEvent}, ok}.
5053
5054
5055ssmmsr2_mg_service_change_request_ar(_Mid, Cid) ->
5056    Prof  = cre_serviceChangeProf("resgw", 1),
5057    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
5058    Root  = #megaco_term_id{id = ["root"]},
5059    SCR   = cre_serviceChangeReq([Root], SCP),
5060    CMD   = cre_command(SCR),
5061    CR    = cre_cmdReq(CMD),
5062    cre_actionReq(Cid, [CR]).
5063
5064ssmmsr2_mg_notify_reply_ar(Cid, Tid) ->
5065    NR = cre_notifyReply([Tid]),
5066    CR = cre_cmdReply(NR),
5067    cre_actionReply(Cid, [CR]).
5068
5069
5070
5071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5072
5073
5074
5075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076%%%                                                                   %%%
5077%%%                 Segmented reply received test cases               %%%
5078%%%                                                                   %%%
5079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5080
5081recv_segmented_msg_plain(suite) ->
5082    [];
5083recv_segmented_msg_plain(doc) ->
5084    "Received segmented megaco message [plain]";
5085recv_segmented_msg_plain(Config) when is_list(Config) ->
5086    Pre = fun() ->
5087                  MgcNode = make_node_name(mgc),
5088                  MgNode  = make_node_name(mg),
5089                  d("start nodes: "
5090                    "~n      MgcNode: ~p"
5091                    "~n      MgNode:  ~p",
5092                    [MgcNode, MgNode]),
5093                  Nodes = [MgcNode, MgNode],
5094                  ok = ?START_NODES(Nodes),
5095                  Nodes
5096          end,
5097    Case = fun do_recv_segmented_msg_plain/1,
5098    Post = fun(Nodes) ->
5099                   d("stop nodes"),
5100                   ?STOP_NODES(lists:reverse(Nodes))
5101           end,
5102    try_tc(rsmp, Pre, Case, Post).
5103
5104do_recv_segmented_msg_plain([MgcNode, MgNode]) ->
5105
5106    d("[MGC] start the simulator "),
5107    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
5108
5109    d("[MGC] create the event sequence"),
5110    MgcEvSeq = rsmp_mgc_event_sequence(text, tcp),
5111
5112    i("wait some time before starting the MGC simulation"),
5113    sleep(1000),
5114
5115    d("[MGC] start the simulation"),
5116    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
5117
5118    i("wait some time before starting the MG simulator"),
5119    sleep(1000),
5120
5121    d("[MG] start the simulator (generator)"),
5122    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
5123
5124    d("[MG] create the event sequence"),
5125    MgEvSeq = rsmp_mg_event_sequence(text, tcp),
5126
5127    i("wait some time before starting the MG simulation"),
5128    sleep(1000),
5129
5130    d("[MG] start the simulation"),
5131    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
5132
5133    d("await the generator reply(s)"),
5134    await_completion([MgcId, MgId]),
5135
5136    %% Tell Mgc to stop
5137    i("[MGC] stop generator"),
5138    megaco_test_tcp_generator:stop(Mgc),
5139
5140    %% Tell Mg to stop
5141    i("[MG] stop generator"),
5142    megaco_test_megaco_generator:stop(Mg),
5143
5144    i("done", []),
5145    ok.
5146
5147
5148%%
5149%% MGC generator stuff
5150%%
5151
5152rsmp_mgc_event_sequence(text, tcp) ->
5153    DecodeFun = rsmp_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
5154    EncodeFun = rsmp_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
5155    Mid       = {deviceName,"mgc"},
5156    ScrVerifyFun     = rsmp_mgc_verify_service_change_req_msg_fun(),
5157    ServiceChangeRep = rsmp_mgc_service_change_reply_msg(Mid, 1),
5158    TermId1   =
5159	#megaco_term_id{id = ["00000000","00000000","00000001"]},
5160    TermId2   =
5161	#megaco_term_id{id = ["00000000","00000000","00000002"]},
5162    TermId3   =
5163	#megaco_term_id{id = ["00000000","00000000","00000003"]},
5164    TermIds   = [TermId1, TermId2, TermId3],
5165    TransId   = 2,
5166    ReqId     = 1,
5167    CtxId     = 1,
5168    NrVerifyFun  =
5169	rsmp_mgc_verify_notify_req_msg_fun(TermIds, TransId, ReqId, CtxId),
5170    NotifyRep1   = rsmp_mgc_notify_reply_msg(1, Mid, TransId, CtxId, TermId1),
5171    NotifyRep2   = rsmp_mgc_notify_reply_msg(2, Mid, TransId, CtxId, TermId2),
5172    NotifyRep3   = rsmp_mgc_notify_reply_msg(3, Mid, TransId, CtxId, TermId3),
5173    SrVerifyFun1 = rsmp_mgc_verify_segment_reply_msg_fun(1, TransId),
5174    SrVerifyFun2 = rsmp_mgc_verify_segment_reply_msg_fun(2, TransId),
5175    SrVerifyFun3 = rsmp_mgc_verify_segment_reply_msg_fun(3, TransId),
5176    AckVerifyFun = rsmp_mgc_verify_trans_ack_msg_fun(TransId),
5177    EvSeq = [{debug,  false},
5178             {decode, DecodeFun},
5179             {encode, EncodeFun},
5180             {listen, 2944},
5181	     {expect_accept, any},
5182             {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
5183             {sleep, 500},
5184
5185             {send, "service-change-reply",             ServiceChangeRep},
5186             {expect_receive, "notify-request(1)",      {NrVerifyFun, 4000}},
5187             {sleep, 500},
5188
5189             {send, "notify reply - segment 1",         NotifyRep1},
5190             {expect_receive, "segment reply 1",        {SrVerifyFun1, 2000}},
5191             {sleep, 500},
5192
5193             {send, "notify reply - segment 2",         NotifyRep2},
5194             {expect_receive, "segment reply 2",        {SrVerifyFun2, 2000}},
5195             {sleep, 500},
5196
5197             {send, "notify reply - segment 3 (last)",  NotifyRep3},
5198             {expect_receive, "segment reply 3 (last)", {SrVerifyFun3, 2000}},
5199             {expect_receive, "ack",                    {AckVerifyFun, 4000}},
5200             {sleep, 1000},
5201             disconnect
5202            ],
5203    EvSeq.
5204
5205rsmp_mgc_encode_msg_fun(Mod, Conf) ->
5206    fun(M) ->
5207            Mod:encode_message(Conf, M)
5208    end.
5209
5210rsmp_mgc_decode_msg_fun(Mod, Conf) ->
5211    fun(M) ->
5212            Mod:decode_message(Conf, M)
5213    end.
5214
5215rsmp_mgc_verify_service_change_req_msg_fun() ->
5216    fun(Msg) ->
5217	    (catch rsmp_mgc_verify_service_change_req(Msg))
5218    end.
5219
5220rsmp_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
5221    io:format("rsmp_mgc_verify_service_change_req -> entry with"
5222	      "~n   M: ~p"
5223	      "~n", [M]),
5224    Body =
5225	case Mess of
5226	    #'Message'{version     = 1,
5227                       mId         = _MgMid,
5228                       messageBody = MsgBody} ->
5229		MsgBody;
5230	    _ ->
5231		throw({error, {invalid_Message, Mess}})
5232	end,
5233    Trans =
5234	case Body of
5235            {transactions, [Transactions]} ->
5236		Transactions;
5237	    _ ->
5238		throw({error, {invalid_messageBody, Body}})
5239	end,
5240    TR =
5241	case Trans of
5242            {transactionRequest, TransRequest} ->
5243		TransRequest;
5244	    _ ->
5245		throw({error, {invalid_transactions, Trans}})
5246	end,
5247    AR =
5248	case TR of
5249            #'TransactionRequest'{transactionId = _TransId,
5250				  actions       = [ActionReq]} ->
5251		ActionReq;
5252	    _ ->
5253		throw({error, {invalid_transactionRequest, TR}})
5254	end,
5255    CR =
5256	case AR of
5257	    #'ActionRequest'{contextId       = _Cid,
5258			     commandRequests = [CmdReq]} ->
5259		CmdReq;
5260	    _ ->
5261		throw({error, {invalid_action, AR}})
5262	end,
5263    Cmd =
5264	case CR of
5265	    #'CommandRequest'{command = Command} ->
5266		Command;
5267	    _ ->
5268		throw({error, {invalid_commandRequest, CR}})
5269	end,
5270    {Tid, Parms} =
5271	case Cmd of
5272	    {serviceChangeReq,
5273	     #'ServiceChangeRequest'{terminationID      = [TermID],
5274				     serviceChangeParms = ServChParms}} ->
5275		{TermID, ServChParms};
5276	    _ ->
5277		throw({error, {invalid_command, Cmd}})
5278	end,
5279    case Tid of
5280	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
5281	    ok;
5282	_ ->
5283	    throw({error, {invalid_terminationID, Tid}})
5284    end,
5285    case Parms of
5286	%% Version 1 'ServiceChangeParm'
5287	{'ServiceChangeParm',
5288	 restart,                            % serviceChangeMethod
5289	 asn1_NOVALUE,                       % serviceChangeAddress
5290	 ?VERSION,                           % serviceChangeVersion,
5291	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
5292	 [[$9,$0,$1|_]],                     % serviceChangeReason
5293	 asn1_NOVALUE,                       % serviceChangeDelay
5294	 asn1_NOVALUE,                       % serviceChangeMgcId
5295	 asn1_NOVALUE,                       % timeStamp
5296	 asn1_NOVALUE                        % nonStandardData
5297	} ->
5298	    {ok, M};
5299	_ ->
5300	    {error, {invalid_serviceChangeParms, Parms}}
5301    end.
5302
5303rsmp_mgc_verify_notify_req_msg_fun(TermIds, TransId, Rid, Cid) ->
5304    fun(Msg) ->
5305	    (catch rsmp_mgc_verify_notify_req(Msg,
5306					      TermIds, TransId, Rid, Cid))
5307    end.
5308
5309rsmp_mgc_verify_notify_req(#'MegacoMessage'{mess = Mess} = M,
5310			     TermIds, TransId, Rid, Cid) ->
5311    io:format("rsmp_mgc_verify_notify_req -> entry with"
5312	      "~n   M:       ~p"
5313	      "~n   TermIds: ~p"
5314	      "~n   TransId: ~p"
5315	      "~n   Rid:     ~p"
5316	      "~n   Cid:     ~p"
5317	      "~n", [M, TermIds, TransId, Rid, Cid]),
5318    Body =
5319	case Mess of
5320	    #'Message'{version     = ?VERSION,
5321                       mId         = _Mid,
5322                       messageBody = MsgBody} ->
5323		MsgBody;
5324	    _ ->
5325		throw({error, {invalid_Message, Mess}})
5326	end,
5327    Trans =
5328	case Body of
5329            {transactions, [Transactions]} ->
5330		Transactions;
5331	    _ ->
5332		throw({error, {invalid_messageBody, Body}})
5333	end,
5334    TR =
5335	case Trans of
5336            {transactionRequest, TransRequest} ->
5337		TransRequest;
5338	    _ ->
5339		throw({error, {invalid_transactions, Trans}})
5340	end,
5341    AR =
5342	case TR of
5343            #'TransactionRequest'{transactionId = TransId,
5344				  actions       = [ActReq]} ->
5345		ActReq;
5346	    _ ->
5347		throw({error, {invalid_transactionRequest, TR}})
5348	end,
5349    Cmds =
5350	case AR of
5351	    #'ActionRequest'{contextId       = Cid,
5352			     commandRequests = Commands} ->
5353		Commands;
5354	    _ ->
5355		throw({error, {invalid_actions, AR}})
5356	end,
5357    ok = rsmp_mgc_verify_notify_req_cmds(TermIds, Cmds),
5358    {ok, M};
5359rsmp_mgc_verify_notify_req(Crap, _TermId, _TransId, _Rid, _Cid) ->
5360    {error, {invalid_MegacoMessage, Crap}}.
5361
5362rsmp_mgc_verify_notify_req_cmds([], []) ->
5363    ok;
5364rsmp_mgc_verify_notify_req_cmds([TermId|TermIds], [Cmd|Cmds]) ->
5365    rsmp_mgc_verify_notify_req_cmd(TermId, Cmd),
5366    rsmp_mgc_verify_notify_req_cmds(TermIds, Cmds);
5367rsmp_mgc_verify_notify_req_cmds(TermIds, Cmds) ->
5368     throw({error, {invalid_commands, TermIds, Cmds}}).
5369
5370rsmp_mgc_verify_notify_req_cmd(TermId, #'CommandRequest'{command = Cmd}) ->
5371    io:format("rsmp_mgc_verify_notify_req_cmd -> entry with"
5372	      "~n   TermId: ~p"
5373	      "~n   Cmd:    ~p"
5374	      "~n", [TermId, Cmd]),
5375    NR =
5376	case Cmd of
5377	    {notifyReq, NotifReq} ->
5378		NotifReq;
5379	    _ ->
5380		throw({error, {invalid_command}})
5381	end,
5382    OED =
5383	case NR of
5384	    #'NotifyRequest'{terminationID            = [TermId],
5385			     observedEventsDescriptor = ObsEvsDesc,
5386			     errorDescriptor          = asn1_NOVALUE} ->
5387		ObsEvsDesc;
5388	    _ ->
5389		throw({error, {invalid_notifyReq, NR}})
5390	end,
5391    OE =
5392	case OED of
5393	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
5394		ObsEvLst;
5395	    _ ->
5396		throw({error, {invalid_observedEventsDescriptor, OED}})
5397	end,
5398    case OE of
5399	#'ObservedEvent'{eventName = "al/of"} ->
5400	    ok;
5401	_ ->
5402	    throw({error, {invalid_observedEventLst, OE}})
5403    end;
5404rsmp_mgc_verify_notify_req_cmd(_, BadCmdReq) ->
5405    io:format("rsmp_mgc_verify_notify_req_cmd -> invalid"
5406	      "~n   BadCmdReq: ~p"
5407	      "~n", [BadCmdReq]),
5408    throw({error, {invalid_CommandRequest, BadCmdReq}}).
5409
5410rsmp_mgc_verify_segment_reply_msg_fun(SN, TransId) ->
5411    fun(Msg) ->
5412	    (catch rsmp_mgc_verify_segment_reply(Msg, SN, TransId))
5413    end.
5414
5415rsmp_mgc_verify_segment_reply(#'MegacoMessage'{mess = Mess} = M,
5416			      SN, TransId) ->
5417    io:format("rsmp_mgc_verify_segment_reply -> entry with"
5418	      "~n   SN:      ~p"
5419	      "~n   TransId: ~p"
5420	      "~n   M:       ~p"
5421	      "~n", [SN, TransId, M]),
5422    Body =
5423	case Mess of
5424	    #'Message'{version     = ?VERSION,
5425                       mId         = _MgMid,
5426                       messageBody = MsgBody} ->
5427		MsgBody;
5428	    _ ->
5429		throw({error, {invalid_Message, Mess}})
5430	end,
5431    Trans =
5432	case Body of
5433            {transactions, [Transactions]} ->
5434		Transactions;
5435	    _ ->
5436		throw({error, {invalid_messageBody, Body}})
5437	end,
5438    SR =
5439	case Trans of
5440            {segmentReply, SegmentReply} ->
5441		SegmentReply;
5442	    _ ->
5443		throw({error, {invalid_transactions, Trans}})
5444	end,
5445    case SR of
5446	#'SegmentReply'{transactionId        = TransId,
5447			segmentNumber        = SN,
5448			segmentationComplete = 'NULL'} when SN == 3 ->
5449	    {ok, M};
5450	#'SegmentReply'{transactionId        = TransId,
5451			segmentNumber        = SN,
5452			segmentationComplete = asn1_NOVALUE} ->
5453	    {ok, M};
5454	_ ->
5455	    throw({error, {invalid_segmentReply, SR}})
5456    end;
5457rsmp_mgc_verify_segment_reply(Crap, SN, TransId) ->
5458    io:format("rsmp_mgc_verify_segment_reply -> invalid: "
5459	      "~n   SN:      ~p"
5460	      "~n   TransId: ~p"
5461	      "~n   Crap:    ~p"
5462	      "~n", [SN, TransId, Crap]),
5463    {error, {invalid_MegacoMessage, Crap, SN, TransId}}.
5464
5465rsmp_mgc_verify_trans_ack_msg_fun(TransId) ->
5466    fun(Msg) ->
5467	    (catch rsmp_mgc_verify_trans_ack(Msg, TransId))
5468    end.
5469
5470rsmp_mgc_verify_trans_ack(#'MegacoMessage'{mess = Mess} = M, TransId) ->
5471    io:format("rsmp_mgc_verify_trans_ack -> entry with"
5472	      "~n   TransId: ~p"
5473	      "~n   M:       ~p"
5474	      "~n", [TransId, M]),
5475    Body =
5476	case Mess of
5477	    #'Message'{version     = ?VERSION,
5478                       mId         = _Mid,
5479                       messageBody = MsgBody} ->
5480		MsgBody;
5481	    _ ->
5482		throw({error, {invalid_Message, Mess}})
5483	end,
5484    Trans =
5485	case Body of
5486            {transactions, [Transactions]} ->
5487		Transactions;
5488	    _ ->
5489		throw({error, {invalid_messageBody, Body}})
5490	end,
5491    TA =
5492	case Trans of
5493            {transactionResponseAck, [TransAck]} ->
5494		TransAck;
5495	    _ ->
5496		throw({error, {invalid_transactions, Trans}})
5497	end,
5498    case TA of
5499            #'TransactionAck'{firstAck = TransId,
5500			      lastAck  = asn1_NOVALUE} ->
5501		{ok, M};
5502	    _ ->
5503		throw({error, {invalid_transactionResponseAck, TA}})
5504    end;
5505rsmp_mgc_verify_trans_ack(Crap, _TransId) ->
5506    {error, {invalid_MegacoMessage, Crap}}.
5507
5508rsmp_mgc_service_change_reply_msg(Mid, Cid) ->
5509    SCRP  = cre_serviceChangeResParm(Mid),
5510    SCRes = cre_serviceChangeResult(SCRP),
5511    Root  = #megaco_term_id{id = ["root"]},
5512    SCR   = cre_serviceChangeReply([Root], SCRes),
5513    CR    = cre_cmdReply(SCR),
5514    AR    = cre_actionReply(Cid, [CR]),
5515    TRes  = cre_transResult([AR]),
5516    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
5517    Trans = cre_transaction(TR),
5518    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
5519    cre_megacoMessage(Mess).
5520
5521rsmp_mgc_notify_reply_ar(Cid, TermId) ->
5522    NR    = cre_notifyReply([TermId]),
5523    CR    = cre_cmdReply(NR),
5524    cre_actionReply(Cid, [CR]).
5525
5526rsmp_mgc_notify_reply_msg(SN, Mid, TransId, Cid, TermId) ->
5527    AR    = rsmp_mgc_notify_reply_ar(Cid, TermId),
5528    TRes  = cre_transResult([AR]),
5529    TR =
5530	if
5531	    SN == 3 ->
5532		cre_transReply(TransId, TRes, SN, 'NULL');
5533	    true ->
5534		cre_transReply(TransId, TRes, SN)
5535	end,
5536    Trans = cre_transaction(TR),
5537    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
5538    cre_megacoMessage(Mess).
5539
5540
5541%%
5542%% MG generator stuff
5543%%
5544rsmp_mg_event_sequence(text, tcp) ->
5545    Mid = {deviceName,"mg"},
5546    RI = [
5547          {port,             2944},
5548          {encoding_module,  megaco_pretty_text_encoder},
5549          {encoding_config,  []},
5550          {transport_module, megaco_tcp}
5551         ],
5552    ServiceChangeReq = rsmp_mg_service_change_request_ar(Mid, 1),
5553    ConnectVerify = rsmp_mg_verify_handle_connect_fun(),
5554    ServiceChangeReplyVerify = rsmp_mg_verify_service_change_reply_fun(),
5555    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
5556    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
5557    Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
5558    Tids = [Tid1, Tid2, Tid3],
5559    NotifyReq = rsmp_mg_notify_request_ar(1, Tids, 1),
5560    NotifyReplyVerify1 = rsmp_mg_verify_notify_reply_fun(1, Tid1),
5561    NotifyReplyVerify2 = rsmp_mg_verify_notify_reply_fun(2, Tid2),
5562    NotifyReplyVerify3 = rsmp_mg_verify_notify_reply_fun(3, Tid3),
5563    EvSeq = [
5564             {debug, true},
5565             %% {megaco_trace, disable},
5566             {megaco_trace, max},
5567             megaco_start,
5568             {megaco_start_user, Mid, RI, []},
5569             start_transport,
5570             {megaco_system_info, users},
5571             {megaco_system_info, connections},
5572             connect,
5573             {megaco_callback, handle_connect, ConnectVerify},
5574             megaco_connect,
5575             {megaco_cast,     [ServiceChangeReq], []},
5576             {megaco_callback, handle_connect,     ConnectVerify},
5577             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
5578	     {megaco_update_user_info, protocol_version, ?VERSION},
5579	     {megaco_update_conn_info, protocol_version, ?VERSION},
5580             {sleep, 1000},
5581             {megaco_cast,     [NotifyReq],        []},
5582             {megaco_callback, handle_trans_reply, NotifyReplyVerify1},
5583             {megaco_callback, handle_trans_reply, NotifyReplyVerify2},
5584             {megaco_callback, handle_trans_reply, NotifyReplyVerify3},
5585             {sleep, 1000},
5586             megaco_stop_user,
5587             megaco_stop,
5588             {sleep, 1000}
5589            ],
5590    EvSeq.
5591
5592
5593rsmp_mg_verify_handle_connect_fun() ->
5594    fun(Ev) -> rsmp_mg_verify_handle_connect(Ev) end.
5595
5596rsmp_mg_verify_handle_connect({handle_connect, CH, 1}) ->
5597    io:format("rsmp_mg_verify_handle_connect -> ok"
5598	      "~n   CH: ~p~n", [CH]),
5599    {ok, CH, ok};
5600rsmp_mg_verify_handle_connect(Else) ->
5601    io:format("rsmp_mg_verify_handle_connect -> unknown"
5602	      "~n   Else: ~p~n", [Else]),
5603    {error, Else, ok}.
5604
5605
5606rsmp_mg_verify_service_change_reply_fun() ->
5607    fun(Rep) -> rsmp_mg_verify_scr(Rep) end.
5608
5609rsmp_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
5610    (catch rsmp_mg_do_verify_scr(AR));
5611rsmp_mg_verify_scr(Crap) ->
5612    io:format("rsmp_mg_verify_scr -> error: "
5613	      "~n   Crap: ~p"
5614	      "~n", [Crap]),
5615    {error, Crap, ok}.
5616
5617rsmp_mg_do_verify_scr(AR) ->
5618    io:format("rsmp_mg_do_verify_scr -> ok: "
5619	      "~n   AR: ~p~n", [AR]),
5620    CR =
5621	case AR of
5622	    #'ActionReply'{commandReply = [CmdRep]} ->
5623		CmdRep;
5624	    _ ->
5625		Reason1 = {invalid_action_reply, AR},
5626		throw({error, Reason1, ok})
5627	end,
5628    SCR =
5629	case CR of
5630	    {serviceChangeReply, ServChRep} ->
5631		ServChRep;
5632	    _ ->
5633		Reason2 = {invalid_command_reply, CR},
5634		throw({error, Reason2, ok})
5635	end,
5636    {Tid, SCRes} =
5637	case SCR of
5638	    #'ServiceChangeReply'{terminationID       = [TermID],
5639				  serviceChangeResult = Res} ->
5640		{TermID, Res};
5641	    _ ->
5642		Reason3 = {invalid_service_change_reply, SCR},
5643		throw({error, Reason3, ok})
5644	end,
5645    case Tid of
5646	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
5647	    ok;
5648	_ ->
5649	    Reason4 = {invalid_termination_id, Tid},
5650	    throw({error, Reason4, ok})
5651    end,
5652    SCRParm =
5653	case SCRes of
5654	    {serviceChangeResParms, ServChResParms} ->
5655		ServChResParms;
5656	    _ ->
5657		Reason5 = {invalid_serviceChangeResult, SCRes},
5658		throw({error, Reason5, ok})
5659	end,
5660    case SCRParm of
5661	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
5662	    {ok, AR, ok};
5663	_ ->
5664	    Reason6 = {invalid_service_change_result, SCRParm},
5665	    {error, Reason6, ok}
5666    end.
5667
5668rsmp_mg_verify_notify_reply_fun(SN, Tid) ->
5669    fun(Rep) -> rsmp_mg_verify_notify_reply(Rep, SN, Tid) end.
5670
5671rsmp_mg_verify_notify_reply(
5672  {handle_trans_reply, _CH, ?VERSION, {ok, {SN, Last, [AR]}}, _}, SN, Tid)
5673  when ((SN =:= 3) andalso (Last =:= true)) orelse
5674       ((SN =/= 3) andalso (Last =:= false)) ->
5675    (catch rsmp_mg_do_verify_notify_reply(Tid, AR));
5676rsmp_mg_verify_notify_reply(
5677  {handle_trans_reply, _CH, Version, {ok, {SN1, Last, ARs}}, _}, SN2, Tid) ->
5678    io:format("rsmp_mg_verify_notify_reply -> unknown reply"
5679	      "~n   Version: ~p"
5680	      "~n   SN1:     ~p"
5681	      "~n   Last:    ~p"
5682	      "~n   ARs:     ~p"
5683	      "~n   SN2:     ~p"
5684	      "~n   Tid:     ~p"
5685	      "~n", [Version, SN1, Last, ARs, SN2, Tid]),
5686    Crap = {unexpected_segment_data, [SN1, Last, ARs, SN2, Tid]},
5687    {error, Crap, ok};
5688rsmp_mg_verify_notify_reply(Crap, SN, Tid) ->
5689    io:format("rsmp_mg_verify_notify_reply -> unknown reply"
5690	      "~n   SN:   ~p"
5691	      "~n   Tid:  ~p"
5692	      "~n   Crap: ~p"
5693	      "~n", [SN, Tid, Crap]),
5694    {error, Crap, ok}.
5695
5696rsmp_mg_do_verify_notify_reply(Tid, AR) ->
5697    io:format("rsmp_mg_do_verify_notify_reply -> ok"
5698	      "~n   Tid:  ~p"
5699	      "~n   AR:   ~p"
5700	      "~n", [Tid, AR]),
5701    CR =
5702	case AR of
5703	    #'ActionReply'{commandReply = [CmdRep]} ->
5704		CmdRep;
5705	    _ ->
5706		Reason1 = {invalid_action_reply, AR},
5707		throw({error, Reason1, ok})
5708	end,
5709    NR =
5710	case CR of
5711	    {notifyReply, NotifyReply} ->
5712		NotifyReply;
5713	    _ ->
5714		Reason2 = {invalid_command_reply, CR},
5715		throw({error, Reason2, ok})
5716	end,
5717    case NR of
5718	#'NotifyReply'{terminationID   = [Tid],
5719		       errorDescriptor = asn1_NOVALUE} ->
5720	    {ok, AR, ok};
5721	_ ->
5722	    Reason3 = {invalid_NotifyReply, NR},
5723	    {error, Reason3, ok}
5724    end.
5725
5726
5727rsmp_mg_service_change_request_ar(_Mid, Cid) ->
5728    Prof  = cre_serviceChangeProf("resgw", 1),
5729    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
5730    Root  = #megaco_term_id{id = ["root"]},
5731    SCR   = cre_serviceChangeReq([Root], SCP),
5732    CMD   = cre_command(SCR),
5733    CR    = cre_cmdReq(CMD),
5734    cre_actionReq(Cid, [CR]).
5735
5736rsmp_mg_notify_request_ar(Rid, Tids, Cid) ->
5737    rsmp_mg_notify_request_ar(Rid, Tids, Cid, []).
5738
5739rsmp_mg_notify_request_ar(_Rid, [], Cid, Cmds) ->
5740    cre_actionReq(Cid, lists:reverse(Cmds));
5741rsmp_mg_notify_request_ar(Rid, [Tid|Tids], Cid, Cmds) ->
5742    TT      = cre_timeNotation("19990729", "22000000"),
5743    Ev      = cre_obsEvent("al/of", TT),
5744    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
5745    NR      = cre_notifyReq([Tid], EvsDesc),
5746    CMD     = cre_command(NR),
5747    CR      = cre_cmdReq(CMD),
5748    rsmp_mg_notify_request_ar(Rid, Tids, Cid, [CR|Cmds]).
5749
5750%% rsmp_internalError(Text) ->
5751%%     Code = ?megaco_internal_gateway_error,
5752%%     cre_errorDesc(Code, Text).
5753
5754
5755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5756
5757recv_segmented_msg_ooo_seg(suite) ->
5758    [];
5759recv_segmented_msg_ooo_seg(doc) ->
5760    "Received segmented megaco message [out-of-order segments]";
5761recv_segmented_msg_ooo_seg(Config) when is_list(Config) ->
5762    Pre = fun() ->
5763                  MgcNode = make_node_name(mgc),
5764                  MgNode  = make_node_name(mg),
5765                  d("start nodes: "
5766                    "~n   MgcNode: ~p"
5767                    "~n   MgNode:  ~p",
5768                    [MgcNode, MgNode]),
5769                  Nodes = [MgcNode, MgNode],
5770                  ok = ?START_NODES(Nodes),
5771                  Nodes
5772          end,
5773    Case = fun do_recv_segmented_msg_ooo_seg/1,
5774    Post = fun(Nodes) ->
5775                   d("stop nodes"),
5776                   ?STOP_NODES(lists:reverse(Nodes))
5777           end,
5778    try_tc(rsmos, Pre, Case, Post).
5779
5780do_recv_segmented_msg_ooo_seg([MgcNode, MgNode]) ->
5781
5782    d("[MGC] start the simulator "),
5783    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
5784
5785    d("[MGC] create the event sequence"),
5786    MgcEvSeq = rsmos_mgc_event_sequence(text, tcp),
5787
5788    i("wait some time before starting the MGC simulation"),
5789    sleep(1000),
5790
5791    d("[MGC] start the simulation"),
5792    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
5793
5794    i("wait some time before starting the MG simulator"),
5795    sleep(1000),
5796
5797    d("[MG] start the simulator (generator)"),
5798    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
5799
5800    d("[MG] create the event sequence"),
5801    MgEvSeq = rsmos_mg_event_sequence(text, tcp),
5802
5803    i("wait some time before starting the MG simulation"),
5804    sleep(1000),
5805
5806    d("[MG] start the simulation"),
5807    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
5808
5809    d("await the generator reply(s)"),
5810    await_completion([MgcId, MgId]),
5811
5812    %% Tell Mgc to stop
5813    i("[MGC] stop generator"),
5814    megaco_test_tcp_generator:stop(Mgc),
5815
5816    %% Tell Mg to stop
5817    i("[MG] stop generator"),
5818    megaco_test_megaco_generator:stop(Mg),
5819
5820    i("done", []),
5821    ok.
5822
5823
5824%%
5825%% MGC generator stuff
5826%%
5827
5828rsmos_mgc_event_sequence(text, tcp) ->
5829    DecodeFun = rsmos_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
5830    EncodeFun = rsmos_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
5831    Mid       = {deviceName,"mgc"},
5832    ScrVerifyFun     = rsmos_mgc_verify_service_change_req_msg_fun(),
5833    ServiceChangeRep = rsmos_mgc_service_change_reply_msg(Mid, 1),
5834    TermId1   =
5835	#megaco_term_id{id = ["00000000","00000000","00000001"]},
5836    TermId2   =
5837	#megaco_term_id{id = ["00000000","00000000","00000002"]},
5838    TermId3   =
5839	#megaco_term_id{id = ["00000000","00000000","00000003"]},
5840    TermIds   = [TermId1, TermId2, TermId3],
5841    TransId   = 2,
5842    ReqId     = 1,
5843    CtxId     = 1,
5844    NrVerifyFun  =
5845	rsmos_mgc_verify_notify_req_msg_fun(TermIds, TransId, ReqId, CtxId),
5846    NotifyRep1   = rsmos_mgc_notify_reply_msg(1, Mid, TransId, CtxId, TermId1),
5847    NotifyRep2   = rsmos_mgc_notify_reply_msg(2, Mid, TransId, CtxId, TermId2),
5848    NotifyRep3   = rsmos_mgc_notify_reply_msg(3, Mid, TransId, CtxId, TermId3),
5849    SrVerifyFun1 = rsmos_mgc_verify_segment_reply_msg_fun(1, TransId),
5850    SrVerifyFun2 = rsmos_mgc_verify_segment_reply_msg_fun(2, TransId),
5851    SrVerifyFun3 = rsmos_mgc_verify_segment_reply_msg_fun(3, TransId),
5852    AckVerifyFun = rsmos_mgc_verify_trans_ack_msg_fun(TransId),
5853    EvSeq = [{debug,  false},
5854             {decode, DecodeFun},
5855             {encode, EncodeFun},
5856             {listen, 2944},
5857	     {expect_accept, any},
5858             {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
5859             {send, "service-change-reply",             ServiceChangeRep},
5860             {expect_receive, "notify-request",         {NrVerifyFun,  4000}},
5861             {send, "notify reply - segment 3",  NotifyRep3},
5862             {expect_receive, "segment reply 3", {SrVerifyFun3, 2000}},
5863             {sleep, 1000},
5864             {send, "notify reply - segment 2",         NotifyRep2},
5865             {expect_receive, "segment reply 2",        {SrVerifyFun2, 2000}},
5866             {sleep, 1000},
5867             {send, "notify reply - segment 1 (last)",  NotifyRep1},
5868             {expect_receive, "segment reply 1 (last)", {SrVerifyFun1, 2000}},
5869             {expect_receive, "ack",                    {AckVerifyFun, 4000}},
5870	     {expect_nothing, 10000},
5871             disconnect
5872            ],
5873    EvSeq.
5874
5875rsmos_mgc_encode_msg_fun(Mod, Conf) ->
5876    fun(M) ->
5877            Mod:encode_message(Conf, M)
5878    end.
5879
5880rsmos_mgc_decode_msg_fun(Mod, Conf) ->
5881    fun(M) ->
5882            Mod:decode_message(Conf, M)
5883    end.
5884
5885rsmos_mgc_verify_service_change_req_msg_fun() ->
5886    fun(Msg) ->
5887	    (catch rsmos_mgc_verify_service_change_req(Msg))
5888    end.
5889
5890rsmos_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
5891    io:format("rsmos_mgc_verify_service_change_req -> entry with"
5892	      "~n   M: ~p"
5893	      "~n", [M]),
5894    Body =
5895	case Mess of
5896	    #'Message'{version     = 1,
5897                       mId         = _MgMid,
5898                       messageBody = MsgBody} ->
5899		MsgBody;
5900	    _ ->
5901		throw({error, {invalid_Message, Mess}})
5902	end,
5903    Trans =
5904	case Body of
5905            {transactions, [Transactions]} ->
5906		Transactions;
5907	    _ ->
5908		throw({error, {invalid_messageBody, Body}})
5909	end,
5910    TR =
5911	case Trans of
5912            {transactionRequest, TransRequest} ->
5913		TransRequest;
5914	    _ ->
5915		throw({error, {invalid_transactions, Trans}})
5916	end,
5917    AR =
5918	case TR of
5919            #'TransactionRequest'{transactionId = _TransId,
5920				  actions       = [ActionReq]} ->
5921		ActionReq;
5922	    _ ->
5923		throw({error, {invalid_transactionRequest, TR}})
5924	end,
5925    CR =
5926	case AR of
5927	    #'ActionRequest'{contextId       = _Cid,
5928			     commandRequests = [CmdReq]} ->
5929		CmdReq;
5930	    _ ->
5931		throw({error, {invalid_action, AR}})
5932	end,
5933    Cmd =
5934	case CR of
5935	    #'CommandRequest'{command = Command} ->
5936		Command;
5937	    _ ->
5938		throw({error, {invalid_commandRequest, CR}})
5939	end,
5940    {Tid, Parms} =
5941	case Cmd of
5942	    {serviceChangeReq,
5943	     #'ServiceChangeRequest'{terminationID      = [TermID],
5944				     serviceChangeParms = ServChParms}} ->
5945		{TermID, ServChParms};
5946	    _ ->
5947		throw({error, {invalid_command, Cmd}})
5948	end,
5949    case Tid of
5950	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
5951	    ok;
5952	_ ->
5953	    throw({error, {invalid_terminationID, Tid}})
5954    end,
5955    case Parms of
5956	%% Version 1 'ServiceChangeParm'
5957	{'ServiceChangeParm',
5958	 restart,                            % serviceChangeMethod
5959	 asn1_NOVALUE,                       % serviceChangeAddress
5960	 ?VERSION,                           % serviceChangeVersion,
5961	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
5962	 [[$9,$0,$1|_]],                     % serviceChangeReason
5963	 asn1_NOVALUE,                       % serviceChangeDelay
5964	 asn1_NOVALUE,                       % serviceChangeMgcId
5965	 asn1_NOVALUE,                       % timeStamp
5966	 asn1_NOVALUE                        % nonStandardData
5967	} ->
5968	    {ok, M};
5969	_ ->
5970	    {error, {invalid_serviceChangeParms, Parms}}
5971    end.
5972
5973rsmos_mgc_verify_notify_req_msg_fun(TermIds, TransId, Rid, Cid) ->
5974    fun(Msg) ->
5975	    (catch rsmos_mgc_verify_notify_req(Msg,
5976					      TermIds, TransId, Rid, Cid))
5977    end.
5978
5979rsmos_mgc_verify_notify_req(#'MegacoMessage'{mess = Mess} = M,
5980			     TermIds, TransId, Rid, Cid) ->
5981    io:format("rsmos_mgc_verify_notify_req -> entry with"
5982	      "~n   M:       ~p"
5983	      "~n   TermIds: ~p"
5984	      "~n   TransId: ~p"
5985	      "~n   Rid:     ~p"
5986	      "~n   Cid:     ~p"
5987	      "~n", [M, TermIds, TransId, Rid, Cid]),
5988    Body =
5989	case Mess of
5990	    #'Message'{version     = ?VERSION,
5991                       mId         = _Mid,
5992                       messageBody = MsgBody} ->
5993		MsgBody;
5994	    _ ->
5995		throw({error, {invalid_Message, Mess}})
5996	end,
5997    Trans =
5998	case Body of
5999            {transactions, [Transactions]} ->
6000		Transactions;
6001	    _ ->
6002		throw({error, {invalid_messageBody, Body}})
6003	end,
6004    TR =
6005	case Trans of
6006            {transactionRequest, TransRequest} ->
6007		TransRequest;
6008	    _ ->
6009		throw({error, {invalid_transactions, Trans}})
6010	end,
6011    AR =
6012	case TR of
6013            #'TransactionRequest'{transactionId = TransId,
6014				  actions       = [ActReq]} ->
6015		ActReq;
6016	    _ ->
6017		throw({error, {invalid_transactionRequest, TR}})
6018	end,
6019    Cmds =
6020	case AR of
6021	    #'ActionRequest'{contextId       = Cid,
6022			     commandRequests = Commands} ->
6023		Commands;
6024	    _ ->
6025		throw({error, {invalid_actions, AR}})
6026	end,
6027    ok = rsmos_mgc_verify_notify_req_cmds(TermIds, Cmds),
6028    {ok, M};
6029rsmos_mgc_verify_notify_req(Crap, _TermId, _TransId, _Rid, _Cid) ->
6030    {error, {invalid_MegacoMessage, Crap}}.
6031
6032rsmos_mgc_verify_notify_req_cmds([], []) ->
6033    ok;
6034rsmos_mgc_verify_notify_req_cmds([TermId|TermIds], [Cmd|Cmds]) ->
6035    rsmos_mgc_verify_notify_req_cmd(TermId, Cmd),
6036    rsmos_mgc_verify_notify_req_cmds(TermIds, Cmds);
6037rsmos_mgc_verify_notify_req_cmds(TermIds, Cmds) ->
6038     throw({error, {invalid_commands, TermIds, Cmds}}).
6039
6040rsmos_mgc_verify_notify_req_cmd(TermId, #'CommandRequest'{command = Cmd}) ->
6041    io:format("rsmos_mgc_verify_notify_req_cmd -> entry with"
6042	      "~n   TermId: ~p"
6043	      "~n   Cmd:    ~p"
6044	      "~n", [TermId, Cmd]),
6045    NR =
6046	case Cmd of
6047	    {notifyReq, NotifReq} ->
6048		NotifReq;
6049	    _ ->
6050		throw({error, {invalid_command}})
6051	end,
6052    OED =
6053	case NR of
6054	    #'NotifyRequest'{terminationID            = [TermId],
6055			     observedEventsDescriptor = ObsEvsDesc,
6056			     errorDescriptor          = asn1_NOVALUE} ->
6057		ObsEvsDesc;
6058	    _ ->
6059		throw({error, {invalid_notifyReq, NR}})
6060	end,
6061    OE =
6062	case OED of
6063	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
6064		ObsEvLst;
6065	    _ ->
6066		throw({error, {invalid_observedEventsDescriptor, OED}})
6067	end,
6068    case OE of
6069	#'ObservedEvent'{eventName = "al/of"} ->
6070	    ok;
6071	_ ->
6072	    throw({error, {invalid_observedEventLst, OE}})
6073    end;
6074rsmos_mgc_verify_notify_req_cmd(_, BadCmdReq) ->
6075    io:format("rsmos_mgc_verify_notify_req_cmd -> invalid"
6076	      "~n   BadCmdReq: ~p"
6077	      "~n", [BadCmdReq]),
6078    throw({error, {invalid_CommandRequest, BadCmdReq}}).
6079
6080rsmos_mgc_verify_segment_reply_msg_fun(SN, TransId) ->
6081    fun(Msg) ->
6082	    (catch rsmos_mgc_verify_segment_reply(Msg, SN, TransId))
6083    end.
6084
6085rsmos_mgc_verify_segment_reply(#'MegacoMessage'{mess = Mess} = M,
6086			      SN, TransId) ->
6087    io:format("rsmos_mgc_verify_segment_reply -> entry with"
6088	      "~n   SN:      ~p"
6089	      "~n   TransId: ~p"
6090	      "~n   M:       ~p"
6091	      "~n", [SN, TransId, M]),
6092    Body =
6093	case Mess of
6094	    #'Message'{version     = ?VERSION,
6095                       mId         = _MgMid,
6096                       messageBody = MsgBody} ->
6097		MsgBody;
6098	    _ ->
6099		throw({error, {invalid_Message, Mess}})
6100	end,
6101    Trans =
6102	case Body of
6103            {transactions, [Transactions]} ->
6104		Transactions;
6105	    _ ->
6106		throw({error, {invalid_messageBody, Body}})
6107	end,
6108    SR =
6109	case Trans of
6110            {segmentReply, SegmentReply} ->
6111		SegmentReply;
6112	    _ ->
6113		throw({error, {invalid_transactions, Trans}})
6114	end,
6115    case SR of
6116	#'SegmentReply'{transactionId        = TransId,
6117			segmentNumber        = SN,
6118			segmentationComplete = 'NULL'} when SN == 3 ->
6119	    {ok, M};
6120	#'SegmentReply'{transactionId        = TransId,
6121			segmentNumber        = SN,
6122			segmentationComplete = asn1_NOVALUE} ->
6123	    {ok, M};
6124	_ ->
6125	    throw({error, {invalid_segmentReply, SR}})
6126    end;
6127rsmos_mgc_verify_segment_reply(Crap, SN, TransId) ->
6128    io:format("rsmos_mgc_verify_segment_reply -> invalid: "
6129	      "~n   SN:      ~p"
6130	      "~n   TransId: ~p"
6131	      "~n   Crap:    ~p"
6132	      "~n", [SN, TransId, Crap]),
6133    {error, {invalid_MegacoMessage, Crap, SN, TransId}}.
6134
6135rsmos_mgc_verify_trans_ack_msg_fun(TransId) ->
6136    fun(Msg) ->
6137	    (catch rsmos_mgc_verify_trans_ack(Msg, TransId))
6138    end.
6139
6140rsmos_mgc_verify_trans_ack(#'MegacoMessage'{mess = Mess} = M, TransId) ->
6141    io:format("rsmos_mgc_verify_trans_ack -> entry with"
6142	      "~n   TransId: ~p"
6143	      "~n   M:       ~p"
6144	      "~n", [TransId, M]),
6145    Body =
6146	case Mess of
6147	    #'Message'{version     = ?VERSION,
6148                       mId         = _Mid,
6149                       messageBody = MsgBody} ->
6150		MsgBody;
6151	    _ ->
6152		throw({error, {invalid_Message, Mess}})
6153	end,
6154    Trans =
6155	case Body of
6156            {transactions, [Transactions]} ->
6157		Transactions;
6158	    _ ->
6159		throw({error, {invalid_messageBody, Body}})
6160	end,
6161    TA =
6162	case Trans of
6163            {transactionResponseAck, [TransAck]} ->
6164		TransAck;
6165	    _ ->
6166		throw({error, {invalid_transactions, Trans}})
6167	end,
6168    case TA of
6169            #'TransactionAck'{firstAck = TransId,
6170			      lastAck  = asn1_NOVALUE} ->
6171		{ok, M};
6172	    _ ->
6173		throw({error, {invalid_transactionResponseAck, TA}})
6174    end;
6175rsmos_mgc_verify_trans_ack(Crap, _TransId) ->
6176    {error, {invalid_MegacoMessage, Crap}}.
6177
6178rsmos_mgc_service_change_reply_msg(Mid, Cid) ->
6179    SCRP  = cre_serviceChangeResParm(Mid),
6180    SCRes = cre_serviceChangeResult(SCRP),
6181    Root  = #megaco_term_id{id = ["root"]},
6182    SCR   = cre_serviceChangeReply([Root], SCRes),
6183    CR    = cre_cmdReply(SCR),
6184    AR    = cre_actionReply(Cid, [CR]),
6185    TRes  = cre_transResult([AR]),
6186    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
6187    Trans = cre_transaction(TR),
6188    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
6189    cre_megacoMessage(Mess).
6190
6191rsmos_mgc_notify_reply_ar(Cid, TermId) ->
6192    NR    = cre_notifyReply([TermId]),
6193    CR    = cre_cmdReply(NR),
6194    cre_actionReply(Cid, [CR]).
6195
6196rsmos_mgc_notify_reply_msg(SN, Mid, TransId, Cid, TermId) ->
6197    AR    = rsmos_mgc_notify_reply_ar(Cid, TermId),
6198    TRes  = cre_transResult([AR]),
6199    TR =
6200	if
6201	    SN == 3 ->
6202		cre_transReply(TransId, TRes, SN, 'NULL');
6203	    true ->
6204		cre_transReply(TransId, TRes, SN)
6205	end,
6206    Trans = cre_transaction(TR),
6207    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
6208    cre_megacoMessage(Mess).
6209
6210
6211%%
6212%% MG generator stuff
6213%%
6214rsmos_mg_event_sequence(text, tcp) ->
6215    Mid = {deviceName,"mg"},
6216    RI = [
6217          {port,             2944},
6218          {encoding_module,  megaco_pretty_text_encoder},
6219          {encoding_config,  []},
6220          {transport_module, megaco_tcp}
6221         ],
6222    ServiceChangeReq = rsmos_mg_service_change_request_ar(Mid, 1),
6223    ConnectVerify = rsmos_mg_verify_handle_connect_fun(),
6224    ServiceChangeReplyVerify = rsmos_mg_verify_service_change_reply_fun(),
6225    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
6226    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
6227    Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
6228    Tids = [Tid1, Tid2, Tid3],
6229    NotifyReq = rsmos_mg_notify_request_ar(1, Tids, 1),
6230    NotifyReplyVerify1 = rsmos_mg_verify_notify_reply_fun(1, Tid1),
6231    NotifyReplyVerify2 = rsmos_mg_verify_notify_reply_fun(2, Tid2),
6232    NotifyReplyVerify3 = rsmos_mg_verify_notify_reply_fun(3, Tid3),
6233    DiscoVerify        = rsmos_mg_verify_handle_disco_fun(),
6234    EvSeq = [
6235             {debug, true},
6236             %% {megaco_trace, disable},
6237             {megaco_trace, max},
6238             megaco_start,
6239             {megaco_start_user, Mid, RI, []},
6240             start_transport,
6241             {megaco_system_info, users},
6242             {megaco_system_info, connections},
6243	     {megaco_update_user_info, segment_recv_timer, 3000},
6244             connect,
6245             {megaco_callback, handle_connect, ConnectVerify},
6246             megaco_connect,
6247             {megaco_cast,     [ServiceChangeReq], []},
6248             {megaco_callback, handle_connect,     ConnectVerify},
6249             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
6250	     {megaco_update_conn_info, protocol_version, ?VERSION},
6251             {sleep, 1000},
6252             {megaco_cast,     [NotifyReq],        []},
6253             {megaco_callback, handle_trans_reply, NotifyReplyVerify3},
6254             {megaco_callback, handle_trans_reply, NotifyReplyVerify2},
6255             {megaco_callback, handle_trans_reply, NotifyReplyVerify1},
6256             {megaco_callback, handle_disconnect,  DiscoVerify},
6257             megaco_stop_user,
6258             megaco_stop
6259            ],
6260    EvSeq.
6261
6262
6263rsmos_mg_verify_handle_connect_fun() ->
6264    fun(Ev) -> rsmos_mg_verify_handle_connect(Ev) end.
6265
6266rsmos_mg_verify_handle_connect({handle_connect, CH, 1}) ->
6267    io:format("rsmos_mg_verify_handle_connect -> ok"
6268	      "~n   CH: ~p~n", [CH]),
6269    {ok, CH, ok};
6270rsmos_mg_verify_handle_connect(Else) ->
6271    io:format("rsmos_mg_verify_handle_connect -> unknown"
6272	      "~n   Else: ~p~n", [Else]),
6273    {error, Else, ok}.
6274
6275
6276rsmos_mg_verify_service_change_reply_fun() ->
6277    fun(Rep) -> rsmos_mg_verify_scr(Rep) end.
6278
6279rsmos_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
6280    (catch rsmos_mg_do_verify_scr(AR));
6281rsmos_mg_verify_scr(Crap) ->
6282    io:format("rsmos_mg_verify_scr -> error: "
6283	      "~n   Crap: ~p"
6284	      "~n", [Crap]),
6285    {error, Crap, ok}.
6286
6287rsmos_mg_do_verify_scr(AR) ->
6288    io:format("rsmos_mg_do_verify_scr -> ok: "
6289	      "~n   AR: ~p~n", [AR]),
6290    CR =
6291	case AR of
6292	    #'ActionReply'{commandReply = [CmdRep]} ->
6293		CmdRep;
6294	    _ ->
6295		Reason1 = {invalid_action_reply, AR},
6296		throw({error, Reason1, ok})
6297	end,
6298    SCR =
6299	case CR of
6300	    {serviceChangeReply, ServChRep} ->
6301		ServChRep;
6302	    _ ->
6303		Reason2 = {invalid_command_reply, CR},
6304		throw({error, Reason2, ok})
6305	end,
6306    {Tid, SCRes} =
6307	case SCR of
6308	    #'ServiceChangeReply'{terminationID       = [TermID],
6309				  serviceChangeResult = Res} ->
6310		{TermID, Res};
6311	    _ ->
6312		Reason3 = {invalid_service_change_reply, SCR},
6313		throw({error, Reason3, ok})
6314	end,
6315    case Tid of
6316	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
6317	    ok;
6318	_ ->
6319	    Reason4 = {invalid_termination_id, Tid},
6320	    throw({error, Reason4, ok})
6321    end,
6322    SCRParm =
6323	case SCRes of
6324	    {serviceChangeResParms, ServChResParms} ->
6325		ServChResParms;
6326	    _ ->
6327		Reason5 = {invalid_serviceChangeResult, SCRes},
6328		throw({error, Reason5, ok})
6329	end,
6330    case SCRParm of
6331	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
6332	    {ok, AR, ok};
6333	_ ->
6334	    Reason6 = {invalid_service_change_result, SCRParm},
6335	    {error, Reason6, ok}
6336    end.
6337
6338rsmos_mg_verify_notify_reply_fun(SN, Tid) ->
6339    fun(Rep) -> rsmos_mg_verify_notify_reply(Rep, SN, Tid) end.
6340
6341rsmos_mg_verify_notify_reply(
6342  {handle_trans_reply, _CH, ?VERSION, {ok, {SN, Last, [AR]}}, _}, SN, Tid)
6343  when ((SN == 1) and (Last == true)) or
6344       ((SN =/= 1) and (Last == false)) ->
6345    (catch rsmos_mg_do_verify_notify_reply(Tid, AR));
6346rsmos_mg_verify_notify_reply(Crap, SN, Tid) ->
6347    io:format("rsmos_mg_verify_notify_reply -> unknown reply"
6348	      "~n   SN:   ~p"
6349	      "~n   Tid:  ~p"
6350	      "~n   Crap: ~p"
6351	      "~n", [SN, Tid, Crap]),
6352    {error, Crap, ok}.
6353
6354rsmos_mg_do_verify_notify_reply(Tid, AR) ->
6355    io:format("rsmos_mg_do_verify_notify_reply -> ok"
6356	      "~n   Tid:  ~p"
6357	      "~n   AR:   ~p"
6358	      "~n", [Tid, AR]),
6359    CR =
6360	case AR of
6361	    #'ActionReply'{commandReply = [CmdRep]} ->
6362		CmdRep;
6363	    _ ->
6364		Reason1 = {invalid_action_reply, AR},
6365		throw({error, Reason1, ok})
6366	end,
6367    NR =
6368	case CR of
6369	    {notifyReply, NotifyReply} ->
6370		NotifyReply;
6371	    _ ->
6372		Reason2 = {invalid_command_reply, CR},
6373		throw({error, Reason2, ok})
6374	end,
6375    case NR of
6376	#'NotifyReply'{terminationID   = [Tid],
6377		       errorDescriptor = asn1_NOVALUE} ->
6378	    {ok, AR, ok};
6379	_ ->
6380	    Reason3 = {invalid_NotifyReply, NR},
6381	    {error, Reason3, ok}
6382    end.
6383
6384rsmos_mg_verify_handle_disco_fun() ->
6385    fun(Ev) -> rsmos_mg_verify_handle_disconnect(Ev) end.
6386
6387rsmos_mg_verify_handle_disconnect({handle_disconnect, _CH, ?VERSION, R}) ->
6388    io:format("rsmos_mg_verify_handle_disconnect -> ok"
6389	      "~n   R: ~p"
6390	      "~n", [R]),
6391    case R of
6392	{no_controlling_process,shutdown} ->
6393	    {ok, R, ok};
6394	_ ->
6395	    {error, {unexpected_reason, R}, ok}
6396    end;
6397rsmos_mg_verify_handle_disconnect(Crap) ->
6398    io:format("rsmos_mg_verify_handle_disconnect -> invalid: "
6399	      "~n   Crap: ~p"
6400	      "~n", [Crap]),
6401    {error, Crap, ok}.
6402
6403
6404rsmos_mg_service_change_request_ar(_Mid, Cid) ->
6405    Prof  = cre_serviceChangeProf("resgw", 1),
6406    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
6407    Root  = #megaco_term_id{id = ["root"]},
6408    SCR   = cre_serviceChangeReq([Root], SCP),
6409    CMD   = cre_command(SCR),
6410    CR    = cre_cmdReq(CMD),
6411    cre_actionReq(Cid, [CR]).
6412
6413rsmos_mg_notify_request_ar(Rid, Tids, Cid) ->
6414    rsmos_mg_notify_request_ar(Rid, Tids, Cid, []).
6415
6416rsmos_mg_notify_request_ar(_Rid, [], Cid, Cmds) ->
6417    cre_actionReq(Cid, lists:reverse(Cmds));
6418rsmos_mg_notify_request_ar(Rid, [Tid|Tids], Cid, Cmds) ->
6419    TT      = cre_timeNotation("19990729", "22000000"),
6420    Ev      = cre_obsEvent("al/of", TT),
6421    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
6422    NR      = cre_notifyReq([Tid], EvsDesc),
6423    CMD     = cre_command(NR),
6424    CR      = cre_cmdReq(CMD),
6425    rsmos_mg_notify_request_ar(Rid, Tids, Cid, [CR|Cmds]).
6426
6427
6428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6429
6430recv_segmented_msg_missing_seg1(suite) ->
6431    [];
6432recv_segmented_msg_missing_seg1(doc) ->
6433    "Received segmented megaco message with one segment missing "
6434	"using plain integer recv segment timer";
6435recv_segmented_msg_missing_seg1(Config) when is_list(Config) ->
6436    Pre = fun() ->
6437                  MgcNode = make_node_name(mgc),
6438                  MgNode  = make_node_name(mg),
6439                  d("start nodes: "
6440                    "~n   MgcNode: ~p"
6441                    "~n   MgNode:  ~p",
6442                    [MgcNode, MgNode]),
6443                  Nodes = [MgcNode, MgNode],
6444                  ok = ?START_NODES(Nodes),
6445                  Nodes
6446          end,
6447    Case = fun do_recv_segmented_msg_missing_seg1/1,
6448    Post = fun(Nodes) ->
6449                   d("stop nodes"),
6450                   ?STOP_NODES(lists:reverse(Nodes))
6451           end,
6452    try_tc(rsmms1, Pre, Case, Post).
6453
6454do_recv_segmented_msg_missing_seg1([MgcNode, MgNode]) ->
6455
6456    d("[MGC] start the simulator "),
6457    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
6458
6459    d("[MGC] create the event sequence"),
6460    MgcEvSeq = rsmms1_mgc_event_sequence(text, tcp),
6461
6462    i("wait some time before starting the MGC simulation"),
6463    sleep(1000),
6464
6465    d("[MGC] start the simulation"),
6466    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
6467
6468    i("wait some time before starting the MG simulator"),
6469    sleep(1000),
6470
6471    d("[MG] start the simulator (generator)"),
6472    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
6473
6474    d("[MG] create the event sequence"),
6475    MgEvSeq = rsmms1_mg_event_sequence(text, tcp),
6476
6477    i("wait some time before starting the MG simulation"),
6478    sleep(1000),
6479
6480    d("[MG] start the simulation"),
6481    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
6482
6483    d("await the generator reply(s)"),
6484    await_completion([MgcId, MgId]),
6485
6486    %% Tell Mgc to stop
6487    i("[MGC] stop generator"),
6488    megaco_test_tcp_generator:stop(Mgc),
6489
6490    %% Tell Mg to stop
6491    i("[MG] stop generator"),
6492    megaco_test_megaco_generator:stop(Mg),
6493
6494    i("done", []),
6495    ok.
6496
6497
6498%%
6499%% MGC generator stuff
6500%%
6501
6502rsmms1_mgc_event_sequence(text, tcp) ->
6503    DecodeFun = rsmms1_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
6504    EncodeFun = rsmms1_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
6505    Mid       = {deviceName,"mgc"},
6506    ScrVerifyFun     = rsmms1_mgc_verify_service_change_req_msg_fun(),
6507    ServiceChangeRep = rsmms1_mgc_service_change_reply_msg(Mid, 1),
6508    TermId1   =
6509	#megaco_term_id{id = ["00000000","00000000","00000001"]},
6510    TermId2   =
6511	#megaco_term_id{id = ["00000000","00000000","00000002"]},
6512    TermId3   =
6513	#megaco_term_id{id = ["00000000","00000000","00000003"]},
6514    TermIds   = [TermId1, TermId2, TermId3],
6515    TransId   = 2,
6516    ReqId     = 1,
6517    CtxId     = 1,
6518    NrVerifyFun  =
6519	rsmms1_mgc_verify_notify_req_msg_fun(TermIds, TransId, ReqId, CtxId),
6520    NotifyRep1   =
6521	rsmms1_mgc_notify_reply_msg(1, Mid, TransId, CtxId, TermId1),
6522    NotifyRep3   =
6523	rsmms1_mgc_notify_reply_msg(3, Mid, TransId, CtxId, TermId3),
6524    SrVerifyFun1 = rsmms1_mgc_verify_segment_reply_msg_fun(1, TransId),
6525    SrVerifyFun3 = rsmms1_mgc_verify_segment_reply_msg_fun(3, TransId),
6526    MissingSegVerifyFun = rsmms1_mgc_verify_missing_segment_fun("2"),
6527    EvSeq = [{debug,  false},
6528             {decode, DecodeFun},
6529             {encode, EncodeFun},
6530             {listen, 2944},
6531	     {expect_accept, any},
6532             {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
6533             {send, "service-change-reply",             ServiceChangeRep},
6534             {expect_receive, "notify-request",         {NrVerifyFun,  4000}},
6535             {sleep, 1000},
6536             {send, "notify reply - segment 1",         NotifyRep1},
6537             {expect_receive, "segment reply 1",        {SrVerifyFun1, 2000}},
6538             {sleep, 1000},
6539             {send, "notify reply - segment 3",         NotifyRep3},
6540             {expect_receive, "segment reply 3",        {SrVerifyFun3, 2000}},
6541             {expect_receive, "missing segment error",  {MissingSegVerifyFun, 4000}},
6542	     {expect_nothing, 10000},
6543             disconnect
6544            ],
6545    EvSeq.
6546
6547rsmms1_mgc_encode_msg_fun(Mod, Conf) ->
6548    fun(M) ->
6549            Mod:encode_message(Conf, M)
6550    end.
6551
6552rsmms1_mgc_decode_msg_fun(Mod, Conf) ->
6553    fun(M) ->
6554            Mod:decode_message(Conf, M)
6555    end.
6556
6557rsmms1_mgc_verify_service_change_req_msg_fun() ->
6558    fun(Msg) ->
6559	    (catch rsmms1_mgc_verify_service_change_req(Msg))
6560    end.
6561
6562rsmms1_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
6563    io:format("rsmms1_mgc_verify_service_change_req -> entry with"
6564	      "~n   M: ~p"
6565	      "~n", [M]),
6566    Body =
6567	case Mess of
6568	    #'Message'{version     = 1,
6569                       mId         = _MgMid,
6570                       messageBody = MsgBody} ->
6571		MsgBody;
6572	    _ ->
6573		throw({error, {invalid_Message, Mess}})
6574	end,
6575    Trans =
6576	case Body of
6577            {transactions, [Transactions]} ->
6578		Transactions;
6579	    _ ->
6580		throw({error, {invalid_messageBody, Body}})
6581	end,
6582    TR =
6583	case Trans of
6584            {transactionRequest, TransRequest} ->
6585		TransRequest;
6586	    _ ->
6587		throw({error, {invalid_transactions, Trans}})
6588	end,
6589    AR =
6590	case TR of
6591            #'TransactionRequest'{transactionId = _TransId,
6592				  actions       = [ActionReq]} ->
6593		ActionReq;
6594	    _ ->
6595		throw({error, {invalid_transactionRequest, TR}})
6596	end,
6597    CR =
6598	case AR of
6599	    #'ActionRequest'{contextId       = _Cid,
6600			     commandRequests = [CmdReq]} ->
6601		CmdReq;
6602	    _ ->
6603		throw({error, {invalid_action, AR}})
6604	end,
6605    Cmd =
6606	case CR of
6607	    #'CommandRequest'{command = Command} ->
6608		Command;
6609	    _ ->
6610		throw({error, {invalid_commandRequest, CR}})
6611	end,
6612    {Tid, Parms} =
6613	case Cmd of
6614	    {serviceChangeReq,
6615	     #'ServiceChangeRequest'{terminationID      = [TermID],
6616				     serviceChangeParms = ServChParms}} ->
6617		{TermID, ServChParms};
6618	    _ ->
6619		throw({error, {invalid_command, Cmd}})
6620	end,
6621    case Tid of
6622	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
6623	    ok;
6624	_ ->
6625	    throw({error, {invalid_terminationID, Tid}})
6626    end,
6627    case Parms of
6628	%% Version 1 'ServiceChangeParm'
6629	{'ServiceChangeParm',
6630	 restart,                            % serviceChangeMethod
6631	 asn1_NOVALUE,                       % serviceChangeAddress
6632	 ?VERSION,                           % serviceChangeVersion,
6633	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
6634	 [[$9,$0,$1|_]],                     % serviceChangeReason
6635	 asn1_NOVALUE,                       % serviceChangeDelay
6636	 asn1_NOVALUE,                       % serviceChangeMgcId
6637	 asn1_NOVALUE,                       % timeStamp
6638	 asn1_NOVALUE                        % nonStandardData
6639	} ->
6640	    {ok, M};
6641	_ ->
6642	    {error, {invalid_serviceChangeParms, Parms}}
6643    end.
6644
6645rsmms1_mgc_verify_notify_req_msg_fun(TermIds, TransId, Rid, Cid) ->
6646    fun(Msg) ->
6647	    (catch rsmms1_mgc_verify_notify_req(Msg,
6648					      TermIds, TransId, Rid, Cid))
6649    end.
6650
6651rsmms1_mgc_verify_notify_req(#'MegacoMessage'{mess = Mess} = M,
6652			     TermIds, TransId, Rid, Cid) ->
6653    io:format("rsmms1_mgc_verify_notify_req -> entry with"
6654	      "~n   M:       ~p"
6655	      "~n   TermIds: ~p"
6656	      "~n   TransId: ~p"
6657	      "~n   Rid:     ~p"
6658	      "~n   Cid:     ~p"
6659	      "~n", [M, TermIds, TransId, Rid, Cid]),
6660    Body =
6661	case Mess of
6662	    #'Message'{version     = ?VERSION,
6663                       mId         = _Mid,
6664                       messageBody = MsgBody} ->
6665		MsgBody;
6666	    _ ->
6667		throw({error, {invalid_Message, Mess}})
6668	end,
6669    Trans =
6670	case Body of
6671            {transactions, [Transactions]} ->
6672		Transactions;
6673	    _ ->
6674		throw({error, {invalid_messageBody, Body}})
6675	end,
6676    TR =
6677	case Trans of
6678            {transactionRequest, TransRequest} ->
6679		TransRequest;
6680	    _ ->
6681		throw({error, {invalid_transactions, Trans}})
6682	end,
6683    AR =
6684	case TR of
6685            #'TransactionRequest'{transactionId = TransId,
6686				  actions       = [ActReq]} ->
6687		ActReq;
6688	    _ ->
6689		throw({error, {invalid_transactionRequest, TR}})
6690	end,
6691    Cmds =
6692	case AR of
6693	    #'ActionRequest'{contextId       = Cid,
6694			     commandRequests = Commands} ->
6695		Commands;
6696	    _ ->
6697		throw({error, {invalid_actions, AR}})
6698	end,
6699    ok = rsmms1_mgc_verify_notify_req_cmds(TermIds, Cmds),
6700    {ok, M};
6701rsmms1_mgc_verify_notify_req(Crap, _TermId, _TransId, _Rid, _Cid) ->
6702    {error, {invalid_MegacoMessage, Crap}}.
6703
6704rsmms1_mgc_verify_notify_req_cmds([], []) ->
6705    ok;
6706rsmms1_mgc_verify_notify_req_cmds([TermId|TermIds], [Cmd|Cmds]) ->
6707    rsmms1_mgc_verify_notify_req_cmd(TermId, Cmd),
6708    rsmms1_mgc_verify_notify_req_cmds(TermIds, Cmds);
6709rsmms1_mgc_verify_notify_req_cmds(TermIds, Cmds) ->
6710     throw({error, {invalid_commands, TermIds, Cmds}}).
6711
6712rsmms1_mgc_verify_notify_req_cmd(TermId, #'CommandRequest'{command = Cmd}) ->
6713    io:format("rsmms1_mgc_verify_notify_req_cmd -> entry with"
6714	      "~n   TermId: ~p"
6715	      "~n   Cmd:    ~p"
6716	      "~n", [TermId, Cmd]),
6717    NR =
6718	case Cmd of
6719	    {notifyReq, NotifReq} ->
6720		NotifReq;
6721	    _ ->
6722		throw({error, {invalid_command}})
6723	end,
6724    OED =
6725	case NR of
6726	    #'NotifyRequest'{terminationID            = [TermId],
6727			     observedEventsDescriptor = ObsEvsDesc,
6728			     errorDescriptor          = asn1_NOVALUE} ->
6729		ObsEvsDesc;
6730	    _ ->
6731		throw({error, {invalid_notifyReq, NR}})
6732	end,
6733    OE =
6734	case OED of
6735	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
6736		ObsEvLst;
6737	    _ ->
6738		throw({error, {invalid_observedEventsDescriptor, OED}})
6739	end,
6740    case OE of
6741	#'ObservedEvent'{eventName = "al/of"} ->
6742	    ok;
6743	_ ->
6744	    throw({error, {invalid_observedEventLst, OE}})
6745    end;
6746rsmms1_mgc_verify_notify_req_cmd(_, BadCmdReq) ->
6747    io:format("rsmms1_mgc_verify_notify_req_cmd -> invalid"
6748	      "~n   BadCmdReq: ~p"
6749	      "~n", [BadCmdReq]),
6750    throw({error, {invalid_CommandRequest, BadCmdReq}}).
6751
6752rsmms1_mgc_verify_segment_reply_msg_fun(SN, TransId) ->
6753    fun(Msg) ->
6754	    (catch rsmms1_mgc_verify_segment_reply(Msg, SN, TransId))
6755    end.
6756
6757rsmms1_mgc_verify_segment_reply(#'MegacoMessage'{mess = Mess} = M,
6758			      SN, TransId) ->
6759    io:format("rsmms1_mgc_verify_segment_reply -> entry with"
6760	      "~n   SN:      ~p"
6761	      "~n   TransId: ~p"
6762	      "~n   M:       ~p"
6763	      "~n", [SN, TransId, M]),
6764    Body =
6765	case Mess of
6766	    #'Message'{version     = ?VERSION,
6767                       mId         = _MgMid,
6768                       messageBody = MsgBody} ->
6769		MsgBody;
6770	    _ ->
6771		throw({error, {invalid_Message, Mess}})
6772	end,
6773    Trans =
6774	case Body of
6775            {transactions, [Transactions]} ->
6776		Transactions;
6777	    _ ->
6778		throw({error, {invalid_messageBody, Body}})
6779	end,
6780    SR =
6781	case Trans of
6782            {segmentReply, SegmentReply} ->
6783		SegmentReply;
6784	    _ ->
6785		throw({error, {invalid_transactions, Trans}})
6786	end,
6787    case SR of
6788	#'SegmentReply'{transactionId        = TransId,
6789			segmentNumber        = SN,
6790			segmentationComplete = 'NULL'} when SN == 3 ->
6791	    {ok, M};
6792	#'SegmentReply'{transactionId        = TransId,
6793			segmentNumber        = SN,
6794			segmentationComplete = asn1_NOVALUE} ->
6795	    {ok, M};
6796	_ ->
6797	    throw({error, {invalid_segmentReply, SR}})
6798    end;
6799rsmms1_mgc_verify_segment_reply(Crap, SN, TransId) ->
6800    io:format("rsmms1_mgc_verify_segment_reply -> invalid: "
6801	      "~n   SN:      ~p"
6802	      "~n   TransId: ~p"
6803	      "~n   Crap:    ~p"
6804	      "~n", [SN, TransId, Crap]),
6805    {error, {invalid_MegacoMessage, Crap, SN, TransId}}.
6806
6807
6808rsmms1_mgc_verify_missing_segment_fun(SN) ->
6809    fun(Msg) -> (catch rsmms1_mgc_verify_missing_segment(Msg, SN)) end.
6810
6811rsmms1_mgc_verify_missing_segment(#'MegacoMessage'{mess = Mess} = M, Text) ->
6812    io:format("rsmms1_mgc_verify_missing_segment -> entry with"
6813	      "~n   Text: ~p"
6814	      "~n   M:    ~p"
6815	      "~n", [Text, M]),
6816    Body =
6817	case Mess of
6818	    #'Message'{version     = ?VERSION,
6819                       mId         = _Mid,
6820                       messageBody = MsgBody} ->
6821		MsgBody;
6822	    _ ->
6823		throw({error, {invalid_Message, Mess}})
6824	end,
6825    case Body of
6826	{messageError,
6827	 #'ErrorDescriptor'{errorCode = ?megaco_segments_not_received,
6828			    errorText = Text}} ->
6829	    {ok, M};
6830	_ ->
6831	    throw({error, {invalid_messageError, Body}})
6832    end;
6833rsmms1_mgc_verify_missing_segment(Crap, _SN) ->
6834    {error, {invalid_MegacoMessage, Crap}}.
6835
6836rsmms1_mgc_service_change_reply_msg(Mid, Cid) ->
6837    SCRP  = cre_serviceChangeResParm(Mid),
6838    SCRes = cre_serviceChangeResult(SCRP),
6839    Root  = #megaco_term_id{id = ["root"]},
6840    SCR   = cre_serviceChangeReply([Root], SCRes),
6841    CR    = cre_cmdReply(SCR),
6842    AR    = cre_actionReply(Cid, [CR]),
6843    TRes  = cre_transResult([AR]),
6844    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
6845    Trans = cre_transaction(TR),
6846    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
6847    cre_megacoMessage(Mess).
6848
6849rsmms1_mgc_notify_reply_ar(Cid, TermId) ->
6850    NR    = cre_notifyReply([TermId]),
6851    CR    = cre_cmdReply(NR),
6852    cre_actionReply(Cid, [CR]).
6853
6854rsmms1_mgc_notify_reply_msg(SN, Mid, TransId, Cid, TermId) ->
6855    AR    = rsmms1_mgc_notify_reply_ar(Cid, TermId),
6856    TRes  = cre_transResult([AR]),
6857    TR =
6858	if
6859	    SN == 3 ->
6860		cre_transReply(TransId, TRes, SN, 'NULL');
6861	    true ->
6862		cre_transReply(TransId, TRes, SN)
6863	end,
6864    Trans = cre_transaction(TR),
6865    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
6866    cre_megacoMessage(Mess).
6867
6868
6869%%
6870%% MG generator stuff
6871%%
6872rsmms1_mg_event_sequence(text, tcp) ->
6873    Mid = {deviceName,"mg"},
6874    RI = [
6875          {port,             2944},
6876          {encoding_module,  megaco_pretty_text_encoder},
6877          {encoding_config,  []},
6878          {transport_module, megaco_tcp}
6879         ],
6880    ServiceChangeReq = rsmms1_mg_service_change_request_ar(Mid, 1),
6881    ConnectVerify = rsmms1_mg_verify_handle_connect_fun(),
6882    ServiceChangeReplyVerify = rsmms1_mg_verify_service_change_reply_fun(),
6883    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
6884    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
6885    Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
6886    Tids = [Tid1, Tid2, Tid3],
6887    NotifyReq = rsmms1_mg_notify_request_ar(1, Tids, 1),
6888    NotifyReplyVerify1 = rsmms1_mg_verify_notify_reply_fun(1, Tid1),
6889    NotifyReplyVerify3 = rsmms1_mg_verify_notify_reply_fun(3, Tid3),
6890    SegTimeoutVerify   = rsmms1_mg_verify_segment_timeout_fun(2),
6891    DiscoVerify        = rsmms1_mg_verify_handle_disco_fun(),
6892    EvSeq = [
6893             {debug, true},
6894	     {megaco_trace, disable},
6895             %% {megaco_trace, max},
6896             megaco_start,
6897             {megaco_start_user, Mid, RI, []},
6898             start_transport,
6899             {megaco_system_info, users},
6900             {megaco_system_info, connections},
6901	     {megaco_update_user_info, segment_recv_timer, 3000},
6902             connect,
6903             {megaco_callback, handle_connect, ConnectVerify},
6904             megaco_connect,
6905             {megaco_cast,     [ServiceChangeReq], []},
6906             {megaco_callback, handle_connect,     ConnectVerify},
6907             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
6908	     {megaco_update_conn_info, protocol_version, ?VERSION},
6909             {sleep, 1000},
6910             {megaco_cast,     [NotifyReq],        []},
6911             {megaco_callback, handle_trans_reply, NotifyReplyVerify1},
6912             {megaco_callback, handle_trans_reply, NotifyReplyVerify3},
6913             {megaco_callback, handle_trans_reply, SegTimeoutVerify},
6914             {megaco_callback, handle_disconnect,  DiscoVerify},
6915             megaco_stop_user,
6916             megaco_stop
6917            ],
6918    EvSeq.
6919
6920
6921rsmms1_mg_verify_handle_connect_fun() ->
6922    fun(Ev) -> rsmms1_mg_verify_handle_connect(Ev) end.
6923
6924rsmms1_mg_verify_handle_connect({handle_connect, CH, 1}) ->
6925    io:format("rsmms1_mg_verify_handle_connect -> ok"
6926	      "~n   CH: ~p~n", [CH]),
6927    {ok, CH, ok};
6928rsmms1_mg_verify_handle_connect(Else) ->
6929    io:format("rsmms1_mg_verify_handle_connect -> unknown"
6930	      "~n   Else: ~p~n", [Else]),
6931    {error, Else, ok}.
6932
6933
6934rsmms1_mg_verify_service_change_reply_fun() ->
6935    fun(Rep) -> rsmms1_mg_verify_scr(Rep) end.
6936
6937rsmms1_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
6938    (catch rsmms1_mg_do_verify_scr(AR));
6939rsmms1_mg_verify_scr(Crap) ->
6940    io:format("rsmms1_mg_verify_scr -> error: "
6941	      "~n   Crap: ~p"
6942	      "~n", [Crap]),
6943    {error, Crap, ok}.
6944
6945rsmms1_mg_do_verify_scr(AR) ->
6946    io:format("rsmms1_mg_do_verify_scr -> ok: "
6947	      "~n   AR: ~p~n", [AR]),
6948    CR =
6949	case AR of
6950	    #'ActionReply'{commandReply = [CmdRep]} ->
6951		CmdRep;
6952	    _ ->
6953		Reason1 = {invalid_action_reply, AR},
6954		throw({error, Reason1, ok})
6955	end,
6956    SCR =
6957	case CR of
6958	    {serviceChangeReply, ServChRep} ->
6959		ServChRep;
6960	    _ ->
6961		Reason2 = {invalid_command_reply, CR},
6962		throw({error, Reason2, ok})
6963	end,
6964    {Tid, SCRes} =
6965	case SCR of
6966	    #'ServiceChangeReply'{terminationID       = [TermID],
6967				  serviceChangeResult = Res} ->
6968		{TermID, Res};
6969	    _ ->
6970		Reason3 = {invalid_service_change_reply, SCR},
6971		throw({error, Reason3, ok})
6972	end,
6973    case Tid of
6974	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
6975	    ok;
6976	_ ->
6977	    Reason4 = {invalid_termination_id, Tid},
6978	    throw({error, Reason4, ok})
6979    end,
6980    SCRParm =
6981	case SCRes of
6982	    {serviceChangeResParms, ServChResParms} ->
6983		ServChResParms;
6984	    _ ->
6985		Reason5 = {invalid_serviceChangeResult, SCRes},
6986		throw({error, Reason5, ok})
6987	end,
6988    case SCRParm of
6989	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
6990	    {ok, AR, ok};
6991	_ ->
6992	    Reason6 = {invalid_service_change_result, SCRParm},
6993	    {error, Reason6, ok}
6994    end.
6995
6996rsmms1_mg_verify_notify_reply_fun(SN, Tid) ->
6997    fun(Rep) -> rsmms1_mg_verify_notify_reply(Rep, SN, Tid) end.
6998
6999rsmms1_mg_verify_notify_reply(
7000  {handle_trans_reply, _CH, ?VERSION, {ok, {SN, Last, [AR]}}, _}, SN, Tid)
7001  when (Last == false) ->
7002    (catch rsmms1_mg_do_verify_notify_reply(Tid, AR));
7003rsmms1_mg_verify_notify_reply(Crap, SN, Tid) ->
7004    io:format("rsmms1_mg_verify_notify_reply -> unknown reply"
7005	      "~n   SN:   ~p"
7006	      "~n   Tid:  ~p"
7007	      "~n   Crap: ~p"
7008	      "~n", [SN, Tid, Crap]),
7009    {error, Crap, ok}.
7010
7011rsmms1_mg_do_verify_notify_reply(Tid, AR) ->
7012    io:format("rsmms1_mg_do_verify_notify_reply -> ok"
7013	      "~n   Tid:  ~p"
7014	      "~n   AR:   ~p"
7015	      "~n", [Tid, AR]),
7016    CR =
7017	case AR of
7018	    #'ActionReply'{commandReply = [CmdRep]} ->
7019		CmdRep;
7020	    _ ->
7021		Reason1 = {invalid_action_reply, AR},
7022		throw({error, Reason1, ok})
7023	end,
7024    NR =
7025	case CR of
7026	    {notifyReply, NotifyReply} ->
7027		NotifyReply;
7028	    _ ->
7029		Reason2 = {invalid_command_reply, CR},
7030		throw({error, Reason2, ok})
7031	end,
7032    case NR of
7033	#'NotifyReply'{terminationID   = [Tid],
7034		       errorDescriptor = asn1_NOVALUE} ->
7035	    {ok, AR, ok};
7036	_ ->
7037	    Reason3 = {invalid_NotifyReply, NR},
7038	    {error, Reason3, ok}
7039    end.
7040
7041rsmms1_mg_verify_segment_timeout_fun(SN) ->
7042    fun(Rep) -> rsmms1_mg_verify_segment_timeout(Rep, SN) end.
7043
7044rsmms1_mg_verify_segment_timeout(
7045  {handle_trans_reply, _CH, ?VERSION, {error, Reason}, _}, SN) ->
7046    case Reason of
7047	{segment_timeout, [SN]} ->
7048	    {ok, Reason, ok};
7049	_ ->
7050	    {error, {invalid_reason, Reason}, ok}
7051    end;
7052rsmms1_mg_verify_segment_timeout(Crap, SN) ->
7053    io:format("rsmms1_mg_verify_segment_timeout -> unknown reply"
7054	      "~n   SN:   ~p"
7055	      "~n   Crap: ~p"
7056	      "~n", [SN, Crap]),
7057    {error, Crap, ok}.
7058
7059rsmms1_mg_verify_handle_disco_fun() ->
7060    fun(Ev) -> rsmms1_mg_verify_handle_disconnect(Ev) end.
7061
7062rsmms1_mg_verify_handle_disconnect({handle_disconnect, _CH, ?VERSION, R}) ->
7063    io:format("rsmms1_mg_verify_handle_disconnect -> ok"
7064	      "~n   R: ~p"
7065	      "~n", [R]),
7066    case R of
7067	{no_controlling_process,shutdown} ->
7068	    {ok, R, ok};
7069	_ ->
7070	    {error, {unexpected_reason, R}, ok}
7071    end;
7072rsmms1_mg_verify_handle_disconnect(Crap) ->
7073    io:format("rsmms1_mg_verify_handle_disconnect -> invalid: "
7074	      "~n   Crap: ~p"
7075	      "~n", [Crap]),
7076    {error, Crap, ok}.
7077
7078
7079rsmms1_mg_service_change_request_ar(_Mid, Cid) ->
7080    Prof  = cre_serviceChangeProf("resgw", 1),
7081    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
7082    Root  = #megaco_term_id{id = ["root"]},
7083    SCR   = cre_serviceChangeReq([Root], SCP),
7084    CMD   = cre_command(SCR),
7085    CR    = cre_cmdReq(CMD),
7086    cre_actionReq(Cid, [CR]).
7087
7088rsmms1_mg_notify_request_ar(Rid, Tids, Cid) ->
7089    rsmms1_mg_notify_request_ar(Rid, Tids, Cid, []).
7090
7091rsmms1_mg_notify_request_ar(_Rid, [], Cid, Cmds) ->
7092    cre_actionReq(Cid, lists:reverse(Cmds));
7093rsmms1_mg_notify_request_ar(Rid, [Tid|Tids], Cid, Cmds) ->
7094    TT      = cre_timeNotation("19990729", "22000000"),
7095    Ev      = cre_obsEvent("al/of", TT),
7096    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
7097    NR      = cre_notifyReq([Tid], EvsDesc),
7098    CMD     = cre_command(NR),
7099    CR      = cre_cmdReq(CMD),
7100    rsmms1_mg_notify_request_ar(Rid, Tids, Cid, [CR|Cmds]).
7101
7102
7103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7104
7105recv_segmented_msg_missing_seg2(suite) ->
7106    [];
7107recv_segmented_msg_missing_seg2(doc) ->
7108    "Received segmented megaco message with one segment missing "
7109	"using incremental recv segment timer";
7110recv_segmented_msg_missing_seg2(Config) when is_list(Config) ->
7111    Pre = fun() ->
7112                  MgcNode = make_node_name(mgc),
7113                  MgNode  = make_node_name(mg),
7114                  d("start nodes: "
7115                    "~n   MgcNode: ~p"
7116                    "~n   MgNode:  ~p",
7117                    [MgcNode, MgNode]),
7118                  Nodes = [MgcNode, MgNode],
7119                  ok = ?START_NODES(Nodes),
7120                  Nodes
7121          end,
7122    Case = fun do_recv_segmented_msg_missing_seg2/1,
7123    Post = fun(Nodes) ->
7124                   d("stop nodes"),
7125                   ?STOP_NODES(lists:reverse(Nodes))
7126           end,
7127    try_tc(rsmms2, Pre, Case, Post).
7128
7129do_recv_segmented_msg_missing_seg2([MgcNode, MgNode]) ->
7130
7131    d("[MGC] start the simulator "),
7132    {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
7133
7134    d("[MGC] create the event sequence"),
7135    MgcEvSeq = rsmms2_mgc_event_sequence(text, tcp),
7136
7137    i("wait some time before starting the MGC simulation"),
7138    sleep(1000),
7139
7140    d("[MGC] start the simulation"),
7141    {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
7142
7143    i("wait some time before starting the MG simulator"),
7144    sleep(1000),
7145
7146    d("[MG] start the simulator (generator)"),
7147    {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
7148
7149    d("[MG] create the event sequence"),
7150    MgEvSeq = rsmms2_mg_event_sequence(text, tcp),
7151
7152    i("wait some time before starting the MG simulation"),
7153    sleep(1000),
7154
7155    d("[MG] start the simulation"),
7156    {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
7157
7158    d("await the generator reply(s)"),
7159    await_completion([MgcId, MgId]),
7160
7161    %% Tell Mgc to stop
7162    i("[MGC] stop generator"),
7163    megaco_test_tcp_generator:stop(Mgc),
7164
7165    %% Tell Mg to stop
7166    i("[MG] stop generator"),
7167    megaco_test_megaco_generator:stop(Mg),
7168
7169    i("done", []),
7170    ok.
7171
7172
7173%%
7174%% MGC generator stuff
7175%%
7176
7177rsmms2_mgc_event_sequence(text, tcp) ->
7178    DecodeFun = rsmms2_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
7179    EncodeFun = rsmms2_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
7180    Mid       = {deviceName,"mgc"},
7181    ScrVerifyFun     = rsmms2_mgc_verify_service_change_req_msg_fun(),
7182    ServiceChangeRep = rsmms2_mgc_service_change_reply_msg(Mid, 1),
7183    TermId1   =
7184	#megaco_term_id{id = ["00000000","00000000","00000001"]},
7185    TermId2   =
7186	#megaco_term_id{id = ["00000000","00000000","00000002"]},
7187    TermId3   =
7188	#megaco_term_id{id = ["00000000","00000000","00000003"]},
7189    TermIds   = [TermId1, TermId2, TermId3],
7190    TransId   = 2,
7191    ReqId     = 1,
7192    CtxId     = 1,
7193    NrVerifyFun  =
7194	rsmms2_mgc_verify_notify_req_msg_fun(TermIds, TransId, ReqId, CtxId),
7195    NotifyRep1   =
7196	rsmms2_mgc_notify_reply_msg(1, Mid, TransId, CtxId, TermId1),
7197    NotifyRep3   =
7198	rsmms2_mgc_notify_reply_msg(3, Mid, TransId, CtxId, TermId3),
7199    SrVerifyFun1 = rsmms2_mgc_verify_segment_reply_msg_fun(1, TransId),
7200    SrVerifyFun3 = rsmms2_mgc_verify_segment_reply_msg_fun(3, TransId),
7201    MissingSegVerifyFun = rsmms2_mgc_verify_missing_segment_fun("2"),
7202    EvSeq = [{debug,  false},
7203             {decode, DecodeFun},
7204             {encode, EncodeFun},
7205             {listen, 2944},
7206	     {expect_accept, any},
7207             {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
7208             {send, "service-change-reply",             ServiceChangeRep},
7209             {expect_receive, "notify-request",         {NrVerifyFun,  4000}},
7210             {sleep, 1000},
7211             {send, "notify reply - segment 1",         NotifyRep1},
7212             {expect_receive, "segment reply 1",        {SrVerifyFun1, 2000}},
7213             {sleep, 1000},
7214             {send, "notify reply - segment 3",         NotifyRep3},
7215             {expect_receive, "segment reply 3",        {SrVerifyFun3, 2000}},
7216             {expect_receive, "missing segment error",  {MissingSegVerifyFun, 4000}},
7217	     {expect_nothing, 10000},
7218             disconnect
7219            ],
7220    EvSeq.
7221
7222rsmms2_mgc_encode_msg_fun(Mod, Conf) ->
7223    fun(M) ->
7224            Mod:encode_message(Conf, M)
7225    end.
7226
7227rsmms2_mgc_decode_msg_fun(Mod, Conf) ->
7228    fun(M) ->
7229            Mod:decode_message(Conf, M)
7230    end.
7231
7232rsmms2_mgc_verify_service_change_req_msg_fun() ->
7233    fun(Msg) ->
7234	    (catch rsmms2_mgc_verify_service_change_req(Msg))
7235    end.
7236
7237rsmms2_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
7238    io:format("rsmms2_mgc_verify_service_change_req -> entry with"
7239	      "~n   M: ~p"
7240	      "~n", [M]),
7241    Body =
7242	case Mess of
7243	    #'Message'{version     = 1,
7244                       mId         = _MgMid,
7245                       messageBody = MsgBody} ->
7246		MsgBody;
7247	    _ ->
7248		throw({error, {invalid_Message, Mess}})
7249	end,
7250    Trans =
7251	case Body of
7252            {transactions, [Transactions]} ->
7253		Transactions;
7254	    _ ->
7255		throw({error, {invalid_messageBody, Body}})
7256	end,
7257    TR =
7258	case Trans of
7259            {transactionRequest, TransRequest} ->
7260		TransRequest;
7261	    _ ->
7262		throw({error, {invalid_transactions, Trans}})
7263	end,
7264    AR =
7265	case TR of
7266            #'TransactionRequest'{transactionId = _TransId,
7267				  actions       = [ActionReq]} ->
7268		ActionReq;
7269	    _ ->
7270		throw({error, {invalid_transactionRequest, TR}})
7271	end,
7272    CR =
7273	case AR of
7274	    #'ActionRequest'{contextId       = _Cid,
7275			     commandRequests = [CmdReq]} ->
7276		CmdReq;
7277	    _ ->
7278		throw({error, {invalid_action, AR}})
7279	end,
7280    Cmd =
7281	case CR of
7282	    #'CommandRequest'{command = Command} ->
7283		Command;
7284	    _ ->
7285		throw({error, {invalid_commandRequest, CR}})
7286	end,
7287    {Tid, Parms} =
7288	case Cmd of
7289	    {serviceChangeReq,
7290	     #'ServiceChangeRequest'{terminationID      = [TermID],
7291				     serviceChangeParms = ServChParms}} ->
7292		{TermID, ServChParms};
7293	    _ ->
7294		throw({error, {invalid_command, Cmd}})
7295	end,
7296    case Tid of
7297	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
7298	    ok;
7299	_ ->
7300	    throw({error, {invalid_terminationID, Tid}})
7301    end,
7302    case Parms of
7303	%% Version 1 'ServiceChangeParm'
7304	{'ServiceChangeParm',
7305	 restart,                            % serviceChangeMethod
7306	 asn1_NOVALUE,                       % serviceChangeAddress
7307	 ?VERSION,                           % serviceChangeVersion,
7308	 {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
7309	 [[$9,$0,$1|_]],                     % serviceChangeReason
7310	 asn1_NOVALUE,                       % serviceChangeDelay
7311	 asn1_NOVALUE,                       % serviceChangeMgcId
7312	 asn1_NOVALUE,                       % timeStamp
7313	 asn1_NOVALUE                        % nonStandardData
7314	} ->
7315	    {ok, M};
7316	_ ->
7317	    {error, {invalid_serviceChangeParms, Parms}}
7318    end.
7319
7320rsmms2_mgc_verify_notify_req_msg_fun(TermIds, TransId, Rid, Cid) ->
7321    fun(Msg) ->
7322	    (catch rsmms2_mgc_verify_notify_req(Msg,
7323					      TermIds, TransId, Rid, Cid))
7324    end.
7325
7326rsmms2_mgc_verify_notify_req(#'MegacoMessage'{mess = Mess} = M,
7327			     TermIds, TransId, Rid, Cid) ->
7328    io:format("rsmms2_mgc_verify_notify_req -> entry with"
7329	      "~n   M:       ~p"
7330	      "~n   TermIds: ~p"
7331	      "~n   TransId: ~p"
7332	      "~n   Rid:     ~p"
7333	      "~n   Cid:     ~p"
7334	      "~n", [M, TermIds, TransId, Rid, Cid]),
7335    Body =
7336	case Mess of
7337	    #'Message'{version     = ?VERSION,
7338                       mId         = _Mid,
7339                       messageBody = MsgBody} ->
7340		MsgBody;
7341	    _ ->
7342		throw({error, {invalid_Message, Mess}})
7343	end,
7344    Trans =
7345	case Body of
7346            {transactions, [Transactions]} ->
7347		Transactions;
7348	    _ ->
7349		throw({error, {invalid_messageBody, Body}})
7350	end,
7351    TR =
7352	case Trans of
7353            {transactionRequest, TransRequest} ->
7354		TransRequest;
7355	    _ ->
7356		throw({error, {invalid_transactions, Trans}})
7357	end,
7358    AR =
7359	case TR of
7360            #'TransactionRequest'{transactionId = TransId,
7361				  actions       = [ActReq]} ->
7362		ActReq;
7363	    _ ->
7364		throw({error, {invalid_transactionRequest, TR}})
7365	end,
7366    Cmds =
7367	case AR of
7368	    #'ActionRequest'{contextId       = Cid,
7369			     commandRequests = Commands} ->
7370		Commands;
7371	    _ ->
7372		throw({error, {invalid_actions, AR}})
7373	end,
7374    ok = rsmms2_mgc_verify_notify_req_cmds(TermIds, Cmds),
7375    {ok, M};
7376rsmms2_mgc_verify_notify_req(Crap, _TermId, _TransId, _Rid, _Cid) ->
7377    {error, {invalid_MegacoMessage, Crap}}.
7378
7379rsmms2_mgc_verify_notify_req_cmds([], []) ->
7380    ok;
7381rsmms2_mgc_verify_notify_req_cmds([TermId|TermIds], [Cmd|Cmds]) ->
7382    rsmms2_mgc_verify_notify_req_cmd(TermId, Cmd),
7383    rsmms2_mgc_verify_notify_req_cmds(TermIds, Cmds);
7384rsmms2_mgc_verify_notify_req_cmds(TermIds, Cmds) ->
7385     throw({error, {invalid_commands, TermIds, Cmds}}).
7386
7387rsmms2_mgc_verify_notify_req_cmd(TermId, #'CommandRequest'{command = Cmd}) ->
7388    io:format("rsmms2_mgc_verify_notify_req_cmd -> entry with"
7389	      "~n   TermId: ~p"
7390	      "~n   Cmd:    ~p"
7391	      "~n", [TermId, Cmd]),
7392    NR =
7393	case Cmd of
7394	    {notifyReq, NotifReq} ->
7395		NotifReq;
7396	    _ ->
7397		throw({error, {invalid_command}})
7398	end,
7399    OED =
7400	case NR of
7401	    #'NotifyRequest'{terminationID            = [TermId],
7402			     observedEventsDescriptor = ObsEvsDesc,
7403			     errorDescriptor          = asn1_NOVALUE} ->
7404		ObsEvsDesc;
7405	    _ ->
7406		throw({error, {invalid_notifyReq, NR}})
7407	end,
7408    OE =
7409	case OED of
7410	    #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
7411		ObsEvLst;
7412	    _ ->
7413		throw({error, {invalid_observedEventsDescriptor, OED}})
7414	end,
7415    case OE of
7416	#'ObservedEvent'{eventName = "al/of"} ->
7417	    ok;
7418	_ ->
7419	    throw({error, {invalid_observedEventLst, OE}})
7420    end;
7421rsmms2_mgc_verify_notify_req_cmd(_, BadCmdReq) ->
7422    io:format("rsmms2_mgc_verify_notify_req_cmd -> invalid"
7423	      "~n   BadCmdReq: ~p"
7424	      "~n", [BadCmdReq]),
7425    throw({error, {invalid_CommandRequest, BadCmdReq}}).
7426
7427rsmms2_mgc_verify_segment_reply_msg_fun(SN, TransId) ->
7428    fun(Msg) ->
7429	    (catch rsmms2_mgc_verify_segment_reply(Msg, SN, TransId))
7430    end.
7431
7432rsmms2_mgc_verify_segment_reply(#'MegacoMessage'{mess = Mess} = M,
7433			      SN, TransId) ->
7434    io:format("rsmms2_mgc_verify_segment_reply -> entry with"
7435	      "~n   SN:      ~p"
7436	      "~n   TransId: ~p"
7437	      "~n   M:       ~p"
7438	      "~n", [SN, TransId, M]),
7439    Body =
7440	case Mess of
7441	    #'Message'{version     = ?VERSION,
7442                       mId         = _MgMid,
7443                       messageBody = MsgBody} ->
7444		MsgBody;
7445	    _ ->
7446		throw({error, {invalid_Message, Mess}})
7447	end,
7448    Trans =
7449	case Body of
7450            {transactions, [Transactions]} ->
7451		Transactions;
7452	    _ ->
7453		throw({error, {invalid_messageBody, Body}})
7454	end,
7455    SR =
7456	case Trans of
7457            {segmentReply, SegmentReply} ->
7458		SegmentReply;
7459	    _ ->
7460		throw({error, {invalid_transactions, Trans}})
7461	end,
7462    case SR of
7463	#'SegmentReply'{transactionId        = TransId,
7464			segmentNumber        = SN,
7465			segmentationComplete = 'NULL'} when SN == 3 ->
7466	    {ok, M};
7467	#'SegmentReply'{transactionId        = TransId,
7468			segmentNumber        = SN,
7469			segmentationComplete = asn1_NOVALUE} ->
7470	    {ok, M};
7471	_ ->
7472	    throw({error, {invalid_segmentReply, SR}})
7473    end;
7474rsmms2_mgc_verify_segment_reply(Crap, SN, TransId) ->
7475    io:format("rsmms2_mgc_verify_segment_reply -> invalid: "
7476	      "~n   SN:      ~p"
7477	      "~n   TransId: ~p"
7478	      "~n   Crap:    ~p"
7479	      "~n", [SN, TransId, Crap]),
7480    {error, {invalid_MegacoMessage, Crap, SN, TransId}}.
7481
7482
7483rsmms2_mgc_verify_missing_segment_fun(SN) ->
7484    fun(Msg) -> (catch rsmms2_mgc_verify_missing_segment(Msg, SN)) end.
7485
7486rsmms2_mgc_verify_missing_segment(#'MegacoMessage'{mess = Mess} = M, Text) ->
7487    io:format("rsmms2_mgc_verify_missing_segment -> entry with"
7488	      "~n   Text: ~p"
7489	      "~n   M:    ~p"
7490	      "~n", [Text, M]),
7491    Body =
7492	case Mess of
7493	    #'Message'{version     = ?VERSION,
7494                       mId         = _Mid,
7495                       messageBody = MsgBody} ->
7496		MsgBody;
7497	    _ ->
7498		throw({error, {invalid_Message, Mess}})
7499	end,
7500    case Body of
7501	{messageError,
7502	 #'ErrorDescriptor'{errorCode = ?megaco_segments_not_received,
7503			    errorText = Text}} ->
7504	    {ok, M};
7505	_ ->
7506	    throw({error, {invalid_messageError, Body}})
7507    end;
7508rsmms2_mgc_verify_missing_segment(Crap, _SN) ->
7509    {error, {invalid_MegacoMessage, Crap}}.
7510
7511rsmms2_mgc_service_change_reply_msg(Mid, Cid) ->
7512    SCRP  = cre_serviceChangeResParm(Mid),
7513    SCRes = cre_serviceChangeResult(SCRP),
7514    Root  = #megaco_term_id{id = ["root"]},
7515    SCR   = cre_serviceChangeReply([Root], SCRes),
7516    CR    = cre_cmdReply(SCR),
7517    AR    = cre_actionReply(Cid, [CR]),
7518    TRes  = cre_transResult([AR]),
7519    TR    = {'TransactionReply', 1, asn1_NOVALUE, TRes},
7520    Trans = cre_transaction(TR),
7521    Mess  = cre_message(1, Mid, cre_transactions([Trans])),
7522    cre_megacoMessage(Mess).
7523
7524rsmms2_mgc_notify_reply_ar(Cid, TermId) ->
7525    NR    = cre_notifyReply([TermId]),
7526    CR    = cre_cmdReply(NR),
7527    cre_actionReply(Cid, [CR]).
7528
7529rsmms2_mgc_notify_reply_msg(SN, Mid, TransId, Cid, TermId) ->
7530    AR    = rsmms2_mgc_notify_reply_ar(Cid, TermId),
7531    TRes  = cre_transResult([AR]),
7532    TR =
7533	if
7534	    SN == 3 ->
7535		cre_transReply(TransId, TRes, SN, 'NULL');
7536	    true ->
7537		cre_transReply(TransId, TRes, SN)
7538	end,
7539    Trans = cre_transaction(TR),
7540    Mess  = cre_message(?VERSION, Mid, cre_transactions([Trans])),
7541    cre_megacoMessage(Mess).
7542
7543
7544%%
7545%% MG generator stuff
7546%%
7547rsmms2_mg_event_sequence(text, tcp) ->
7548    Mid = {deviceName,"mg"},
7549    RI = [
7550          {port,             2944},
7551          {encoding_module,  megaco_pretty_text_encoder},
7552          {encoding_config,  []},
7553          {transport_module, megaco_tcp}
7554         ],
7555    SegRecvTmr = #megaco_incr_timer{wait_for    = 1000,
7556				    factor      = 1,
7557				    incr        = 0,
7558				    max_retries = 2
7559				   },
7560    ServiceChangeReq = rsmms2_mg_service_change_request_ar(Mid, 1),
7561    ConnectVerify = rsmms2_mg_verify_handle_connect_fun(),
7562    ServiceChangeReplyVerify = rsmms2_mg_verify_service_change_reply_fun(),
7563    Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
7564    Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
7565    Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
7566    Tids = [Tid1, Tid2, Tid3],
7567    NotifyReq = rsmms2_mg_notify_request_ar(1, Tids, 1),
7568    NotifyReplyVerify1 = rsmms2_mg_verify_notify_reply_fun(1, Tid1),
7569    NotifyReplyVerify3 = rsmms2_mg_verify_notify_reply_fun(3, Tid3),
7570    SegTimeoutVerify   = rsmms2_mg_verify_segment_timeout_fun(2),
7571    DiscoVerify        = rsmms2_mg_verify_handle_disco_fun(),
7572    EvSeq = [
7573             {debug, true},
7574             {megaco_trace, disable},
7575             %% {megaco_trace, max},
7576             megaco_start,
7577             {megaco_start_user, Mid, RI, []},
7578             start_transport,
7579             {megaco_system_info, users},
7580             {megaco_system_info, connections},
7581	     {megaco_update_user_info, segment_recv_timer,  SegRecvTmr},
7582             connect,
7583             {megaco_callback, handle_connect, ConnectVerify},
7584             megaco_connect,
7585             {megaco_cast,     [ServiceChangeReq], []},
7586             {megaco_callback, handle_connect,     ConnectVerify},
7587             {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
7588	     {megaco_update_conn_info, protocol_version, ?VERSION},
7589             {sleep, 1000},
7590             {megaco_cast,     [NotifyReq],        []},
7591             {megaco_callback, handle_trans_reply, NotifyReplyVerify1},
7592             {megaco_callback, handle_trans_reply, NotifyReplyVerify3},
7593             {megaco_callback, handle_trans_reply, SegTimeoutVerify},
7594             {megaco_callback, handle_disconnect,  DiscoVerify},
7595             megaco_stop_user,
7596             megaco_stop
7597            ],
7598    EvSeq.
7599
7600
7601rsmms2_mg_verify_handle_connect_fun() ->
7602    fun(Ev) -> rsmms2_mg_verify_handle_connect(Ev) end.
7603
7604rsmms2_mg_verify_handle_connect({handle_connect, CH, 1}) ->
7605    io:format("rsmms2_mg_verify_handle_connect -> ok"
7606	      "~n   CH: ~p~n", [CH]),
7607    {ok, CH, ok};
7608rsmms2_mg_verify_handle_connect(Else) ->
7609    io:format("rsmms2_mg_verify_handle_connect -> unknown"
7610	      "~n   Else: ~p~n", [Else]),
7611    {error, Else, ok}.
7612
7613
7614rsmms2_mg_verify_service_change_reply_fun() ->
7615    fun(Rep) -> rsmms2_mg_verify_scr(Rep) end.
7616
7617rsmms2_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
7618    (catch rsmms2_mg_do_verify_scr(AR));
7619rsmms2_mg_verify_scr(Crap) ->
7620    io:format("rsmms2_mg_verify_scr -> error: "
7621	      "~n   Crap: ~p"
7622	      "~n", [Crap]),
7623    {error, Crap, ok}.
7624
7625rsmms2_mg_do_verify_scr(AR) ->
7626    io:format("rsmms2_mg_do_verify_scr -> ok: "
7627	      "~n   AR: ~p~n", [AR]),
7628    CR =
7629	case AR of
7630	    #'ActionReply'{commandReply = [CmdRep]} ->
7631		CmdRep;
7632	    _ ->
7633		Reason1 = {invalid_action_reply, AR},
7634		throw({error, Reason1, ok})
7635	end,
7636    SCR =
7637	case CR of
7638	    {serviceChangeReply, ServChRep} ->
7639		ServChRep;
7640	    _ ->
7641		Reason2 = {invalid_command_reply, CR},
7642		throw({error, Reason2, ok})
7643	end,
7644    {Tid, SCRes} =
7645	case SCR of
7646	    #'ServiceChangeReply'{terminationID       = [TermID],
7647				  serviceChangeResult = Res} ->
7648		{TermID, Res};
7649	    _ ->
7650		Reason3 = {invalid_service_change_reply, SCR},
7651		throw({error, Reason3, ok})
7652	end,
7653    case Tid of
7654	#megaco_term_id{contains_wildcards = false, id = ["root"]} ->
7655	    ok;
7656	_ ->
7657	    Reason4 = {invalid_termination_id, Tid},
7658	    throw({error, Reason4, ok})
7659    end,
7660    SCRParm =
7661	case SCRes of
7662	    {serviceChangeResParms, ServChResParms} ->
7663		ServChResParms;
7664	    _ ->
7665		Reason5 = {invalid_serviceChangeResult, SCRes},
7666		throw({error, Reason5, ok})
7667	end,
7668    case SCRParm of
7669	#'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
7670	    {ok, AR, ok};
7671	_ ->
7672	    Reason6 = {invalid_service_change_result, SCRParm},
7673	    {error, Reason6, ok}
7674    end.
7675
7676rsmms2_mg_verify_notify_reply_fun(SN, Tid) ->
7677    fun(Rep) -> rsmms2_mg_verify_notify_reply(Rep, SN, Tid) end.
7678
7679rsmms2_mg_verify_notify_reply(
7680  {handle_trans_reply, _CH, ?VERSION, {ok, {SN, Last, [AR]}}, _}, SN, Tid)
7681  when (Last == false) ->
7682    (catch rsmms2_mg_do_verify_notify_reply(Tid, AR));
7683rsmms2_mg_verify_notify_reply(Crap, SN, Tid) ->
7684    io:format("rsmms2_mg_verify_notify_reply -> unknown reply"
7685	      "~n   SN:   ~p"
7686	      "~n   Tid:  ~p"
7687	      "~n   Crap: ~p"
7688	      "~n", [SN, Tid, Crap]),
7689    {error, Crap, ok}.
7690
7691rsmms2_mg_do_verify_notify_reply(Tid, AR) ->
7692    io:format("rsmms2_mg_do_verify_notify_reply -> ok"
7693	      "~n   Tid:  ~p"
7694	      "~n   AR:   ~p"
7695	      "~n", [Tid, AR]),
7696    CR =
7697	case AR of
7698	    #'ActionReply'{commandReply = [CmdRep]} ->
7699		CmdRep;
7700	    _ ->
7701		Reason1 = {invalid_action_reply, AR},
7702		throw({error, Reason1, ok})
7703	end,
7704    NR =
7705	case CR of
7706	    {notifyReply, NotifyReply} ->
7707		NotifyReply;
7708	    _ ->
7709		Reason2 = {invalid_command_reply, CR},
7710		throw({error, Reason2, ok})
7711	end,
7712    case NR of
7713	#'NotifyReply'{terminationID   = [Tid],
7714		       errorDescriptor = asn1_NOVALUE} ->
7715	    {ok, AR, ok};
7716	_ ->
7717	    Reason3 = {invalid_NotifyReply, NR},
7718	    {error, Reason3, ok}
7719    end.
7720
7721rsmms2_mg_verify_segment_timeout_fun(SN) ->
7722    fun(Rep) -> rsmms2_mg_verify_segment_timeout(Rep, SN) end.
7723
7724rsmms2_mg_verify_segment_timeout(
7725  {handle_trans_reply, _CH, ?VERSION, {error, Reason}, _}, SN) ->
7726    case Reason of
7727	{segment_timeout, [SN]} ->
7728	    {ok, Reason, ok};
7729	_ ->
7730	    {error, {invalid_reason, Reason}, ok}
7731    end;
7732rsmms2_mg_verify_segment_timeout(Crap, SN) ->
7733    io:format("rsmms2_mg_verify_segment_timeout -> unknown reply"
7734	      "~n   SN:   ~p"
7735	      "~n   Crap: ~p"
7736	      "~n", [SN, Crap]),
7737    {error, Crap, ok}.
7738
7739rsmms2_mg_verify_handle_disco_fun() ->
7740    fun(Ev) -> rsmms2_mg_verify_handle_disconnect(Ev) end.
7741
7742rsmms2_mg_verify_handle_disconnect({handle_disconnect, _CH, ?VERSION, R}) ->
7743    io:format("rsmms2_mg_verify_handle_disconnect -> ok"
7744	      "~n   R: ~p"
7745	      "~n", [R]),
7746    case R of
7747	{no_controlling_process,shutdown} ->
7748	    {ok, R, ok};
7749	_ ->
7750	    {error, {unexpected_reason, R}, ok}
7751    end;
7752rsmms2_mg_verify_handle_disconnect(Crap) ->
7753    io:format("rsmms2_mg_verify_handle_disconnect -> invalid: "
7754	      "~n   Crap: ~p"
7755	      "~n", [Crap]),
7756    {error, Crap, ok}.
7757
7758
7759rsmms2_mg_service_change_request_ar(_Mid, Cid) ->
7760    Prof  = cre_serviceChangeProf("resgw", 1),
7761    SCP   = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
7762    Root  = #megaco_term_id{id = ["root"]},
7763    SCR   = cre_serviceChangeReq([Root], SCP),
7764    CMD   = cre_command(SCR),
7765    CR    = cre_cmdReq(CMD),
7766    cre_actionReq(Cid, [CR]).
7767
7768rsmms2_mg_notify_request_ar(Rid, Tids, Cid) ->
7769    rsmms2_mg_notify_request_ar(Rid, Tids, Cid, []).
7770
7771rsmms2_mg_notify_request_ar(_Rid, [], Cid, Cmds) ->
7772    cre_actionReq(Cid, lists:reverse(Cmds));
7773rsmms2_mg_notify_request_ar(Rid, [Tid|Tids], Cid, Cmds) ->
7774    TT      = cre_timeNotation("19990729", "22000000"),
7775    Ev      = cre_obsEvent("al/of", TT),
7776    EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
7777    NR      = cre_notifyReq([Tid], EvsDesc),
7778    CMD     = cre_command(NR),
7779    CR      = cre_cmdReq(CMD),
7780    rsmms2_mg_notify_request_ar(Rid, Tids, Cid, [CR|Cmds]).
7781
7782
7783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7784%%
7785%% Common message creation functions
7786%%
7787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7788
7789%% cre_errorDesc(Code, Text) when is_list(Text) ->
7790%%     #'ErrorDescriptor'{errorCode = Code, errorText = Text};
7791%% cre_errorDesc(Code, Text0) ->
7792%%     Text = lists:flatten(io_lib:format("~w",[Text0])),
7793%%     #'ErrorDescriptor'{errorCode = Code, errorText = Text}.
7794
7795cre_segReply(TransId, SN, SC) ->
7796    megaco_test_msg_v3_lib:cre_SegmentReply(TransId, SN, SC).
7797
7798cre_serviceChangeParm(M,R,P) ->
7799    %% Version 1 'ServiceChangeParm'
7800    {'ServiceChangeParm',
7801     M,            % serviceChangeMethod,
7802     asn1_NOVALUE, % serviceChangeAddress
7803     ?VERSION,     % serviceChangeVersion
7804     P,            % serviceChangeProfile
7805     R,            % serviceChangeReason
7806     asn1_NOVALUE, % serviceChangeDelay
7807     asn1_NOVALUE, % serviceChangeMgcId
7808     asn1_NOVALUE, % timeStamp
7809     asn1_NOVALUE  % nonStandardData
7810    }.
7811
7812cre_serviceChangeReq(Tid, Parms) ->
7813    #'ServiceChangeRequest'{terminationID      = Tid,
7814                            serviceChangeParms = Parms}.
7815
7816cre_timeNotation(D,T) ->
7817    #'TimeNotation'{date = D, time = T}.
7818
7819cre_obsEvent(Name, Not) ->
7820    #'ObservedEvent'{eventName    = Name,
7821                     timeNotation = Not}.
7822%% cre_obsEvent(Name, Not, Par) ->
7823%%     #'ObservedEvent'{eventName    = Name,
7824%%                      timeNotation = Not,
7825%%                      eventParList = Par}.
7826
7827cre_obsEvsDesc(Id, EvList) ->
7828    #'ObservedEventsDescriptor'{requestId        = Id,
7829                                observedEventLst = EvList}.
7830
7831cre_notifyReq(Tid, EvsDesc) ->
7832    #'NotifyRequest'{terminationID            = Tid,
7833                     observedEventsDescriptor = EvsDesc}.
7834
7835cre_command(R) when is_record(R, 'NotifyRequest') ->
7836    {notifyReq, R};
7837cre_command(R) when is_record(R, 'ServiceChangeRequest') ->
7838    {serviceChangeReq, R}.
7839
7840cre_cmdReq(Cmd) ->
7841    #'CommandRequest'{command = Cmd}.
7842
7843cre_actionReq(CtxId, CmdReqs) when is_list(CmdReqs) ->
7844    #'ActionRequest'{contextId       = CtxId,
7845                     commandRequests = CmdReqs}.
7846
7847cre_transReq(TransId, ARs) when is_list(ARs) ->
7848    #'TransactionRequest'{transactionId = TransId,
7849			  actions       = ARs}.
7850
7851%% --
7852
7853cre_serviceChangeResParm(Mid) ->
7854    cre_serviceChangeResParm(Mid, ?VERSION).
7855
7856cre_serviceChangeResParm(Mid, V) ->
7857    #'ServiceChangeResParm'{serviceChangeMgcId   = Mid,
7858			    serviceChangeVersion = V}.
7859
7860cre_serviceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
7861    {serviceChangeResParms, SCRP};
7862cre_serviceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
7863    {errorDescriptor, ED}.
7864
7865cre_serviceChangeReply(Tid, Res) ->
7866    #'ServiceChangeReply'{terminationID       = Tid,
7867                          serviceChangeResult = Res}.
7868
7869cre_cmdReply(R) when is_record(R, 'NotifyReply') ->
7870    {notifyReply, R};
7871cre_cmdReply(R) when is_record(R, 'ServiceChangeReply') ->
7872    {serviceChangeReply, R}.
7873
7874cre_notifyReply(Tid) ->
7875    #'NotifyReply'{terminationID = Tid}.
7876
7877cre_actionReply(CtxId, CmdRep) ->
7878    #'ActionReply'{contextId    = CtxId,
7879                   commandReply = CmdRep}.
7880
7881cre_transResult(ED) when is_record(ED, 'ErrorDescriptor') ->
7882    {transactionError, ED};
7883cre_transResult([AR|_] = ARs) when is_record(AR, 'ActionReply') ->
7884    {actionReplies, ARs}.
7885
7886%% cre_transReply(TransId, Res) ->
7887%%     #'TransactionReply'{transactionId     = TransId,
7888%%                         transactionResult = Res}.
7889
7890cre_transReply(TransId, Res, SN) ->
7891    #'TransactionReply'{transactionId     = TransId,
7892                        transactionResult = Res,
7893			segmentNumber     = SN}.
7894
7895cre_transReply(TransId, Res, SN, SC) ->
7896    #'TransactionReply'{transactionId        = TransId,
7897                        transactionResult    = Res,
7898			segmentNumber        = SN,
7899			segmentationComplete = SC}.
7900
7901cre_transAck(TransId) ->
7902    megaco_test_msg_v3_lib:cre_TransactionAck(TransId).
7903
7904
7905%% --
7906
7907cre_serviceChangeProf(Name, Ver) when is_list(Name) andalso is_integer(Ver) ->
7908    #'ServiceChangeProfile'{profileName = Name,
7909                            version     = Ver}.
7910
7911cre_transaction(Trans) when is_record(Trans, 'TransactionRequest') ->
7912    {transactionRequest, Trans};
7913cre_transaction(Trans) when is_record(Trans, 'TransactionPending') ->
7914    {transactionPending, Trans};
7915cre_transaction(Trans)
7916  when is_record(Trans, 'TransactionReply') or
7917       (is_tuple(Trans) and (element(1, Trans) == 'TransactionReply')) ->
7918    {transactionReply, Trans};
7919cre_transaction(Trans) when is_list(Trans) ->
7920    {transactionResponseAck, Trans};
7921cre_transaction(SR) when is_record(SR, 'SegmentReply') ->
7922    {segmentReply, SR}.
7923
7924cre_transactions(Trans) when is_list(Trans) ->
7925    {transactions, Trans}.
7926
7927cre_message(Version, Mid, Body) ->
7928    #'Message'{version     = Version,
7929               mId         = Mid,
7930               messageBody = Body}.
7931
7932cre_megacoMessage(Mess) ->
7933    #'MegacoMessage'{mess = Mess}.
7934
7935
7936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7937
7938%% Transform a short timer to a long one.
7939%% The purpose of this is to trick the stack
7940%% to keep re-sending the request, even after
7941%% having received the first pending (which
7942%% indicates that the other side _IS_
7943%% working on the request).
7944-ifdef(MEGACO_TEST_CODE).
7945
7946init_request_timer({short, Ref}) ->
7947    {long, Ref};
7948init_request_timer(O) ->
7949    O.
7950
7951-endif.
7952
7953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7954
7955await_completion(Ids) ->
7956    case megaco_test_generator_lib:await_completion(Ids) of
7957	{ok, Reply} ->
7958	    d("OK => Reply: ~n~p", [Reply]),
7959	    ok;
7960	{error, {OK, ERROR}} ->
7961	    d("ERROR => "
7962	      "~n      OK:    ~p"
7963	      "~n      ERROR: ~p", [OK, ERROR]),
7964	    ?ERROR({failed, ERROR});
7965	{error, Reply} ->
7966	    d("ERROR => "
7967	      "~n      Reply: ~p", [Reply]),
7968	    ?ERROR({failed, Reply})
7969    end.
7970
7971
7972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7973
7974make_node_name(Name) ->
7975    case string:tokens(atom_to_list(node()), [$@]) of
7976	[_,Host] ->
7977	    list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
7978	_ ->
7979	    exit("Test node must be started with '-sname'")
7980     end.
7981
7982
7983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7984
7985sleep(X) -> receive after X -> ok end.
7986
7987
7988%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7989
7990try_tc(TCName, Pre, Case, Post) ->
7991    try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
7992
7993try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
7994    ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
7995
7996
7997
7998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7999
8000p(F) ->
8001    p(F, []).
8002
8003p(F, A) ->
8004    io:format("*** [~s] ~p ***"
8005	      "~n   " ++ F ++ "~n",
8006	      [?FTS(), self() | A]).
8007
8008
8009%% e(F) ->
8010%%     e(F, []).
8011
8012e(F, A) ->
8013    print(error, get(verbosity), "ERROR", get(tc), F, A).
8014
8015
8016i(F) ->
8017    i(F, []).
8018
8019i(F, A) ->
8020    print(info, get(verbosity), "INFO", get(tc), F, A).
8021
8022
8023d(F) ->
8024    d(F, []).
8025
8026d(F, A) ->
8027    print(debug, get(verbosity), "DBG", get(tc), F, A).
8028
8029
8030printable(_, debug)   -> true;
8031printable(info, info) -> true;
8032printable(error, _)   -> true;
8033printable(_,_)        -> false.
8034
8035print(Severity, Verbosity, P, TC, F, A) ->
8036    print(printable(Severity, Verbosity), P, TC, F, A).
8037
8038print(true, P, TC, F, A) when (TC =:= undefined) ->
8039    print(P, "", F, A);
8040print(true, P, TC, F, A) when is_atom(TC) ->
8041    print(P, ":" ++ atom_to_list(TC), F, A);
8042print(true, P, TC, F, A) when is_list(TC) ->
8043    print(P, TC, F, A);
8044print(_, _, _, _, _) ->
8045    ok.
8046
8047print(P, TCStr, F, A) ->
8048    io:format("*** [~s] ~s ~p ~s~s ***"
8049	      "~n   " ++ F ++ "~n",
8050	      [?FTS(), P, self(), get(sname), TCStr | A]).
8051
8052
8053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8054
8055
8056