static enum ast_test_result_state test_chan_variable(struct ast_test *test, struct ast_channel *c, const char *varname) { const char *values[] = { "one", "three", "reallylongdinosaursoundingthingwithwordsinit" }; int i, okay = 1; char workspace[4096]; struct ast_str *str = ast_str_create(16); struct ast_str *var = ast_str_create(16); ast_str_set(&var, 0, "${%s}", varname); for (i = 0; i < ARRAY_LEN(values); i++) { pbx_builtin_setvar_helper(c, varname, values[i]); ast_str_substitute_variables(&str, 0, c, ast_str_buffer(var)); pbx_substitute_variables_helper(c, ast_str_buffer(var), workspace, sizeof(workspace)); ast_test_status_update(test, "Testing '%s' . . . . . %s\n", ast_str_buffer(var), okay ? "passed" : "FAILED"); if (strcmp(values[i], ast_str_buffer(str)) != 0 || strcmp(values[i], workspace) != 0) { ast_test_status_update(test, "%s != %s != %s\n", values[i], ast_str_buffer(str), workspace); okay = 0; } } ast_free(str); ast_free(var); return okay ? AST_TEST_PASS : AST_TEST_FAIL; }
static int test_exten(const struct pbx_test_pattern *test_pattern, struct ast_test *test) { struct pbx_find_info pfi = { { 0 }, }; struct ast_exten *exten; if (!(exten = pbx_find_extension(NULL, NULL, &pfi, test_pattern->context, test_pattern->test_exten, test_pattern->priority, NULL, test_pattern->test_cid, E_MATCH))) { ast_test_status_update(test, "Cannot find extension %s in context %s." "Test failed.\n", test_pattern->test_exten, test_pattern->context); return -1; } if (strcmp(ast_get_extension_name(exten), test_pattern->exten->exten)) { ast_test_status_update(test, "Expected extension %s but got extension %s instead." "Test failed.\n", test_pattern->exten->exten, ast_get_extension_name(exten)); return -1; } if (test_pattern->test_cid && strcmp(ast_get_extension_cidmatch(exten), test_pattern->test_cid)) { ast_test_status_update(test, "Expected CID match %s but got CID match %s instead." "Test failed.\n", test_pattern->exten->cid, ast_get_extension_cidmatch(exten)); return -1; } ast_test_status_update(test, "Successfully matched %s to exten %s in context %s\n", test_pattern->test_exten, test_pattern->exten->exten, test_pattern->context); return 0; }
static enum ast_test_result_state test_chan_string(struct ast_test *test, struct ast_channel *c, char *cfield, size_t cfieldsize, const char *expression) { const char *values[] = { "one", "three", "reallylongdinosaursoundingthingwithwordsinit" }; int i, okay = 1; char workspace[4096]; struct ast_str *str = ast_str_create(16); for (i = 0; i < ARRAY_LEN(values); i++) { ast_copy_string(cfield, values[i], cfieldsize); ast_str_substitute_variables(&str, 0, c, expression); pbx_substitute_variables_helper(c, expression, workspace, sizeof(workspace)); ast_test_status_update(test, "Testing '%s' . . . . . %s\n", expression, okay ? "passed" : "FAILED"); if (strcmp(cfield, ast_str_buffer(str)) != 0 || strcmp(cfield, workspace) != 0) { ast_test_status_update(test, "%s != %s != %s\n", cfield, ast_str_buffer(str), workspace); okay = 0; } } ast_free(str); return okay ? AST_TEST_PASS : AST_TEST_FAIL; }
static int test_exten(const struct pbx_test_pattern *test_pattern, struct ast_test *test, int new_engine) { struct pbx_find_info pfi = { { 0 }, }; struct ast_exten *exten; if (!(exten = pbx_find_extension(NULL, NULL, &pfi, test_pattern->context, test_pattern->test_exten, test_pattern->priority, NULL, test_pattern->test_cid, E_MATCH))) { ast_test_status_update(test, "Cannot find extension %s in context %s with the %s pattern match engine. " "Test failed.\n", test_pattern->test_exten, test_pattern->context, (new_engine ? "new" : "old")); return -1; } if (strcmp(ast_get_extension_name(exten), test_pattern->exten->exten)) { ast_test_status_update(test, "Expected extension %s but got extension %s instead with the %s pattern match engine. " "Test failed.\n", test_pattern->exten->exten, ast_get_extension_name(exten), (new_engine ? "new" : "old")); return -1; } if (test_pattern->test_cid && strcmp(ast_get_extension_cidmatch(exten), test_pattern->test_cid)) { ast_test_status_update(test, "Expected CID match %s but got CID match %s instead with the %s pattern match engine. " "Test failed.\n", test_pattern->exten->cid, ast_get_extension_cidmatch(exten), (new_engine ? "new" : "old")); return -1; } if (!ast_canmatch_extension(NULL, test_pattern->context, test_pattern->test_exten, test_pattern->priority, test_pattern->test_cid)) { ast_test_status_update(test, "Partial match failed for extension %s in context %s with the %s pattern match engine. " "Test failed.\n", test_pattern->test_exten, test_pattern->context, (new_engine ? "new" : "old")); return -1; } ast_test_status_update(test, "Successfully matched %s to exten %s in context %s with the %s pattern match engine\n", test_pattern->test_exten, test_pattern->exten->exten, test_pattern->context, (new_engine ? "new" : "old")); return 0; }
static enum ast_test_result_state test_2way_function(struct ast_test *test, struct ast_channel *c, const char *encode1, const char *encode2, const char *decode1, const char *decode2) { struct ast_str *str = ast_str_create(16), *expression = ast_str_alloca(120); int okay; ast_str_set(&expression, 0, "%s%s%s", encode1, "foobarbaz", encode2); ast_str_substitute_variables(&str, 0, c, ast_str_buffer(expression)); ast_str_set(&expression, 0, "%s%s%s", decode1, ast_str_buffer(str), decode2); ast_str_substitute_variables(&str, 0, c, ast_str_buffer(expression)); okay = !strcmp(ast_str_buffer(str), "foobarbaz"); ast_test_status_update(test, "Testing '%s%s' and '%s%s' . . . . . %s\n", encode1, encode2, decode1, decode2, okay ? "passed" : "FAILED"); if (!okay) { ast_test_status_update(test, " '%s' != 'foobarbaz'\n", ast_str_buffer(str)); } ast_free(str); return okay ? AST_TEST_PASS : AST_TEST_FAIL; }
/*! * \brief Wait for a successful resolution to complete * * This is called whenever a successful DNS resolution occurs. This function * serves to ensure that parameters are as we expect them to be. * * \param test The test being executed * \param rdata DNS query user data * \param expected_lapse The amount of time we expect to wait for the query to complete * \param num_resolves The number of DNS resolutions that have been executed * \param num_completed The number of DNS resolutions we expect to have completed successfully * \param canceled Whether the query is expected to have been canceled */ static int wait_for_resolution(struct ast_test *test, struct recurring_data *rdata, int expected_lapse, int num_resolves, int num_completed, int canceled) { struct timespec begin; struct timespec end; struct timespec timeout; int secdiff; clock_gettime(CLOCK_REALTIME, &begin); timeout.tv_sec = begin.tv_sec + 20; timeout.tv_nsec = begin.tv_nsec; ast_mutex_lock(&rdata->lock); while (!rdata->query_complete) { if (ast_cond_timedwait(&rdata->cond, &rdata->lock, &timeout) == ETIMEDOUT) { break; } } ast_mutex_unlock(&rdata->lock); if (!rdata->query_complete) { ast_test_status_update(test, "Query timed out\n"); return -1; } rdata->query_complete = 0; clock_gettime(CLOCK_REALTIME, &end); secdiff = end.tv_sec - begin.tv_sec; /* Give ourselves some wiggle room */ if (secdiff < expected_lapse - 2 || secdiff > expected_lapse + 2) { ast_test_status_update(test, "Query did not complete in expected time\n"); return -1; } if (rdata->resolves != num_resolves || rdata->complete_resolutions != num_completed) { ast_test_status_update(test, "Query has not undergone expected number of resolutions\n"); return -1; } if (rdata->canceled != canceled) { ast_test_status_update(test, "Query was canceled unexpectedly\n"); return -1; } ast_test_status_update(test, "Query completed in expected time frame\n"); return 0; }
static int container_test2_no_locking_helper(struct ast_format_cap *cap, struct ast_test *test) { int num = 0; struct ast_format tmpformat = { 0, }; ast_format_cap_add(cap, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)); ast_format_cap_add(cap, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)); ast_format_cap_add(cap, ast_format_set(&tmpformat, AST_FORMAT_G722, 0)); ast_format_cap_iter_start(cap); while (!ast_format_cap_iter_next(cap, &tmpformat)) { num++; } ast_format_cap_iter_end(cap); ast_format_cap_iter_start(cap); while (!ast_format_cap_iter_next(cap, &tmpformat)) { num++; } ast_format_cap_iter_end(cap); ast_format_cap_destroy(cap); ast_test_status_update(test, "%d items iterated over\n", num); return (num == 6) ? AST_TEST_PASS : AST_TEST_FAIL; }
/*! * \brief unref callback function * * Unrefs the object passed in. Only sets the unreffed flag if * the object is not locked. This allows us to ensure that * unreffing always occurs after unlocking. */ static void test_unref(struct test_struct *test) { ast_test_status_update(current_test, "Unref is occurring\n"); ao2_ref(test, -1); if (!test->locked) { test->reffed = 0; } }
/*! * \brief unlock callback function * * Unlocks the object passed in. Only clears the locked * flag if the object is still reffed. This allows us to * ensure that unlocking is always occurring before unreffing. */ static void test_unlock(struct test_struct *test) { ast_test_status_update(current_test, "Unlock is occurring\n"); ao2_unlock(test); if (test->reffed) { test->locked = 0; } }
/*! * \brief ref callback function * * Refs the object passed in. Only sets the reffed flag if * the object is not locked. This allows us to ensure that * reffing always occurs before locking. */ static struct test_struct *test_ref(struct test_struct *test) { ast_test_status_update(current_test, "Ref is occurring\n"); ao2_ref(test, +1); if (!test->locked) { test->reffed = 1; } return test; }
static int is_timed_out(struct hash_test const *data) { struct timeval now = ast_tvnow(); int val = ast_tvdiff_us(data->deadline, now) < 0; if (val) { /* tv_usec is suseconds_t, which could be int or long */ ast_test_status_update(data->test, "Now: %ld.%06ld Deadline: %ld.%06ld\n", now.tv_sec, (long)now.tv_usec, data->deadline.tv_sec, (long)data->deadline.tv_usec); } return val; }
static void test_xml(struct ast_test *test, const char *input, const char *expected, int max_len, int expected_res) { char actual[256] = ""; int res; if (max_len == -1) { max_len = sizeof(actual); } res = ast_xml_escape(input, actual, max_len); if (res != expected_res) { ast_test_status_update(test, "Expected result '%d', got '%d'\n", expected_res, res); test_res = AST_TEST_FAIL; } if (strcmp(expected, actual) != 0) { ast_test_status_update(test, "Expected output '%s', got '%s'\n", expected, actual); test_res = AST_TEST_FAIL; } }
static enum ast_test_result_state invalid_record_test(struct ast_test *test, struct srv_record *records, int num_records) { RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free); const struct ast_dns_record *record; enum ast_test_result_state res = AST_TEST_PASS; test_records = records; num_test_records = num_records; memset(ans_buffer, 0, sizeof(ans_buffer)); ast_dns_resolver_register(&srv_resolver); if (ast_dns_resolve("goose.feathers", ns_t_srv, ns_c_in, &result)) { ast_test_status_update(test, "DNS resolution failed\n"); res = AST_TEST_FAIL; goto cleanup; } if (!result) { ast_test_status_update(test, "DNS resolution returned no result\n"); res = AST_TEST_FAIL; goto cleanup; } record = ast_dns_result_get_records(result); if (record) { ast_test_status_update(test, "Unexpected record returned from SRV query\n"); res = AST_TEST_FAIL; } cleanup: ast_dns_resolver_unregister(&srv_resolver); test_records = NULL; num_test_records = 0; memset(ans_buffer, 0, sizeof(ans_buffer)); return res; }
static enum ast_test_result_state test_chan_function(struct ast_test *test, struct ast_channel *c, const char *expression) { int okay = 1; char workspace[4096]; struct ast_str *str = ast_str_create(16); ast_str_substitute_variables(&str, 0, c, expression); pbx_substitute_variables_helper(c, expression, workspace, sizeof(workspace)); ast_test_status_update(test, "Testing '%s' . . . . . %s\n", expression, okay ? "passed" : "FAILED"); if (strcmp(workspace, ast_str_buffer(str)) != 0) { ast_test_status_update(test, "test_chan_function, expr: '%s' ... %s != %s\n", expression, ast_str_buffer(str), workspace); okay = 0; } ast_free(str); return okay ? AST_TEST_PASS : AST_TEST_FAIL; }
static enum ast_test_result_state off_nominal_test(struct ast_test *test, struct naptr_record *records, int num_records) { RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free); enum ast_test_result_state res = AST_TEST_PASS; const struct ast_dns_record *record; test_records = records; num_test_records = num_records; memset(ans_buffer, 0, sizeof(ans_buffer)); ast_dns_resolver_register(&naptr_resolver); if (ast_dns_resolve("goose.feathers", ns_t_naptr, ns_c_in, &result)) { ast_test_status_update(test, "Failed to perform DNS resolution, despite using valid inputs\n"); res = AST_TEST_FAIL; goto cleanup; } if (!result) { ast_test_status_update(test, "Synchronous DNS resolution failed to set a result\n"); res = AST_TEST_FAIL; goto cleanup; } record = ast_dns_result_get_records(result); if (record) { ast_test_status_update(test, "DNS resolution returned records when it was not expected to\n"); res = AST_TEST_FAIL; goto cleanup; } cleanup: ast_dns_resolver_unregister(&naptr_resolver); test_records = NULL; num_test_records = 0; memset(ans_buffer, 0, sizeof(ans_buffer)); return res; }
static enum ast_test_result_state test_chan_integer(struct ast_test *test, struct ast_channel *c, int *ifield, const char *expression) { int i, okay = 1, value1 = -1, value2 = -1; char workspace[4096]; struct ast_str *str = ast_str_create(16); ast_test_status_update(test, "Testing '%s' . . . . . %s\n", expression, okay ? "passed" : "FAILED"); for (i = 0; i < 256; i++) { *ifield = i; ast_str_substitute_variables(&str, 0, c, expression); pbx_substitute_variables_helper(c, expression, workspace, sizeof(workspace)); if (sscanf(workspace, "%d", &value1) != 1 || value1 != i || sscanf(ast_str_buffer(str), "%d", &value2) != 1 || value2 != i) { ast_test_status_update(test, "%s != %s and/or %d != %d != %d\n", ast_str_buffer(str), workspace, value1, value2, i); okay = 0; } } ast_free(str); return okay ? AST_TEST_PASS : AST_TEST_FAIL; }
/*! * \brief helper to ensure that statistics the listener is keeping are what we expect * * \param test The currently-running test * \param pvt The private data for the taskprocessor listener * \param num_pushed The expected current number of tasks pushed to the processor * \param num_emptied The expected current number of times the taskprocessor has become empty * \param num_was_empty The expected current number of times that tasks were pushed to an empty taskprocessor * \retval -1 Stats were not as expected * \retval 0 Stats were as expected */ static int check_stats(struct ast_test *test, const struct test_listener_pvt *pvt, int num_pushed, int num_emptied, int num_was_empty) { if (pvt->num_pushed != num_pushed) { ast_test_status_update(test, "Unexpected number of tasks pushed. Expected %d but got %d\n", num_pushed, pvt->num_pushed); return -1; } if (pvt->num_emptied != num_emptied) { ast_test_status_update(test, "Unexpected number of empties. Expected %d but got %d\n", num_emptied, pvt->num_emptied); return -1; } if (pvt->num_was_empty != num_was_empty) { ast_test_status_update(test, "Unexpected number of empties. Expected %d but got %d\n", num_was_empty, pvt->num_emptied); return -1; } return 0; }
static int container_test3_helper(int nolocking, struct ast_test *test) { int x; int res = AST_TEST_PASS; struct ast_format_cap *cap1; struct ast_format_cap *cap2; struct ast_format_cap *joint; for (x = 0; x < 2000; x++) { if (nolocking) { cap1 = ast_format_cap_alloc_nolock(); cap2 = ast_format_cap_alloc_nolock(); joint = ast_format_cap_alloc_nolock(); } else { cap1 = ast_format_cap_alloc(); cap2 = ast_format_cap_alloc(); joint = ast_format_cap_alloc(); } if (!cap1 || !cap2 || !joint) { ast_test_status_update(test, "cap alloc fail\n"); return AST_TEST_FAIL; } ast_format_cap_add_all(cap1); ast_format_cap_add_all_by_type(cap2, AST_FORMAT_TYPE_AUDIO); ast_format_cap_joint_copy(cap1, cap2, joint); if (!(ast_format_cap_identical(cap2, joint))) { ast_test_status_update(test, "failed identical test\n"); res = AST_TEST_FAIL; cap1 = ast_format_cap_destroy(cap1); cap2 = ast_format_cap_destroy(cap2); joint = ast_format_cap_destroy(joint); break; } cap1 = ast_format_cap_destroy(cap1); cap2 = ast_format_cap_destroy(cap2); joint = ast_format_cap_destroy(joint); } return res; }
static enum ast_test_result_state test_expected_result(struct ast_test *test, struct ast_channel *c, const char *expression, const char *result) { struct ast_str *str = ast_str_create(16); int okay; ast_str_substitute_variables(&str, 0, c, expression); okay = !strcmp(ast_str_buffer(str), result); ast_test_status_update(test, "Testing '%s' ('%s') == '%s' . . . . . %s\n", ast_str_buffer(str), expression, result, okay ? "passed" : "FAILED"); if (!okay) { ast_test_status_update(test, "test_expected_result: '%s' != '%s'\n", ast_str_buffer(str), result); } ast_free(str); return okay ? AST_TEST_PASS : AST_TEST_FAIL; }
static int build_ha(const struct acl *acl, size_t len, struct ast_ha **ha, const char *acl_name, int *err, struct ast_test *test, enum ast_test_result_state *res) { size_t i; for (i = 0; i < len; ++i) { if (!(*ha = ast_append_ha(acl[i].access, acl[i].host, *ha, err))) { ast_test_status_update(test, "Failed to add rule %s with access %s to %s\n", acl[i].host, acl[i].access, acl_name); *res = AST_TEST_FAIL; return -1; } } return 0; }
static int check_event(struct ast_event *event, struct ast_test *test, enum ast_event_type expected_type, const char *type_name, const char *str, uint32_t uint) { enum ast_event_type type; const void *foo; /* Check #1: Ensure event type is set properly. */ type = ast_event_get_type(event); if (ast_event_get_type(event) != type) { ast_test_status_update(test, "Expected event type: '%u', got '%u'\n", expected_type, type); return -1; } /* Check #4: Check for the string IE */ if (strcmp(str, ast_event_get_ie_str(event, AST_EVENT_IE_CEL_USEREVENT_NAME))) { ast_test_status_update(test, "Failed to get string IE.\n"); return -1; } /* Check #5: Check for the uint IE */ if (uint != ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_AMAFLAGS)) { ast_test_status_update(test, "Failed to get uint IE.\n"); return -1; } /* Check #6: Check if a check for a str IE that isn't there works */ if ((foo = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_CIDNAME))) { ast_test_status_update(test, "CEL_CIDNAME IE check returned non-NULL %p\n", foo); return -1; } /* Check #7: Check if a check for a uint IE that isn't there returns 0 */ if (ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_EVENT_TIME_USEC)) { ast_test_status_update(test, "UNIQUEID IE should be 0\n"); return -1; } ast_test_status_update(test, "Event looks good.\n"); return 0; }
static int scheduler(struct ast_test *test, int serialized) { RAII_VAR(struct ast_taskprocessor *, tp1, NULL, ast_taskprocessor_unreference); RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup); RAII_VAR(struct test_data *, test_data2, ao2_alloc(sizeof(*test_data2), data_cleanup), ao2_cleanup); RAII_VAR(struct ast_sip_sched_task *, task1, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_sched_task *, task2, NULL, ao2_cleanup); int duration; int delay; struct timeval task1_start; ast_test_validate(test, test_data1 != NULL); ast_test_validate(test, test_data2 != NULL); test_data1->test = test; test_data1->test_start = ast_tvnow(); test_data1->interval = 2000; test_data1->sleep = 1000; ast_mutex_init(&test_data1->lock); ast_cond_init(&test_data1->cond, NULL); test_data2->test = test; test_data2->test_start = ast_tvnow(); test_data2->interval = 2000; test_data2->sleep = 1000; ast_mutex_init(&test_data2->lock); ast_cond_init(&test_data2->cond, NULL); if (serialized) { ast_test_status_update(test, "This test will take about %3.1f seconds\n", (test_data1->interval + test_data1->sleep + (MAX(test_data1->interval - test_data2->interval, 0)) + test_data2->sleep) / 1000.0); tp1 = ast_sip_create_serializer("test-scheduler-serializer"); ast_test_validate(test, (tp1 != NULL)); } else { ast_test_status_update(test, "This test will take about %3.1f seconds\n", ((MAX(test_data1->interval, test_data2->interval) + MAX(test_data1->sleep, test_data2->sleep)) / 1000.0)); } task1 = ast_sip_schedule_task(tp1, test_data1->interval, task_1, NULL, test_data1, AST_SIP_SCHED_TASK_FIXED); ast_test_validate(test, task1 != NULL); task2 = ast_sip_schedule_task(tp1, test_data2->interval, task_1, NULL, test_data2, AST_SIP_SCHED_TASK_FIXED); ast_test_validate(test, task2 != NULL); waitfor(test_data1); ast_sip_sched_task_cancel(task1); ast_test_validate(test, test_data1->is_servant); duration = ast_tvdiff_ms(test_data1->task_end, test_data1->test_start); ast_test_validate(test, (duration > ((test_data1->interval + test_data1->sleep) * 0.9)) && (duration < ((test_data1->interval + test_data1->sleep) * 1.1))); ast_sip_sched_task_get_times(task1, NULL, &task1_start, NULL); delay = ast_tvdiff_ms(task1_start, test_data1->test_start); ast_test_validate(test, (delay > (test_data1->interval * 0.9) && (delay < (test_data1->interval * 1.1)))); waitfor(test_data2); ast_sip_sched_task_cancel(task2); ast_test_validate(test, test_data2->is_servant); if (serialized) { ast_test_validate(test, test_data1->tid == test_data2->tid); ast_test_validate(test, ast_tvdiff_ms(test_data2->task_start, test_data1->task_end) >= 0); } else { ast_test_validate(test, test_data1->tid != test_data2->tid); } return AST_TEST_PASS; }
static enum ast_test_result_state nominal_test(struct ast_test *test, struct srv_record *records, int *srv_record_order, int num_records) { RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free); const struct ast_dns_record *record; enum ast_test_result_state res = AST_TEST_PASS; int i; test_records = records; num_test_records = num_records; memset(ans_buffer, 0, sizeof(ans_buffer)); ast_dns_resolver_register(&srv_resolver); if (ast_dns_resolve("goose.feathers", ns_t_srv, ns_c_in, &result)) { ast_test_status_update(test, "DNS resolution failed\n"); res = AST_TEST_FAIL; goto cleanup; } if (!result) { ast_test_status_update(test, "DNS resolution returned no result\n"); res = AST_TEST_FAIL; goto cleanup; } i = 0; for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) { if (ast_dns_srv_get_priority(record) != records[srv_record_order[i]].priority) { ast_test_status_update(test, "Unexpected priority in returned SRV record\n"); res = AST_TEST_FAIL; } if (ast_dns_srv_get_weight(record) != records[srv_record_order[i]].weight) { ast_test_status_update(test, "Unexpected weight in returned SRV record\n"); res = AST_TEST_FAIL; } if (ast_dns_srv_get_port(record) != records[srv_record_order[i]].port) { ast_test_status_update(test, "Unexpected port in returned SRV record\n"); res = AST_TEST_FAIL; } if (strcmp(ast_dns_srv_get_host(record), records[srv_record_order[i]].host)) { ast_test_status_update(test, "Unexpected host in returned SRV record\n"); res = AST_TEST_FAIL; } ++i; } if (i != num_records) { ast_test_status_update(test, "Unexpected number of records returned in SRV lookup\n"); res = AST_TEST_FAIL; } cleanup: ast_dns_resolver_unregister(&srv_resolver); test_records = NULL; num_test_records = 0; memset(ans_buffer, 0, sizeof(ans_buffer)); return res; }
/*! \brief Wait for the \ref test_msg_handler to receive the message */ static int handler_wait_for_message(struct ast_test *test) { int error = 0; struct timeval wait_now = ast_tvnow(); struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 }; ast_mutex_lock(&handler_lock); while (!handler_received_message) { error = ast_cond_timedwait(&handler_cond, &handler_lock, &wait_time); if (error == ETIMEDOUT) { ast_test_status_update(test, "Test timed out while waiting for handler to get message\n"); ast_test_set_result(test, AST_TEST_FAIL); break; } } ast_mutex_unlock(&handler_lock); return (error != ETIMEDOUT); } /*! \brief Wait for the expected number of user events to be received */ static int user_event_wait_for_events(struct ast_test *test, int expected_events) { int error; struct timeval wait_now = ast_tvnow(); struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 1, .tv_nsec = wait_now.tv_usec * 1000 }; expected_user_events = expected_events; ast_mutex_lock(&user_event_lock); while (received_user_events != expected_user_events) { error = ast_cond_timedwait(&user_event_cond, &user_event_lock, &wait_time); if (error == ETIMEDOUT) { ast_test_status_update(test, "Test timed out while waiting for %d expected user events\n", expected_events); ast_test_set_result(test, AST_TEST_FAIL); break; } } ast_mutex_unlock(&user_event_lock); ast_test_status_update(test, "Received %d of %d user events\n", received_user_events, expected_events); return !(received_user_events == expected_events); } static int verify_bad_headers(struct ast_test *test) { int res = 0; int i; for (i = 0; i < AST_VECTOR_SIZE(&bad_headers); i++) { struct ast_variable *headers; struct ast_variable *current; headers = AST_VECTOR_GET(&bad_headers, i); if (!headers) { continue; } res = -1; for (current = headers; current; current = current->next) { ast_test_status_update(test, "Expected UserEvent %d: Failed to match %s: %s\n", i, current->name, current->value); ast_test_set_result(test, AST_TEST_FAIL); } } return res; }
static int container_test1_helper(struct ast_format_cap *cap1, struct ast_format_cap *cap2, struct ast_test *test) { int res = AST_TEST_PASS; struct ast_format_cap *cap_joint = NULL; struct ast_format tmpformat; if (ast_format_attr_reg_interface(&test_interface)) { ast_test_status_update(test, "test_interface failed to register.\n"); ast_format_cap_destroy(cap1); ast_format_cap_destroy(cap2); return AST_TEST_FAIL; } ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)); ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)); ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_G722, 0)); ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)); ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)); ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H263, 0)); ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0)); ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)); ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, TEST_ATTR_KEY_STRING, "testing caps hooray", TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ, AST_FORMAT_ATTR_END)); /* Test is compatible */ if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) || !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) || !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) || !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) || !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) || !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) { ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 1.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* Test things that are not compatible */ if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX, 0)) || ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX16, 0)) || ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H261, 0))) { ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 2.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* Test compatiblity with format with attributes. */ if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, TEST_ATTR_KEY_STRING, "testing caps hooray", TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, AST_FORMAT_ATTR_END))) { ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 3.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, AST_FORMAT_ATTR_END))) { ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 4.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ, /* 48khz was not compatible, so this should fail iscompatible check */ AST_FORMAT_ATTR_END))) { ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 5.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* Lets start testing the functions that compare ast_format_cap objects. * Genreate the cap2 object to contain some similar formats as cap1 * and some different formats as well. */ ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)); ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)); ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0)); ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_H261, 0)); ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_T140, 0)); ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, TEST_ATTR_KEY_STRING, "testing caps hooray", TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_12KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ, AST_FORMAT_ATTR_END)); /* find joint formats between cap1 and cap2 */ cap_joint = ast_format_cap_joint(cap1, cap2); if (!cap_joint) { ast_test_status_update(test, "failed to create joint capabilities correctly.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* determine if cap_joint is what we think it should be */ if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) || !ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) || !ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0)) || !ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, TEST_ATTR_KEY_STRING, "testing caps hooray", TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, AST_FORMAT_ATTR_END))) { ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* make sure joint cap does not have formats that should not be there */ if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0)) || ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, TEST_ATTR_KEY_STRING, "testing caps hooray", TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ, AST_FORMAT_ATTR_END))) { ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* Lets test removing a capability */ if (ast_format_cap_remove(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) { ast_test_status_update(test, "ast_format_cap_remove failed. \n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* Lets make sure what we just removed does not still exist */ if (ast_format_cap_iscompatible(cap_joint, &tmpformat)) { ast_test_status_update(test, "ast_format_cap_remove failed 2. \n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* Lets test removing a capability by id.*/ if (ast_format_cap_remove_byid(cap_joint, AST_FORMAT_GSM)) { ast_test_status_update(test, "ast_format_cap_remove failed 3. \n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* Lets make sure what we just removed does not still exist */ if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0))) { ast_test_status_update(test, "ast_format_cap_remove failed 4. \n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* lets test getting joint formats by type */ ast_format_cap_destroy(cap_joint); if (!(cap_joint = ast_format_cap_get_type(cap1, AST_FORMAT_TYPE_VIDEO))) { ast_test_status_update(test, "ast_format_cap_get_type failed.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* lets make sure our joint capability structure has what we expect */ if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) || !ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H263, 0))) { ast_test_status_update(test, "get_type failed 2.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* now make sure joint does not have anything but video */ if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) || ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) || ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) || ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) || ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) { ast_test_status_update(test, "get_type failed 3.\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* now lets remove everythign from cap_joint */ ast_format_cap_remove_all(cap_joint); if (!ast_format_cap_is_empty(cap_joint)) { ast_test_status_update(test, "failed to remove all\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* now lets add all by type */ ast_format_cap_add_all_by_type(cap_joint, AST_FORMAT_TYPE_AUDIO); if (ast_format_cap_is_empty(cap_joint)) { ast_test_status_update(test, "failed to add all by type AUDIO\n"); res = AST_TEST_FAIL; } ast_format_cap_iter_start(cap_joint); while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) { if (AST_FORMAT_GET_TYPE(tmpformat.id) != AST_FORMAT_TYPE_AUDIO) { ast_test_status_update(test, "failed to add all by type AUDIO\n"); res = AST_TEST_FAIL; ast_format_cap_iter_end(cap_joint); goto test3_cleanup; } } ast_format_cap_iter_end(cap_joint); /* test append */ ast_format_cap_append(cap_joint, cap1); ast_format_cap_iter_start(cap1); while (!(ast_format_cap_iter_next(cap1, &tmpformat))) { if (!ast_format_cap_iscompatible(cap_joint, &tmpformat)) { ast_test_status_update(test, "failed to append format capabilities.\n"); res = AST_TEST_FAIL; ast_format_cap_iter_end(cap1); goto test3_cleanup; } } ast_format_cap_iter_end(cap1); /* test copy */ cap1 = ast_format_cap_destroy(cap1); cap1 = ast_format_cap_dup(cap_joint); if (!ast_format_cap_identical(cap_joint, cap1)) { ast_test_status_update(test, "failed to copy capabilities\n"); res = AST_TEST_FAIL; goto test3_cleanup; } /* test remove by type */ ast_format_cap_remove_bytype(cap_joint, AST_FORMAT_TYPE_AUDIO); if (ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_AUDIO)) { ast_test_status_update(test, "failed to remove all by type audio\n"); res = AST_TEST_FAIL; goto test3_cleanup; } if (!ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_TEXT)) { /* it should still have text */ ast_test_status_update(test, "failed to remove all by type audio\n"); res = AST_TEST_FAIL; goto test3_cleanup; } ast_format_cap_iter_start(cap_joint); while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) { if (AST_FORMAT_GET_TYPE(tmpformat.id) == AST_FORMAT_TYPE_AUDIO) { ast_test_status_update(test, "failed to remove all by type audio\n"); res = AST_TEST_FAIL; ast_format_cap_iter_end(cap_joint); goto test3_cleanup; } } ast_format_cap_iter_end(cap_joint); /* test add all */ ast_format_cap_remove_all(cap_joint); ast_format_cap_add_all(cap_joint); { int video = 0, audio = 0, text = 0, image = 0; ast_format_cap_iter_start(cap_joint); while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) { switch (AST_FORMAT_GET_TYPE(tmpformat.id)) { case AST_FORMAT_TYPE_AUDIO: audio++; break; case AST_FORMAT_TYPE_VIDEO: video++; break; case AST_FORMAT_TYPE_TEXT: text++; break; case AST_FORMAT_TYPE_IMAGE: image++; break; } } ast_format_cap_iter_end(cap_joint); if (!video || !audio || !text || !image) { ast_test_status_update(test, "failed to add all\n"); res = AST_TEST_FAIL; goto test3_cleanup; } } /* test copy2 */ ast_format_cap_copy(cap2, cap_joint); if (!ast_format_cap_identical(cap2, cap_joint)) { ast_test_status_update(test, "ast_format_cap_copy failed\n"); res = AST_TEST_FAIL; goto test3_cleanup; } test3_cleanup: ast_format_cap_destroy(cap1); ast_format_cap_destroy(cap2); ast_format_cap_destroy(cap_joint); /* unregister interface */ if (ast_format_attr_unreg_interface(&test_interface)) { ast_test_status_update(test, "test_interface failed to unregister.\n"); res = AST_TEST_FAIL; } return res; }
static int check_event(struct ast_event *event, struct ast_test *test, enum ast_event_type expected_type, const char *type_name, const char *str, uint32_t uint, uint32_t bitflags) { enum ast_event_type type; const void *foo; /* Check #1: Ensure event type is set properly. */ type = ast_event_get_type(event); if (ast_event_get_type(event) != type) { ast_test_status_update(test, "Expected event type: '%d', got '%d'\n", expected_type, type); return -1; } /* Check #2: Check string representation of event type */ if (strcmp(type_name, ast_event_get_type_name(event))) { ast_test_status_update(test, "Didn't get expected type name: '%s' != '%s'\n", type_name, ast_event_get_type_name(event)); return -1; } /* Check #3: Check for automatically included EID */ if (memcmp(&ast_eid_default, ast_event_get_ie_raw(event, AST_EVENT_IE_EID), sizeof(ast_eid_default))) { ast_test_status_update(test, "Failed to get EID\n"); return -1; } /* Check #4: Check for the string IE */ if (strcmp(str, ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX))) { ast_test_status_update(test, "Failed to get string IE.\n"); return -1; } /* Check #5: Check for the uint IE */ if (uint != ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS)) { ast_test_status_update(test, "Failed to get uint IE.\n"); return -1; } /* Check #6: Check for the bitflags IE */ if (bitflags != ast_event_get_ie_bitflags(event, AST_EVENT_IE_OLDMSGS)) { ast_test_status_update(test, "Failed to get bitflags IE.\n"); return -1; } /* Check #7: Check if a check for a str IE that isn't there works */ if ((foo = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE))) { ast_test_status_update(test, "DEVICE IE check returned non-NULL %p\n", foo); return -1; } /* Check #8: Check if a check for a uint IE that isn't there returns 0 */ if (ast_event_get_ie_uint(event, AST_EVENT_IE_STATE)) { ast_test_status_update(test, "OLDMSGS IE should be 0\n"); return -1; } ast_test_status_update(test, "Event looks good.\n"); return 0; }
static int astobj2_test_helper(int use_hash, int use_cmp, unsigned int lim, struct ast_test *test) { struct ao2_container *c1; struct ao2_container *c2; struct ao2_iterator it; struct test_obj *obj; struct test_obj tmp_obj; int bucket_size; int increment = 0; int destructor_count = 0; int num; int res = AST_TEST_PASS; /* This test needs at least 5 objects */ if (lim < 5) { lim = 5; } bucket_size = (ast_random() % ((lim / 4) + 1)) + 1; c1 = ao2_container_alloc(bucket_size, use_hash ? test_hash_cb : NULL, use_cmp ? test_cmp_cb : NULL); c2 = ao2_container_alloc(bucket_size, test_hash_cb, test_cmp_cb); if (!c1 || !c2) { ast_test_status_update(test, "ao2_container_alloc failed.\n"); res = AST_TEST_FAIL; goto cleanup; } /* Create objects and link into container */ destructor_count = lim; for (num = 1; num <= lim; num++) { if (!(obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor))) { ast_test_status_update(test, "ao2_alloc failed.\n"); res = AST_TEST_FAIL; goto cleanup; } snprintf(obj->c, sizeof(obj->c), "zombie #%d", num); obj->destructor_count = &destructor_count; obj->i = num; ao2_link(c1, obj); ao2_ref(obj, -1); if (ao2_container_count(c1) != num) { ast_test_status_update(test, "container did not link correctly\n"); res = AST_TEST_FAIL; } } ast_test_status_update(test, "Container created: random bucket size %d: number of items: %d\n", bucket_size, lim); /* Testing ao2_find with no flags */ num = 100; for (; num; num--) { int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */ tmp_obj.i = i; if (!(obj = ao2_find(c1, &tmp_obj, 0))) { res = AST_TEST_FAIL; ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with no flags failed.\n", i); } else { /* a correct match will only take place when the custom cmp function is used */ if (use_cmp && obj->i != i) { ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i); res = AST_TEST_FAIL; } ao2_ref(obj, -1); } } /* Testing ao2_find with OBJ_POINTER */ num = 75; for (; num; num--) { int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */ snprintf(tmp_obj.c, sizeof(tmp_obj.c), "zombie #%d", i); tmp_obj.i = i; if (!(obj = ao2_find(c1, &tmp_obj, OBJ_POINTER))) { res = AST_TEST_FAIL; ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_POINTER flag failed.\n", i); } else { /* a correct match will only take place when the custom cmp function is used */ if (use_cmp && obj->i != i) { ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i); res = AST_TEST_FAIL; } ao2_ref(obj, -1); } } /* Testing ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE. * In this test items are unlinked from c1 and placed in c2. Then * unlinked from c2 and placed back into c1. * * For this module and set of custom hash/cmp functions, an object * should only be found if the astobj2 default cmp function is used. * This test is designed to mimic the chan_iax.c call number use case. */ num = lim < 25 ? lim : 25; for (; num; num--) { if (!(obj = ao2_find(c1, NULL, OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE))) { if (!use_cmp) { ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with default hash function.\n"); res = AST_TEST_FAIL; } } else { if (use_cmp) { ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with custom hash function.\n"); res = AST_TEST_FAIL; } ao2_link(c2, obj); ao2_ref(obj, -1); } } it = ao2_iterator_init(c2, 0); while ((obj = ao2_iterator_next(&it))) { ao2_unlink(c2, obj); ao2_link(c1, obj); ao2_ref(obj, -1); } ao2_iterator_destroy(&it); /* Test Callback with no flags. */ increment = 0; ao2_callback(c1, 0, increment_cb, &increment); if (increment != lim) { ast_test_status_update(test, "callback with no flags failed. Increment is %d\n", increment); res = AST_TEST_FAIL; } /* Test Callback with OBJ_NODATA. This should do nothing different than with no flags here. */ increment = 0; ao2_callback(c1, OBJ_NODATA, increment_cb, &increment); if (increment != lim) { ast_test_status_update(test, "callback with OBJ_NODATA failed. Increment is %d\n", increment); res = AST_TEST_FAIL; } /* Is the container count what we expect after all the finds and unlinks?*/ if (ao2_container_count(c1) != lim) { ast_test_status_update(test, "container count does not match what is expected after ao2_find tests.\n"); res = AST_TEST_FAIL; } /* Testing iterator. Unlink a single object and break. do not add item back */ it = ao2_iterator_init(c1, 0); num = (lim / 4) + 1; while ((obj = ao2_iterator_next(&it))) { if (obj->i == num) { ao2_ref(obj, -1); ao2_unlink(c1, obj); break; } ao2_ref(obj, -1); } ao2_iterator_destroy(&it); /* Is the container count what we expect after removing a single item? */ if (ao2_container_count(c1) != (lim - 1)) { ast_test_status_update(test, "unlink during iterator failed. Number %d was not removed.\n", num); res = AST_TEST_FAIL; } /* Test unlink all with OBJ_MULTIPLE, leave a single object for the container to destroy */ ao2_callback(c1, OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA, all_but_one_cb, NULL); /* check to make sure all test_obj destructors were called except for 1 */ if (destructor_count != 1) { ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA failed. destructor count %d\n", destructor_count); res = AST_TEST_FAIL; } cleanup: /* destroy containers */ if (c1) { ao2_ref(c1, -1); } if (c2) { ao2_ref(c2, -1); } if (destructor_count > 0) { ast_test_status_update(test, "all destructors were not called, destructor count is %d\n", destructor_count); res = AST_TEST_FAIL; } else if (destructor_count < 0) { ast_test_status_update(test, "Destructor was called too many times, destructor count is %d\n", destructor_count); res = AST_TEST_FAIL; } return res; }