[asterisk-commits] mjordan: branch mjordan/cdrs-of-doom r382762 - in /team/mjordan/cdrs-of-doom:...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Mar 8 17:43:26 CST 2013
Author: mjordan
Date: Fri Mar 8 17:43:22 2013
New Revision: 382762
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=382762
Log:
Start the great migration over the cliff
* Remove some uncalled functions from cdr.c
* Remove some duplicate functions from cdr.c
* Add a unit test module that covers some single party
scenarios
* Subscribe to channel cache topic, add a callback
* Create a new internal CDR object that is relatively sane(r)
* Implement a mini state machine for the new CDR object
And it almost compiles...
Added:
team/mjordan/cdrs-of-doom/tests/test_cdr.c (with props)
Modified:
team/mjordan/cdrs-of-doom/include/asterisk/cdr.h
team/mjordan/cdrs-of-doom/main/cdr.c
team/mjordan/cdrs-of-doom/main/channel.c
team/mjordan/cdrs-of-doom/main/features.c
team/mjordan/cdrs-of-doom/main/pbx.c
Modified: team/mjordan/cdrs-of-doom/include/asterisk/cdr.h
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/include/asterisk/cdr.h?view=diff&rev=382762&r1=382761&r2=382762
==============================================================================
--- team/mjordan/cdrs-of-doom/include/asterisk/cdr.h (original)
+++ team/mjordan/cdrs-of-doom/include/asterisk/cdr.h Fri Mar 8 17:43:22 2013
@@ -201,12 +201,6 @@
*/
void ast_cdr_free(struct ast_cdr *cdr);
-/*!
- * \brief Discard and free a CDR record
- * \param cdr ast_cdr structure to free
- * Returns nothing -- same as free, but no checks or complaints
- */
-void ast_cdr_discard(struct ast_cdr *cdr);
/*!
* \brief Initialize based on a channel
@@ -410,13 +404,6 @@
char *ast_cdr_flags2str(int flags);
/*!
- * \brief Move the non-null data from the "from" cdr to the "to" cdr
- * \param to the cdr to get the goodies
- * \param from the cdr to give the goodies
- */
-void ast_cdr_merge(struct ast_cdr *to, struct ast_cdr *from);
-
-/*!
* \brief Set account code, will generate AMI event
* \note The channel should be locked before calling.
*/
Modified: team/mjordan/cdrs-of-doom/main/cdr.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/cdr.c?view=diff&rev=382762&r1=382761&r2=382762
==============================================================================
--- team/mjordan/cdrs-of-doom/main/cdr.c (original)
+++ team/mjordan/cdrs-of-doom/main/cdr.c Fri Mar 8 17:43:22 2013
@@ -205,69 +205,6 @@
BATCH_MODE_SAFE_SHUTDOWN = 1 << 1, /*< During safe shutdown, submit the batched CDRs */
};
-static struct stasis_subscription *channel_state_sub;
-
-struct cdr_object;
-
-struct cdr_object_fn_table {
- void (* const init_function)(struct cdr_object *cdr);
- void (* const process_channel_message)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
- void (* const process_varset_message)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot, const char *name, const char *value);
-};
-
-static void single_active_state_process_channel_message(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-struct cdr_object_fn_table single_active_state_fn_table = {
- .process_channel_message = single_active_state_process_channel_message,
-};
-
-struct cdr_object_fn_table hangup_state_fn_table = {
- .process_channel_message = NULL,
-};
-
-struct cdr_object {
- struct ast_channel_snapshot *party_a;
- struct varshead party_a_variables;
- struct ast_channel_snapshot *party_b;
- struct varshead party_b_variables;
- struct cdr_object_fn_table *fn_table;
-
- AST_LIST_ENTRY(cdr_object) list;
-};
-
-/* NON-INHERITABLE FUNCTIONS */
-
-static void transition_state(struct cdr_object *cdr, cdr_object_fn_table *fn_table)
-{
- cdr->fn_table = fn_table;
- if (cdr->fn_table->init_function) {
- cdr->fn_table->init_function(cdr);
- }
-}
-
-static void check_for_hangup(struct cdr_object *cdr)
-{
- if (ast_test_flag(&cdr->party_a->flags, AST_FLAG_ZOMBIE)) {
- transition_state(cdr, &hangup_state_fn_table);
- }
-}
-
-/* SINGLE STATE */
-
-static void single_active_state_process_channel_message(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
-{
- ast_assert(cdr != NULL);
- ast_assert(snapshot != NULL);
-
- if (!strcmp(snapshot->name, cdr->party_a->name)) {
- ao2_ref(cdr->party_a, -1);
- cdr->party_a = snapshot;
- ao2_ref(cdr->party_a, +1);
- }
- check_for_hangup();
-}
-
-
-
/*! \brief The global options available for CDRs */
struct cdr_config {
struct ast_flags settings; /*< CDR settings */
@@ -376,6 +313,307 @@
/* these are used to wake up the CDR thread when there's work to do */
AST_MUTEX_DEFINE_STATIC(cdr_pending_lock);
static ast_cond_t cdr_pending_cond;
+
+
+
+
+
+
+
+
+
+static struct stasis_subscription *channel_state_sub;
+
+struct cdr_object;
+
+struct cdr_object_fn_table {
+ void (* const init_function)(struct cdr_object *cdr);
+ void (* const process_channel_message)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+ void (* const process_channel_varset_message)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot, const char *name, const char *value);
+};
+
+static void single_state_process_channel_message(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+static void single_state_process_channel_varset_message(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot, const char *name, const char *value);
+
+struct cdr_object_fn_table single_state_fn_table = {
+ .process_channel_message = single_state_process_channel_message,
+ .process_channel_varset_message = single_state_process_channel_varset_message,
+};
+
+static void hangup_state_init_function(struct cdr_object *cdr);
+
+struct cdr_object_fn_table hangup_state_fn_table = {
+ .init_function = hangup_state_init_function,
+ .process_channel_message = NULL,
+ .process_channel_varset_message = NULL,
+};
+
+enum cdr_object_timestamps {
+ CDR_OBJECT_TIME_CREATED = 0,
+ CDR_OBJECT_TIME_ANSWERED,
+ CDR_OBJECT_TIME_FINALIZED,
+ CDR_OBJECT_TIME_LENGTH, /* Must be last */
+};
+
+struct cdr_object {
+ struct ast_channel_snapshot *party_a;
+ struct varshead party_a_variables;
+ struct ast_channel_snapshot *party_b;
+ struct varshead party_b_variables;
+ struct cdr_object_fn_table *fn_table;
+
+ unsigned int disposition;
+ struct timeval timestamps[CDR_OBJECT_TIME_LENGTH];
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(linkedid);
+ );
+ struct cdr_object *next;
+};
+
+/* NON-VIRTUAL FUNCTIONS */
+
+static void cdr_object_destructor(void *obj)
+{
+ struct cdr_object *cdr = obj;
+ struct ast_var_t *it_var;
+
+ if (!cdr) {
+ return;
+ }
+
+ ao2_cleanup(cdr->party_a);
+ ao2_cleanup(cdr->party_b);
+ while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_a_variables, entries))) {
+ ast_var_delete(it_var);
+ }
+ while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_b_variables, entries))) {
+ ast_var_delete(it_var);
+ }
+ ast_string_field_free_memory(cdr);
+
+ if (cdr->next) {
+ ao2_cleanup(cdr->next);
+ }
+}
+
+static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
+{
+ struct cdr_object *cdr;
+
+ ast_assert(chan != NULL);
+
+ cdr = ao2_alloc(sizeof(*cdr), cdr_object_destructor);
+ if (!cdr) {
+ return NULL;
+ }
+ ast_string_field_init(cdr, 64);
+
+ cdr->party_a = chan;
+ ast_string_field_set(cdr, linkedid, chan->linkedid);
+ ao2_ref(cdr->party_a, +1);
+
+ return cdr;
+}
+
+static struct ast_cdr *create_public_cdr_records(struct cdr_object *cdr)
+{
+ struct ast_cdr *pub_cdr = NULL, *cdr_prev;
+ struct ast_var_t *it_var, *it_copy_var;
+
+ while (cdr) {
+ struct ast_cdr *cdr_copy;
+ cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
+ if (!cdr_copy) {
+ ast_free(pub_cdr);
+ return NULL;
+ }
+
+ /* Party A */
+ ast_copy_string(cdr_copy->accountcode, cdr->party_a->accountcode, sizeof(cdr_copy->accountcode));
+ cdr_copy->amaflags = cdr->party_a->amaflags;
+ ast_copy_string(cdr_copy->channel, cdr->party_a->name, sizeof(cdr_copy->channel));
+ /* XXX TODO: we need to get the full caller ID somehow */
+ ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), cdr->party_a->caller_name, cdr->party_a->caller_number, "");
+ ast_copy_string(cdr_copy->src, cdr->party_a->caller_number, sizeof(cdr_copy->src));
+ ast_copy_string(cdr_copy->uniqueid, cdr->party_a->uniqueid, sizeof(cdr_copy->uniqueid));
+ ast_copy_string(cdr_copy->lastapp, cdr->party_a->appl, sizeof(cdr_copy->lastapp));
+ ast_copy_string(cdr_copy->lastdata, cdr->party_a->data, sizeof(cdr_copy->lastdata));
+ ast_copy_string(cdr_copy->dst, cdr->party_a->exten, sizeof(cdr_copy->dst));
+ ast_copy_string(cdr_copy->dcontext, cdr->party_a->context, sizeof(cdr_copy->dcontext));
+ ast_copy_string(cdr_copy->userfield, cdr->party_a->userfield, sizeof(cdr_copy->userfield));
+
+
+ /* Party B */
+ ast_copy_string(cdr_copy->dstchannel, cdr->party_b->name, sizeof(cdr_copy->dstchannel));
+ ast_copy_string(cdr_copy->peeraccount, cdr->party_b->accountcode, sizeof(cdr_copy->peeraccount));
+
+ /* Timestamps */
+ cdr_copy->start = cdr->timestamps[CDR_OBJECT_TIME_CREATED];
+ cdr_copy->answer = cdr->timestamps[CDR_OBJECT_TIME_ANSWERED];
+ cdr_copy->end = cdr->timestamps[CDR_OBJECT_TIME_FINALIZED];
+
+ /* Durations */
+ cdr_copy->billsec = ast_tvzero(cdr->timestamps[CDR_OBJECT_TIME_ANSWERED]) ?
+ (long)(ast_tvdiff_ms(cdr->timestamps[CDR_OBJECT_TIME_FINALIZED], cdr->timestamps[CDR_OBJECT_TIME_CREATED]) / 1000) :
+ (long)(ast_tvdiff_ms(cdr->timestamps[CDR_OBJECT_TIME_FINALIZED], cdr->timestamps[CDR_OBJECT_TIME_ANSWERED]) / 1000);
+ cdr_copy->duration = (long)(ast_tvdiff_ms(cdr->timestamps[CDR_OBJECT_TIME_FINALIZED], cdr->timestamps[CDR_OBJECT_TIME_ANSWERED]) / 1000);
+
+ ast_copy_string(cdr_copy->linkedid, cdr->linkedid, sizeof(cdr_copy->linkedid));
+ cdr_copy->disposition = cdr->disposition;
+ cdr_copy->sequence = ast_atomic_fetchadd_int(&cdr_sequence, +1);
+
+ AST_LIST_TRAVERSE(&cdr->party_a_variables, it_var, entries) {
+ AST_LIST_INSERT_TAIL(&cdr_copy->varshead, ast_var_assign(ast_var_name(it_var), ast_var_value(it_var)), entries);
+ }
+ AST_LIST_TRAVERSE(&cdr->party_b_variables, it_var, entries) {
+ int found = 0;
+ AST_LIST_TRAVERSE(&cdr_copy->varshead, it_copy_var, entries) {
+ if (!strcmp(ast_var_name(it_var), ast_var_name(it_copy_var))) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ AST_LIST_INSERT_TAIL(&cdr_copy->varshead, ast_var_assign(ast_var_name(it_var), ast_var_value(it_var)), entries);
+ }
+ }
+
+ if (!pub_cdr) {
+ pub_cdr = cdr_copy;
+ cdr_prev = pub_cdr;
+ } else {
+ cdr_prev->next = cdr_copy;
+ cdr_prev = cdr_copy;
+ }
+ cdr = cdr->next;
+ }
+
+ return pub_cdr;
+}
+
+static void dispatch_cdr_record(struct cdr_object *cdr)
+{
+ struct ast_cdr *pub_cdr;
+
+ /* We shouldn't be dispatching unless party A is hung up */
+ ast_assert(cdr->fn_table == &hangup_state_fn_table);
+
+ pub_cdr = create_public_cdr_records(cdr);
+ ast_cdr_detach(pub_cdr);
+ ast_cdr_free(pub_cdr);
+
+
+}
+
+static void transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
+{
+ cdr->fn_table = fn_table;
+ if (cdr->fn_table->init_function) {
+ cdr->fn_table->init_function(cdr);
+ }
+}
+
+static void check_for_hangup(struct cdr_object *cdr)
+{
+ if (ast_test_flag(&cdr->party_a->flags, AST_FLAG_ZOMBIE)) {
+ transition_state(cdr, &hangup_state_fn_table);
+ }
+}
+
+/* SINGLE STATE */
+
+static void single_state_process_channel_message(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+{
+ ast_assert(cdr != NULL);
+ ast_assert(snapshot != NULL);
+
+ if (strcmp(snapshot->name, cdr->party_a->name)) {
+ return;
+ }
+
+ ao2_ref(cdr->party_a, -1);
+ cdr->party_a = snapshot;
+ ao2_ref(cdr->party_a, +1);
+ check_for_hangup(cdr);
+}
+
+static void single_state_process_channel_varset_message(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot, const char *name, const char *value)
+{
+ return;
+}
+
+/* HANGUP STATE */
+
+static void hangup_state_init_function(struct cdr_object *cdr) {
+ RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
+
+ if (ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)) {
+ /* DO something? */
+ }
+
+ /* Set the end time if it isn't yet set */
+ if (ast_tvzero(cdr->timestamps[CDR_OBJECT_TIME_FINALIZED])) {
+ cdr->timestamps[CDR_OBJECT_TIME_FINALIZED] = ast_tvnow();
+ }
+
+ if (!ast_tvzero(cdr->timestamps[CDR_OBJECT_TIME_ANSWERED])) {
+ cdr->disposition = AST_CDR_ANSWERED;
+ }
+
+ /* Change the disposition based on the hang up cause */
+ switch (cdr->party_a->hangupcause) {
+ case AST_CAUSE_BUSY:
+ cdr->disposition = AST_CDR_BUSY;
+ break;
+ case AST_CAUSE_CONGESTION:
+ cdr->disposition = AST_CDR_CONGESTION;
+ break;
+ case AST_CAUSE_NO_ROUTE_DESTINATION:
+ case AST_CAUSE_UNREGISTERED:
+ cdr->disposition = AST_CDR_FAILED;
+ break;
+ case AST_CAUSE_NO_ANSWER:
+ cdr->disposition = AST_CDR_NOANSWER;
+ break;
+ default:
+ break;
+ }
+
+ dispatch_cdr_record(cdr);
+}
+
+
+
+
+/* TOPIC CALLBACKS */
+
+static void channel_topic_callback(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message)
+{
+ if (stasis_message_type(message) == stasis_cache_update()) {
+ struct stasis_cache_update *update = stasis_message_data(message);
+ if (ast_channel_snapshot() == update->type) {
+ struct ast_channel_snapshot *old_snapshot =
+ stasis_message_data(update->old_snapshot);
+ struct ast_channel_snapshot *new_snapshot =
+ stasis_message_data(update->new_snapshot);
+
+ }
+ } else if (stasis_message_type(message) == ast_channel_varset()) {
+ struct ast_channel_varset *varset = stasis_message_data(message);
+ const char *name = varset->snapshot ? varset->snapshot->name : "none";
+ const char *uniqueid = varset->snapshot ? varset->snapshot->uniqueid : "none";
+
+ }
+}
+
+
+
+
+
+
+
+
+
int check_cdr_enabled(void)
{
@@ -753,18 +991,6 @@
}
}
-/*! \brief the same as a cdr_free call, only with no checks; just get rid of it */
-void ast_cdr_discard(struct ast_cdr *cdr)
-{
- while (cdr) {
- struct ast_cdr *next = cdr->next;
-
- ast_cdr_free_vars(cdr, 0);
- ast_free(cdr);
- cdr = next;
- }
-}
-
struct ast_cdr *ast_cdr_alloc(void)
{
struct ast_cdr *x;
@@ -772,225 +998,6 @@
if (!x)
ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
return x;
-}
-
-static void cdr_merge_vars(struct ast_cdr *to, struct ast_cdr *from)
-{
- struct ast_var_t *variablesfrom,*variablesto;
- struct varshead *headpfrom = &to->varshead;
- struct varshead *headpto = &from->varshead;
- AST_LIST_TRAVERSE_SAFE_BEGIN(headpfrom, variablesfrom, entries) {
- /* for every var in from, stick it in to */
- const char *fromvarname, *fromvarval;
- const char *tovarname = NULL, *tovarval = NULL;
- fromvarname = ast_var_name(variablesfrom);
- fromvarval = ast_var_value(variablesfrom);
- tovarname = 0;
-
- /* now, quick see if that var is in the 'to' cdr already */
- AST_LIST_TRAVERSE(headpto, variablesto, entries) {
-
- /* now, quick see if that var is in the 'to' cdr already */
- if ( strcasecmp(fromvarname, ast_var_name(variablesto)) == 0 ) {
- tovarname = ast_var_name(variablesto);
- tovarval = ast_var_value(variablesto);
- break;
- }
- }
- if (tovarname && strcasecmp(fromvarval,tovarval) != 0) { /* this message here to see how irritating the userbase finds it */
- ast_log(LOG_NOTICE, "Merging CDR's: variable %s value %s dropped in favor of value %s\n", tovarname, fromvarval, tovarval);
- continue;
- } else if (tovarname && strcasecmp(fromvarval,tovarval) == 0) /* if they are the same, the job is done */
- continue;
-
- /* rip this var out of the from cdr, and stick it in the to cdr */
- AST_LIST_MOVE_CURRENT(headpto, entries);
- }
- AST_LIST_TRAVERSE_SAFE_END;
-}
-
-void ast_cdr_merge(struct ast_cdr *to, struct ast_cdr *from)
-{
- struct ast_cdr *zcdr;
- struct ast_cdr *lto = NULL;
- struct ast_cdr *lfrom = NULL;
- int discard_from = 0;
-
- if (!to || !from)
- return;
-
- /* don't merge into locked CDR's -- it's bad business */
- if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
- zcdr = to; /* safety valve? */
- while (to->next) {
- lto = to;
- to = to->next;
- }
-
- if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
- ast_log(LOG_WARNING, "Merging into locked CDR... no choice.\n");
- to = zcdr; /* safety-- if all there are is locked CDR's, then.... ?? */
- lto = NULL;
- }
- }
-
- if (ast_test_flag(from, AST_CDR_FLAG_LOCKED)) {
- struct ast_cdr *llfrom = NULL;
- discard_from = 1;
- if (lto) {
- /* insert the from stuff after lto */
- lto->next = from;
- lfrom = from;
- while (lfrom && lfrom->next) {
- if (!lfrom->next->next)
- llfrom = lfrom;
- lfrom = lfrom->next;
- }
- /* rip off the last entry and put a copy of the to at the end */
- if (llfrom) {
- llfrom->next = to;
- }
- from = lfrom;
- } else {
- /* save copy of the current *to cdr */
- struct ast_cdr tcdr;
- memcpy(&tcdr, to, sizeof(tcdr));
- /* copy in the locked from cdr */
- memcpy(to, from, sizeof(*to));
- lfrom = from;
- while (lfrom && lfrom->next) {
- if (!lfrom->next->next)
- llfrom = lfrom;
- lfrom = lfrom->next;
- }
- from->next = NULL;
- /* rip off the last entry and put a copy of the to at the end */
- if (llfrom == from) {
- to = to->next = ast_cdr_dup(&tcdr);
- } else if (llfrom) {
- to = llfrom->next = ast_cdr_dup(&tcdr);
- }
- from = lfrom;
- }
- }
-
- if (!ast_tvzero(from->start)) {
- if (!ast_tvzero(to->start)) {
- if (ast_tvcmp(to->start, from->start) > 0 ) {
- to->start = from->start; /* use the earliest time */
- from->start = ast_tv(0,0); /* we actively "steal" these values */
- }
- /* else nothing to do */
- } else {
- to->start = from->start;
- from->start = ast_tv(0,0); /* we actively "steal" these values */
- }
- }
- if (!ast_tvzero(from->answer)) {
- if (!ast_tvzero(to->answer)) {
- if (ast_tvcmp(to->answer, from->answer) > 0 ) {
- to->answer = from->answer; /* use the earliest time */
- from->answer = ast_tv(0,0); /* we actively "steal" these values */
- }
- /* we got the earliest answer time, so we'll settle for that? */
- } else {
- to->answer = from->answer;
- from->answer = ast_tv(0,0); /* we actively "steal" these values */
- }
- }
- if (!ast_tvzero(from->end)) {
- if (!ast_tvzero(to->end)) {
- if (ast_tvcmp(to->end, from->end) < 0 ) {
- to->end = from->end; /* use the latest time */
- from->end = ast_tv(0,0); /* we actively "steal" these values */
- to->duration = to->end.tv_sec - to->start.tv_sec; /* don't forget to update the duration, billsec, when we set end */
- to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
- }
- /* else, nothing to do */
- } else {
- to->end = from->end;
- from->end = ast_tv(0,0); /* we actively "steal" these values */
- to->duration = to->end.tv_sec - to->start.tv_sec;
- to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
- }
- }
- if (to->disposition < from->disposition) {
- to->disposition = from->disposition;
- from->disposition = AST_CDR_NOANSWER;
- }
- if (ast_strlen_zero(to->lastapp) && !ast_strlen_zero(from->lastapp)) {
- ast_copy_string(to->lastapp, from->lastapp, sizeof(to->lastapp));
- from->lastapp[0] = 0; /* theft */
- }
- if (ast_strlen_zero(to->lastdata) && !ast_strlen_zero(from->lastdata)) {
- ast_copy_string(to->lastdata, from->lastdata, sizeof(to->lastdata));
- from->lastdata[0] = 0; /* theft */
- }
- if (ast_strlen_zero(to->dcontext) && !ast_strlen_zero(from->dcontext)) {
- ast_copy_string(to->dcontext, from->dcontext, sizeof(to->dcontext));
- from->dcontext[0] = 0; /* theft */
- }
- if (ast_strlen_zero(to->dstchannel) && !ast_strlen_zero(from->dstchannel)) {
- ast_copy_string(to->dstchannel, from->dstchannel, sizeof(to->dstchannel));
- from->dstchannel[0] = 0; /* theft */
- }
- if (!ast_strlen_zero(from->channel) && (ast_strlen_zero(to->channel) || !strncasecmp(from->channel, "Agent/", 6))) {
- ast_copy_string(to->channel, from->channel, sizeof(to->channel));
- from->channel[0] = 0; /* theft */
- }
- if (ast_strlen_zero(to->src) && !ast_strlen_zero(from->src)) {
- ast_copy_string(to->src, from->src, sizeof(to->src));
- from->src[0] = 0; /* theft */
- }
- if (ast_strlen_zero(to->clid) && !ast_strlen_zero(from->clid)) {
- ast_copy_string(to->clid, from->clid, sizeof(to->clid));
- from->clid[0] = 0; /* theft */
- }
- if (ast_strlen_zero(to->dst) && !ast_strlen_zero(from->dst)) {
- ast_copy_string(to->dst, from->dst, sizeof(to->dst));
- from->dst[0] = 0; /* theft */
- }
- if (!to->amaflags)
- to->amaflags = AST_CDR_DOCUMENTATION;
- if (!from->amaflags)
- from->amaflags = AST_CDR_DOCUMENTATION; /* make sure both amaflags are set to something (DOC is default) */
- if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (to->amaflags == AST_CDR_DOCUMENTATION && from->amaflags != AST_CDR_DOCUMENTATION)) {
- to->amaflags = from->amaflags;
- }
- if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->accountcode) && !ast_strlen_zero(from->accountcode))) {
- ast_copy_string(to->accountcode, from->accountcode, sizeof(to->accountcode));
- }
- if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->peeraccount) && !ast_strlen_zero(from->peeraccount))) {
- ast_copy_string(to->peeraccount, from->peeraccount, sizeof(to->peeraccount));
- }
- if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->userfield) && !ast_strlen_zero(from->userfield))) {
- ast_copy_string(to->userfield, from->userfield, sizeof(to->userfield));
- }
- /* flags, varsead, ? */
- cdr_merge_vars(from, to);
-
- if (ast_test_flag(from, AST_CDR_FLAG_KEEP_VARS))
- ast_set_flag(to, AST_CDR_FLAG_KEEP_VARS);
- if (ast_test_flag(from, AST_CDR_FLAG_POSTED))
- ast_set_flag(to, AST_CDR_FLAG_POSTED);
- if (ast_test_flag(from, AST_CDR_FLAG_LOCKED))
- ast_set_flag(to, AST_CDR_FLAG_LOCKED);
- if (ast_test_flag(from, AST_CDR_FLAG_CHILD))
- ast_set_flag(to, AST_CDR_FLAG_CHILD);
- if (ast_test_flag(from, AST_CDR_FLAG_POST_DISABLED))
- ast_set_flag(to, AST_CDR_FLAG_POST_DISABLED);
-
- /* last, but not least, we need to merge any forked CDRs to the 'to' cdr */
- while (from->next) {
- /* just rip 'em off the 'from' and insert them on the 'to' */
- zcdr = from->next;
- from->next = zcdr->next;
- zcdr->next = NULL;
- /* zcdr is now ripped from the current list; */
- ast_cdr_append(to, zcdr);
- }
- if (discard_from)
- ast_cdr_discard(from);
}
void ast_cdr_start(struct ast_cdr *cdr)
@@ -1903,8 +1910,8 @@
}
channel_state_sub = stasis_subscribe(
- stasis_caching_get_topic(ast_channel_events_all_cached()),
- channel_message_cb, NULL);
+ stasis_caching_get_topic(ast_channel_topic_all_cached()),
+ channel_topic_callback, NULL);
sched = ast_sched_context_create();
if (!sched) {
Modified: team/mjordan/cdrs-of-doom/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/channel.c?view=diff&rev=382762&r1=382761&r2=382762
==============================================================================
--- team/mjordan/cdrs-of-doom/main/channel.c (original)
+++ team/mjordan/cdrs-of-doom/main/channel.c Fri Mar 8 17:43:22 2013
@@ -2521,7 +2521,7 @@
ast_jb_destroy(chan);
if (ast_channel_cdr(chan)) {
- ast_cdr_discard(ast_channel_cdr(chan));
+ ast_cdr_free(ast_channel_cdr(chan));
ast_channel_cdr_set(chan, NULL);
}
@@ -2581,7 +2581,7 @@
ast_var_delete(vardata);
if (ast_channel_cdr(chan)) {
- ast_cdr_discard(ast_channel_cdr(chan));
+ ast_cdr_free(ast_channel_cdr(chan));
ast_channel_cdr_set(chan, NULL);
}
@@ -2892,6 +2892,12 @@
ast_channel_unlock(chan);
+ /* XXX We need to publish before the hangup extensions are run. Some
+ * subscribers care about being in a particular state before those
+ * dialplan subroutines are executed.
+ */
+ publish_channel_state(chan);
+
/*
* XXX if running the hangup handlers here causes problems
* because the handlers take too long to execute, we could move
@@ -2950,7 +2956,6 @@
ast_cc_offer(chan);
- publish_channel_state(chan);
publish_cache_clear(chan);
if (ast_channel_cdr(chan) && !ast_test_flag(ast_channel_cdr(chan), AST_CDR_FLAG_BRIDGED) &&
Modified: team/mjordan/cdrs-of-doom/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/features.c?view=diff&rev=382762&r1=382761&r2=382762
==============================================================================
--- team/mjordan/cdrs-of-doom/main/features.c (original)
+++ team/mjordan/cdrs-of-doom/main/features.c Fri Mar 8 17:43:22 2013
@@ -4796,7 +4796,7 @@
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT)) {
ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
if (bridge_cdr) {
- ast_cdr_discard(bridge_cdr);
+ ast_cdr_free(bridge_cdr);
/* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
}
return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
Modified: team/mjordan/cdrs-of-doom/main/pbx.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/pbx.c?view=diff&rev=382762&r1=382761&r2=382762
==============================================================================
--- team/mjordan/cdrs-of-doom/main/pbx.c (original)
+++ team/mjordan/cdrs-of-doom/main/pbx.c Fri Mar 8 17:43:22 2013
@@ -9555,13 +9555,13 @@
/* Do not hold any channel locks while calling channel_alloc() since the function
* locks the channel container when linking the new channel in. */
if (!(tmpchan = ast_channel_alloc(0, tmpvars.state, 0, 0, tmpvars.accountcode, tmpvars.exten, tmpvars.context, tmpvars.linkedid, tmpvars.amaflags, "AsyncGoto/%s", tmpvars.name))) {
- ast_cdr_discard(tmpvars.cdr);
+ ast_cdr_free(tmpvars.cdr);
return -1;
}
/* copy the cdr info over */
if (tmpvars.cdr) {
- ast_cdr_discard(ast_channel_cdr(tmpchan));
+ ast_cdr_free(ast_channel_cdr(tmpchan));
ast_channel_cdr_set(tmpchan, tmpvars.cdr);
tmpvars.cdr = NULL;
}
Added: team/mjordan/cdrs-of-doom/tests/test_cdr.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/tests/test_cdr.c?view=auto&rev=382762
==============================================================================
--- team/mjordan/cdrs-of-doom/tests/test_cdr.c (added)
+++ team/mjordan/cdrs-of-doom/tests/test_cdr.c Fri Mar 8 17:43:22 2013
@@ -1,0 +1,455 @@
+/*
+ * test_cdrs.c
+ *
+ * Created on: Mar 3, 2013
+ * Author: mjordan
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "asterisk/cdr.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/chanvars.h"
+#include "asterisk/utils.h"
+
+#define MOCK_CDR_BACKEND "mock_cdr_backend"
+
+#define CHANNEL_TECH_NAME "CDRTestChannel"
+
+static AST_LIST_HEAD(, test_cdr_entry) actual_cdr_entries = AST_LIST_HEAD_INIT_VALUE;
+
+static struct ast_channel_tech test_cdr_chan_tech = {
+ .type = CHANNEL_TECH_NAME,
+ .description = "Mock channel technology for CDR tests",
+};
+
+struct test_cdr_entry {
+ struct ast_cdr *cdr;
+ AST_LIST_ENTRY(test_cdr_entry) list;
+};
+
+static int mock_cdr_backend(struct ast_cdr *cdr)
+{
+ struct ast_cdr *cdr_copy, *cdr_prev = NULL;
+ struct ast_cdr *mock_cdr = NULL;
+ struct test_cdr_entry *cdr_wrapper;
+
+ cdr_wrapper = ast_calloc(1, sizeof(*cdr_wrapper));
+ if (!cdr_wrapper) {
+ return -1;
+ }
+
+ for (; cdr; cdr = cdr->next) {
+ struct ast_var_t *var_entry, *var_copy;
+
+ cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
+ if (!cdr_copy) {
+ return -1;
+ }
+ *cdr_copy = *cdr;
+ cdr_copy->varshead.first = NULL;
+ cdr_copy->varshead.last = NULL;
+ cdr_copy->next = NULL;
+
+ AST_LIST_TRAVERSE(&cdr->varshead, var_entry, entries) {
+ var_copy = ast_var_assign(var_entry->name, var_entry->value);
+ if (!var_copy) {
+ return -1;
+ }
+ AST_LIST_INSERT_TAIL(&cdr_copy->varshead, var_copy, entries);
+ }
+
+ if (!mock_cdr) {
+ mock_cdr = cdr_copy;
+ }
+ if (cdr_prev) {
+ cdr_prev->next = cdr_copy;
+ }
+ cdr_prev = cdr_copy;
+ }
+ cdr_wrapper->cdr = mock_cdr;
+
+ AST_LIST_LOCK(&actual_cdr_entries);
+ AST_LIST_INSERT_TAIL(&actual_cdr_entries, cdr_wrapper, list);
+ AST_LIST_UNLOCK(&actual_cdr_entries);
+ return 0;
+}
+
+static void clear_mock_cdr_backend(void)
+{
+ struct test_cdr_entry *cdr_wrapper;
+
+ AST_LIST_LOCK(&actual_cdr_entries);
+ while ((cdr_wrapper = AST_LIST_REMOVE_HEAD(&actual_cdr_entries, list))) {
+ ast_cdr_free(cdr_wrapper->cdr);
+ ast_free(cdr_wrapper);
+ }
+ AST_LIST_UNLOCK(&actual_cdr_entries);
+}
+
+#define VERIFY_STRING_FIELD(field, actual, expected) do { \
+ if (strcmp((actual)->field, (expected)->field)) { \
+ ast_test_status_update(test, "Field %s failed: actual %s, expected %s\n", #field, (actual)->field, (expected)->field); \
+ ast_test_set_result(test, AST_TEST_FAIL); \
+ res = AST_TEST_FAIL; \
+ } } while (0)
+
+#define VERIFY_NUMERIC_FIELD(field, actual, expected) do { \
+ if ((actual)->field != (expected)->field) { \
+ ast_test_status_update(test, "Field %s failed: actual %ld, expected %ld\n", #field, (long)(actual)->field, (long)(expected)->field); \
+ ast_test_set_result(test, AST_TEST_FAIL); \
+ res = AST_TEST_FAIL; \
+ } } while (0)
+
+static enum ast_test_result_state verify_mock_cdr_record(struct ast_test *test, struct ast_cdr *expected, int record)
+{
+ struct ast_cdr *actual = NULL;
+ struct test_cdr_entry *cdr_wrapper;
+ int pos = 0;
+ enum ast_test_result_state res = AST_TEST_PASS;
+
+ AST_LIST_LOCK(&actual_cdr_entries);
+ AST_LIST_TRAVERSE(&actual_cdr_entries, cdr_wrapper, list) {
+ if (pos == record) {
+ actual = cdr_wrapper->cdr;
+ break;
+ }
+ pos++;
+ }
+ AST_LIST_UNLOCK(&actual_cdr_entries);
+
+ if (!actual) {
+ ast_test_status_update(test, "Unable to find actual CDR record at %d\n", record);
+ return AST_TEST_FAIL;
+ }
+
+ for (; actual && expected; actual = actual->next, expected = expected->next) {
+ VERIFY_STRING_FIELD(accountcode, actual, expected);
+ VERIFY_NUMERIC_FIELD(amaflags, actual, expected);
+ VERIFY_NUMERIC_FIELD(billsec, actual, expected);
+ VERIFY_STRING_FIELD(channel, actual, expected);
+ VERIFY_STRING_FIELD(clid, actual, expected);
+ VERIFY_STRING_FIELD(dcontext, actual, expected);
+ VERIFY_NUMERIC_FIELD(disposition, actual, expected);
+ VERIFY_STRING_FIELD(dst, actual, expected);
+ VERIFY_STRING_FIELD(dstchannel, actual, expected);
+ VERIFY_NUMERIC_FIELD(duration, actual, expected);
+ VERIFY_NUMERIC_FIELD(flags, actual, expected);
+ VERIFY_STRING_FIELD(lastapp, actual, expected);
+ VERIFY_STRING_FIELD(lastdata, actual, expected);
+ VERIFY_STRING_FIELD(linkedid, actual, expected);
+ VERIFY_STRING_FIELD(peeraccount, actual, expected);
+ VERIFY_NUMERIC_FIELD(sequence, actual, expected);
+ VERIFY_STRING_FIELD(src, actual, expected);
+ VERIFY_STRING_FIELD(uniqueid, actual, expected);
+ VERIFY_STRING_FIELD(userfield, actual, expected);
+ }
+
+ if (actual || expected) {
+ ast_test_status_update(test, "Unbalanced CDR records - %s had more than %s\n",
+ actual ? "actual" : "expected",
+ actual ? "actual" : "expected");
+ res = AST_TEST_FAIL;
+ }
+
+ return res;
+}
+
+static void safe_channel_release(struct ast_channel *chan)
+{
+ if (!chan) {
+ return;
+ }
+ ast_channel_release(chan);
+}
+
+AST_TEST_DEFINE(test_cdr_channel_creation)
+{
+ RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ struct ast_cdr expected = {
+ .clid = "Alice <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .dstchannel = "",
+ .lastapp = "",
+ .lastdata = "",
+ .duration = 0,
+ .billsec = 0,
+ .amaflags = 0,
+ .disposition = AST_CDR_NOANSWER,
+ .accountcode = "100",
+ .peeraccount = "",
+ .flags = 0,
+ };
+ enum ast_test_result_state result = AST_TEST_NOT_RUN;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "cdr_channel_creation";
+ info->category = "/main/cdr/";
+ info->summary = "Test that a CDR is created when a channel is created";
+ info->description =
+ "Test that a CDR is created when a channel is created";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice");
+ ast_copy_string(expected.uniqueid, ast_channel_uniqueid(chan), sizeof(expected.uniqueid));
+ ast_copy_string(expected.linkedid, ast_channel_linkedid(chan), sizeof(expected.linkedid));
+ if (!ast_hangup(chan)) {
+ chan = NULL;
+ }
+
+ result = verify_mock_cdr_record(test, &expected, 0);
+
+ return result;
+}
+
+AST_TEST_DEFINE(test_cdr_unanswered_inbound_call)
+{
+ RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+
+ struct ast_cdr expected = {
+ .clid = "Alice <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .dstchannel = "",
+ .lastapp = "Wait",
+ .lastdata = "1",
+ .duration = 0,
+ .billsec = 0,
+ .amaflags = 0,
+ .disposition = AST_CDR_NOANSWER,
+ .accountcode = "100",
+ .peeraccount = "",
+ .flags = 0,
+ };
+ enum ast_test_result_state result = AST_TEST_NOT_RUN;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "cdr_unanswered_inbound_call";
+ info->category = "/main/cdr/";
+ info->summary = "Test inbound unanswered calls";
+ info->description =
+ "Test the properties of a CDR for a call that is\n"
+ "inbound to Asterisk, executes some dialplan, but\n"
+ "is never answered.\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice");
+ ast_copy_string(expected.uniqueid, ast_channel_uniqueid(chan), sizeof(expected.uniqueid));
+ ast_copy_string(expected.linkedid, ast_channel_linkedid(chan), sizeof(expected.linkedid));
+
+ snapshot = ast_channel_snapshot_create(chan);
+ ast_assert(snapshot != NULL);
+ ast_string_field_set(snapshot, appl, "Wait");
+ ast_string_field_set(snapshot, data, "1");
+
+ message = stasis_message_create(ast_channel_snapshot(), snapshot);
+ ast_assert(message != NULL);
+
+ stasis_publish(ast_channel_topic(chan), message);
+
+ if (!ast_hangup(chan)) {
+ chan = NULL;
+ }
+
+ result = verify_mock_cdr_record(test, &expected, 0);
+
+ return result;
+}
+
+AST_TEST_DEFINE(test_cdr_unanswered_outbound_call)
+{
+ RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+
+ struct ast_cdr expected = {
+ .clid = "",
+ .src = "",
+ .dst = "s",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .dstchannel = "",
+ .lastapp = "",
+ .lastdata = "",
+ .duration = 0,
+ .billsec = 0,
+ .amaflags = 0,
+ .disposition = AST_CDR_NOANSWER,
+ .accountcode = "100",
+ .peeraccount = "",
+ .flags = 0,
+ };
+ enum ast_test_result_state result = AST_TEST_NOT_RUN;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "cdr_unanswered_outbound_call";
+ info->category = "/main/cdr/";
+ info->summary = "Test outbound unanswered calls";
+ info->description =
+ "Test the properties of a CDR for a call that is\n"
+ "outbound to Asterisk but is never answered.\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice");
+ ast_copy_string(expected.uniqueid, ast_channel_uniqueid(chan), sizeof(expected.uniqueid));
+ ast_copy_string(expected.linkedid, ast_channel_linkedid(chan), sizeof(expected.linkedid));
+
+ snapshot = ast_channel_snapshot_create(chan);
+ ast_assert(snapshot != NULL);
+ ast_string_field_set(snapshot, appl, "Dial");
+ ast_string_field_set(snapshot, data, CHANNEL_TECH_NAME "/Alice");
+
+ message = stasis_message_create(ast_channel_snapshot(), snapshot);
+ ast_assert(message != NULL);
+
+ stasis_publish(ast_channel_topic(chan), message);
+
+ ast_channel_publish_varset(chan, "DIALSTATUS", "NOANSWER");
+
+ result = verify_mock_cdr_record(test, &expected, 0);
+
+ return result;
+}
+
+AST_TEST_DEFINE(test_cdr_single_party)
+{
+ RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+
+ struct ast_cdr expected = {
+ .clid = "Alice <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .dstchannel = "",
+ .lastapp = "Wait",
+ .lastdata = "1",
+ .duration = 0,
+ .billsec = 0,
+ .amaflags = 0,
+ .disposition = AST_CDR_ANSWERED,
+ .accountcode = "100",
+ .peeraccount = "",
+ .flags = 0,
+ };
+ enum ast_test_result_state result = AST_TEST_NOT_RUN;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "cdr_single_party";
+ info->category = "/main/cdr/";
+ info->summary = "Test cdrs for a single party";
+ info->description =
+ "Test the properties of a CDR for a call that is\n"
+ "answered, but only involves a single channel\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice");
+ ast_copy_string(expected.uniqueid, ast_channel_uniqueid(chan), sizeof(expected.uniqueid));
+ ast_copy_string(expected.linkedid, ast_channel_linkedid(chan), sizeof(expected.linkedid));
+
+ /* Channel enters Answer app */
+ snapshot = ast_channel_snapshot_create(chan);
+ ast_assert(snapshot != NULL);
+ ast_string_field_set(snapshot, appl, "Answer");
+ snapshot->priority = 1;
+ message = stasis_message_create(ast_channel_snapshot(), snapshot);
+ ast_assert(message != NULL);
+
+ stasis_publish(ast_channel_topic(chan), message);
+ ao2_cleanup(snapshot);
+ ao2_cleanup(message);
+
+ /* Answer the channel */
+ snapshot = ast_channel_snapshot_create(chan);
+ ast_assert(snapshot != NULL);
+ ast_string_field_set(snapshot, appl, "Answer");
+ snapshot->priority = 1;
+ snapshot->state = AST_STATE_UP;
+ message = stasis_message_create(ast_channel_snapshot(), snapshot);
+ ast_assert(message != NULL);
+
+ stasis_publish(ast_channel_topic(chan), message);
+ ao2_cleanup(snapshot);
+ ao2_cleanup(message);
+
+ /* Channel enters the Wait app */
+ snapshot = ast_channel_snapshot_create(chan);
+ ast_assert(snapshot != NULL);
+ ast_string_field_set(snapshot, appl, "Wait");
+ ast_string_field_set(snapshot, data, "1");
+ snapshot->priority = 2;
+ message = stasis_message_create(ast_channel_snapshot(), snapshot);
+ ast_assert(message != NULL);
+
+ stasis_publish(ast_channel_topic(chan), message);
+
+ if (!ast_hangup(chan)) {
+ chan = NULL;
+ }
+
+ result = verify_mock_cdr_record(test, &expected, 0);
+
+ return result;
+}
+
+static int unload_module(void)
+{
+ AST_TEST_UNREGISTER(test_cdr_channel_creation);
+ AST_TEST_UNREGISTER(test_cdr_unanswered_inbound_call);
+ AST_TEST_UNREGISTER(test_cdr_unanswered_outbound_call);
+ AST_TEST_UNREGISTER(test_cdr_single_party);
+
+ ast_cdr_unregister(MOCK_CDR_BACKEND);
+ ast_channel_unregister(&test_cdr_chan_tech);
+ clear_mock_cdr_backend();
+ return 0;
+}
+
+static int load_module(void)
+{
+ AST_TEST_REGISTER(test_cdr_channel_creation);
+ AST_TEST_REGISTER(test_cdr_unanswered_inbound_call);
+ AST_TEST_REGISTER(test_cdr_unanswered_outbound_call);
+ AST_TEST_REGISTER(test_cdr_single_party);
+
+ ast_channel_register(&test_cdr_chan_tech);
+ ast_cdr_register(MOCK_CDR_BACKEND, "Mock CDR backend", mock_cdr_backend);
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
[... 14 lines stripped ...]
More information about the asterisk-commits
mailing list