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