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