Newer
Older
EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob&" CHANNEL_TECH_NAME "/Charlie&" CHANNEL_TECH_NAME "/David");
/* Outbound channels are created */
START_DIALED_FULL(chan_caller, chan_bob, "200", "Bob");
START_DIALED_FULL(chan_caller, chan_charlie, "300", "Charlie");
START_DIALED_FULL(chan_caller, chan_david, "400", "David");
/* Dial starts */
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
/* Charlie is busy */
ast_channel_publish_dial(chan_caller, chan_charlie, NULL, "BUSY");
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_BUSY, "");
/* David is congested */
ast_channel_publish_dial(chan_caller, chan_david, NULL, "CONGESTION");
HANGUP_CHANNEL(chan_david, AST_CAUSE_CONGESTION, "");
/* Bob is canceled */
ast_channel_publish_dial(chan_caller, chan_bob, NULL, "CANCEL");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "BUSY");
return AST_TEST_PASS;
}
AST_TEST_DEFINE(test_cel_dial_answer_no_bridge)
{
RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
struct ast_party_caller caller = ALICE_CALLERID;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test dialing, answering, and not going into a bridge.";
info->description =
"This is a weird one, but theoretically possible. You can perform\n"
"a dial, then bounce both channels to different priorities and\n"
"never have them enter a bridge together. Ew. This makes sure that\n"
"when we answer, we get a CEL, it gets ended at that point, and\n"
"that it gets finalized appropriately.";
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
CREATE_ALICE_CHANNEL(chan_caller, &caller);
EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
START_DIALED(chan_caller, chan_callee);
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
ANSWER_NO_APP(chan_caller);
ast_clear_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
ANSWER_NO_APP(chan_callee);
EMULATE_APP_DATA(chan_caller, 2, "Wait", "1");
EMULATE_APP_DATA(chan_callee, 1, "Wait", "1");
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
return AST_TEST_PASS;
}
AST_TEST_DEFINE(test_cel_dial_answer_twoparty_bridge_a)
{
RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller caller = ALICE_CALLERID;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test dialing, answering, and going into a 2-party bridge";
info->description =
"The most 'basic' of scenarios";
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
bridge = ast_bridge_basic_new();
ast_test_validate(test, bridge != NULL);
CREATE_ALICE_CHANNEL(chan_caller, &caller);
EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
START_DIALED(chan_caller, chan_callee);
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
ANSWER_NO_APP(chan_caller);
ANSWER_NO_APP(chan_callee);
do_sleep();
BRIDGE_ENTER(chan_caller, bridge);
BRIDGE_ENTER(chan_callee, bridge);
BRIDGE_EXIT(chan_caller, bridge);
BRIDGE_EXIT(chan_callee, bridge);
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
return AST_TEST_PASS;
}
AST_TEST_DEFINE(test_cel_dial_answer_twoparty_bridge_b)
{
RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller caller = ALICE_CALLERID;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test dialing, answering, and going into a 2-party bridge";
info->description =
"The most 'basic' of scenarios";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
bridge = ast_bridge_basic_new();
ast_test_validate(test, bridge != NULL);
CREATE_ALICE_CHANNEL(chan_caller, &caller);
EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
START_DIALED(chan_caller, chan_callee);
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
ANSWER_NO_APP(chan_caller);
ANSWER_NO_APP(chan_callee);
do_sleep();
BRIDGE_ENTER(chan_callee, bridge);
BRIDGE_ENTER(chan_caller, bridge);
BRIDGE_EXIT(chan_caller, bridge);
BRIDGE_EXIT(chan_callee, bridge);
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
return AST_TEST_PASS;
}
AST_TEST_DEFINE(test_cel_dial_answer_multiparty)
{
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller alice_caller = ALICE_CALLERID;
struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test dialing, answering, and going into a multi-party bridge";
info->description =
"A little tricky to get to do, but possible with some redirects.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
bridge = ast_bridge_basic_new();
ast_test_validate(test, bridge != NULL);
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
EMULATE_DIAL(chan_alice, CHANNEL_TECH_NAME "/Bob");
START_DIALED(chan_alice, chan_bob);
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
EMULATE_DIAL(chan_charlie, CHANNEL_TECH_NAME "/Bob");
START_DIALED_FULL(chan_charlie, chan_david, "400", "David");
ast_channel_state_set(chan_alice, AST_STATE_RINGING);
ast_channel_state_set(chan_charlie, AST_STATE_RINGING);
ast_channel_publish_dial(chan_alice, chan_bob, NULL, "ANSWER");
ast_channel_publish_dial(chan_charlie, chan_david, NULL, "ANSWER");
BRIDGE_ENTER(chan_charlie, bridge);
BRIDGE_ENTER(chan_david, bridge);
BRIDGE_ENTER(chan_bob, bridge);
BRIDGE_ENTER(chan_alice, bridge);
BRIDGE_EXIT(chan_alice, bridge);
BRIDGE_EXIT(chan_bob, bridge);
BRIDGE_EXIT(chan_charlie, bridge);
BRIDGE_EXIT(chan_david, bridge);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "ANSWER");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "ANSWER");
HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
return AST_TEST_PASS;
}
AST_TEST_DEFINE(test_cel_blind_transfer)
{
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
Mark Michelson
committed
RAII_VAR(struct ast_blind_transfer_message *, transfer_msg, NULL, ao2_cleanup);
struct ast_party_caller alice_caller = ALICE_CALLERID;
struct ast_party_caller bob_caller = BOB_CALLERID;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test blind transfers to an extension";
info->description =
"This test creates two channels, bridges them, and then"
" blind transfers the bridge to an extension.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
bridge = ast_bridge_basic_new();
ast_test_validate(test, bridge != NULL);
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
ANSWER_NO_APP(chan_alice);
ANSWER_NO_APP(chan_bob);
BRIDGE_ENTER(chan_bob, bridge);
BRIDGE_ENTER(chan_alice, bridge);
ast_bridge_lock(bridge);
Mark Michelson
committed
transfer_msg = ast_blind_transfer_message_create(1, chan_alice,
"transfer_extension", "transfer_context");
if (!transfer_msg) {
ast_bridge_unlock(bridge);
Mark Michelson
committed
ast_test_status_update(test, "Failed to create transfer Stasis message\n");
return AST_TEST_FAIL;
}
transfer_msg->bridge = ast_bridge_snapshot_create(bridge);
if (!transfer_msg->bridge) {
ast_bridge_unlock(bridge);
Mark Michelson
committed
ast_test_status_update(test, "Failed to create bridge snapshot\n");
return AST_TEST_FAIL;
}
ast_bridge_unlock(bridge);
Mark Michelson
committed
transfer_msg->result = AST_BRIDGE_TRANSFER_SUCCESS;
ast_bridge_publish_blind_transfer(transfer_msg);
BLINDTRANSFER_EVENT(chan_alice, bridge, "transfer_extension", "transfer_context");
BRIDGE_EXIT(chan_alice, bridge);
BRIDGE_EXIT(chan_bob, bridge);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
return AST_TEST_PASS;
}
Matthew Jordan
committed
/* XXX Validation needs to take into account the BRIDGE_EXIT for Alice and the
* ATTENDEDTRANSFER message are not guaranteed to be ordered
*/
#ifdef RACEY_TESTS
AST_TEST_DEFINE(test_cel_attended_transfer_bridges_swap)
{
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
struct ast_party_caller alice_caller = ALICE_CALLERID;
struct ast_party_caller bob_caller = BOB_CALLERID;
struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
struct ast_party_caller david_caller = ALICE_CALLERID;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test attended transfers between two pairs of bridged parties";
info->description =
"This test creates four channels, places each pair in"
" a bridge, and then attended transfers the bridges"
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
/* Create first set of bridged parties */
bridge1 = ast_bridge_basic_new();
ast_test_validate(test, bridge1 != NULL);
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
ANSWER_NO_APP(chan_alice);
ANSWER_NO_APP(chan_bob);
BRIDGE_ENTER(chan_bob, bridge1);
BRIDGE_ENTER(chan_alice, bridge1);
/* Create second set of bridged parties */
bridge2 = ast_bridge_basic_new();
ast_test_validate(test, bridge2 != NULL);
CREATE_DAVID_CHANNEL(chan_david, &david_caller);
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
BRIDGE_ENTER(chan_charlie, bridge2);
BRIDGE_ENTER(chan_david, bridge2);
BRIDGE_EXIT_EVENT(chan_bob, bridge1);
do_sleep();
/* Perform attended transfer */
if (ast_bridge_transfer_attended(chan_alice, chan_david)) {
ast_test_status_update(test, "Attended transfer failed!\n");
return AST_TEST_FAIL;
}
BRIDGE_ENTER_EVENT_PEER(chan_bob, bridge2, "CELTestChannel/David,CELTestChannel/Charlie");
BRIDGE_EXIT_EVENT(chan_david, bridge2);
BRIDGE_EXIT_EVENT(chan_alice, bridge1);
Matthew Jordan
committed
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2, chan_charlie, chan_bob);
BRIDGE_EXIT(chan_bob, bridge2);
BRIDGE_EXIT(chan_charlie, bridge2);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
return AST_TEST_PASS;
}
Matthew Jordan
committed
#endif
AST_TEST_DEFINE(test_cel_attended_transfer_bridges_merge)
{
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
struct ast_party_caller alice_caller = ALICE_CALLERID;
struct ast_party_caller bob_caller = BOB_CALLERID;
struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
struct ast_party_caller david_caller = ALICE_CALLERID;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test attended transfers between two pairs of"
" bridged parties that results in a bridge merge";
info->description =
"This test creates four channels, places each pair"
" in a bridge, and then attended transfers the bridges"
" together causing a bridge merge.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
/* Create first set of bridged parties */
bridge1 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_SMART,
Richard Mudgett
committed
"test_cel", "test_cel_atxfer_bridges_merge_1", NULL);
ast_test_validate(test, bridge1 != NULL);
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
ANSWER_NO_APP(chan_alice);
ANSWER_NO_APP(chan_bob);
BRIDGE_ENTER(chan_bob, bridge1);
BRIDGE_ENTER(chan_alice, bridge1);
/* Create second set of bridged parties */
bridge2 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_SMART,
Richard Mudgett
committed
"test_cel", "test_cel_atxfer_bridges_merge_2", NULL);
ast_test_validate(test, bridge2 != NULL);
CREATE_DAVID_CHANNEL(chan_david, &david_caller);
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
BRIDGE_ENTER(chan_charlie, bridge2);
BRIDGE_ENTER(chan_david, bridge2);
if (ast_bridge_transfer_attended(chan_alice, chan_david)) {
ast_test_status_update(test, "Attended transfer failed!\n");
return AST_TEST_FAIL;
}
BRIDGE_EXIT_EVENT_PEER(chan_charlie, bridge2, "CELTestChannel/David");
BRIDGE_ENTER_EVENT_PEER(chan_charlie, bridge1, "CELTestChannel/Bob,CELTestChannel/Alice");
BRIDGE_EXIT_EVENT(chan_david, bridge2);
BRIDGE_EXIT_EVENT(chan_alice, bridge1);
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2, chan_charlie, chan_bob);
BRIDGE_EXIT(chan_bob, bridge1);
BRIDGE_EXIT(chan_charlie, bridge1);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
/* XXX Validation needs to take into account the BRIDGE_EXIT for David and the
* ATTENDEDTRANSFER message are not guaranteed to be ordered
*/
#ifdef RACEY_TESTS
AST_TEST_DEFINE(test_cel_attended_transfer_bridges_link)
{
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
struct ast_party_caller alice_caller = ALICE_CALLERID;
struct ast_party_caller bob_caller = BOB_CALLERID;
struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
struct ast_party_caller david_caller = ALICE_CALLERID;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test attended transfers between two pairs of"
" bridged parties that results in a bridge merge";
info->description =
"This test creates four channels, places each pair"
" in a bridge, and then attended transfers the bridges"
" together causing a bridge link.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
/* Create first set of bridged parties */
bridge1 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
| AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
| AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_SMART,
Richard Mudgett
committed
"test_cel", "test_cel_atxfer_bridges_link_1", NULL);
ast_test_validate(test, bridge1 != NULL);
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
ANSWER_NO_APP(chan_alice);
ANSWER_NO_APP(chan_bob);
BRIDGE_ENTER(chan_bob, bridge1);
BRIDGE_ENTER(chan_alice, bridge1);
/* Create second set of bridged parties */
bridge2 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
| AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
| AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_SMART,
Richard Mudgett
committed
"test_cel", "test_cel_atxfer_bridges_link_2", NULL);
ast_test_validate(test, bridge2 != NULL);
CREATE_DAVID_CHANNEL(chan_david, &david_caller);
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
BRIDGE_ENTER(chan_charlie, bridge2);
BRIDGE_ENTER(chan_david, bridge2);
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2, chan_charlie, chan_bob);
ast_bridge_transfer_attended(chan_alice, chan_david);
do_sleep();
/* BRIDGE_EXIT alice and david */
APPEND_DUMMY_EVENT();
BRIDGE_EXIT(chan_bob, bridge1);
BRIDGE_EXIT(chan_charlie, bridge2);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
do_sleep();
#endif
AST_TEST_DEFINE(test_cel_dial_pickup)
{
RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
struct ast_party_caller caller = ALICE_CALLERID;
struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test call pickup";
info->description =
"Test CEL records for a call that is\n"
"inbound to Asterisk, executes some dialplan, and\n"
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
CREATE_ALICE_CHANNEL(chan_caller, &caller);
EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
START_DIALED(chan_caller, chan_callee);
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
{
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
extra = ast_json_pack("{s: s, s: s}", "pickup_channel", ast_channel_name(chan_charlie),
"pickup_channel_uniqueid", ast_channel_uniqueid(chan_charlie));
ast_test_validate(test, extra != NULL);
APPEND_EVENT(chan_callee, AST_CEL_PICKUP, NULL, extra);
ast_test_validate(test, !ast_do_pickup(chan_charlie, chan_callee));
}
/* Hang up the masqueraded zombie */
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "CANCEL");
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
return AST_TEST_PASS;
}
AST_TEST_DEFINE(test_cel_local_optimize)
{
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
struct ast_party_caller alice_caller = ALICE_CALLERID;
struct ast_party_caller bob_caller = BOB_CALLERID;
RAII_VAR(struct ast_multi_channel_blob *, mc_blob, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel_snapshot *, alice_snapshot, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel_snapshot *, bob_snapshot, NULL, ao2_cleanup);
RAII_VAR(struct stasis_message *, local_opt_begin, NULL, ao2_cleanup);
RAII_VAR(struct stasis_message *, local_opt_end, NULL, ao2_cleanup);
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
info->summary = "Test local channel optimization record generation";
info->description =
"Test CEL records for two local channels being optimized\n"
"out by sending a messages indicating local optimization\n"
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
mc_blob = ast_multi_channel_blob_create(ast_json_null());
ast_test_validate(test, mc_blob != NULL);
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
ast_channel_lock(chan_alice);
alice_snapshot = ast_channel_snapshot_create(chan_alice);
ast_channel_unlock(chan_alice);
ast_test_validate(test, alice_snapshot != NULL);
ast_channel_lock(chan_bob);
bob_snapshot = ast_channel_snapshot_create(chan_bob);
ast_channel_unlock(chan_bob);
ast_test_validate(test, bob_snapshot != NULL);
ast_multi_channel_blob_add_channel(mc_blob, "1", alice_snapshot);
ast_multi_channel_blob_add_channel(mc_blob, "2", bob_snapshot);
local_opt_begin = stasis_message_create(ast_local_optimization_begin_type(), mc_blob);
ast_test_validate(test, local_opt_begin != NULL);
local_opt_end = stasis_message_create(ast_local_optimization_end_type(), mc_blob);
ast_test_validate(test, local_opt_end != NULL);
stasis_publish(ast_channel_topic(chan_alice), local_opt_begin);
stasis_publish(ast_channel_topic(chan_alice), local_opt_end);
extra = ast_json_pack("{s: s, s: s}", "local_two", bob_snapshot->name,
"local_two_uniqueid", bob_snapshot->uniqueid);
ast_test_validate(test, extra != NULL);
APPEND_EVENT_SNAPSHOT(alice_snapshot, AST_CEL_LOCAL_OPTIMIZE, NULL, extra, NULL);
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
return AST_TEST_PASS;
}
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
/*! Container for astobj2 duplicated ast_events */
static struct ao2_container *cel_received_events = NULL;
/*! Container for expected CEL events */
static struct ao2_container *cel_expected_events = NULL;
static struct ast_event *ao2_dup_event(const struct ast_event *event)
{
struct ast_event *event_dup;
uint16_t event_len;
event_len = ast_event_get_size(event);
event_dup = ao2_alloc(event_len, NULL);
if (!event_dup) {
return NULL;
}
memcpy(event_dup, event, event_len);
return event_dup;
}
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
static void mid_test_sync(void)
{
ast_mutex_lock(&mid_test_sync_lock);
if (ao2_container_count(cel_expected_events) <= ao2_container_count(cel_received_events)) {
ast_mutex_unlock(&mid_test_sync_lock);
return;
}
do_mid_test_sync = 1;
ast_mutex_unlock(&mid_test_sync_lock);
{
struct timeval start = ast_tvnow();
struct timespec end = {
.tv_sec = start.tv_sec + 15,
.tv_nsec = start.tv_usec * 1000
};
SCOPED_MUTEX(lock, &sync_lock);
ast_cond_timedwait(&sync_out, &sync_lock, &end);
}
}
static int append_event(struct ast_event *ev)
{
RAII_VAR(struct ast_event *, ao2_ev, NULL, ao2_cleanup);
ao2_ev = ao2_dup_event(ev);
if (!ao2_ev) {
return -1;
}
ao2_link(cel_expected_events, ao2_ev);
return 0;
}
#ifdef RACEY_TESTS
{
RAII_VAR(struct ast_event *, ev, NULL, ast_free);
RAII_VAR(struct ast_event *, ao2_ev, NULL, ao2_cleanup);
ev = ast_event_new(AST_EVENT_CUSTOM, AST_EVENT_IE_END);
if (!ev) {
#endif
static int append_expected_event_snapshot(
struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type type,
const char *userdefevname,
struct ast_json *extra,
const char *peer)
{
RAII_VAR(struct ast_event *, ev, NULL, ast_free);
ev = ast_cel_create_event(snapshot, type, userdefevname, extra, peer);
if (!ev) {
return -1;
}
return append_event(ev);
}
static int append_expected_event(
struct ast_channel *chan,
enum ast_cel_event_type type,
const char *userdefevname,
struct ast_json *extra,
const char *peer)
{
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
ast_channel_lock(chan);
snapshot = ast_channel_snapshot_create(chan);
ast_channel_unlock(chan);
return append_expected_event_snapshot(snapshot, type, userdefevname, extra, peer);
static void test_sub(struct ast_event *event)
{
struct ast_event *event_dup = ao2_dup_event(event);
Matthew Jordan
committed
const char *chan_name;
SCOPED_MUTEX(mid_test_lock, &mid_test_sync_lock);
if (!event_dup) {
return;
}
Matthew Jordan
committed
chan_name = ast_event_get_ie_str(event_dup, AST_EVENT_IE_CEL_CHANNAME);
if (chan_name && strncmp(chan_name, CHANNEL_TECH_NAME, 14)) {
return;
}
/* save the event for later processing */
ao2_link(cel_received_events, event_dup);
if (do_mid_test_sync) {
int expected = ao2_container_count(cel_expected_events);
int received = ao2_container_count(cel_received_events);
if (expected <= received) {
{
SCOPED_MUTEX(lock, &sync_lock);
ast_cond_signal(&sync_out);
do_mid_test_sync = 0;
}
}
}
* \internal
* \brief Callback function called before each test executes
*/
static int test_cel_init_cb(struct ast_test_info *info, struct ast_test *test)
{
ast_assert(cel_received_events == NULL);
ast_assert(cel_expected_events == NULL);
ast_mutex_init(&mid_test_sync_lock);
ast_mutex_init(&sync_lock);
ast_cond_init(&sync_out, NULL);
/* Back up the real CEL config and insert the test's config */
saved_config = ast_cel_get_config();
ast_cel_set_config(cel_test_config);
/* init CEL event storage (degenerate hash table becomes a linked list) */
cel_received_events = ao2_container_alloc(1, NULL, NULL);
cel_expected_events = ao2_container_alloc(1, NULL, NULL);
/* start the CEL event callback */
if (ast_cel_backend_register(TEST_BACKEND_NAME, test_sub)) {
return -1;
}
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
/*!
* \brief Check two peer strings for equality
*
* \retval zero if the peer strings do not match
* \retval non-zero if the peer strings match
*/
static int test_cel_peer_strings_match(const char *str1, const char *str2)
{
struct ao2_container *intersection = ast_str_container_alloc(11);
RAII_VAR(char *, str1_dup, ast_strdup(str1), ast_free);
RAII_VAR(char *, str2_dup, ast_strdup(str2), ast_free);
char *chan;
while ((chan = strsep(&str1_dup, ","))) {
ast_str_container_add(intersection, chan);
}
while ((chan = strsep(&str2_dup, ","))) {
RAII_VAR(char *, ao2_chan, ao2_find(intersection, chan, OBJ_SEARCH_KEY), ao2_cleanup);
/* item in str2 not in str1 */
if (!ao2_chan) {
return 0;
}
ast_str_container_remove(intersection, chan);
}
/* item in str1 not in str2 */
if (ao2_container_count(intersection)) {
return 0;
}
return 1;
}
/*!
* \brief Check an IE value from two events
*
* \retval zero if the IEs in the events of the specified type do not match
* \retval non-zero if the IEs in the events of the specified type match
*/
static int match_ie_val(
const struct ast_event *event1,
const struct ast_event *event2,
enum ast_event_ie_type type)
{
enum ast_event_ie_pltype pltype = ast_event_get_ie_pltype(type);
/* XXX ignore sec/usec for now */
if (type == AST_EVENT_IE_CEL_EVENT_TIME_USEC) {
return 1;
}
if (type == AST_EVENT_IE_CEL_EVENT_TIME) {
return 1;
}
switch (pltype) {
case AST_EVENT_IE_PLTYPE_UINT:
{
uint32_t val = ast_event_get_ie_uint(event2, type);
return (val == ast_event_get_ie_uint(event1, type)) ? 1 : 0;
}
case AST_EVENT_IE_PLTYPE_STR:
{
const char *str1 = ast_event_get_ie_str(event1, type);
const char *str2 = ast_event_get_ie_str(event2, type);
if (!str1 && !str2) {
return 1;
} else if (!str1) {
return 0;
} else if (!str2) {
return 0;
}
/* use special matching for CEL PEER field */
if (type == AST_EVENT_IE_CEL_PEER) {
return test_cel_peer_strings_match(str1, str2);
case AST_EVENT_IE_PLTYPE_RAW:
case AST_EVENT_IE_PLTYPE_BITFLAGS:
/* Fall through: just pass on these types */
return 1;
default:
break;
}
return 0;
}
static int events_are_equal(struct ast_test *test, struct ast_event *received, struct ast_event *expected)
{
struct ast_event_iterator iterator;
int res;
if (ast_event_get_type(expected) == AST_EVENT_CUSTOM) {
/* this event is flagged as a wildcard match */
return 1;
}
for (res = ast_event_iterator_init(&iterator, received); !res; res = ast_event_iterator_next(&iterator)) {
int ie_type = ast_event_iterator_get_ie_type(&iterator);
if (!match_ie_val(received, expected, ie_type)) {
ast_test_status_update(test, "Failed matching on field %s\n", ast_event_get_ie_type_name(ie_type));
return 0;
}
}
return 1;
}
static int dump_event(struct ast_test *test, struct ast_event *event)
{
struct ast_event_iterator i;
if (ast_event_iterator_init(&i, event)) {
ast_test_status_update(test, "Failed to initialize event iterator. :-(\n");
ast_test_status_update(test, "Event: %s\n",
ast_cel_get_type_name(ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_EVENT_TYPE)));
do {
enum ast_event_ie_type ie_type;
enum ast_event_ie_pltype ie_pltype;
const char *ie_type_name;
ie_type = ast_event_iterator_get_ie_type(&i);
ie_type_name = ast_event_get_ie_type_name(ie_type);
ie_pltype = ast_event_get_ie_pltype(ie_type);
switch (ie_pltype) {
case AST_EVENT_IE_PLTYPE_UNKNOWN:
case AST_EVENT_IE_PLTYPE_STR:
ast_test_status_update(test, "%.30s: %s\n", ie_type_name,
ast_event_iterator_get_ie_str(&i));
break;
case AST_EVENT_IE_PLTYPE_UINT:
ast_test_status_update(test, "%.30s: %u\n", ie_type_name,
ast_event_iterator_get_ie_uint(&i));
break;
default:
break;