[svn-commits] mjordan: branch mjordan/cdrs-of-doom r384475 - in /team/mjordan/cdrs-of-doom:...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Mon Apr 1 12:02:59 CDT 2013
Author: mjordan
Date: Mon Apr 1 12:02:56 2013
New Revision: 384475
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=384475
Log:
Update dial unit tests
Now with actual working parallel unanswered CDRs. And unit tests that
don't block waiting for a CDR that never comes. And that take into
account the backends weird way of dispatching CDRs that have a chain
but that still dispatch each CDR in that chain.
A->B->C
B->C
C
Ew.
Modified:
team/mjordan/cdrs-of-doom/main/cdr.c
team/mjordan/cdrs-of-doom/tests/test_cdr.c
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=384475&r1=384474&r2=384475
==============================================================================
--- team/mjordan/cdrs-of-doom/main/cdr.c (original)
+++ team/mjordan/cdrs-of-doom/main/cdr.c Mon Apr 1 12:02:56 2013
@@ -202,7 +202,7 @@
/*! \brief The configuration settings for this module */
struct module_config {
- struct cdr_config *general; /*< CDR global settings */
+ struct ast_cdr_config *general; /*< CDR global settings */
};
/*! \brief The container for the module configuration */
@@ -247,7 +247,7 @@
static void *module_config_alloc(void)
{
struct module_config *mod_cfg;
- struct cdr_config *cdr_config;
+ struct ast_cdr_config *cdr_config;
mod_cfg = ao2_alloc(sizeof(*mod_cfg), module_config_destructor);
if (!mod_cfg) {
@@ -313,13 +313,13 @@
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);
- void (* const process_dial_message)(struct cdr_object *cdr, struct ast_channel_dial *dial_message);
+ int (* const process_dial_message)(struct cdr_object *cdr, struct ast_channel_dial *dial_message);
};
static void single_state_init_function(struct cdr_object *cdr);
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);
-static void single_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_dial *dial_message);
+static int single_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_dial *dial_message);
struct cdr_object_fn_table single_state_fn_table = {
.name = "Single",
@@ -331,7 +331,7 @@
static void dial_state_init_function(struct cdr_object *cdr);
static void dial_state_process_channel_message(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static void dial_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_dial *dial_message);
+static int dial_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_dial *dial_message);
struct cdr_object_fn_table dial_state_fn_table = {
.name = "Dial",
@@ -393,7 +393,7 @@
return strcasecmp(left->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
}
-static void cdr_object_destructor(void *obj)
+static void cdr_object_dtor(void *obj)
{
struct cdr_object *cdr = obj;
struct ast_var_t *it_var;
@@ -419,11 +419,12 @@
static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
{
+ RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
struct cdr_object *cdr;
ast_assert(chan != NULL);
- cdr = ao2_alloc(sizeof(*cdr), cdr_object_destructor);
+ cdr = ao2_alloc(sizeof(*cdr), cdr_object_dtor);
if (!cdr) {
return NULL;
}
@@ -434,6 +435,8 @@
ast_string_field_set(cdr, linkedid, chan->linkedid);
ao2_ref(cdr->party_a, +1);
+ CDR_DEBUG(mod_cfg, "%p - created CDR for channel %s\n", cdr, chan->name);
+
transition_state(cdr, &single_state_fn_table);
return cdr;
@@ -449,6 +452,9 @@
}
/* TODO copy the variables over */
+ while (cdr->next) {
+ cdr = cdr->next;
+ }
cdr->next = new_cdr;
return new_cdr;
}
@@ -538,7 +544,8 @@
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
struct ast_cdr *pub_cdr;
- CDR_DEBUG(mod_cfg, "%p - Dispatching CDR for Party A %s\n", cdr, cdr->party_a->name);
+ CDR_DEBUG(mod_cfg, "%p - Dispatching CDR for Party A %s, Party B %s\n", cdr, cdr->party_a->name,
+ cdr->party_b ? cdr->party_b->name : "<none>");
pub_cdr = create_public_cdr_records(cdr);
ast_cdr_detach(pub_cdr);
}
@@ -547,7 +554,6 @@
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
- /* If the end time is set, we've been finalized already */
if (ast_tvzero(cdr->timestamps[CDR_OBJECT_TIME_FINALIZED])) {
cdr->timestamps[CDR_OBJECT_TIME_FINALIZED] = ast_tvnow();
}
@@ -655,14 +661,14 @@
return;
}
-static void single_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_dial *message)
+static int single_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_dial *message)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
struct ast_channel_snapshot *caller = message->caller;
struct ast_channel_snapshot *peer = message->peer;
+ /* We shouldn't get a Dial end without first transitioning to a dial state */
ast_assert(ast_strlen_zero(message->dialstatus));
- ast_assert(!ast_strlen_zero(message->dialstring));
if (caller && !strcmp(cdr->party_a->name, caller->name)) {
cdr->party_a = swap_channel_snapshot(cdr->party_a, caller);
@@ -676,6 +682,7 @@
}
transition_state(cdr, &dial_state_fn_table);
+ return 0;
}
/* DIAL STATE */
@@ -694,7 +701,6 @@
} else if (cdr->party_b && !strcmp(cdr->party_b->name, snapshot->name)) {
cdr->party_b = swap_channel_snapshot(cdr->party_b, snapshot);
} else {
- ast_log(AST_LOG_WARNING, "WTF\n");
ast_assert(0);
}
@@ -702,56 +708,50 @@
check_for_hangup(cdr);
}
-static void dial_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_dial *dial_message)
-{
+static int dial_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_dial *dial_message)
+{
+ RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
struct ast_channel_snapshot *caller = dial_message->caller;
struct ast_channel_snapshot *peer = dial_message->peer;
- struct cdr_object *new_cdr;
-
- ast_assert(!strcmp(cdr->party_a->name, caller->name));
- cdr->party_a = swap_channel_snapshot(cdr->party_a, caller);
-
- if (!ast_strlen_zero(dial_message->dialstatus)) {
+ struct ast_channel_snapshot *party_a;
+
+ if (caller) {
+ party_a = caller;
+ } else {
+ party_a = peer;
+ }
+ ast_assert(!strcmp(cdr->party_a->name, party_a->name));
+ cdr->party_a = swap_channel_snapshot(cdr->party_a, party_a);
+
+ if (ast_strlen_zero(dial_message->dialstatus)) {
+ /* If this isn't a dial end, don't process it here */
+ return 1;
+ }
+ if (cdr->party_b) {
if (strcmp(cdr->party_b->name, peer->name)) {
- /* Not our status, defer to the next CDR in the chain */
- ast_assert(cdr->next != NULL);
- ast_assert(cdr->next->fn_table->process_dial_message != NULL);
- cdr->next->fn_table->process_dial_message(cdr->next, dial_message);
- return;
- }
-
+ /* Not the status for this CDR */
+ return 1;
+ }
cdr->party_b = swap_channel_snapshot(cdr->party_b, peer);
- /* Set the party A hangup cause based on the dial string. A subsequent hangup
- * message will update this if needed. This will at least let us set the CDR
- * disposition properly.
- */
- if (!strcmp(dial_message->dialstatus, "BUSY")) {
- cdr->party_a->hangupcause = AST_CAUSE_BUSY;
- finalize_cdr_object(cdr);
- } else if (!strcmp(dial_message->dialstatus, "CANCEL")) {
- cdr->party_a->hangupcause = AST_CAUSE_NORMAL;
- finalize_cdr_object(cdr);
- } else if (!strcmp(dial_message->dialstatus, "CONGESTION")) {
- cdr->party_a->hangupcause = AST_CAUSE_CONGESTION;
- finalize_cdr_object(cdr);
- } else if (!strcmp(dial_message->dialstatus, "FAILED")) {
- cdr->party_a->hangupcause = AST_CAUSE_NO_ROUTE_DESTINATION;
- finalize_cdr_object(cdr);
- }
- /* TODO: if ANSWER, do NOTHING? */
- }
- if (!ast_strlen_zero(dial_message->dialstring)) {
- struct cdr_object *it_cdr = cdr;
- /* If we're in a dial and we get a new dial, then ... yay! new CDR. */
- /* No new dials if we aren't dialing someone ... */
- ast_assert(peer != NULL);
- while (it_cdr->next != NULL) {
- it_cdr = it_cdr->next;
- }
- new_cdr = create_and_append_cdr(it_cdr);
- new_cdr->party_b = swap_channel_snapshot(new_cdr->party_b, peer);
- transition_state(new_cdr, &dial_state_fn_table);
- }
+ }
+ /* Set the party A hangup cause based on the dial string. A
+ * subsequent hangup message will update this if needed.
+ */
+ if (!strcmp(dial_message->dialstatus, "BUSY")) {
+ cdr->party_a->hangupcause = AST_CAUSE_BUSY;
+ finalize_cdr_object(cdr);
+ } else if (!strcmp(dial_message->dialstatus, "CANCEL")) {
+ cdr->party_a->hangupcause = AST_CAUSE_NORMAL;
+ finalize_cdr_object(cdr);
+ } else if (!strcmp(dial_message->dialstatus, "CONGESTION")) {
+ cdr->party_a->hangupcause = AST_CAUSE_CONGESTION;
+ finalize_cdr_object(cdr);
+ } else if (!strcmp(dial_message->dialstatus, "FAILED")) {
+ cdr->party_a->hangupcause = AST_CAUSE_NO_ROUTE_DESTINATION;
+ finalize_cdr_object(cdr);
+ }
+ /* TODO: if ANSWER, do NOTHING? */
+ return 0;
}
@@ -815,6 +815,8 @@
struct ast_channel_dial *payload = stasis_message_data(message);
struct ast_channel_snapshot *party_a;
struct ast_channel_snapshot *party_b;
+ struct cdr_object *it_cdr;
+ int res = 1;
ast_assert(payload != NULL);
@@ -832,13 +834,33 @@
cdr = find_or_create_cdr_by_channel(party_a);
if (!cdr) {
- ast_assert(0);
+ ast_debug(1, "No CDR for %s; passing on dial message\n", party_a->name);
return;
}
+
+ if (ast_test_flag(&party_a->flags, AST_FLAG_OUTGOING)
+ && !ast_test_flag(&party_a->flags, AST_FLAG_ORIGINATED)) {
+ CDR_DEBUG(mod_cfg, "%p - removing CDR for outbound channel %s\n", cdr, party_a->name);
+ ao2_unlink(active_cdrs_by_channel, cdr);
+ return;
+ }
+
CDR_DEBUG(mod_cfg, "%p - processing dial message for channel %s, peer %s\n",
cdr, party_a->name, party_b ? party_b->name : "(none)");
- if (cdr->fn_table->process_dial_message) {
- cdr->fn_table->process_dial_message(cdr, payload);
+ for (it_cdr = cdr; res && it_cdr; it_cdr = it_cdr->next) {
+ if (it_cdr->fn_table->process_dial_message) {
+ res = it_cdr->fn_table->process_dial_message(it_cdr, payload);
+ }
+ }
+ /* If no CDR handled the dial message, make a new one */
+ if (res) {
+ struct cdr_object *new_cdr;
+
+ new_cdr = create_and_append_cdr(cdr);
+ if (!new_cdr) {
+ return;
+ }
+ new_cdr->fn_table->process_dial_message(new_cdr, payload);
}
}
@@ -847,6 +869,7 @@
RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
struct stasis_cache_update *update = stasis_message_data(message);
+ struct cdr_object *it_cdr;
ast_assert(update != NULL);
if (ast_channel_snapshot() == update->type) {
@@ -856,26 +879,37 @@
stasis_message_data(update->new_snapshot);
const char *name = new_snapshot ? new_snapshot->name : old_snapshot->name;
+ if (new_snapshot && ast_test_flag(&new_snapshot->flags, AST_FLAG_OUTGOING)
+ && !ast_test_flag(&new_snapshot->flags, AST_FLAG_ORIGINATED)) {
+ cdr = ao2_find(active_cdrs_by_channel, name, OBJ_KEY);
+ if (cdr) {
+ CDR_DEBUG(mod_cfg, "%p - removing CDR for outbound channel %s\n", cdr, name);
+ ao2_unlink(active_cdrs_by_channel, cdr);
+ }
+ return;
+ }
+
if (new_snapshot && !old_snapshot) {
cdr = cdr_object_alloc(new_snapshot);
if (!cdr) {
return;
}
- CDR_DEBUG(mod_cfg, "%p - created CDR for channel %s\n", cdr, name);
ao2_link(active_cdrs_by_channel, cdr);
}
if (!cdr) {
cdr = ao2_find(active_cdrs_by_channel, name, OBJ_KEY);
if (!cdr) {
- ast_log(AST_LOG_WARNING, "Unable to find CDR for channel %s\n", name);
+ ast_debug(1, "No CDR for channel %s\n", name);
return;
}
}
- if (cdr->fn_table->process_channel_message && new_snapshot) {
- CDR_DEBUG(mod_cfg, "%p - processing new channel snapshot %s\n", cdr, new_snapshot->name);
- cdr->fn_table->process_channel_message(cdr, new_snapshot);
+ for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
+ if (it_cdr->fn_table->process_channel_message && new_snapshot) {
+ CDR_DEBUG(mod_cfg, "%p - processing new channel snapshot %s\n", it_cdr, new_snapshot->name);
+ it_cdr->fn_table->process_channel_message(it_cdr, new_snapshot);
+ }
}
if (!new_snapshot) {
@@ -895,23 +929,19 @@
-struct cdr_config *ast_cdr_get_config(void)
+struct ast_cdr_config *ast_cdr_get_config(void)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
ao2_ref(mod_cfg->general, +1);
return mod_cfg->general;
}
-void ast_cdr_set_config(struct cdr_config *config)
-{
- RAII_VAR(struct module_config *, mod_cfg, module_config_alloc(), ao2_cleanup);
-
- if (!mod_cfg) {
- return;
- }
+void ast_cdr_set_config(struct ast_cdr_config *config)
+{
+ RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
ao2_cleanup(mod_cfg->general);
mod_cfg->general = config;
- ao2_global_obj_replace_unref(module_configs, mod_cfg);
+ ao2_ref(mod_cfg->general, +1);
}
int check_cdr_enabled(void)
@@ -2165,16 +2195,16 @@
return 1;
}
- aco_option_register(&cfg_info, "enable", ACO_EXACT, general_options, DEFAULT_ENABLED, OPT_BOOLFLAG_T, 1, FLDSET(struct cdr_config, settings), CDR_ENABLED);
- aco_option_register(&cfg_info, "unanswered", ACO_EXACT, general_options, DEFAULT_UNANSWERED, OPT_BOOLFLAG_T, 1, FLDSET(struct cdr_config, settings), CDR_UNANSWERED);
- aco_option_register(&cfg_info, "congestion", ACO_EXACT, general_options, DEFAULT_CONGESTION, OPT_BOOLFLAG_T, 1, FLDSET(struct cdr_config, settings), CDR_CONGESTION);
- aco_option_register(&cfg_info, "batch", ACO_EXACT, general_options, DEFAULT_BATCHMODE, OPT_BOOLFLAG_T, 1, FLDSET(struct cdr_config, settings), CDR_BATCHMODE);
- aco_option_register(&cfg_info, "endbeforehexten", ACO_EXACT, general_options, DEFAULT_END_BEFORE_H_EXTEN, OPT_BOOLFLAG_T, 1, FLDSET(struct cdr_config, settings), CDR_END_BEFORE_H_EXTEN);
- aco_option_register(&cfg_info, "initiatedseconds", ACO_EXACT, general_options, DEFAULT_INITIATED_SECONDS, OPT_BOOLFLAG_T, 1, FLDSET(struct cdr_config, settings), CDR_INITIATED_SECONDS);
- aco_option_register(&cfg_info, "scheduleronly", ACO_EXACT, general_options, DEFAULT_BATCH_SCHEDULER_ONLY, OPT_BOOLFLAG_T, 1, FLDSET(struct cdr_config, batch_settings.settings), BATCH_MODE_SCHEDULER_ONLY);
- aco_option_register(&cfg_info, "safeshutdown", ACO_EXACT, general_options, DEFAULT_BATCH_SAFE_SHUTDOWN, OPT_BOOLFLAG_T, 1, FLDSET(struct cdr_config, batch_settings.settings), BATCH_MODE_SAFE_SHUTDOWN);
- aco_option_register(&cfg_info, "size", ACO_EXACT, general_options, DEFAULT_BATCH_SIZE, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct cdr_config, batch_settings.size), 0, MAX_BATCH_SIZE);
- aco_option_register(&cfg_info, "time", ACO_EXACT, general_options, DEFAULT_BATCH_TIME, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct cdr_config, batch_settings.time), 0, MAX_BATCH_TIME);
+ aco_option_register(&cfg_info, "enable", ACO_EXACT, general_options, DEFAULT_ENABLED, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_ENABLED);
+ aco_option_register(&cfg_info, "unanswered", ACO_EXACT, general_options, DEFAULT_UNANSWERED, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_UNANSWERED);
+ aco_option_register(&cfg_info, "congestion", ACO_EXACT, general_options, DEFAULT_CONGESTION, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_CONGESTION);
+ aco_option_register(&cfg_info, "batch", ACO_EXACT, general_options, DEFAULT_BATCHMODE, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_BATCHMODE);
+ aco_option_register(&cfg_info, "endbeforehexten", ACO_EXACT, general_options, DEFAULT_END_BEFORE_H_EXTEN, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_END_BEFORE_H_EXTEN);
+ aco_option_register(&cfg_info, "initiatedseconds", ACO_EXACT, general_options, DEFAULT_INITIATED_SECONDS, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, settings), CDR_INITIATED_SECONDS);
+ aco_option_register(&cfg_info, "scheduleronly", ACO_EXACT, general_options, DEFAULT_BATCH_SCHEDULER_ONLY, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, batch_settings.settings), BATCH_MODE_SCHEDULER_ONLY);
+ aco_option_register(&cfg_info, "safeshutdown", ACO_EXACT, general_options, DEFAULT_BATCH_SAFE_SHUTDOWN, OPT_BOOLFLAG_T, 1, FLDSET(struct ast_cdr_config, batch_settings.settings), BATCH_MODE_SAFE_SHUTDOWN);
+ aco_option_register(&cfg_info, "size", ACO_EXACT, general_options, DEFAULT_BATCH_SIZE, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_cdr_config, batch_settings.size), 0, MAX_BATCH_SIZE);
+ aco_option_register(&cfg_info, "time", ACO_EXACT, general_options, DEFAULT_BATCH_TIME, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_cdr_config, batch_settings.time), 0, MAX_BATCH_TIME);
}
if (aco_process_config(&cfg_info, reload)) {
@@ -2212,7 +2242,7 @@
ao2_ref(active_cdrs_by_channel, -1);
}
-static void cdr_enable_batch_mode(struct cdr_config *config)
+static void cdr_enable_batch_mode(struct ast_cdr_config *config)
{
SCOPED_LOCK(batch, &cdr_batch_lock, ast_mutex_lock, ast_mutex_unlock);
Modified: 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=diff&rev=384475&r1=384474&r2=384475
==============================================================================
--- team/mjordan/cdrs-of-doom/tests/test_cdr.c (original)
+++ team/mjordan/cdrs-of-doom/tests/test_cdr.c Mon Apr 1 12:02:56 2013
@@ -23,9 +23,24 @@
#include "asterisk/causes.h"
#include "asterisk/time.h"
+#define TEST_CATEGORY "/main/cdr/"
+
#define MOCK_CDR_BACKEND "mock_cdr_backend"
#define CHANNEL_TECH_NAME "CDRTestChannel"
+
+/*! \brief A placeholder for Asterisk's 'real' CDR configuration */
+static struct ast_cdr_config *saved_config;
+
+/*! \brief A configuration suitable for CDRs with unanswered records */
+static struct ast_cdr_config unanswered_cdr_config = {
+ .settings.flags = CDR_ENABLED | CDR_UNANSWERED | CDR_DEBUG,
+};
+
+#define SWAP_CONFIG(ao2_config, template) do { \
+ *(ao2_config) = (template); \
+ ast_cdr_set_config((ao2_config)); \
+ } while (0)
static AST_LIST_HEAD(, test_cdr_entry) actual_cdr_entries = AST_LIST_HEAD_INIT_VALUE;
@@ -85,7 +100,6 @@
cdr_wrapper->cdr = mock_cdr;
AST_LIST_LOCK(&actual_cdr_entries);
- ast_log(LOG_NOTICE, "Received CDR for mock backend: %d\n", mock_cdr_count + 1);
AST_LIST_INSERT_TAIL(&actual_cdr_entries, cdr_wrapper, list);
mock_cdr_count++;
ast_cond_signal(&mock_cdr_cond);
@@ -139,13 +153,11 @@
struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 5, .tv_nsec = wait_now.tv_usec * 1000 };
enum ast_test_result_state res = AST_TEST_PASS;
while (count < record) {
- if (mock_cdr_count == count) {
- AST_LIST_LOCK(&actual_cdr_entries);
+ AST_LIST_LOCK(&actual_cdr_entries);
+ if (mock_cdr_count < record) {
ast_cond_timedwait(&mock_cdr_cond, &actual_cdr_entries.lock, &wait_time);
- AST_LIST_UNLOCK(&actual_cdr_entries);
}
- AST_LIST_LOCK(&actual_cdr_entries);
- cdr_wrapper = AST_LIST_FIRST(&actual_cdr_entries);
+ cdr_wrapper = AST_LIST_REMOVE_HEAD(&actual_cdr_entries, list);
AST_LIST_UNLOCK(&actual_cdr_entries);
if (!cdr_wrapper) {
@@ -154,40 +166,32 @@
}
actual = cdr_wrapper->cdr;
- for (; actual && expected; actual = actual->next, expected = expected->next) {
- VERIFY_STRING_FIELD(accountcode, actual, expected);
- VERIFY_NUMERIC_FIELD(amaflags, 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(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_STRING_FIELD(src, actual, expected);
- VERIFY_STRING_FIELD(uniqueid, actual, expected);
- VERIFY_STRING_FIELD(userfield, actual, expected);
- VERIFY_TIME_VALUE(start, actual);
- VERIFY_TIME_VALUE(end, actual);
- /* Note: there's no way we can really calculate a duration or
- * billsec - the unit tests are too short. However, if billsec is
- * non-zero in the expected, then make sure we have an answer time
- */
- if (expected->billsec) {
- VERIFY_TIME_VALUE(answer, actual);
- }
+ VERIFY_STRING_FIELD(accountcode, actual, expected);
+ VERIFY_NUMERIC_FIELD(amaflags, 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_STRING_FIELD(lastapp, actual, expected);
+ VERIFY_STRING_FIELD(lastdata, actual, expected);
+ VERIFY_STRING_FIELD(linkedid, actual, expected);
+ VERIFY_STRING_FIELD(peeraccount, actual, expected);
+ VERIFY_STRING_FIELD(src, actual, expected);
+ VERIFY_STRING_FIELD(uniqueid, actual, expected);
+ VERIFY_STRING_FIELD(userfield, actual, expected);
+ VERIFY_TIME_VALUE(start, actual);
+ VERIFY_TIME_VALUE(end, actual);
+ /* Note: there's no way we can really calculate a duration or
+ * billsec - the unit tests are too short. However, if billsec is
+ * non-zero in the expected, then make sure we have an answer time
+ */
+ if (expected->billsec) {
+ VERIFY_TIME_VALUE(answer, actual);
}
- 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;
- }
+ expected = expected->next;
++count;
}
@@ -227,6 +231,8 @@
AST_TEST_DEFINE(test_cdr_channel_creation)
{
RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
@@ -247,8 +253,8 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_channel_creation";
- info->category = "/main/cdr/";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
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";
@@ -257,6 +263,8 @@
break;
}
+ SWAP_CONFIG(config, unanswered_cdr_config);
+
chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice");
ast_channel_set_caller(chan, &caller, NULL);
ast_copy_string(expected.uniqueid, ast_channel_uniqueid(chan), sizeof(expected.uniqueid));
@@ -269,14 +277,14 @@
result = verify_mock_cdr_record(test, &expected, 1);
- clear_mock_cdr_backend();
-
return result;
}
AST_TEST_DEFINE(test_cdr_unanswered_inbound_call)
{
RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
@@ -297,8 +305,8 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_unanswered_inbound_call";
- info->category = "/main/cdr/";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
info->summary = "Test inbound unanswered calls";
info->description =
"Test the properties of a CDR for a call that is\n"
@@ -309,6 +317,8 @@
break;
}
+ SWAP_CONFIG(config, unanswered_cdr_config);
+
chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice");
ast_channel_set_caller(chan, &caller, NULL);
ast_copy_string(expected.uniqueid, ast_channel_uniqueid(chan), sizeof(expected.uniqueid));
@@ -327,14 +337,14 @@
result = verify_mock_cdr_record(test, &expected, 1);
- clear_mock_cdr_backend();
-
return result;
}
AST_TEST_DEFINE(test_cdr_unanswered_outbound_call)
{
RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_cdr expected = {
.clid = "\"\" <>",
@@ -354,8 +364,8 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_unanswered_outbound_call";
- info->category = "/main/cdr/";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
info->summary = "Test outbound unanswered calls";
info->description =
"Test the properties of a CDR for a call that is\n"
@@ -364,6 +374,8 @@
case TEST_EXECUTE:
break;
}
+
+ SWAP_CONFIG(config, unanswered_cdr_config);
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));
@@ -380,8 +392,6 @@
result = verify_mock_cdr_record(test, &expected, 1);
- clear_mock_cdr_backend();
-
return result;
}
@@ -409,8 +419,8 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_single_party";
- info->category = "/main/cdr/";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
info->summary = "Test cdrs for a single party";
info->description =
"Test the properties of a CDR for a call that is\n"
@@ -448,8 +458,6 @@
result = verify_mock_cdr_record(test, &expected, 1);
- clear_mock_cdr_backend();
-
return result;
}
@@ -457,6 +465,8 @@
{
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_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
@@ -477,8 +487,8 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_dial_unanswered";
- info->category = "/main/cdr/";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
info->summary = "Test CDRs for a dial that isn't answered";
info->description =
"Test the properties of a CDR for a channel that\n"
@@ -488,6 +498,8 @@
break;
}
+ SWAP_CONFIG(config, unanswered_cdr_config);
+
chan_caller = 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_caller), sizeof(expected.uniqueid));
ast_copy_string(expected.linkedid, ast_channel_linkedid(chan_caller), sizeof(expected.linkedid));
@@ -525,8 +537,6 @@
result = verify_mock_cdr_record(test, &expected, 1);
- clear_mock_cdr_backend();
-
return result;
}
@@ -535,6 +545,8 @@
{
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_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
@@ -555,8 +567,8 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_dial_busy";
- info->category = "/main/cdr/";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
info->summary = "Test CDRs for a dial that results in a busy";
info->description =
"Test the properties of a CDR for a channel that\n"
@@ -566,6 +578,8 @@
break;
}
+ SWAP_CONFIG(config, unanswered_cdr_config);
+
chan_caller = 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_caller), sizeof(expected.uniqueid));
ast_copy_string(expected.linkedid, ast_channel_linkedid(chan_caller), sizeof(expected.linkedid));
@@ -603,8 +617,6 @@
result = verify_mock_cdr_record(test, &expected, 1);
- clear_mock_cdr_backend();
-
return result;
}
@@ -612,6 +624,8 @@
{
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_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
@@ -632,8 +646,8 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_dial_congestion";
- info->category = "/main/cdr/";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
info->summary = "Test CDRs for a dial that results in congestion";
info->description =
"Test the properties of a CDR for a channel that\n"
@@ -643,6 +657,8 @@
break;
}
+ SWAP_CONFIG(config, unanswered_cdr_config);
+
chan_caller = 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_caller), sizeof(expected.uniqueid));
ast_copy_string(expected.linkedid, ast_channel_linkedid(chan_caller), sizeof(expected.linkedid));
@@ -680,8 +696,6 @@
result = verify_mock_cdr_record(test, &expected, 1);
- clear_mock_cdr_backend();
-
return result;
}
@@ -689,6 +703,8 @@
{
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_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
@@ -709,8 +725,8 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_dial_unavailable";
- info->category = "/main/cdr/";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
info->summary = "Test CDRs for a dial that results in unavailable";
info->description =
"Test the properties of a CDR for a channel that\n"
@@ -720,6 +736,8 @@
break;
}
+ SWAP_CONFIG(config, unanswered_cdr_config);
+
chan_caller = 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_caller), sizeof(expected.uniqueid));
ast_copy_string(expected.linkedid, ast_channel_linkedid(chan_caller), sizeof(expected.linkedid));
@@ -757,8 +775,6 @@
result = verify_mock_cdr_record(test, &expected, 1);
- clear_mock_cdr_backend();
-
return result;
}
@@ -766,6 +782,8 @@
{
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_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
@@ -786,8 +804,8 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_dial_caller_cancel";
- info->category = "/main/cdr/";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
info->summary = "Test CDRs for a dial where the caller cancels";
info->description =
"Test the properties of a CDR for a channel that\n"
@@ -798,6 +816,8 @@
break;
}
+ SWAP_CONFIG(config, unanswered_cdr_config);
+
chan_caller = 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_caller), sizeof(expected.uniqueid));
ast_copy_string(expected.linkedid, ast_channel_linkedid(chan_caller), sizeof(expected.linkedid));
@@ -837,8 +857,6 @@
result = verify_mock_cdr_record(test, &expected, 1);
- clear_mock_cdr_backend();
-
return result;
}
@@ -848,6 +866,8 @@
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_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_cdr bob_expected = {
.clid = "\"Alice\" <100>",
@@ -903,19 +923,27 @@
switch (cmd) {
case TEST_INIT:
- info->name = "cdr_dial_parallel_failed";
- info->category = "/main/cdr/";
- info->summary = "blah";
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
+ info->summary = "Test a parallel dial where all channels fail to answer";
info->description =
- "blah\n";
+ "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";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
+ SWAP_CONFIG(config, unanswered_cdr_config);
+
chan_caller = 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_caller), sizeof(expected->uniqueid));
- ast_copy_string(expected->linkedid, ast_channel_linkedid(chan_caller), sizeof(expected->linkedid));
+ ast_copy_string(bob_expected.uniqueid, ast_channel_uniqueid(chan_caller), sizeof(bob_expected.uniqueid));
+ ast_copy_string(bob_expected.linkedid, ast_channel_linkedid(chan_caller), sizeof(bob_expected.linkedid));
+ ast_copy_string(charlie_expected.uniqueid, ast_channel_uniqueid(chan_caller), sizeof(charlie_expected.uniqueid));
+ ast_copy_string(charlie_expected.linkedid, ast_channel_linkedid(chan_caller), sizeof(charlie_expected.linkedid));
+ ast_copy_string(david_expected.uniqueid, ast_channel_uniqueid(chan_caller), sizeof(david_expected.uniqueid));
+ ast_copy_string(david_expected.linkedid, ast_channel_linkedid(chan_caller), sizeof(david_expected.linkedid));
/* Channel enters Dial app */
ast_channel_appl_set(chan_caller, "Dial");
@@ -928,16 +956,19 @@
ast_set_flag(ast_channel_flags(chan_bob), AST_FLAG_OUTGOING);
ast_channel_appl_set(chan_bob, "AppDial");
ast_channel_data_set(chan_bob, "(Outgoing Line)");
+ publish_channel_snapshot(chan_bob);
chan_charlie = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "300", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Charlie");
ast_set_flag(ast_channel_flags(chan_charlie), AST_FLAG_OUTGOING);
ast_channel_appl_set(chan_charlie, "AppDial");
ast_channel_data_set(chan_charlie, "(Outgoing Line)");
+ publish_channel_snapshot(chan_charlie);
chan_david = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "400", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/David");
ast_set_flag(ast_channel_flags(chan_david), AST_FLAG_OUTGOING);
ast_channel_appl_set(chan_david, "AppDial");
ast_channel_data_set(chan_david, "(Outgoing Line)");
+ publish_channel_snapshot(chan_david);
/* Dial starts */
ast_channel_publish_dial(chan_caller, chan_bob, "Bob", NULL);
@@ -955,10 +986,17 @@
}
/* David is congested */
- ast_channel_publish_dial(chan_caller, chan_david, NULL, "CONGESTED");
+ ast_channel_publish_dial(chan_caller, chan_david, NULL, "CONGESTION");
ast_channel_hangupcause_set(chan_david, AST_CAUSE_CONGESTION);
if (!ast_hangup(chan_david)) {
chan_david = NULL;
+ }
+
+ /* Bob is canceled */
+ ast_channel_publish_dial(chan_caller, chan_bob, NULL, "CANCEL");
+ ast_channel_hangupcause_set(chan_bob, AST_CAUSE_NORMAL);
+ if (!ast_hangup(chan_bob)) {
+ chan_bob = NULL;
}
/* Alice hangs up */
@@ -967,18 +1005,34 @@
chan_caller = NULL;
}
- /* Bob is cancelled */
- ast_channel_publish_dial(chan_caller, chan_bob, NULL, "CANCEL");
- ast_channel_hangupcause_set(chan_bob, AST_CAUSE_NORMAL);
- if (!ast_hangup(chan_bob)) {
- chan_bob = NULL;
- }
-
- result = verify_mock_cdr_record(test, expected, 1);
-
+ result = verify_mock_cdr_record(test, expected, 3);
+
+ return result;
+}
+
+/*!
+ * \internal \brief Callback function called before each test executes
+ */
+static int test_cdr_init_cb(struct ast_test_info *info, struct ast_test *test)
+{
+ /* Back up the real config */
+ saved_config = ast_cdr_get_config();
clear_mock_cdr_backend();
-
- return result;
+ return 0;
+}
+
+/*!
+ * \internal \brief Callback function called after each test executes
+ */
+static int test_cdr_cleanup_cb(struct ast_test_info *info, struct ast_test *test)
+{
+ /* Restore the real config */
+ ast_cdr_set_config(saved_config);
+ ao2_cleanup(saved_config);
+ saved_config = NULL;
+ clear_mock_cdr_backend();
+
+ return 0;
}
@@ -1017,8 +1071,10 @@
AST_TEST_REGISTER(test_cdr_dial_caller_cancel);
AST_TEST_REGISTER(test_cdr_dial_parallel_failed);
+ ast_test_register_init(TEST_CATEGORY, test_cdr_init_cb);
+ ast_test_register_cleanup(TEST_CATEGORY, test_cdr_cleanup_cb);
+
ast_channel_register(&test_cdr_chan_tech);
-
ast_cdr_register(MOCK_CDR_BACKEND, "Mock CDR backend", mock_cdr_backend);
return AST_MODULE_LOAD_SUCCESS;
More information about the svn-commits
mailing list