Skip to content
Snippets Groups Projects
test_cdr.c 89.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	ast_channel_state_set(chan_david, AST_STATE_UP);
    
    	bridge = ast_bridge_basic_new();
    	ast_test_validate(test, bridge != NULL);
    
    
    	ast_test_validate(test, !ast_bridge_impart(bridge, chan_charlie, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
    
    	ast_test_validate(test, !ast_bridge_impart(bridge, chan_david, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
    
    	ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
    
    	ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
    
    	ast_test_validate(test, !ast_bridge_depart(chan_alice));
    	ast_test_validate(test, !ast_bridge_depart(chan_bob));
    	ast_test_validate(test, !ast_bridge_depart(chan_charlie));
    	ast_test_validate(test, !ast_bridge_depart(chan_david));
    
    
    	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL);
    	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL);
    	HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL);
    	HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL);
    
    
    	result = verify_mock_cdr_record(test, &alice_expected_one, 6);
    
    
    	return result;
    }
    
    AST_TEST_DEFINE(test_cdr_park)
    {
    	RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
    	RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
    
    	RAII_VAR(struct ast_bridge *, bridge, NULL, safe_bridge_destroy);
    
    	RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
    			ao2_cleanup);
    	struct timespec to_sleep = {1, 0};
    
    	struct ast_party_caller bob_caller = BOB_CALLERID;
    	struct ast_party_caller alice_caller = ALICE_CALLERID;
    	struct ast_cdr bob_expected = {
    		.clid = "\"Bob\" <200>",
    		.src = "200",
    		.dst = "200",
    		.dcontext = "default",
    		.channel = CHANNEL_TECH_NAME "/Bob",
    		.lastapp = "Park",
    		.lastdata = "701",
    		.billsec = 1,
    		.amaflags = AST_AMA_DOCUMENTATION,
    		.disposition = AST_CDR_ANSWERED,
    		.accountcode = "200",
    	};
    	struct ast_cdr alice_expected = {
    		.clid = "\"Alice\" <100>",
    		.src = "100",
    		.dst = "100",
    		.dcontext = "default",
    		.channel = CHANNEL_TECH_NAME "/Alice",
    		.lastapp = "Park",
    		.lastdata = "700",
    		.billsec = 1,
    		.amaflags = AST_AMA_DOCUMENTATION,
    		.disposition = AST_CDR_ANSWERED,
    		.accountcode = "100",
    		.next = &bob_expected,
    	};
    	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 cdrs for a single party entering Park";
    		info->description =
    			"Test the properties of a CDR for calls that are\n"
    
    			"answered, enters Park, and leaves it.";
    
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    	SWAP_CONFIG(config, debug_cdr_config);
    	CREATE_ALICE_CHANNEL(chan_alice, &alice_caller, &alice_expected);
    	CREATE_BOB_CHANNEL(chan_bob, &bob_caller, &bob_expected);
    
    
    	ast_channel_lock(chan_alice);
    
    	EMULATE_APP_DATA(chan_alice, 1, "Park", "700");
    	ast_setstate(chan_alice, AST_STATE_UP);
    
    	ast_channel_unlock(chan_alice);
    
    	ast_channel_lock(chan_bob);
    
    	EMULATE_APP_DATA(chan_bob, 1, "Park", "701");
    	ast_setstate(chan_bob, AST_STATE_UP);
    
    	ast_channel_unlock(chan_bob);
    
    
    	bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
    		AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
    
    			| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED,
    
    	ast_test_validate(test, bridge != NULL);
    
    
    	ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
    
    	ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
    
    	ast_bridge_depart(chan_alice);
    	ast_bridge_depart(chan_bob);
    
    	/* And then it hangs up */
    	HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL);
    	HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL);
    
    	result = verify_mock_cdr_record(test, &alice_expected, 2);
    
    	return result;
    }
    
    
    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);
    	char varbuffer[128];
    	int int_buffer;
    	double db_buffer;
    	struct timespec to_sleep = {2, 0};
    	struct ast_flags fork_options = { 0, };
    
    	struct ast_party_caller caller = ALICE_CALLERID;
    	struct ast_cdr original = {
    		.clid = "\"Alice\" <100>",
    		.src = "100",
    		.dst = "100",
    		.dcontext = "default",
    		.channel = CHANNEL_TECH_NAME "/Alice",
    		.lastapp = "Wait",
    		.lastdata = "10",
    		.billsec = 0,
    		.amaflags = AST_AMA_OMIT,
    		.disposition = AST_CDR_FAILED,
    		.accountcode = "XXX",
    		.userfield = "yackity",
    	};
    	struct ast_cdr fork_expected_one = {
    		.clid = "\"Alice\" <100>",
    		.src = "100",
    		.dst = "100",
    		.dcontext = "default",
    		.channel = CHANNEL_TECH_NAME "/Alice",
    		.lastapp = "Wait",
    		.lastdata = "10",
    		.billsec = 0,
    		.amaflags = AST_AMA_OMIT,
    		.disposition = AST_CDR_FAILED,
    		.accountcode = "XXX",
    		.userfield = "yackity",
    	};
    	struct ast_cdr fork_expected_two = {
    		.clid = "\"Alice\" <100>",
    		.src = "100",
    		.dst = "100",
    		.dcontext = "default",
    		.channel = CHANNEL_TECH_NAME "/Alice",
    		.lastapp = "Answer",
    		.billsec = 0,
    		.amaflags = AST_AMA_OMIT,
    		.disposition = AST_CDR_ANSWERED,
    		.accountcode = "ZZZ",
    		.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 CDRs";
    		info->description =
    
    			"This tests setting/retrieving data on CDR records.";
    
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	SWAP_CONFIG(config, unanswered_cdr_config);
    
    	CREATE_ALICE_CHANNEL(chan, &caller, &original);
    	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);
    	ast_channel_publish_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. */
    
    
    	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, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "foobar") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", varbuffer, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "record_1") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "amaflags", varbuffer, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "XXX") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "clid", varbuffer, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "\"Alice\" <100>") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "src", varbuffer, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "100") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "dst", varbuffer, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "100") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "dcontext", varbuffer, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "default") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "channel", varbuffer, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "lastapp", varbuffer, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "Wait") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "lastdata", varbuffer, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "10") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", varbuffer, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 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, sizeof(varbuffer)) == 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);
    	ast_channel_publish_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);
    
    	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_party_caller caller = ALICE_CALLERID;
    	struct ast_cdr expected = {
    		.clid = "\"Alice\" <100>",
    		.src = "100",
    		.dst = "100",
    		.dcontext = "default",
    		.channel = CHANNEL_TECH_NAME "/Alice",
    		.billsec = 0,
    		.amaflags = AST_AMA_DOCUMENTATION,
    		.disposition = AST_CDR_FAILED,
    		.accountcode = "100",
    	};
    	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.";
    
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	SWAP_CONFIG(config, unanswered_cdr_config);
    
    	CREATE_ALICE_CHANNEL(chan, &caller, &expected);
    
    
    
    	/* 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);
    
    	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);
    	char varbuffer[128];
    	char fork_varbuffer[128];
    	char answer_time[128];
    	char fork_answer_time[128];
    	char start_time[128];
    	char fork_start_time[128];
    	struct ast_flags fork_options = { 0, };
    	struct timespec to_sleep = {1, 10000};
    
    	struct ast_party_caller caller = ALICE_CALLERID;
    	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.";
    
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	SWAP_CONFIG(config, debug_cdr_config);
    
    	CREATE_ALICE_CHANNEL(chan, &caller, &original);
    	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));
    
    
    
    	/* 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, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "record_1") == 0);
    	ast_copy_string(varbuffer, "", sizeof(varbuffer));
    
    	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, sizeof(fork_varbuffer)) == 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);
    
    	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, sizeof(varbuffer)) == 0);
    	ast_test_validate(test, strcmp(varbuffer, "record_2") == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "answer", answer_time, sizeof(answer_time)) == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", start_time, sizeof(start_time)) == 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, sizeof(fork_answer_time)) == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", fork_start_time, sizeof(fork_start_time)) == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", fork_varbuffer, sizeof(fork_varbuffer)) == 0);
    	ast_test_validate(test, strcmp(fork_varbuffer, varbuffer) == 0);
    	ast_test_validate(test, strcmp(fork_start_time, start_time) == 0);
    	ast_test_validate(test, strcmp(fork_answer_time, answer_time) != 0);
    
    	ast_clear_flag(&fork_options, AST_CDR_FLAG_SET_ANSWER);
    	ast_set_flag(&fork_options, AST_CDR_FLAG_RESET);
    	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, sizeof(fork_answer_time)) == 0);
    	ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "start", fork_start_time, sizeof(fork_start_time)) == 0);
    	ast_test_validate(test, strcmp(fork_start_time, start_time) != 0);
    	ast_test_validate(test, strcmp(fork_answer_time, answer_time) != 0);
    
    	ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL);
    
    	ast_hangup(chan);
    	chan = NULL;
    
    	result = verify_mock_cdr_record(test, expected, 3);
    
    	return result;
    }
    
    /*!
    
    Richard Mudgett's avatar
    Richard Mudgett committed
     * \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 0;
    }
    
    /*!
    
    Richard Mudgett's avatar
    Richard Mudgett committed
     * \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;
    }
    
    
    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_TEST_UNREGISTER(test_cdr_single_bridge);
    	AST_TEST_UNREGISTER(test_cdr_single_bridge_continue);
    	AST_TEST_UNREGISTER(test_cdr_single_twoparty_bridge_a);
    	AST_TEST_UNREGISTER(test_cdr_single_twoparty_bridge_b);
    	AST_TEST_UNREGISTER(test_cdr_single_multiparty_bridge);
    
    
    	AST_TEST_UNREGISTER(test_cdr_outbound_bridged_call);
    
    
    	AST_TEST_UNREGISTER(test_cdr_dial_unanswered);
    	AST_TEST_UNREGISTER(test_cdr_dial_congestion);
    	AST_TEST_UNREGISTER(test_cdr_dial_busy);
    	AST_TEST_UNREGISTER(test_cdr_dial_unavailable);
    	AST_TEST_UNREGISTER(test_cdr_dial_caller_cancel);
    	AST_TEST_UNREGISTER(test_cdr_dial_parallel_failed);
    	AST_TEST_UNREGISTER(test_cdr_dial_answer_no_bridge);
    	AST_TEST_UNREGISTER(test_cdr_dial_answer_twoparty_bridge_a);
    	AST_TEST_UNREGISTER(test_cdr_dial_answer_twoparty_bridge_b);
    	AST_TEST_UNREGISTER(test_cdr_dial_answer_multiparty);
    
    	AST_TEST_UNREGISTER(test_cdr_park);
    
    	AST_TEST_UNREGISTER(test_cdr_fields);
    	AST_TEST_UNREGISTER(test_cdr_no_reset_cdr);
    	AST_TEST_UNREGISTER(test_cdr_fork_cdr);
    
    	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_cond_init(&mock_cdr_cond, NULL);
    
    	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_TEST_REGISTER(test_cdr_single_bridge);
    	AST_TEST_REGISTER(test_cdr_single_bridge_continue);
    	AST_TEST_REGISTER(test_cdr_single_twoparty_bridge_a);
    	AST_TEST_REGISTER(test_cdr_single_twoparty_bridge_b);
    	AST_TEST_REGISTER(test_cdr_single_multiparty_bridge);
    
    
    	AST_TEST_REGISTER(test_cdr_outbound_bridged_call);
    
    
    	AST_TEST_REGISTER(test_cdr_dial_unanswered);
    	AST_TEST_REGISTER(test_cdr_dial_congestion);
    	AST_TEST_REGISTER(test_cdr_dial_busy);
    	AST_TEST_REGISTER(test_cdr_dial_unavailable);
    	AST_TEST_REGISTER(test_cdr_dial_caller_cancel);
    	AST_TEST_REGISTER(test_cdr_dial_parallel_failed);
    	AST_TEST_REGISTER(test_cdr_dial_answer_no_bridge);
    	AST_TEST_REGISTER(test_cdr_dial_answer_twoparty_bridge_a);
    	AST_TEST_REGISTER(test_cdr_dial_answer_twoparty_bridge_b);
    	AST_TEST_REGISTER(test_cdr_dial_answer_multiparty);
    
    	AST_TEST_REGISTER(test_cdr_park);
    
    	AST_TEST_REGISTER(test_cdr_fields);
    	AST_TEST_REGISTER(test_cdr_no_reset_cdr);
    	AST_TEST_REGISTER(test_cdr_fork_cdr);
    
    	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_cb);
    
    	return AST_MODULE_LOAD_SUCCESS;
    }
    
    AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "CDR unit tests");