113 int *
i = (
int *) arg;
124 int *
i = (
int *) arg;
128 int *
i = (
int *) arg;
130 return (*i - partial_key_match_range <= cmp_obj->i
152 const struct test_obj *hash_obj = obj;
158 static int test_sort_cb(
const void *obj_left,
const void *obj_right,
int flags)
160 const struct test_obj *test_left = obj_left;
163 const int *
i = obj_right;
165 return test_left->
i - *
i;
167 int *
i = (
int *) obj_right;
169 if (*i - partial_key_match_range <= test_left->i
174 return test_left->
i - *
i;
176 const struct test_obj *test_right = obj_right;
178 return test_left->
i - test_right->
i;
182 #if defined(TEST_CONTAINER_DEBUG_DUMP) 194 static void test_prnt_obj(
void *v_obj,
void *where,
ao2_prnt_fn *prnt)
248 "Orig container has an object %p not in the clone container.\n", obj);
285 for (num = 100; num--;) {
289 obj =
ao2_find(look_in, &tmp_obj, 0);
324 for (num = 75; num--;) {
362 for (num = 75; num--;) {
402 for (num = 100; num--;) {
437 tst_num, c_type, use_sort ?
"sorted" :
"non-sorted");
448 n_buckets = (
ast_random() % ((lim / 4) + 1)) + 1;
468 for (num = 0; num < lim; ++num) {
491 c_type, n_buckets, lim);
511 if (increment != lim) {
519 if (increment != lim) {
525 num = lim < 25 ? lim : 25;
532 ast_test_status_update(test,
"OBJ_MULTIPLE | OBJ_UNLINK test failed, did not unlink correct number of objects.\n");
615 if (destructor_count != 1) {
616 ast_test_status_update(test,
"OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA failed. destructor count %d\n", destructor_count);
623 #if defined(TEST_CONTAINER_DEBUG_DUMP) 637 if (destructor_count > 0) {
638 ast_test_status_update(test,
"all destructors were not called, destructor count is %d\n", destructor_count);
640 }
else if (destructor_count < 0) {
641 ast_test_status_update(test,
"Destructor was called too many times, destructor count is %d\n", destructor_count);
654 info->name =
"astobj2_test1";
655 info->category =
"/main/astobj2/";
656 info->summary =
"Test ao2 objects, containers, callbacks, and iterators";
658 "Builds ao2_containers with various item numbers, bucket sizes, cmp and hash " 659 "functions. Runs a series of tests to manipulate the container using callbacks " 660 "and iterators. Verifies expected behavior.";
697 static const int NUM_OBJS = 5;
703 info->name =
"astobj2_test2";
704 info->category =
"/main/astobj2/";
705 info->summary =
"Test a certain scenario using ao2 iterators";
707 "This test is aimed at testing for a specific regression that occurred. " 708 "Add some objects into a container. Mix finds and iteration and make " 709 "sure that the iterator still sees all objects.";
722 for (num = 1; num <= NUM_OBJS; num++) {
754 if (num != NUM_OBJS) {
764 tmp_obj.
i = NUM_OBJS;
781 if (num != NUM_OBJS) {
796 tmp_obj.
i = NUM_OBJS - 1;
810 if (num != NUM_OBJS) {
838 info->name =
"astobj2_test3";
839 info->category =
"/main/astobj2/";
840 info->summary =
"Test global ao2 holder";
842 "This test is to see if the global ao2 holder works as intended.";
856 obj->
i = ++num_objects;
874 obj->
i = ++num_objects;
900 obj->
i = ++num_objects;
928 destructor_count += num_objects;
929 if (0 < destructor_count) {
931 "all destructors were not called, destructor count is %d\n",
934 }
else if (destructor_count < 0) {
936 "Destructor was called too many times, destructor count is %d\n",
943 ao2_t_ref(obj, -1,
"Test cleanup external object 1");
946 ao2_t_ref(obj2, -1,
"Test cleanup external object 2");
949 ao2_t_ref(obj3, -1,
"Test cleanup external object 3");
1045 for (idx = 0; idx < count; ++idx) {
1051 if (destroy_counter) {
1056 obj->
i = vector[idx];
1061 prefix, idx, vector[idx]);
1067 "%s: Unexpected container count. Expected:%d Got:%d\n",
1108 for (count = 0; count < 4; ++count) {
1117 if (destroy_counter) {
1135 prefix, number, count);
1188 for (idx = 0; idx < count; ++idx) {
1195 if (vector[idx] != obj->
i) {
1197 prefix, obj->
i, idx, vector[idx]);
1247 for (idx = 0; idx < count; ++idx) {
1254 if (vector[idx] != obj->
i) {
1256 prefix, obj->
i, idx, vector[idx]);
1304 for (idx = 0; idx < count; ++idx) {
1311 if (number != obj->
i) {
1313 prefix, obj->
i, number);
1326 "%s: Too many objects found. Object %d, dup id %d\n",
1356 static const int test_initial[] = {
1357 1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1361 static const int test_reverse[] = {
1362 8, 9, 3, 5, 7, 4, 6, 2, 0, 1
1364 static const int test_list_partial_forward[] = {
1367 static const int test_list_partial_backward[] = {
1372 static const int test_hash_end_forward[] = {
1373 0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1375 static const int test_hash_end_backward[] = {
1376 9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1378 static const int test_hash_begin_forward[] = {
1379 5, 0, 6, 1, 7, 2, 8, 3, 9, 4
1381 static const int test_hash_begin_backward[] = {
1382 4, 9, 3, 8, 2, 7, 1, 6, 0, 5
1384 static const int test_hash_partial_forward[] = {
1387 static const int test_hash_partial_backward[] = {
1423 "Iteration (ascending, insert end)", test);
1426 "Iteration (descending, insert end)", test);
1430 "Iteration (ascending, insert begin)", test);
1433 "Iteration (descending, insert begin)", test);
1437 test_hash_end_forward,
ARRAY_LEN(test_hash_end_forward),
1438 "Iteration (ascending, insert end)", test);
1440 test_hash_end_backward,
ARRAY_LEN(test_hash_end_backward),
1441 "Iteration (descending, insert end)", test);
1444 test_hash_begin_forward,
ARRAY_LEN(test_hash_begin_forward),
1445 "Iteration (ascending, insert begin)", test);
1447 test_hash_begin_backward,
ARRAY_LEN(test_hash_begin_backward),
1448 "Iteration (descending, insert begin)", test);
1459 "Traversal (ascending, insert end)", test);
1462 "Traversal (descending, insert end)", test);
1466 "Traversal (ascending, insert begin)", test);
1469 "Traversal (descending, insert begin)", test);
1473 test_hash_end_forward,
ARRAY_LEN(test_hash_end_forward),
1474 "Traversal (ascending, insert end)", test);
1476 test_hash_end_backward,
ARRAY_LEN(test_hash_end_backward),
1477 "Traversal (descending, insert end)", test);
1480 test_hash_begin_forward,
ARRAY_LEN(test_hash_begin_forward),
1481 "Traversal (ascending, insert begin)", test);
1483 test_hash_begin_backward,
ARRAY_LEN(test_hash_begin_backward),
1484 "Traversal (descending, insert begin)", test);
1497 test_list_partial_forward,
ARRAY_LEN(test_list_partial_forward),
1498 "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1501 test_list_partial_backward,
ARRAY_LEN(test_list_partial_backward),
1502 "Traversal OBJ_PARTIAL_KEY (descending)", test);
1507 test_hash_partial_forward,
ARRAY_LEN(test_hash_partial_forward),
1508 "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1511 test_hash_partial_backward,
ARRAY_LEN(test_hash_partial_backward),
1512 "Traversal OBJ_PARTIAL_KEY (descending)", test);
1527 if (destructor_count > 0) {
1529 "all destructors were not called, destructor count is %d\n",
1532 }
else if (destructor_count < 0) {
1534 "Destructor was called too many times, destructor count is %d\n",
1560 int duplicate_number = 100;
1563 static const int test_initial[] = {
1564 1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1568 static const int test_forward[] = {
1569 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
1572 static const int test_backward[] = {
1573 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
1576 static const int test_partial_forward[] = {
1579 static const int test_partial_backward[] = {
1584 static const int test_hash_forward[] = {
1585 0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1587 static const int test_hash_backward[] = {
1588 9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1590 static const int test_hash_partial_forward[] = {
1593 static const int test_hash_partial_backward[] = {
1598 static const int test_dup_allow_forward[] = {
1601 static const int test_dup_allow_backward[] = {
1604 static const int test_dup_reject[] = {
1607 static const int test_dup_obj_reject_forward[] = {
1610 static const int test_dup_obj_reject_backward[] = {
1613 static const int test_dup_replace[] = {
1644 #if defined(TEST_CONTAINER_DEBUG_DUMP) 1657 "Iteration (ascending)", test);
1659 test_backward,
ARRAY_LEN(test_backward),
1660 "Iteration (descending)", test);
1664 test_hash_forward,
ARRAY_LEN(test_hash_forward),
1665 "Iteration (ascending)", test);
1667 test_hash_backward,
ARRAY_LEN(test_hash_backward),
1668 "Iteration (descending)", test);
1678 "Traversal (ascending)", test);
1680 test_backward,
ARRAY_LEN(test_backward),
1681 "Traversal (descending)", test);
1685 test_hash_forward,
ARRAY_LEN(test_hash_forward),
1686 "Traversal (ascending, insert end)", test);
1688 test_hash_backward,
ARRAY_LEN(test_hash_backward),
1689 "Traversal (descending)", test);
1701 test_partial_forward,
ARRAY_LEN(test_partial_forward),
1702 "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1705 test_partial_backward,
ARRAY_LEN(test_partial_backward),
1706 "Traversal OBJ_PARTIAL_KEY (descending)", test);
1711 test_hash_partial_forward,
ARRAY_LEN(test_hash_partial_forward),
1712 "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1715 test_hash_partial_backward,
ARRAY_LEN(test_hash_partial_backward),
1716 "Traversal OBJ_PARTIAL_KEY (descending)", test);
1730 #if defined(TEST_CONTAINER_DEBUG_DUMP) 1739 test_dup_allow_forward,
ARRAY_LEN(test_dup_allow_forward),
1740 "Duplicates (ascending, DUPS_ALLOW)", test);
1742 test_dup_allow_backward,
ARRAY_LEN(test_dup_allow_backward),
1743 "Duplicates (descending, DUPS_ALLOW)", test);
1782 test_dup_reject,
ARRAY_LEN(test_dup_reject),
1783 "Duplicates (ascending, DUPS_REJECT)", test);
1785 test_dup_reject,
ARRAY_LEN(test_dup_reject),
1786 "Duplicates (descending, DUPS_REJECT)", test);
1825 test_dup_obj_reject_forward,
ARRAY_LEN(test_dup_obj_reject_forward),
1826 "Duplicates (ascending, DUPS_OBJ_REJECT)", test);
1828 test_dup_obj_reject_backward,
ARRAY_LEN(test_dup_obj_reject_backward),
1829 "Duplicates (descending, DUPS_OBJ_REJECT)", test);
1868 test_dup_replace,
ARRAY_LEN(test_dup_replace),
1869 "Duplicates (ascending, DUPS_REPLACE)", test);
1871 test_dup_replace,
ARRAY_LEN(test_dup_replace),
1872 "Duplicates (descending, DUPS_REPLACE)", test);
1883 if (destructor_count > 0) {
1885 "all destructors were not called, destructor count is %d\n",
1888 }
else if (destructor_count < 0) {
1890 "Destructor was called too many times, destructor count is %d\n",
1904 info->name =
"astobj2_test4";
1905 info->category =
"/main/astobj2/";
1906 info->summary =
"Test container traversal/iteration";
1908 "This test is to see if the container traversal/iteration works " 1909 "as intended for each supported container type.";
1953 for (i = 0; i <
OBJS; i++) {
1963 for (i = 0; i <
OBJS; i++) {
1974 for (i = 0; i <
OBJS; i++) {
1985 for (i = 0; i <
OBJS ; i++) {
1997 int reportcount = iterations / 5;
1998 struct timeval start;
2001 for (i = 1 ; i <= iterations && res ==
AST_TEST_PASS ; i++) {
2002 if (i % reportcount == 0 && i != iterations) {
2022 #define ITERATIONS 25000 2024 #define ITERATIONS 100000 2031 info->name =
"astobj2_test_perf";
2032 info->category =
"/main/astobj2/perf/";
2033 info->summary =
"Test container performance";
2035 "Runs container traversal tests.";
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
static int insert_test_duplicates(struct ao2_container *container, int *destroy_counter, int number, const char *prefix, struct ast_test *test)
void ao2_container_dump(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
Display contents of the specified container.
void ast_test_debug(struct ast_test *test, const char *fmt,...)
static int test_traversal_sorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
#define AST_MODULE_INFO_STANDARD(keystr, desc)
static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int use_sort, unsigned int lim, struct ast_test *test)
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
int partial_key_match_range
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
static int test_ao2_find_w_no_flags(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
static int multiple_cb(void *obj, void *arg, int flag)
static int test_ao2_iteration(int res, struct ao2_container *container, enum ao2_iterator_flags flags, const int *vector, int count, const char *prefix, struct ast_test *test)
#define ao2_container_clone(orig, flags)
#define ao2_t_global_obj_replace_unref(holder, obj, tag)
Replace an ao2 object in the global holder, throwing away any old object.
static int test_cmp_cb(void *obj, void *arg, int flags)
static void test_obj_destructor(void *v_obj)
#define ao2_callback(c, flags, cb_fn, arg)
Allow objects with duplicate keys in container.
static int test_ao2_find_w_OBJ_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
AST_TEST_DEFINE(astobj2_test_1)
static int increment_cb(void *obj, void *arg, int flag)
#define AST_TEST_REGISTER(cb)
#define ao2_t_global_obj_release(holder, tag)
Release the ao2 object held in the global holder.
#define ao2_t_link(container, obj, tag)
Add an object to a container.
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag)
Allocate and initialize a list container.
#define ao2_t_unlink(container, obj, tag)
Remove an object from a container.
static int all_but_one_cb(void *obj, void *arg, int flag)
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
static struct ao2_container * test_make_nonsorted(enum test_container_type type, int options)
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
search_flags
Flags passed to ao2_callback_fn(), ao2_hash_fn(), and ao2_sort_fn() to modify behaviour.
void ao2_container_stats(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt)
Display statistics of the specified container.
static int test_expected_duplicates(int res, struct ao2_container *container, enum search_flags flags, int number, const int *vector, int count, const char *prefix, struct ast_test *test)
Insert objects at the beginning of the container. (Otherwise it is the opposite; insert at the end...
void() ao2_prnt_fn(void *where, const char *fmt,...)
Print output.
static struct ao2_container * test_make_sorted(enum test_container_type type, int options)
Traverse in ascending order (First to last container object)
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
int() ao2_callback_fn(void *obj, void *arg, int flags)
Type of a generic callback function.
static int test_container_clone(int res, struct ao2_container *orig, struct ast_test *test)
#define ast_test_status_update(a, b, c...)
static int test_sort_cb(const void *obj_left, const void *obj_right, int flags)
#define ao2_ref(o, delta)
long int ast_random(void)
#define ao2_t_global_obj_replace(holder, obj, tag)
Replace an ao2 object in the global holder.
struct ao2_container * container
static int load_module(void)
Traverse in descending order (Last to first container object)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
static int test_traversal_nonsorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
#define ao2_t_global_obj_ref(holder, tag)
Get a reference to the object stored in the global holder.
#define ao2_t_iterator_next(iter, tag)
#define AST_TEST_UNREGISTER(cb)
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
#define ao2_iterator_next(iter)
#define ao2_alloc(data_size, destructor_fn)
static int test_ao2_callback_traversal(int res, struct ao2_container *container, enum search_flags flags, ao2_callback_fn *cmp_fn, void *arg, const int *vector, int count, const char *prefix, struct ast_test *test)
static void test_cleanup(void)
int ao2_match_by_addr(void *obj, void *arg, int flags)
A common ao2_callback is one that matches by address.
static enum ast_test_result_state test_performance(struct ast_test *test, enum test_container_type type, unsigned int copt)
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag)
Allocate and initialize a hash container with the desired number of buckets.
static int test_ao2_find_w_OBJ_PARTIAL_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
#define ao2_find(container, arg, flags)
static int test_hash_cb(const void *obj, const int flags)
static void * cleanup(void *unused)
static AO2_GLOBAL_OBJ_STATIC(astobj2_holder)
Replace objects with duplicate keys in container.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
static int unload_module(void)
static enum ast_test_result_state testloop(struct ast_test *test, enum test_container_type type, int copt, int iterations)
static int test_ao2_find_w_OBJ_POINTER(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag)
Allocate and initialize a red-black tree container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Reject objects with duplicate keys in container.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
Reject duplicate objects in container.
static int insert_test_vector(struct ao2_container *container, int *destroy_counter, const int *vector, int count, const char *prefix, struct ast_test *test)
static const char * test_container2str(enum test_container_type type)
static char prefix[MAX_PREFIX]
#define ao2_link(container, obj)