#include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
#include <math.h>
#include "asterisk/module.h"
#include "asterisk/test.h"
#include "asterisk/cel.h"
#include "asterisk/channel.h"
+#include "asterisk/format_cache.h"
#include "asterisk/linkedlists.h"
#include "asterisk/chanvars.h"
#include "asterisk/utils.h"
static void do_sleep(void)
{
- while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR));
+ while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)) {
+ }
}
#define APPEND_EVENT(chan, ev_type, userevent, extra) do { \
#define BRIDGE_EXIT_EVENT_PEER(channel, bridge, peer) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
- extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
+ extra = ast_json_pack("{s: s, s: s}", "bridge_id", bridge->uniqueid, "bridge_technology", bridge->technology->name); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT_PEER(channel, AST_CEL_BRIDGE_EXIT, NULL, extra, peer); \
} while (0)
RAII_VAR(struct ast_str *, peer_str, NULL, ast_free); \
peer_str = test_cel_generate_peer_str_snapshot(channel, bridge); \
ast_test_validate(test, peer_str != NULL); \
- extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
+ extra = ast_json_pack("{s: s, s: s}", "bridge_id", bridge->uniqueid, "bridge_technology", bridge->technology->name); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT_SNAPSHOT(channel, AST_CEL_BRIDGE_EXIT, NULL, extra, ast_str_buffer(peer_str)); \
} while (0)
#define BRIDGE_ENTER_EVENT_PEER(channel, bridge, peer) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
- extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
+ extra = ast_json_pack("{s: s, s: s}", "bridge_id", bridge->uniqueid, "bridge_technology", bridge->technology->name); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT_PEER(channel, AST_CEL_BRIDGE_ENTER, NULL, extra, peer); \
} while (0)
#define BLINDTRANSFER_EVENT(channel, bridge, extension, context) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
- extra = ast_json_pack("{s: s, s: s, s: s}", \
+ extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", \
"extension", extension, \
"context", context, \
- "bridge_id", bridge->uniqueid); \
+ "bridge_id", bridge->uniqueid, \
+ "transferee_channel_name", "N/A", \
+ "transferee_channel_uniqueid", "N/A"); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT(channel, AST_CEL_BLINDTRANSFER, NULL, extra); \
} while (0)
-#define ATTENDEDTRANSFER_BRIDGE(channel1, bridge1, channel2, bridge2) do { \
+#define ATTENDEDTRANSFER_BRIDGE(channel1, bridge1, channel2, bridge2, channel3, channel4) do { \
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
- extra = ast_json_pack("{s: s, s: s, s: s}", \
+ extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}", \
"bridge1_id", bridge1->uniqueid, \
"channel2_name", ast_channel_name(channel2), \
- "bridge2_id", bridge2->uniqueid); \
+ "channel2_uniqueid", ast_channel_uniqueid(channel2), \
+ "bridge2_id", bridge2->uniqueid, \
+ "transferee_channel_name", ast_channel_name(channel4), \
+ "transferee_channel_uniqueid", ast_channel_uniqueid(channel4), \
+ "transfer_target_channel_name", ast_channel_name(channel3), \
+ "transfer_target_channel_uniqueid", ast_channel_uniqueid(channel3)); \
ast_test_validate(test, extra != NULL); \
APPEND_EVENT(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra); \
} while (0)
/*! \brief David's Caller ID */
#define DAVID_CALLERID { .id.name.str = "David", .id.name.valid = 1, .id.number.str = "400", .id.number.valid = 1, }
+/*! \brief Set ulaw format on channel */
+#define SET_FORMATS(chan) do {\
+ struct ast_format_cap *caps;\
+ caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);\
+ ast_format_cap_append(caps, ast_format_ulaw, 0);\
+ ast_channel_nativeformats_set((chan), caps);\
+ ast_channel_set_writeformat((chan), ast_format_ulaw);\
+ ast_channel_set_rawwriteformat((chan), ast_format_ulaw);\
+ ast_channel_set_readformat((chan), ast_format_ulaw);\
+ ast_channel_set_rawreadformat((chan), ast_format_ulaw);\
+ ao2_ref(caps, -1);\
+} while (0)
+
/*! \brief Create a \ref test_cel_chan_tech for Alice. */
#define CREATE_ALICE_CHANNEL(channel_var, caller_id) do { \
- (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
+ (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "100", "100", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
+ SET_FORMATS((channel_var));\
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
ast_channel_unlock((channel_var)); \
} while (0)
/*! \brief Create a \ref test_cel_chan_tech for Bob. */
#define CREATE_BOB_CHANNEL(channel_var, caller_id) do { \
- (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "200", "200", "default", NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
+ (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "200", "200", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
+ SET_FORMATS((channel_var));\
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
ast_channel_unlock((channel_var)); \
} while (0)
/*! \brief Create a \ref test_cel_chan_tech for Charlie. */
#define CREATE_CHARLIE_CHANNEL(channel_var, caller_id) do { \
- (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "300", "300", "default", NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
+ (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "300", "300", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
+ SET_FORMATS((channel_var));\
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
ast_channel_unlock((channel_var)); \
} while (0)
/*! \brief Create a \ref test_cel_chan_tech for David. */
#define CREATE_DAVID_CHANNEL(channel_var, caller_id) do { \
- (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "400", "400", "default", NULL, 0, CHANNEL_TECH_NAME "/David"); \
+ (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "400", "400", "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/David"); \
+ SET_FORMATS((channel_var));\
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
ast_channel_unlock((channel_var)); \
} while (0)
struct ast_json *extra,
const char *peer);
+#ifdef RACEY_TESTS
static int append_dummy_event(void);
+#endif
static struct ast_str *__test_cel_generate_peer_str(struct ast_channel_snapshot *chan, struct ast_bridge_snapshot *bridge)
{
ast_channel_release(chan);
}
+static void safe_bridge_destroy(struct ast_bridge *bridge)
+{
+ if (!bridge) {
+ return;
+ }
+ ast_bridge_destroy(bridge, 0);
+}
+
AST_TEST_DEFINE(test_cel_channel_creation)
{
RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
info->description =
"Test CEL records for a call that is\n"
"inbound to Asterisk, executes some dialplan, but\n"
- "is never answered.\n";
+ "is never answered.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
info->summary = "Test outbound unanswered calls";
info->description =
"Test CEL records for a call that is\n"
- "outbound to Asterisk but is never answered.\n";
+ "outbound to Asterisk but is never answered.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
info->summary = "Test CEL for a single party";
info->description =
"Test CEL records for a call that is\n"
- "answered, but only involves a single channel\n";
+ "answered, but only involves a single channel";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
AST_TEST_DEFINE(test_cel_single_bridge)
{
RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
- RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller caller = ALICE_CALLERID;
info->summary = "Test CEL for a single party entering/leaving a bridge";
info->description =
"Test CEL records for a call that is\n"
- "answered, enters a bridge, and leaves it.\n";
+ "answered, enters a bridge, and leaves it.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
AST_TEST_DEFINE(test_cel_single_bridge_continue)
{
RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
- RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller caller = ALICE_CALLERID;
switch (cmd) {
info->summary = "Test CEL for a single party entering/leaving a bridge";
info->description =
"Test CEL records for a call that is\n"
- "answered, enters a bridge, and leaves it.\n";
+ "answered, enters a bridge, and leaves it.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
{
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, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller caller_alice = ALICE_CALLERID;
struct ast_party_caller caller_bob = BOB_CALLERID;
info->description =
"Test CEL records for a call that is\n"
"answered, enters a bridge, and leaves it. In this scenario, the\n"
- "Party A should answer the bridge first.\n";
+ "Party A should answer the bridge first.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
{
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, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller caller_alice = ALICE_CALLERID;
struct ast_party_caller caller_bob = BOB_CALLERID;
info->description =
"Test CEL records for a call that is\n"
"answered, enters a bridge, and leaves it. In this scenario, the\n"
- "Party B should answer the bridge first.\n";
+ "Party B should answer the bridge first.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
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_bridge *, bridge, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller caller_alice = ALICE_CALLERID;
struct ast_party_caller caller_bob = BOB_CALLERID;
struct ast_party_caller caller_charlie = CHARLIE_CALLERID;
info->description =
"Test CEL records for a call that is\n"
"answered, enters a bridge, and leaves it. A total of three\n"
- "parties perform this action.\n";
+ "parties perform this action.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
START_DIALED_FULL(caller, callee, "200", "Bob")
#define START_DIALED_FULL(caller, callee, number, name) do { \
- callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, number, NULL, NULL, ast_channel_linkedid(caller), 0, CHANNEL_TECH_NAME "/" name); \
+ callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, number, NULL, NULL, NULL, caller, 0, CHANNEL_TECH_NAME "/" name); \
+ SET_FORMATS(callee);\
ast_channel_unlock(callee); \
if (append_expected_event(callee, AST_CEL_CHANNEL_START, NULL, NULL, NULL)) { \
return AST_TEST_FAIL; \
info->summary = "Test CEL for a dial that isn't answered";
info->description =
"Test CEL records for a channel that\n"
- "performs a dial operation that isn't answered\n";
+ "performs a dial operation that isn't answered";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
return AST_TEST_PASS;
}
+AST_TEST_DEFINE(test_cel_dial_unanswered_filter)
+{
+ 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 CEL for a dial that isn't answered";
+ info->description =
+ "Test CEL records for a channel that\n"
+ "performs a dial operation that isn't answered";
+ 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, "NOT A VALID DIAL STATUS");
+ ast_channel_publish_dial(chan_caller, chan_callee, NULL, "NOANSWER");
+
+ HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ANSWER, "NOANSWER");
+ HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ANSWER, "");
+
+ return AST_TEST_PASS;
+}
AST_TEST_DEFINE(test_cel_dial_busy)
{
info->summary = "Test CEL for a dial that results in a busy";
info->description =
"Test CEL records for a channel that\n"
- "performs a dial operation to an endpoint that's busy\n";
+ "performs a dial operation to an endpoint that's busy";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
info->summary = "Test CEL for a dial that results in congestion";
info->description =
"Test CEL records for a channel that\n"
- "performs a dial operation to an endpoint that's congested\n";
+ "performs a dial operation to an endpoint that's congested";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
info->summary = "Test CEL for a dial that results in unavailable";
info->description =
"Test CEL records for a channel that\n"
- "performs a dial operation to an endpoint that's unavailable\n";
+ "performs a dial operation to an endpoint that's unavailable";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
info->description =
"Test CEL records for a channel that\n"
"performs a dial operation to an endpoint but then decides\n"
- "to hang up, cancelling the dial\n";
+ "to hang up, cancelling the dial";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
info->description =
"This tests dialing three parties: Bob, Charlie, David. Charlie\n"
"returns BUSY; David returns CONGESTION; Bob fails to answer and\n"
- "Alice hangs up. Three records are created for Alice as a result.\n";
+ "Alice hangs up. Three records are created for Alice as a result.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
"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.\n";
+ "that it gets finalized appropriately.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
{
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, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller caller = ALICE_CALLERID;
switch (cmd) {
info->category = TEST_CATEGORY;
info->summary = "Test dialing, answering, and going into a 2-party bridge";
info->description =
- "The most 'basic' of scenarios\n";
+ "The most 'basic' of scenarios";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
{
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, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
struct ast_party_caller caller = ALICE_CALLERID;
switch (cmd) {
info->category = TEST_CATEGORY;
info->summary = "Test dialing, answering, and going into a 2-party bridge";
info->description =
- "The most 'basic' of scenarios\n";
+ "The most 'basic' of scenarios";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
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, ao2_cleanup);
+ 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;
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.\n";
+ "A little tricky to get to do, but possible with some redirects.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
{
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, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
+ 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;
- struct ast_bridge_channel_pair pair;
switch (cmd) {
case TEST_INIT:
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.\n";
+ " blind transfers the bridge to an extension.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
BRIDGE_ENTER(chan_bob, bridge);
BRIDGE_ENTER(chan_alice, bridge);
- pair.bridge = bridge;
- pair.channel = chan_alice;
- ast_bridge_publish_blind_transfer(1, AST_BRIDGE_TRANSFER_SUCCESS,
- &pair, "transfer_context", "transfer_extension");
+ ast_bridge_lock(bridge);
+ transfer_msg = ast_blind_transfer_message_create(1, chan_alice,
+ "transfer_extension", "transfer_context");
+ if (!transfer_msg) {
+ ast_bridge_unlock(bridge);
+ 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);
+ ast_test_status_update(test, "Failed to create bridge snapshot\n");
+ return AST_TEST_FAIL;
+ }
+ ast_bridge_unlock(bridge);
+ 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);
return AST_TEST_PASS;
}
+/* 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, ao2_cleanup);
- RAII_VAR(struct ast_bridge *, bridge2, NULL, ao2_cleanup);
+ 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;
info->description =
"This test creates four channels, places each pair in"
" a bridge, and then attended transfers the bridges"
- " together.\n";
+ " together.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
do_sleep();
/* Perform attended transfer */
- ast_bridge_transfer_attended(chan_alice, chan_david);
+ if (ast_bridge_transfer_attended(chan_alice, chan_david)) {
+ ast_test_status_update(test, "Attended transfer failed!\n");
+ return AST_TEST_FAIL;
+ }
do_sleep();
BRIDGE_ENTER_EVENT_PEER(chan_bob, bridge2, "CELTestChannel/David,CELTestChannel/Charlie");
BRIDGE_EXIT_EVENT(chan_david, bridge2);
- ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2);
BRIDGE_EXIT_EVENT(chan_alice, bridge1);
+ ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2, chan_charlie, chan_bob);
do_sleep();
BRIDGE_EXIT(chan_bob, bridge2);
return AST_TEST_PASS;
}
+#endif
AST_TEST_DEFINE(test_cel_attended_transfer_bridges_merge)
{
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, ao2_cleanup);
- RAII_VAR(struct ast_bridge *, bridge2, NULL, ao2_cleanup);
+ 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;
info->description =
"This test creates four channels, places each pair"
" in a bridge, and then attended transfers the bridges"
- " together causing a bridge merge.\n";
+ " 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,
- "test_cel", "test_cel_atxfer_bridges_merge_1");
+ "test_cel", "test_cel_atxfer_bridges_merge_1", NULL);
ast_test_validate(test, bridge1 != NULL);
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
/* 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,
- "test_cel", "test_cel_atxfer_bridges_merge_2");
+ "test_cel", "test_cel_atxfer_bridges_merge_2", NULL);
ast_test_validate(test, bridge2 != NULL);
CREATE_DAVID_CHANNEL(chan_david, &david_caller);
BRIDGE_ENTER(chan_david, bridge2);
/* Perform attended transfer */
- ast_bridge_transfer_attended(chan_alice, chan_david);
+ if (ast_bridge_transfer_attended(chan_alice, chan_david)) {
+ ast_test_status_update(test, "Attended transfer failed!\n");
+ return AST_TEST_FAIL;
+ }
do_sleep();
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);
+ ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_david, bridge2, chan_charlie, chan_bob);
do_sleep();
BRIDGE_EXIT(chan_bob, bridge1);
return AST_TEST_PASS;
}
+/* 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, ao2_cleanup);
- RAII_VAR(struct ast_bridge *, bridge2, NULL, ao2_cleanup);
+ 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;
info->description =
"This test creates four channels, places each pair"
" in a bridge, and then attended transfers the bridges"
- " together causing a bridge link.\n";
+ " together causing a bridge link.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
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,
- "test_cel", "test_cel_atxfer_bridges_link_1");
+ "test_cel", "test_cel_atxfer_bridges_link_1", NULL);
ast_test_validate(test, bridge1 != NULL);
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
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,
- "test_cel", "test_cel_atxfer_bridges_link_2");
+ "test_cel", "test_cel_atxfer_bridges_link_2", NULL);
ast_test_validate(test, bridge2 != NULL);
CREATE_DAVID_CHANNEL(chan_david, &david_caller);
BRIDGE_ENTER(chan_david, bridge2);
/* Perform attended transfer */
-
- /* The following events can not be matched directly since nothing is known
- * about the linking local channel.
- * local channel ;1 and ;2 creation and ;2 answer */
- APPEND_DUMMY_EVENT();
- APPEND_DUMMY_EVENT();
- APPEND_DUMMY_EVENT();
-
- ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, 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();
- /* ;1 and ;2 BRIDGE_ENTER and ;1 ANSWER */
- APPEND_DUMMY_EVENT();
- APPEND_DUMMY_EVENT();
- APPEND_DUMMY_EVENT();
-
/* BRIDGE_EXIT alice and david */
APPEND_DUMMY_EVENT();
APPEND_DUMMY_EVENT();
HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
do_sleep();
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
+ do_sleep();
return AST_TEST_PASS;
}
+#endif
AST_TEST_DEFINE(test_cel_dial_pickup)
{
info->description =
"Test CEL records for a call that is\n"
"inbound to Asterisk, executes some dialplan, and\n"
- "is picked up.\n";
+ "is picked up.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
SCOPED_CHANNELLOCK(lock, chan_callee);
- extra = ast_json_pack("{s: s}", "pickup_channel", ast_channel_name(chan_charlie));
+ 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);
info->description =
"Test CEL records for two local channels being optimized\n"
"out by sending a messages indicating local optimization\n"
- "begin and end\n";
+ "begin and end";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
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);
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}", "local_two", bob_snapshot->name);
+ 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);
return 0;
}
+#ifdef RACEY_TESTS
static int append_dummy_event(void)
{
RAII_VAR(struct ast_event *, ev, NULL, ast_free);
return append_event(ev);
}
+#endif
static int append_expected_event_snapshot(
struct ast_channel_snapshot *snapshot,
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);
if (!snapshot) {
return -1;
}
static void test_sub(struct ast_event *event)
{
struct ast_event *event_dup = ao2_dup_event(event);
+ const char *chan_name;
SCOPED_MUTEX(mid_test_lock, &mid_test_sync_lock);
if (!event_dup) {
return;
}
+ 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);
return !strcmp(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;
}
static int check_events(struct ast_test *test, struct ao2_container *local_expected, struct ao2_container *local_received)
{
- struct ao2_iterator expected_it, received_it;
- struct ast_event *rx_event, *ex_event;
+ struct ao2_iterator received_it;
+ struct ao2_iterator expected_it;
+ RAII_VAR(struct ast_event *, rx_event, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_event *, ex_event, NULL, ao2_cleanup);
int debug = 0;
if (ao2_container_count(local_expected) != ao2_container_count(local_received)) {
debug = 1;
}
- expected_it = ao2_iterator_init(local_expected, 0);
received_it = ao2_iterator_init(local_received, 0);
+ expected_it = ao2_iterator_init(local_expected, 0);
rx_event = ao2_iterator_next(&received_it);
ex_event = ao2_iterator_next(&expected_it);
while (rx_event && ex_event) {
if (!events_are_equal(test, rx_event, ex_event)) {
+ ao2_iterator_destroy(&received_it);
+ ao2_iterator_destroy(&expected_it);
ast_test_status_update(test, "Received event:\n");
dump_event(test, rx_event);
ast_test_status_update(test, "Expected event:\n");
return -1;
}
if (debug) {
- ast_test_status_update(test, "Compared events successfully%s\n", ast_event_get_type(ex_event) == AST_EVENT_CUSTOM ? " (wildcard match)" : "");
+ ast_test_status_update(test, "Compared events successfully%s\n",
+ ast_event_get_type(ex_event) == AST_EVENT_CUSTOM
+ ? " (wildcard match)" : "");
dump_event(test, rx_event);
}
ao2_cleanup(rx_event);
rx_event = ao2_iterator_next(&received_it);
ex_event = ao2_iterator_next(&expected_it);
}
+ ao2_iterator_destroy(&received_it);
+ ao2_iterator_destroy(&expected_it);
if (rx_event) {
ast_test_status_update(test, "Received event:\n");
dump_event(test, rx_event);
- ao2_cleanup(rx_event);
return -1;
}
if (ex_event) {
ast_test_status_update(test, "Expected event:\n");
dump_event(test, ex_event);
- ao2_cleanup(ex_event);
return -1;
}
return 0;
#endif
AST_TEST_UNREGISTER(test_cel_dial_unanswered);
+ AST_TEST_UNREGISTER(test_cel_dial_unanswered_filter);
AST_TEST_UNREGISTER(test_cel_dial_congestion);
AST_TEST_UNREGISTER(test_cel_dial_busy);
AST_TEST_UNREGISTER(test_cel_dial_unavailable);
AST_TEST_UNREGISTER(test_cel_dial_answer_twoparty_bridge_b);
#ifdef RACEY_TESTS
AST_TEST_UNREGISTER(test_cel_dial_answer_multiparty);
+ AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_swap);
+ AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_link);
#endif
AST_TEST_UNREGISTER(test_cel_blind_transfer);
- AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_swap);
AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_merge);
- AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_link);
AST_TEST_UNREGISTER(test_cel_dial_pickup);
#endif
AST_TEST_REGISTER(test_cel_dial_unanswered);
+ AST_TEST_REGISTER(test_cel_dial_unanswered_filter);
AST_TEST_REGISTER(test_cel_dial_congestion);
AST_TEST_REGISTER(test_cel_dial_busy);
AST_TEST_REGISTER(test_cel_dial_unavailable);
AST_TEST_REGISTER(test_cel_dial_answer_twoparty_bridge_b);
#ifdef RACEY_TESTS
AST_TEST_REGISTER(test_cel_dial_answer_multiparty);
+ AST_TEST_REGISTER(test_cel_attended_transfer_bridges_swap);
+ AST_TEST_REGISTER(test_cel_attended_transfer_bridges_link);
#endif
AST_TEST_REGISTER(test_cel_blind_transfer);
- AST_TEST_REGISTER(test_cel_attended_transfer_bridges_swap);
AST_TEST_REGISTER(test_cel_attended_transfer_bridges_merge);
- AST_TEST_REGISTER(test_cel_attended_transfer_bridges_link);
AST_TEST_REGISTER(test_cel_dial_pickup);