[asterisk-commits] mjordan: branch mjordan/cdrs-of-doom r386397 - in /team/mjordan/cdrs-of-doom:...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Apr 23 17:03:20 CDT 2013
Author: mjordan
Date: Tue Apr 23 17:03:16 2013
New Revision: 386397
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386397
Log:
Update with unit tests for ForkCDR, NoCDR, ResetCDR and other fixes
This fixes a few other areas, including some dialing problems and some hangup
cause code issues.
Modified:
team/mjordan/cdrs-of-doom/include/asterisk/cdr.h
team/mjordan/cdrs-of-doom/main/asterisk.c
team/mjordan/cdrs-of-doom/main/cdr.c
team/mjordan/cdrs-of-doom/main/stasis_channels.c
team/mjordan/cdrs-of-doom/tests/test_cdr.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=386397&r1=386396&r2=386397
==============================================================================
--- team/mjordan/cdrs-of-doom/include/asterisk/cdr.h (original)
+++ team/mjordan/cdrs-of-doom/include/asterisk/cdr.h Tue Apr 23 17:03:16 2013
@@ -173,6 +173,14 @@
int ast_cdr_isset_unanswered(void);
/*!
+ * \brief Return whether or not a channel has a CDR where it is the Party A
+ *
+ * \retval 0 if the channel does not have a CDR
+ * \retval 1 if the channel does have a CDR
+ */
+int ast_cdr_exists(const char *channel_name);
+
+/*!
* \since 12
* \brief Format a CDR variable from an already posted CDR
*
@@ -197,7 +205,7 @@
* \retval 0 on success
* \retval non-zero on failure
*/
-int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length);
+int ast_cdr_getvar(const char *channel_name, const char *name, char **value, size_t length);
/*!
* \brief Set a variable on a CDR
Modified: team/mjordan/cdrs-of-doom/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/asterisk.c?view=diff&rev=386397&r1=386396&r2=386397
==============================================================================
--- team/mjordan/cdrs-of-doom/main/asterisk.c (original)
+++ team/mjordan/cdrs-of-doom/main/asterisk.c Tue Apr 23 17:03:16 2013
@@ -4225,11 +4225,6 @@
ast_http_init(); /* Start the HTTP server, if needed */
- if (init_manager()) {
- printf("%s", term_quit());
- exit(1);
- }
-
if (ast_cdr_engine_init()) {
printf("%s", term_quit());
exit(1);
@@ -4273,12 +4268,17 @@
exit(1);
}
+ if (ast_features_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
if (ast_bridging_init()) {
printf("%s", term_quit());
exit(1);
}
- if (ast_features_init()) {
+ if (init_manager()) {
printf("%s", term_quit());
exit(1);
}
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=386397&r1=386396&r2=386397
==============================================================================
--- team/mjordan/cdrs-of-doom/main/cdr.c (original)
+++ team/mjordan/cdrs-of-doom/main/cdr.c Tue Apr 23 17:03:16 2013
@@ -482,17 +482,19 @@
{
struct cdr_object *new_cdr;
struct cdr_object *it_cdr;
-
- new_cdr = cdr_object_alloc(cdr->party_a.snapshot);
+ struct cdr_object *cdr_last;
+
+ cdr_last = cdr->last;
+ new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot);
if (!new_cdr) {
return NULL;
}
/* Copy over the linkedid, as it may have changed */
- ast_string_field_set(new_cdr, linkedid, cdr->linkedid);
+ ast_string_field_set(new_cdr, linkedid, cdr_last->linkedid);
/* Copy over other Party A information */
- strcpy(new_cdr->party_a.userfield, cdr->party_a.userfield);
- new_cdr->party_a.flags = cdr->party_a.flags;
- copy_vars(&new_cdr->party_a.variables, &cdr->party_a.variables);
+ strcpy(new_cdr->party_a.userfield, cdr_last->party_a.userfield);
+ new_cdr->party_a.flags = cdr_last->party_a.flags;
+ copy_vars(&new_cdr->party_a.variables, &cdr_last->party_a.variables);
/* Append the CDR to the end of the list */
for (it_cdr = cdr; it_cdr->next; it_cdr = it_cdr->next) {
@@ -563,9 +565,9 @@
ast_copy_string(cdr_copy->lastdata, party_a->data, sizeof(cdr_copy->lastdata));
ast_copy_string(cdr_copy->dst, party_a->exten, sizeof(cdr_copy->dst));
ast_copy_string(cdr_copy->dcontext, party_a->context, sizeof(cdr_copy->dcontext));
- ast_copy_string(cdr_copy->userfield, party_a->userfield, sizeof(cdr_copy->userfield));
+ ast_copy_string(cdr_copy->userfield, cdr->party_a.userfield, sizeof(cdr_copy->userfield));
/* XXX TODO: this should just happen automatically */
- cdr_copy->flags = party_a->flags.flags;
+ ast_copy_flags(cdr_copy, &cdr->flags, AST_FLAGS_ALL);
/* Party B */
if (party_b) {
@@ -646,6 +648,7 @@
case AST_CAUSE_UNREGISTERED:
cdr->disposition = AST_CDR_FAILED;
break;
+ case AST_CAUSE_NORMAL_CLEARING:
case AST_CAUSE_NO_ANSWER:
cdr->disposition = AST_CDR_NOANSWER;
break;
@@ -664,7 +667,7 @@
cdr->end = ast_tvnow();
if (cdr->disposition == AST_CDR_NULL) {
- if (!ast_tvzero(cdr->answer) && cdr->disposition == AST_CDR_NOANSWER) {
+ if (!ast_tvzero(cdr->answer)) {
cdr->disposition = AST_CDR_ANSWERED;
} else if (cdr->party_a.snapshot->hangupcause) {
cdr_object_set_disposition(cdr, cdr->party_a.snapshot->hangupcause);
@@ -857,7 +860,7 @@
return 0;
} else if (!strcmp(dial_status, "BUSY")) {
cdr->disposition = AST_CDR_BUSY;
- } else if (!strcmp(dial_status, "CANCEL")) {
+ } else if (!strcmp(dial_status, "CANCEL") || !strcmp(dial_status, "NOANSWER")) {
cdr->disposition = AST_CDR_NOANSWER;
} else if (!strcmp(dial_status, "CONGESTION")) {
cdr->disposition = AST_CDR_CONGESTION;
@@ -929,7 +932,7 @@
}
dial_status_blob = ast_json_object_get(ast_multi_channel_blob_get_json(payload), "dialstatus");
- if (!dial_status_blob) {
+ if (dial_status_blob) {
dial_status = ast_json_string_get(dial_status_blob);
}
@@ -1053,6 +1056,7 @@
cdr = ao2_find(active_cdrs_by_channel, name, OBJ_KEY);
if (cdr) {
SCOPED_AO2LOCK(lock, cdr);
+
if (new_snapshot) {
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
if (it_cdr->fn_table->process_party_a_update) {
@@ -1061,7 +1065,9 @@
}
}
} else {
- cdr_object_finalize(cdr);
+ for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
+ cdr_object_finalize(it_cdr);
+ }
cdr_object_dispatch(cdr);
ao2_unlink(active_cdrs_by_channel, cdr);
}
@@ -1172,6 +1178,15 @@
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
return ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED);
+}
+
+int ast_cdr_exists(const char *channel_name)
+{
+ RAII_VAR(struct cdr_object *, cdr,
+ ao2_find(active_cdrs_by_channel, channel_name, OBJ_KEY),
+ ao2_cleanup);
+
+ return (cdr != NULL);
}
struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr)
@@ -1327,10 +1342,11 @@
struct ast_var_t *newvariable;
struct varshead *headp;
- if (cdr->fn_table == &hangup_state_fn_table) {
+ if (cdr->fn_table == &finalized_state_fn_table) {
return;
}
+ /* If we're Party B, update its variables. Otherwise, we must be Party A */
if (!ast_strlen_zero(channel_name) && cdr->party_b.snapshot
&& !strcmp(cdr->party_b.snapshot->name, channel_name)) {
headp = &cdr->party_b.variables;
@@ -1361,6 +1377,7 @@
int ast_cdr_setvar(const char *channel_name, const char *name, const char *value)
{
struct cdr_object *cdr;
+ struct cdr_object *it_cdr;
struct ao2_iterator *it_cdrs;
char *arg = ast_strdupa(channel_name);
int x;
@@ -1380,8 +1397,12 @@
while ((cdr = ao2_iterator_next(it_cdrs))) {
ao2_lock(cdr);
- for (; cdr->next; cdr = cdr->next) { }
- cdr_object_setvar(cdr, channel_name, name, value);
+ for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
+ if (it_cdr->fn_table == &finalized_state_fn_table) {
+ continue;
+ }
+ cdr_object_setvar(it_cdr, channel_name, name, value);
+ }
ao2_unlock(cdr);
ao2_ref(cdr, -1);
}
@@ -1390,75 +1411,75 @@
return 0;
}
-static void cdr_object_format_var_internal(struct cdr_object *cdr, const char *name, char *value, size_t length)
+static void cdr_object_format_var_internal(struct cdr_object *cdr, const char *name, char **value, size_t length)
{
struct ast_var_t *variable;
AST_LIST_TRAVERSE(&cdr->party_a.variables, variable, entries) {
if (!strcasecmp(name, ast_var_name(variable))) {
- ast_copy_string(value, ast_var_value(variable), length);
+ ast_copy_string(*value, ast_var_value(variable), length);
return;
}
}
- *value = '\0';
-}
-
-static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *name, char *value, size_t length)
+ **value = '\0';
+}
+
+static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *name, char **value, size_t length)
{
struct ast_channel_snapshot *party_a = cdr_obj->party_a.snapshot;
struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
if (!strcasecmp(name, "clid")) {
- ast_callerid_merge(value, length, party_a->caller_name, party_a->caller_number, "");
+ ast_callerid_merge(*value, length, party_a->caller_name, party_a->caller_number, "");
} else if (!strcasecmp(name, "src")) {
- ast_copy_string(value, party_a->caller_number, length);
+ ast_copy_string(*value, party_a->caller_number, length);
} else if (!strcasecmp(name, "dst")) {
- ast_copy_string(value, party_a->exten, length);
+ ast_copy_string(*value, party_a->exten, length);
} else if (!strcasecmp(name, "dcontext")) {
- ast_copy_string(value, party_a->context, length);
+ ast_copy_string(*value, party_a->context, length);
} else if (!strcasecmp(name, "channel")) {
- ast_copy_string(value, party_a->name, length);
+ ast_copy_string(*value, party_a->name, length);
} else if (!strcasecmp(name, "dstchannel")) {
if (party_b) {
- ast_copy_string(value, party_b->name, length);
+ ast_copy_string(*value, party_b->name, length);
} else {
- ast_copy_string(value, "", length);
+ ast_copy_string(*value, "", length);
}
} else if (!strcasecmp(name, "lastapp")) {
- ast_copy_string(value, party_a->appl, length);
+ ast_copy_string(*value, party_a->appl, length);
} else if (!strcasecmp(name, "lastdata")) {
- ast_copy_string(value, party_a->data, length);
+ ast_copy_string(*value, party_a->data, length);
} else if (!strcasecmp(name, "start")) {
- cdr_get_tv(cdr_obj->start, NULL, value, length);
+ cdr_get_tv(cdr_obj->start, NULL, *value, length);
} else if (!strcasecmp(name, "answer")) {
- cdr_get_tv(cdr_obj->answer, NULL, value, length);
+ cdr_get_tv(cdr_obj->answer, NULL, *value, length);
} else if (!strcasecmp(name, "end")) {
- cdr_get_tv(cdr_obj->end, NULL, value, length);
+ cdr_get_tv(cdr_obj->end, NULL, *value, length);
} else if (!strcasecmp(name, "duration")) {
- snprintf(value, length, "%ld", cdr_object_get_duration(cdr_obj));
+ snprintf(*value, length, "%ld", cdr_object_get_duration(cdr_obj));
} else if (!strcasecmp(name, "billsec")) {
- snprintf(value, length, "%ld", cdr_object_get_billsec(cdr_obj));
+ snprintf(*value, length, "%ld", cdr_object_get_billsec(cdr_obj));
} else if (!strcasecmp(name, "disposition")) {
- snprintf(value, length, "%d", cdr_obj->disposition);
+ snprintf(*value, length, "%d", cdr_obj->disposition);
} else if (!strcasecmp(name, "amaflags")) {
- snprintf(value, length, "%d", party_a->amaflags);
+ snprintf(*value, length, "%d", party_a->amaflags);
} else if (!strcasecmp(name, "accountcode")) {
- ast_copy_string(value, party_a->accountcode, length);
+ ast_copy_string(*value, party_a->accountcode, length);
} else if (!strcasecmp(name, "peeraccount")) {
if (party_b) {
- ast_copy_string(value, party_b->accountcode, length);
+ ast_copy_string(*value, party_b->accountcode, length);
} else {
- ast_copy_string(value, "", length);
+ ast_copy_string(*value, "", length);
}
} else if (!strcasecmp(name, "uniqueid")) {
- ast_copy_string(value, party_a->uniqueid, length);
+ ast_copy_string(*value, party_a->uniqueid, length);
} else if (!strcasecmp(name, "linkedid")) {
- ast_copy_string(value, cdr_obj->linkedid, length);
+ ast_copy_string(*value, cdr_obj->linkedid, length);
} else if (!strcasecmp(name, "userfield")) {
- ast_copy_string(value, party_a->userfield, length);
+ ast_copy_string(*value, cdr_obj->party_a.userfield, length);
} else if (!strcasecmp(name, "sequence")) {
- snprintf(value, length, "%d", cdr_obj->sequence);
+ snprintf(*value, length, "%d", cdr_obj->sequence);
} else {
return 1;
}
@@ -1466,7 +1487,7 @@
return 0;
}
-int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length)
+int ast_cdr_getvar(const char *channel_name, const char *name, char **value, size_t length)
{
RAII_VAR(struct cdr_object *, cdr,
ao2_find(active_cdrs_by_channel, channel_name, OBJ_KEY),
@@ -1503,8 +1524,12 @@
struct cdr_object *it_cdr;
struct ast_var_t *variable;
const char *var;
- char workspace[256];
+ RAII_VAR(char *, workspace, ast_malloc(256), ast_free);
int total = 0, x = 0, i;
+
+ if (!workspace) {
+ return 1;
+ }
if (!cdr) {
ast_debug(3, "Unable to find CDR for channel %s\n", channel_name);
@@ -1534,7 +1559,7 @@
for (i = 0; cdr_readonly_vars[i]; i++) {
/* null out the workspace, because the cdr_get_tv() won't write anything if time is NULL, so you get old vals */
workspace[0] = 0;
- cdr_object_format_property(it_cdr, cdr_readonly_vars[i], workspace, sizeof(workspace));
+ cdr_object_format_property(it_cdr, cdr_readonly_vars[i], &workspace, sizeof(workspace));
if (!ast_strlen_zero(workspace)
&& ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, workspace, sep) < 0) {
@@ -1635,6 +1660,9 @@
struct party_b_userfield_update *info = arg;
struct cdr_object *it_cdr;
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
+ if (it_cdr->fn_table == &finalized_state_fn_table) {
+ continue;
+ }
if (it_cdr->party_b.snapshot
&& !strcmp(it_cdr->party_b.snapshot->name, info->channel_name)) {
strcpy(it_cdr->party_b.userfield, info->userfield);
@@ -1652,20 +1680,25 @@
.channel_name = channel_name,
.userfield = userfield,
};
-
+ struct cdr_object *it_cdr;
/* Handle Party A */
if (cdr) {
- SCOPED_AO2LOCK(lock, cdr);
- for (; cdr; cdr = cdr->next) {
- strcpy(cdr->party_a.userfield, userfield);
- }
+ ao2_lock(cdr);
+ for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
+ if (it_cdr->fn_table == &finalized_state_fn_table) {
+ continue;
+ }
+ strcpy(it_cdr->party_a.userfield, userfield);
+ }
+ ao2_unlock(cdr);
}
/* Handle Party B */
ao2_callback(active_cdrs_by_channel, OBJ_NODATA,
cdr_object_update_party_b_userfield,
&party_b_info);
+
}
static void post_cdr(struct ast_cdr *cdr)
@@ -1782,6 +1815,7 @@
ao2_find(active_cdrs_by_channel, channel_name, OBJ_KEY),
ao2_cleanup);
struct cdr_object *new_cdr;
+ struct cdr_object *it_cdr;
struct cdr_object *cdr_obj;
if (!cdr) {
@@ -1801,7 +1835,7 @@
/* Copy over the basic CDR information. The Party A information is
* copied over automatically as part of the append
*/
- new_cdr = cdr_object_create_and_append_cdr(cdr_obj);
+ new_cdr = cdr_object_create_and_append_cdr(cdr);
if (!new_cdr) {
return -1;
}
@@ -1824,9 +1858,6 @@
new_cdr->answer = cdr_obj->answer;
/* Modify the times based on the flags passed in */
- if (ast_test_flag(options, AST_CDR_FLAG_FINALIZE)) {
- cdr_object_transition_state(cdr_obj, &finalized_state_fn_table);
- }
if (ast_test_flag(options, AST_CDR_FLAG_SET_ANSWER)
&& new_cdr->party_a.snapshot->state == AST_STATE_UP) {
new_cdr->answer = ast_tvnow();
@@ -1835,9 +1866,20 @@
new_cdr->answer = ast_tvnow();
new_cdr->start = ast_tvnow();
}
+
/* Create and append, by default, copies over the variables */
if (!ast_test_flag(options, AST_CDR_FLAG_KEEP_VARS)) {
cdr_free_vars(&new_cdr->party_a.variables);
+ }
+
+ /* Finalize any current CDRs */
+ if (ast_test_flag(options, AST_CDR_FLAG_FINALIZE)) {
+ for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->next) {
+ if (it_cdr->fn_table == &finalized_state_fn_table) {
+ continue;
+ }
+ cdr_object_transition_state(it_cdr, &finalized_state_fn_table);
+ }
}
}
@@ -1956,7 +1998,6 @@
/* maybe they disabled CDR stuff completely, so just drop it */
if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
ast_debug(1, "Dropping CDR !\n");
- ast_set_flag(cdr, AST_CDR_FLAG_DISABLE);
ast_cdr_free(cdr);
return;
}
Modified: team/mjordan/cdrs-of-doom/main/stasis_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/stasis_channels.c?view=diff&rev=386397&r1=386396&r2=386397
==============================================================================
--- team/mjordan/cdrs-of-doom/main/stasis_channels.c (original)
+++ team/mjordan/cdrs-of-doom/main/stasis_channels.c Tue Apr 23 17:03:16 2013
@@ -445,6 +445,7 @@
message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
if (!message) {
+ ast_log(LOG_ERROR, "FARK ME\n");
return;
}
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=386397&r1=386396&r2=386397
==============================================================================
--- team/mjordan/cdrs-of-doom/tests/test_cdr.c (original)
+++ team/mjordan/cdrs-of-doom/tests/test_cdr.c Tue Apr 23 17:03:16 2013
@@ -33,6 +33,7 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+#include <math.h>
#include "asterisk/module.h"
#include "asterisk/test.h"
#include "asterisk/cdr.h"
@@ -43,6 +44,8 @@
#include "asterisk/time.h"
#include "asterisk/stasis_channels.h"
+#define EPSILON 0.001
+
#define TEST_CATEGORY "/main/cdr/"
#define MOCK_CDR_BACKEND "mock_cdr_backend"
@@ -51,10 +54,20 @@
/*! \brief A placeholder for Asterisk's 'real' CDR configuration */
static struct ast_cdr_config *saved_config;
+
+/*! \brief A configuration suitable for 'normal' CDRs */
+static struct ast_cdr_config debug_cdr_config = {
+ .settings.flags = CDR_ENABLED | CDR_DEBUG,
+};
/*! \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,
+};
+
+/*! \brief A configuration suitable for CDRs with congestion enabled */
+static struct ast_cdr_config congestion_cdr_config = {
+ .settings.flags = CDR_ENABLED | CDR_UNANSWERED | CDR_DEBUG | CDR_CONGESTION,
};
#define SWAP_CONFIG(ao2_config, template) do { \
@@ -210,7 +223,8 @@
if (expected->billsec) {
VERIFY_TIME_VALUE(answer, actual);
}
-
+ ast_test_debug(test, "Finished expected record %s, %s\n",
+ expected->channel, S_OR(expected->dstchannel, "<none>"));
expected = expected->next;
++count;
}
@@ -235,16 +249,6 @@
message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
ast_assert(message != NULL);
- stasis_publish(ast_channel_topic(chan), message);
-}
-
-static void publish_channel_cache_clear(struct ast_channel *chan)
-{
- RAII_VAR(struct ast_channel_snapshot *, snapshot, ast_channel_snapshot_create(chan), ao2_cleanup);
- RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-
- ast_assert(snapshot != NULL);
- message = stasis_cache_clear_create(ast_channel_snapshot_type(), ast_channel_uniqueid(chan));
stasis_publish(ast_channel_topic(chan), message);
}
@@ -408,7 +412,10 @@
publish_channel_snapshot(chan);
/* Clear from cache */
- publish_channel_cache_clear(chan);
+ ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL);
+ if (!ast_hangup(chan)) {
+ chan = NULL;
+ }
result = verify_mock_cdr_record(test, &expected, 1);
@@ -677,7 +684,7 @@
break;
}
- SWAP_CONFIG(config, unanswered_cdr_config);
+ SWAP_CONFIG(config, congestion_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));
@@ -955,7 +962,7 @@
break;
}
- SWAP_CONFIG(config, unanswered_cdr_config);
+ SWAP_CONFIG(config, congestion_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(bob_expected.uniqueid, ast_channel_uniqueid(chan_caller), sizeof(bob_expected.uniqueid));
@@ -1030,36 +1037,78 @@
return result;
}
-AST_TEST_DEFINE(test_cdr_single_fields)
-{
- RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
+AST_TEST_DEFINE(test_cdr_fields)
+{
+ 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 = "\"Alice\" <100>",
- .src = "100",
- .dst = "100",
- .dcontext = "default",
- .channel = CHANNEL_TECH_NAME "/Alice",
- .dstchannel = CHANNEL_TECH_NAME "/Bob",
- .lastapp = "Dial",
- .lastdata = CHANNEL_TECH_NAME "/Bob&" CHANNEL_TECH_NAME "/Charlie&" CHANNEL_TECH_NAME "/David",
+ RAII_VAR(char *, varbuffer, ast_malloc(128), ast_free);
+ int int_buffer;
+ double db_buffer;
+ struct timespec to_sleep = {2, 0};
+ struct ast_flags fork_options = { 0, };
+
+ struct ast_cdr original = {
+ .clid = "\"Alice\" <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .dstchannel = "",
+ .lastapp = "Wait",
+ .lastdata = "10",
.billsec = 0,
- .amaflags = AST_AMA_DOCUMENTATION,
- .disposition = AST_CDR_NOANSWER,
- .accountcode = "100",
- .peeraccount = "200",
+ .amaflags = AST_AMA_OMIT,
+ .disposition = AST_CDR_FAILED,
+ .accountcode = "XXX",
+ .peeraccount = "",
+ .userfield = "yackity",
+ };
+ struct ast_cdr fork_expected_one = {
+ .clid = "\"Alice\" <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .dstchannel = "",
+ .lastapp = "Wait",
+ .lastdata = "10",
+ .billsec = 0,
+ .amaflags = AST_AMA_OMIT,
+ .disposition = AST_CDR_FAILED,
+ .accountcode = "XXX",
+ .peeraccount = "",
+ .userfield = "yackity",
+ };
+ struct ast_cdr fork_expected_two = {
+ .clid = "\"Alice\" <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .dstchannel = "",
+ .lastapp = "Answer",
+ .lastdata = "",
+ .billsec = 0,
+ .amaflags = AST_AMA_OMIT,
+ .disposition = AST_CDR_ANSWERED,
+ .accountcode = "ZZZ",
+ .peeraccount = "",
+ .userfield = "schmackity",
};
enum ast_test_result_state result = AST_TEST_NOT_RUN;
+
+ struct ast_cdr *expected = &original;
+ original.next = &fork_expected_one;
+ fork_expected_one.next = &fork_expected_two;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = TEST_CATEGORY;
- info->summary = "Test field access on a single CDR record";
+ info->summary = "Test field access CDRs";
info->description =
- "This tests setting/retrieving data on a single CDR.\n";
+ "This tests setting/retrieving data on CDR records.\n";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
@@ -1067,18 +1116,348 @@
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));
-
-
- result = verify_mock_cdr_record(test, &expected, 3);
+ chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice");
+ ast_copy_string(original.uniqueid, ast_channel_uniqueid(chan), sizeof(original.uniqueid));
+ ast_copy_string(original.linkedid, ast_channel_linkedid(chan), sizeof(original.linkedid));
+ ast_copy_string(fork_expected_one.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_one.uniqueid));
+ ast_copy_string(fork_expected_one.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_one.linkedid));
+ ast_copy_string(fork_expected_two.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_two.uniqueid));
+ ast_copy_string(fork_expected_two.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_two.linkedid));
+
+ /* Channel enters Wait app */
+ ast_channel_appl_set(chan, "Wait");
+ ast_channel_data_set(chan, "10");
+ ast_channel_priority_set(chan, 1);
+ publish_channel_snapshot(chan);
+
+ /* Set properties on the channel that propagate to the CDR */
+ ast_channel_amaflags_set(chan, AST_AMA_OMIT);
+ ast_channel_accountcode_set(chan, "XXX");
+
+ /* Wait one second so we get a duration. Note that sleep/usleep can get
+ * a signal, so we use nanosleep here */
+ while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR));
+ if (!ast_cdr_exists(ast_channel_name(chan))) {
+ ast_test_status_update(test, "Failed to find CDR for channel %s\n", ast_channel_name(chan));
+ return AST_TEST_FAIL;
+ }
+
+ ast_cdr_setuserfield(ast_channel_name(chan), "foobar");
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_1") == 0);
+
+ /* Verify that we can't set read-only fields or other fields directly */
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "clid", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "src", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "dst", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "dcontext", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "channel", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "dstchannel", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "lastapp", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "lastdata", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "start", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "answer", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "end", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "duration", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "billsec", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "disposition", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "amaflags", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "accountcode", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "uniqueid", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "linkedid", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "userfield", "junk") != 0);
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "sequence", "junk") != 0);
+
+ /* Verify the values */
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "userfield", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "foobar") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "record_1") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "amaflags", &varbuffer, 128) == 0);
+ sscanf(varbuffer, "%d", &int_buffer);
+ ast_test_validate(test, int_buffer == AST_AMA_OMIT);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "accountcode", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "XXX") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "clid", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "\"Alice\" <100>") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "src", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "100") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "dst", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "100") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "dcontext", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "default") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "channel", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, CHANNEL_TECH_NAME "/Alice") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "dstchannel", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "lastapp", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "Wait") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "lastdata", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "10") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", &varbuffer, 128) == 0);
+ sscanf(varbuffer, "%lf", &db_buffer);
+ ast_test_validate(test, fabs(db_buffer) > 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "answer", &varbuffer, 128) == 0);
+ sscanf(varbuffer, "%lf", &db_buffer);
+ ast_test_validate(test, fabs(db_buffer) < EPSILON);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "end", &varbuffer, 128) == 0);
+ sscanf(varbuffer, "%lf", &db_buffer);
+ ast_test_validate(test, fabs(db_buffer) < EPSILON);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "duration", &varbuffer, 128) == 0);
+ sscanf(varbuffer, "%lf", &db_buffer);
+ ast_test_validate(test, fabs(db_buffer) > 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "billsec", &varbuffer, 128) == 0);
+ sscanf(varbuffer, "%lf", &db_buffer);
+ ast_test_validate(test, fabs(db_buffer) < EPSILON);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "disposition", &varbuffer, 128) == 0);
+ sscanf(varbuffer, "%d", &int_buffer);
+ ast_test_validate(test, int_buffer == AST_CDR_NULL);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "uniqueid", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, ast_channel_uniqueid(chan)) == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "linkedid", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, ast_channel_linkedid(chan)) == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "sequence", &varbuffer, 128) == 0);
+
+ /* Fork the CDR, and check that we change the properties on both CDRs. */
+ ast_set_flag(&fork_options, AST_CDR_FLAG_KEEP_VARS);
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+
+ /* Change some properties */
+ ast_cdr_setuserfield(ast_channel_name(chan), "yackity");
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_1b") == 0);
+
+ /* Fork the CDR again, finalizing all current CDRs */
+ ast_set_flag(&fork_options, AST_CDR_FLAG_KEEP_VARS | AST_CDR_FLAG_FINALIZE);
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+
+ /* Channel enters Answer app */
+ ast_channel_appl_set(chan, "Answer");
+ ast_channel_data_set(chan, "");
+ ast_channel_priority_set(chan, 1);
+ publish_channel_snapshot(chan);
+ ast_setstate(chan, AST_STATE_UP);
+
+ /* Set properties on the last record */
+ ast_channel_accountcode_set(chan, "ZZZ");
+ ast_cdr_setuserfield(ast_channel_name(chan), "schmackity");
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_2") == 0);
+
+ /* Hang up and verify */
+ ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL);
+ if (!ast_hangup(chan)) {
+ chan = NULL;
+ }
+ result = verify_mock_cdr_record(test, expected, 3);
return result;
}
-
-
+AST_TEST_DEFINE(test_cdr_no_reset_cdr)
+{
+ 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_flags fork_options = { 0, };
+ struct timespec to_sleep = {1, 0};
+
+ struct ast_cdr expected = {
+ .clid = "\"Alice\" <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .dstchannel = "",
+ .lastapp = "",
+ .lastdata = "",
+ .billsec = 0,
+ .amaflags = AST_AMA_DOCUMENTATION,
+ .disposition = AST_CDR_FAILED,
+ .accountcode = "100",
+ .peeraccount = "",
+ };
+ enum ast_test_result_state result = AST_TEST_NOT_RUN;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
+ info->summary = "Test field access CDRs";
+ info->description =
+ "This tests setting/retrieving data on CDR records.\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ 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_copy_string(expected.uniqueid, ast_channel_uniqueid(chan), sizeof(expected.uniqueid));
+ ast_copy_string(expected.linkedid, ast_channel_linkedid(chan), sizeof(expected.linkedid));
+
+ while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR));
+ if (!ast_cdr_exists(ast_channel_name(chan))) {
+ ast_test_status_update(test, "Unable to obtain CDR for channel\n");
+ return AST_TEST_FAIL;
+ }
+
+ /* Disable the CDR */
+ ast_test_validate(test, ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE) == 0);
+
+ /* Fork the CDR. This should be enabled */
+ ast_set_flag(&fork_options, AST_CDR_FLAG_FINALIZE);
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+
+ /* Disable and enable the forked CDR */
+ ast_test_validate(test, ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE) == 0);
+ ast_test_validate(test, ast_cdr_clear_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE) == 0);
+
+ /* Fork and finalize again. This CDR should be propagated */
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+
+ /* Disable all future CDRs */
+ ast_test_validate(test, ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE_ALL) == 0);
+
+ /* Fork a few more */
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+
+ ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL);
+ if (!ast_hangup(chan)) {
+ chan = NULL;
+ }
+ result = verify_mock_cdr_record(test, &expected, 1);
+
+ return result;
+}
+
+AST_TEST_DEFINE(test_cdr_fork_cdr)
+{
+ RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
+ RAII_VAR(char *, varbuffer, ast_malloc(128), ast_free);
+ RAII_VAR(char *, fork_varbuffer, ast_malloc(128), ast_free);
+ RAII_VAR(char *, answer_time, ast_malloc(128), ast_free);
+ RAII_VAR(char *, fork_answer_time, ast_malloc(128), ast_free);
+ RAII_VAR(char *, start_time, ast_malloc(128), ast_free);
+ RAII_VAR(char *, fork_start_time, ast_malloc(128), ast_free);
+ struct ast_flags fork_options = { 0, };
+ struct timespec to_sleep = {1, 10000};
+
+ struct ast_cdr original = {
+ .clid = "\"Alice\" <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .amaflags = AST_AMA_DOCUMENTATION,
+ .disposition = AST_CDR_ANSWERED,
+ .accountcode = "100",
+ };
+ struct ast_cdr fork_expected_one = {
+ .clid = "\"Alice\" <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .amaflags = AST_AMA_DOCUMENTATION,
+ .disposition = AST_CDR_ANSWERED,
+ .accountcode = "100",
+ };
+ struct ast_cdr fork_expected_two = {
+ .clid = "\"Alice\" <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .amaflags = AST_AMA_DOCUMENTATION,
+ .disposition = AST_CDR_ANSWERED,
+ .accountcode = "100",
+ };
+ enum ast_test_result_state result = AST_TEST_NOT_RUN;
+ struct ast_cdr *expected = &original;
+ original.next = &fork_expected_one;
+ fork_expected_one.next = &fork_expected_two;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
+ info->summary = "Test field access CDRs";
+ info->description =
+ "This tests setting/retrieving data on CDR records.\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ SWAP_CONFIG(config, debug_cdr_config);
+
+ chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice");
+ ast_copy_string(original.uniqueid, ast_channel_uniqueid(chan), sizeof(original.uniqueid));
+ ast_copy_string(original.linkedid, ast_channel_linkedid(chan), sizeof(original.linkedid));
+ ast_copy_string(fork_expected_one.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_one.uniqueid));
+ ast_copy_string(fork_expected_one.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_one.linkedid));
+ ast_copy_string(fork_expected_two.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_two.uniqueid));
+ ast_copy_string(fork_expected_two.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_two.linkedid));
+
+ while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR) && (!ast_cdr_exists(ast_channel_name(chan))));
+ if (!ast_cdr_exists(ast_channel_name(chan))) {
+ ast_test_status_update(test, "Unable to obtain CDR for channel\n");
+ return AST_TEST_FAIL;
+ }
+
+ /* Test blowing away variables */
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_1") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "record_1") == 0);
+ ast_copy_string(varbuffer, "", 128);
+
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", &fork_varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "record_1") != 0);
+
+ /* Test finalizing previous CDRs */
+ ast_set_flag(&fork_options, AST_CDR_FLAG_FINALIZE);
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+
+ /* Test keep variables; setting a new answer time */
+ ast_setstate(chan, AST_STATE_UP);
+ while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR));
+ ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_2") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", &varbuffer, 128) == 0);
+ ast_test_validate(test, strcmp(varbuffer, "record_2") == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "answer", &answer_time, 128) == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", &start_time, 128) == 0);
+
+ ast_set_flag(&fork_options, AST_CDR_FLAG_FINALIZE);
+ ast_set_flag(&fork_options, AST_CDR_FLAG_KEEP_VARS);
+ ast_set_flag(&fork_options, AST_CDR_FLAG_SET_ANSWER);
+ ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "answer", &fork_answer_time, 128) == 0);
+ ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", &fork_start_time, 128) == 0);
[... 64 lines stripped ...]
More information about the asterisk-commits
mailing list