41 enum test_container_type {
44 TEST_CONTAINER_RBTREE,
56 static const char *test_container2str(
enum test_container_type type)
62 case TEST_CONTAINER_LIST:
65 case TEST_CONTAINER_HASH:
68 case TEST_CONTAINER_RBTREE:
87 static void test_obj_destructor(
void *v_obj)
96 static int increment_cb(
void *obj,
void *arg,
int flag)
104 static int all_but_one_cb(
void *obj,
void *arg,
int flag)
111 static int multiple_cb(
void *obj,
void *arg,
int flag)
113 int *
i = (
int *) arg;
119 static int test_cmp_cb(
void *obj,
void *arg,
int flags)
124 int *i = (
int *) arg;
128 int *i = (
int *) arg;
130 return (*i - partial_key_match_range <= cmp_obj->i
131 && cmp_obj->
i <= *i + partial_key_match_range) ?
CMP_MATCH : 0;
139 static int test_hash_cb(
const void *obj,
const int flags)
141 if (flags & OBJ_KEY) {
145 }
else if (flags & OBJ_PARTIAL_KEY) {
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;
162 if (flags & OBJ_KEY) {
163 const int *i = obj_right;
165 return test_left->
i - *
i;
166 }
else if (flags & OBJ_PARTIAL_KEY) {
167 int *i = (
int *) obj_right;
169 if (*i - partial_key_match_range <= test_left->i
170 && test_left->
i <= *i + partial_key_match_range) {
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)
192 static void test_prnt_obj(
void *v_obj,
void *where,
ao2_prnt_fn *prnt)
214 static int test_container_clone(
int res,
struct ao2_container *orig,
struct ast_test *
test)
223 ast_test_status_update(test,
"ao2_container_clone failed.\n");
224 return AST_TEST_FAIL;
227 ast_test_status_update(test,
"container integrity check failed\n");
230 ast_test_status_update(test,
"Cloned container does not have the same number of objects.\n");
234 for (; (obj = ao2_t_iterator_next(&iter,
"test orig")); ao2_t_ref(obj, -1,
"test orig")) {
242 ao2_t_ref(obj2, -1,
"test clone");
245 ast_test_status_update(test,
246 "Orig container has an object %p not in the clone container.\n", obj);
251 ast_test_status_update(test,
"Cloned container still has objects.\n");
255 ast_test_status_update(test,
"container integrity check failed\n");
259 ao2_t_ref(clone, -1,
"bye clone");
276 static int test_ao2_find_w_no_flags(
int res,
struct ao2_container *look_in,
int limit,
struct ast_test *test)
283 for (num = 100; num--;) {
284 i = ast_random() % limit;
287 obj = ao2_find(look_in, &tmp_obj, 0);
289 ast_test_status_update(test,
"COULD NOT FIND:%d, ao2_find() with no flags failed.\n", i);
293 ast_test_status_update(test,
"object %d does not match %d\n", obj->
i, i);
296 ao2_t_ref(obj, -1,
"test");
315 static int test_ao2_find_w_OBJ_POINTER(
int res,
struct ao2_container *look_in,
int limit,
struct ast_test *test)
322 for (num = 75; num--;) {
323 i = ast_random() % limit;
328 ast_test_status_update(test,
"COULD NOT FIND:%d, ao2_find() with OBJ_POINTER flag failed.\n", i);
332 ast_test_status_update(test,
"object %d does not match %d\n", obj->
i, i);
335 ao2_t_ref(obj, -1,
"test");
354 static int test_ao2_find_w_OBJ_KEY(
int res,
struct ao2_container *look_in,
int limit,
struct ast_test *test)
360 for (num = 75; num--;) {
361 i = ast_random() % limit;
363 obj = ao2_find(look_in, &i, OBJ_KEY);
365 ast_test_status_update(test,
"COULD NOT FIND:%d, ao2_find() with OBJ_KEY flag failed.\n", i);
369 ast_test_status_update(test,
"object %d does not match %d\n", obj->
i, i);
372 ao2_t_ref(obj, -1,
"test");
391 static int test_ao2_find_w_OBJ_PARTIAL_KEY(
int res,
struct ao2_container *look_in,
int limit,
struct ast_test *test)
398 partial_key_match_range = 0;
400 for (num = 100; num--;) {
401 i = ast_random() % limit;
403 obj = ao2_find(look_in, &i, OBJ_PARTIAL_KEY);
405 ast_test_status_update(test,
"COULD NOT FIND:%d, ao2_find() with OBJ_PARTIAL_KEY flag failed.\n", i);
409 ast_test_status_update(test,
"object %d does not match %d\n", obj->
i, i);
412 ao2_t_ref(obj, -1,
"test");
419 static int astobj2_test_1_helper(
int tst_num,
enum test_container_type type,
int use_sort,
unsigned int lim,
struct ast_test *test)
431 int res = AST_TEST_PASS;
433 c_type = test_container2str(type);
434 ast_test_status_update(test,
"Test %d, %s containers (%s).\n",
435 tst_num, c_type, use_sort ?
"sorted" :
"non-sorted");
439 case TEST_CONTAINER_LIST:
443 use_sort ? test_sort_cb : NULL, test_cmp_cb,
"test");
445 case TEST_CONTAINER_HASH:
446 n_buckets = (ast_random() % ((lim / 4) + 1)) + 1;
448 test_hash_cb, use_sort ? test_sort_cb : NULL, test_cmp_cb,
"test");
450 case TEST_CONTAINER_RBTREE:
454 test_sort_cb, test_cmp_cb,
"test");
460 ast_test_status_update(test,
"ao2_container_alloc failed.\n");
466 for (num = 0; num < lim; ++num) {
467 if (!(obj = ao2_t_alloc(
sizeof(
struct test_obj), test_obj_destructor,
"making zombies"))) {
468 ast_test_status_update(test,
"ao2_alloc failed.\n");
476 ao2_t_ref(obj, -1,
"test");
478 ast_test_status_update(test,
"container integrity check failed linking obj num:%d\n", num);
483 ast_test_status_update(test,
"container did not link correctly\n");
488 ast_test_status_update(test,
"%s container created: buckets: %d, items: %u\n",
489 c_type, n_buckets, lim);
492 res = test_container_clone(res, c1, test);
495 res = test_ao2_find_w_no_flags(res, c1, lim, test);
498 res = test_ao2_find_w_OBJ_POINTER(res, c1, lim, test);
501 res = test_ao2_find_w_OBJ_KEY(res, c1, lim, test);
504 res = test_ao2_find_w_OBJ_PARTIAL_KEY(res, c1, lim, test);
508 ao2_t_callback(c1, 0, increment_cb, &increment,
"test callback");
509 if (increment != lim) {
510 ast_test_status_update(test,
"callback with no flags failed. Increment is %d\n", increment);
516 ao2_t_callback(c1,
OBJ_NODATA, increment_cb, &increment,
"test callback");
517 if (increment != lim) {
518 ast_test_status_update(test,
"callback with OBJ_NODATA failed. Increment is %d\n", increment);
523 num = lim < 25 ? lim : 25;
525 ast_test_status_update(test,
"OBJ_MULTIPLE with OBJ_UNLINK test failed.\n");
530 ast_test_status_update(test,
"OBJ_MULTIPLE | OBJ_UNLINK test failed, did not unlink correct number of objects.\n");
534 ast_test_status_update(test,
"container integrity check failed\n");
540 while ((obj = ao2_t_iterator_next(mult_it,
"test"))) {
541 ao2_t_link(c1, obj,
"test");
542 ao2_t_ref(obj, -1,
"test");
546 ast_test_status_update(test,
"container integrity check failed\n");
554 if (!(mult_it = ao2_t_callback(c1,
OBJ_MULTIPLE, multiple_cb, &num,
"test multiple"))) {
555 ast_test_status_update(test,
"OBJ_MULTIPLE without OBJ_UNLINK test failed.\n");
558 while ((obj = ao2_t_iterator_next(mult_it,
"test"))) {
559 ao2_t_ref(obj, -1,
"test");
566 if (!(mult_it = ao2_t_callback(c1,
OBJ_MULTIPLE, multiple_cb, &num,
"test multiple"))) {
567 ast_test_status_update(test,
"OBJ_MULTIPLE with no OBJ_UNLINK and no iterating failed.\n");
575 ast_test_status_update(test,
"container count does not match what is expected after ao2_find tests.\n");
581 num = ast_random() % lim;
589 while ((obj = ao2_t_iterator_next(&it,
"test"))) {
591 ao2_t_unlink(c1, obj,
"test");
592 ao2_t_ref(obj, -1,
"test");
595 ao2_t_ref(obj, -1,
"test");
601 ast_test_status_update(test,
"unlink during iterator failed. Number %d was not removed.\n", num);
605 ast_test_status_update(test,
"container integrity check failed\n");
613 if (destructor_count != 1) {
614 ast_test_status_update(test,
"OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA failed. destructor count %d\n", destructor_count);
618 ast_test_status_update(test,
"container integrity check failed\n");
621 #if defined(TEST_CONTAINER_DEBUG_DUMP)
629 ao2_t_ref(c1, -1,
"bye c1");
632 ao2_t_ref(c2, -1,
"bye c2");
635 if (destructor_count > 0) {
636 ast_test_status_update(test,
"all destructors were not called, destructor count is %d\n", destructor_count);
638 }
else if (destructor_count < 0) {
639 ast_test_status_update(test,
"Destructor was called too many times, destructor count is %d\n", destructor_count);
648 int res = AST_TEST_PASS;
652 info->name =
"astobj2_test1";
653 info->category =
"/main/astobj2/";
654 info->summary =
"Test ao2 objects, containers, callbacks, and iterators";
656 "Builds ao2_containers with various item numbers, bucket sizes, cmp and hash "
657 "functions. Runs a series of tests to manipulate the container using callbacks "
658 "and iterators. Verifies expected behavior.";
659 return AST_TEST_NOT_RUN;
665 if ((res = astobj2_test_1_helper(1, TEST_CONTAINER_LIST, 0, 50, test)) == AST_TEST_FAIL) {
669 if ((res = astobj2_test_1_helper(2, TEST_CONTAINER_LIST, 1, 50, test)) == AST_TEST_FAIL) {
673 if ((res = astobj2_test_1_helper(3, TEST_CONTAINER_HASH, 0, 1000, test)) == AST_TEST_FAIL) {
677 if ((res = astobj2_test_1_helper(4, TEST_CONTAINER_HASH, 1, 1000, test)) == AST_TEST_FAIL) {
681 if ((res = astobj2_test_1_helper(4, TEST_CONTAINER_RBTREE, 1, 1000, test)) == AST_TEST_FAIL) {
690 int res = AST_TEST_PASS;
695 static const int NUM_OBJS = 5;
696 int destructor_count = NUM_OBJS;
701 info->name =
"astobj2_test2";
702 info->category =
"/main/astobj2/";
703 info->summary =
"Test a certain scenario using ao2 iterators";
705 "This test is aimed at testing for a specific regression that occurred. "
706 "Add some objects into a container. Mix finds and iteration and make "
707 "sure that the iterator still sees all objects.";
708 return AST_TEST_NOT_RUN;
715 ast_test_status_update(test,
"ao2_container_alloc_list failed.\n");
720 for (num = 1; num <= NUM_OBJS; num++) {
721 if (!(obj = ao2_alloc(
sizeof(
struct test_obj), test_obj_destructor))) {
722 ast_test_status_update(test,
"ao2_alloc failed.\n");
731 ast_test_status_update(test,
"container did not link correctly\n");
736 ast_test_status_update(test,
"container integrity check failed\n");
746 while ((obj = ao2_iterator_next(&i))) {
752 if (num != NUM_OBJS) {
753 ast_test_status_update(test,
"iterate take 1, expected '%d', only saw '%d' objects\n",
762 tmp_obj.
i = NUM_OBJS;
765 ast_test_status_update(test,
"ao2_find() failed.\n");
773 while ((obj = ao2_iterator_next(&i))) {
779 if (num != NUM_OBJS) {
780 ast_test_status_update(test,
"iterate take 2, expected '%d', only saw '%d' objects\n",
791 while ((obj = ao2_iterator_next(&i))) {
794 tmp_obj.
i = NUM_OBJS - 1;
797 ast_test_status_update(test,
"ao2_find() failed.\n");
808 if (num != NUM_OBJS) {
809 ast_test_status_update(test,
"iterate take 3, expected '%d', only saw '%d' objects\n",
827 int res = AST_TEST_PASS;
828 int destructor_count = 0;
836 info->name =
"astobj2_test3";
837 info->category =
"/main/astobj2/";
838 info->summary =
"Test global ao2 holder";
840 "This test is to see if the global ao2 holder works as intended.";
841 return AST_TEST_NOT_RUN;
847 obj = ao2_alloc(
sizeof(
struct test_obj), test_obj_destructor);
849 ast_test_status_update(test,
"ao2_alloc failed.\n");
854 obj->
i = ++num_objects;
855 obj2 = ao2_t_global_obj_replace(astobj2_holder, obj,
"Save object in the holder");
857 ast_test_status_update(test,
"Returned object not expected.\n");
865 obj = ao2_alloc(
sizeof(
struct test_obj), test_obj_destructor);
867 ast_test_status_update(test,
"ao2_alloc failed.\n");
872 obj->
i = ++num_objects;
873 obj2 = ao2_t_global_obj_replace(astobj2_holder, obj,
"Replace object in the holder");
875 ast_test_status_update(test,
"Expected an object.\n");
880 ast_test_status_update(test,
"Replaced object not expected object.\n");
891 obj = ao2_alloc(
sizeof(
struct test_obj), test_obj_destructor);
893 ast_test_status_update(test,
"ao2_alloc failed.\n");
898 obj->
i = ++num_objects;
899 if (!ao2_t_global_obj_replace_unref(astobj2_holder, obj,
"Replace w/ unref object in the holder")) {
900 ast_test_status_update(test,
"Expected an object to be replaced.\n");
908 obj = ao2_t_global_obj_ref(astobj2_holder,
"Get a held object reference");
910 ast_test_status_update(test,
"Expected an object.\n");
915 ast_test_status_update(test,
"Referenced object not expected object.\n");
925 ao2_t_global_obj_release(astobj2_holder,
"Check release all objects");
926 destructor_count += num_objects;
927 if (0 < destructor_count) {
928 ast_test_status_update(test,
929 "all destructors were not called, destructor count is %d\n",
932 }
else if (destructor_count < 0) {
933 ast_test_status_update(test,
934 "Destructor was called too many times, destructor count is %d\n",
941 ao2_t_ref(obj, -1,
"Test cleanup external object 1");
944 ao2_t_ref(obj2, -1,
"Test cleanup external object 2");
947 ao2_t_ref(obj3, -1,
"Test cleanup external object 3");
949 ao2_t_global_obj_release(astobj2_holder,
"Test cleanup holder");
971 case TEST_CONTAINER_LIST:
975 case TEST_CONTAINER_HASH:
977 test_hash_cb, NULL, test_cmp_cb);
979 case TEST_CONTAINER_RBTREE:
998 static struct ao2_container *test_make_sorted(
enum test_container_type type,
int options)
1004 case TEST_CONTAINER_LIST:
1006 test_sort_cb, test_cmp_cb,
"test");
1008 case TEST_CONTAINER_HASH:
1010 test_hash_cb, test_sort_cb, test_cmp_cb,
"test");
1012 case TEST_CONTAINER_RBTREE:
1014 test_sort_cb, test_cmp_cb,
"test");
1038 static int insert_test_vector(
struct ao2_container *container,
int *destroy_counter,
const int *vector,
int count,
const char *prefix,
struct ast_test *test)
1043 for (idx = 0; idx < count; ++idx) {
1044 obj = ao2_alloc(
sizeof(
struct test_obj), test_obj_destructor);
1046 ast_test_status_update(test,
"%s: ao2_alloc failed.\n", prefix);
1049 if (destroy_counter) {
1054 obj->
i = vector[idx];
1056 ao2_t_ref(obj, -1,
"test");
1058 ast_test_status_update(test,
"%s: Container integrity check failed linking vector[%d]:%d\n",
1059 prefix, idx, vector[idx]);
1064 ast_test_status_update(test,
1065 "%s: Unexpected container count. Expected:%d Got:%d\n",
1090 static int insert_test_duplicates(
struct ao2_container *container,
int *destroy_counter,
int number,
const char *prefix,
struct ast_test *test)
1097 obj = ao2_find(container, &number, OBJ_KEY);
1099 ast_test_status_update(test,
"%s: Object %d already exists.\n", prefix, number);
1100 ao2_t_ref(obj, -1,
"test");
1106 for (count = 0; count < 4; ++count) {
1107 obj = ao2_alloc(
sizeof(
struct test_obj), test_obj_destructor);
1109 ast_test_status_update(test,
"%s: ao2_alloc failed.\n", prefix);
1111 ao2_t_ref(obj_dup, -1,
"test");
1115 if (destroy_counter) {
1128 ao2_t_ref(obj, -1,
"test");
1132 ast_test_status_update(test,
"%s: Container integrity check failed linking num:%d dup:%d\n",
1133 prefix, number, count);
1135 ao2_t_ref(obj_dup, -1,
"test");
1143 ao2_t_ref(obj_dup, -1,
"test");
1146 ast_test_status_update(test,
"%s: Container integrity check failed linking obj_dup\n",
1169 static int test_ao2_iteration(
int res,
struct ao2_container *container,
1171 const int *vector,
int count,
const char *prefix,
struct ast_test *test)
1178 ast_test_status_update(test,
"%s: Container count doesn't match vector count.\n",
1180 res = AST_TEST_FAIL;
1186 for (idx = 0; idx < count; ++idx) {
1187 obj = ao2_iterator_next(&iter);
1189 ast_test_status_update(test,
"%s: Too few objects found.\n", prefix);
1190 res = AST_TEST_FAIL;
1193 if (vector[idx] != obj->
i) {
1194 ast_test_status_update(test,
"%s: Object %d != vector[%d] %d.\n",
1195 prefix, obj->
i, idx, vector[idx]);
1196 res = AST_TEST_FAIL;
1200 obj = ao2_iterator_next(&iter);
1202 ast_test_status_update(test,
"%s: Too many objects found. Object %d\n",
1205 res = AST_TEST_FAIL;
1230 static int test_ao2_callback_traversal(
int res,
struct ao2_container *container,
1232 const int *vector,
int count,
const char *prefix,
struct ast_test *test)
1240 ast_test_status_update(test,
"%s: Did not return iterator.\n", prefix);
1241 return AST_TEST_FAIL;
1245 for (idx = 0; idx < count; ++idx) {
1246 obj = ao2_iterator_next(mult_iter);
1248 ast_test_status_update(test,
"%s: Too few objects found.\n", prefix);
1249 res = AST_TEST_FAIL;
1252 if (vector[idx] != obj->
i) {
1253 ast_test_status_update(test,
"%s: Object %d != vector[%d] %d.\n",
1254 prefix, obj->
i, idx, vector[idx]);
1255 res = AST_TEST_FAIL;
1259 obj = ao2_iterator_next(mult_iter);
1261 ast_test_status_update(test,
"%s: Too many objects found. Object %d\n",
1264 res = AST_TEST_FAIL;
1287 static int test_expected_duplicates(
int res,
struct ao2_container *container,
1289 const int *vector,
int count,
const char *prefix,
struct ast_test *test)
1295 mult_iter = ao2_find(container, &number, flags |
OBJ_MULTIPLE | OBJ_KEY);
1297 ast_test_status_update(test,
"%s: Did not return iterator.\n", prefix);
1298 return AST_TEST_FAIL;
1302 for (idx = 0; idx < count; ++idx) {
1303 obj = ao2_iterator_next(mult_iter);
1305 ast_test_status_update(test,
"%s: Too few objects found.\n", prefix);
1306 res = AST_TEST_FAIL;
1309 if (number != obj->
i) {
1310 ast_test_status_update(test,
"%s: Object %d != %d.\n",
1311 prefix, obj->
i, number);
1312 res = AST_TEST_FAIL;
1315 ast_test_status_update(test,
"%s: Object dup id %d != vector[%d] %d.\n",
1317 res = AST_TEST_FAIL;
1321 obj = ao2_iterator_next(mult_iter);
1323 ast_test_status_update(test,
1324 "%s: Too many objects found. Object %d, dup id %d\n",
1327 res = AST_TEST_FAIL;
1351 int destructor_count = 0;
1354 static const int test_initial[] = {
1355 1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1359 static const int test_reverse[] = {
1360 8, 9, 3, 5, 7, 4, 6, 2, 0, 1
1362 static const int test_list_partial_forward[] = {
1365 static const int test_list_partial_backward[] = {
1370 static const int test_hash_end_forward[] = {
1371 0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1373 static const int test_hash_end_backward[] = {
1374 9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1376 static const int test_hash_begin_forward[] = {
1377 5, 0, 6, 1, 7, 2, 8, 3, 9, 4
1379 static const int test_hash_begin_backward[] = {
1380 4, 9, 3, 8, 2, 7, 1, 6, 0, 5
1382 static const int test_hash_partial_forward[] = {
1385 static const int test_hash_partial_backward[] = {
1389 ast_test_status_update(test,
"Test %d, %s containers.\n",
1390 tst_num, test_container2str(type));
1393 c1 = test_make_nonsorted(type, 0);
1395 ast_test_status_update(test,
"Container c1 creation failed.\n");
1396 res = AST_TEST_FAIL;
1399 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c1", test)) {
1400 res = AST_TEST_FAIL;
1407 ast_test_status_update(test,
"Container c2 creation failed.\n");
1408 res = AST_TEST_FAIL;
1411 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c2", test)) {
1412 res = AST_TEST_FAIL;
1418 case TEST_CONTAINER_LIST:
1419 res = test_ao2_iteration(res, c1, 0,
1420 test_initial, ARRAY_LEN(test_initial),
1421 "Iteration (ascending, insert end)", test);
1423 test_reverse, ARRAY_LEN(test_reverse),
1424 "Iteration (descending, insert end)", test);
1426 res = test_ao2_iteration(res, c2, 0,
1427 test_reverse, ARRAY_LEN(test_reverse),
1428 "Iteration (ascending, insert begin)", test);
1430 test_initial, ARRAY_LEN(test_initial),
1431 "Iteration (descending, insert begin)", test);
1433 case TEST_CONTAINER_HASH:
1434 res = test_ao2_iteration(res, c1, 0,
1435 test_hash_end_forward, ARRAY_LEN(test_hash_end_forward),
1436 "Iteration (ascending, insert end)", test);
1438 test_hash_end_backward, ARRAY_LEN(test_hash_end_backward),
1439 "Iteration (descending, insert end)", test);
1441 res = test_ao2_iteration(res, c2, 0,
1442 test_hash_begin_forward, ARRAY_LEN(test_hash_begin_forward),
1443 "Iteration (ascending, insert begin)", test);
1445 test_hash_begin_backward, ARRAY_LEN(test_hash_begin_backward),
1446 "Iteration (descending, insert begin)", test);
1448 case TEST_CONTAINER_RBTREE:
1454 case TEST_CONTAINER_LIST:
1456 test_initial, ARRAY_LEN(test_initial),
1457 "Traversal (ascending, insert end)", test);
1459 test_reverse, ARRAY_LEN(test_reverse),
1460 "Traversal (descending, insert end)", test);
1463 test_reverse, ARRAY_LEN(test_reverse),
1464 "Traversal (ascending, insert begin)", test);
1466 test_initial, ARRAY_LEN(test_initial),
1467 "Traversal (descending, insert begin)", test);
1469 case TEST_CONTAINER_HASH:
1471 test_hash_end_forward, ARRAY_LEN(test_hash_end_forward),
1472 "Traversal (ascending, insert end)", test);
1474 test_hash_end_backward, ARRAY_LEN(test_hash_end_backward),
1475 "Traversal (descending, insert end)", test);
1478 test_hash_begin_forward, ARRAY_LEN(test_hash_begin_forward),
1479 "Traversal (ascending, insert begin)", test);
1481 test_hash_begin_backward, ARRAY_LEN(test_hash_begin_backward),
1482 "Traversal (descending, insert begin)", test);
1484 case TEST_CONTAINER_RBTREE:
1490 partial_key_match_range = 1;
1492 case TEST_CONTAINER_LIST:
1494 test_cmp_cb, &partial,
1495 test_list_partial_forward, ARRAY_LEN(test_list_partial_forward),
1496 "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1498 test_cmp_cb, &partial,
1499 test_list_partial_backward, ARRAY_LEN(test_list_partial_backward),
1500 "Traversal OBJ_PARTIAL_KEY (descending)", test);
1502 case TEST_CONTAINER_HASH:
1504 test_cmp_cb, &partial,
1505 test_hash_partial_forward, ARRAY_LEN(test_hash_partial_forward),
1506 "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1508 test_cmp_cb, &partial,
1509 test_hash_partial_backward, ARRAY_LEN(test_hash_partial_backward),
1510 "Traversal OBJ_PARTIAL_KEY (descending)", test);
1512 case TEST_CONTAINER_RBTREE:
1519 ao2_t_ref(c1, -1,
"bye c1");
1522 ao2_t_ref(c2, -1,
"bye c2");
1525 if (destructor_count > 0) {
1526 ast_test_status_update(test,
1527 "all destructors were not called, destructor count is %d\n",
1529 res = AST_TEST_FAIL;
1530 }
else if (destructor_count < 0) {
1531 ast_test_status_update(test,
1532 "Destructor was called too many times, destructor count is %d\n",
1534 res = AST_TEST_FAIL;
1557 int destructor_count = 0;
1558 int duplicate_number = 100;
1561 static const int test_initial[] = {
1562 1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1566 static const int test_forward[] = {
1567 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
1570 static const int test_backward[] = {
1571 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
1574 static const int test_partial_forward[] = {
1577 static const int test_partial_backward[] = {
1582 static const int test_hash_forward[] = {
1583 0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1585 static const int test_hash_backward[] = {
1586 9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1588 static const int test_hash_partial_forward[] = {
1591 static const int test_hash_partial_backward[] = {
1596 static const int test_dup_allow_forward[] = {
1599 static const int test_dup_allow_backward[] = {
1602 static const int test_dup_reject[] = {
1605 static const int test_dup_obj_reject_forward[] = {
1608 static const int test_dup_obj_reject_backward[] = {
1611 static const int test_dup_replace[] = {
1615 ast_test_status_update(test,
"Test %d, %s containers.\n",
1616 tst_num, test_container2str(type));
1621 ast_test_status_update(test,
"Container c1 creation failed.\n");
1622 res = AST_TEST_FAIL;
1625 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c1(DUPS_ALLOW)", test)) {
1626 res = AST_TEST_FAIL;
1633 ast_test_status_update(test,
"Container c2 creation failed.\n");
1634 res = AST_TEST_FAIL;
1637 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c2(DUPS_ALLOW)", test)) {
1638 res = AST_TEST_FAIL;
1642 #if defined(TEST_CONTAINER_DEBUG_DUMP)
1651 case TEST_CONTAINER_RBTREE:
1652 case TEST_CONTAINER_LIST:
1653 res = test_ao2_iteration(res, c1, 0,
1654 test_forward, ARRAY_LEN(test_forward),
1655 "Iteration (ascending)", test);
1657 test_backward, ARRAY_LEN(test_backward),
1658 "Iteration (descending)", test);
1660 case TEST_CONTAINER_HASH:
1661 res = test_ao2_iteration(res, c1, 0,
1662 test_hash_forward, ARRAY_LEN(test_hash_forward),
1663 "Iteration (ascending)", test);
1665 test_hash_backward, ARRAY_LEN(test_hash_backward),
1666 "Iteration (descending)", test);
1672 case TEST_CONTAINER_RBTREE:
1673 case TEST_CONTAINER_LIST:
1675 test_forward, ARRAY_LEN(test_forward),
1676 "Traversal (ascending)", test);
1678 test_backward, ARRAY_LEN(test_backward),
1679 "Traversal (descending)", test);
1681 case TEST_CONTAINER_HASH:
1683 test_hash_forward, ARRAY_LEN(test_hash_forward),
1684 "Traversal (ascending, insert end)", test);
1686 test_hash_backward, ARRAY_LEN(test_hash_backward),
1687 "Traversal (descending)", test);
1693 partial_key_match_range = 1;
1695 case TEST_CONTAINER_RBTREE:
1696 case TEST_CONTAINER_LIST:
1698 test_cmp_cb, &partial,
1699 test_partial_forward, ARRAY_LEN(test_partial_forward),
1700 "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1702 test_cmp_cb, &partial,
1703 test_partial_backward, ARRAY_LEN(test_partial_backward),
1704 "Traversal OBJ_PARTIAL_KEY (descending)", test);
1706 case TEST_CONTAINER_HASH:
1708 test_cmp_cb, &partial,
1709 test_hash_partial_forward, ARRAY_LEN(test_hash_partial_forward),
1710 "Traversal OBJ_PARTIAL_KEY (ascending)", test);
1712 test_cmp_cb, &partial,
1713 test_hash_partial_backward, ARRAY_LEN(test_hash_partial_backward),
1714 "Traversal OBJ_PARTIAL_KEY (descending)", test);
1719 if (insert_test_duplicates(c1, &destructor_count, duplicate_number,
"c1(DUPS_ALLOW)", test)) {
1720 res = AST_TEST_FAIL;
1723 if (insert_test_duplicates(c2, &destructor_count, duplicate_number,
"c2(DUPS_ALLOW)", test)) {
1724 res = AST_TEST_FAIL;
1728 #if defined(TEST_CONTAINER_DEBUG_DUMP)
1737 test_dup_allow_forward, ARRAY_LEN(test_dup_allow_forward),
1738 "Duplicates (ascending, DUPS_ALLOW)", test);
1740 test_dup_allow_backward, ARRAY_LEN(test_dup_allow_backward),
1741 "Duplicates (descending, DUPS_ALLOW)", test);
1743 ao2_t_ref(c1, -1,
"bye c1");
1745 ao2_t_ref(c2, -1,
"bye c2");
1751 ast_test_status_update(test,
"Container c1 creation failed.\n");
1752 res = AST_TEST_FAIL;
1755 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c1(DUPS_REJECT)", test)) {
1756 res = AST_TEST_FAIL;
1759 if (insert_test_duplicates(c1, &destructor_count, duplicate_number,
"c1(DUPS_REJECT)", test)) {
1760 res = AST_TEST_FAIL;
1765 ast_test_status_update(test,
"Container c2 creation failed.\n");
1766 res = AST_TEST_FAIL;
1769 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c2(DUPS_REJECT)", test)) {
1770 res = AST_TEST_FAIL;
1773 if (insert_test_duplicates(c2, &destructor_count, duplicate_number,
"c2(DUPS_REJECT)", test)) {
1774 res = AST_TEST_FAIL;
1780 test_dup_reject, ARRAY_LEN(test_dup_reject),
1781 "Duplicates (ascending, DUPS_REJECT)", test);
1783 test_dup_reject, ARRAY_LEN(test_dup_reject),
1784 "Duplicates (descending, DUPS_REJECT)", test);
1786 ao2_t_ref(c1, -1,
"bye c1");
1788 ao2_t_ref(c2, -1,
"bye c2");
1794 ast_test_status_update(test,
"Container c1 creation failed.\n");
1795 res = AST_TEST_FAIL;
1798 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c1(DUPS_OBJ_REJECT)", test)) {
1799 res = AST_TEST_FAIL;
1802 if (insert_test_duplicates(c1, &destructor_count, duplicate_number,
"c1(DUPS_OBJ_REJECT)", test)) {
1803 res = AST_TEST_FAIL;
1808 ast_test_status_update(test,
"Container c2 creation failed.\n");
1809 res = AST_TEST_FAIL;
1812 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c2(DUPS_OBJ_REJECT)", test)) {
1813 res = AST_TEST_FAIL;
1816 if (insert_test_duplicates(c2, &destructor_count, duplicate_number,
"c2(DUPS_OBJ_REJECT)", test)) {
1817 res = AST_TEST_FAIL;
1823 test_dup_obj_reject_forward, ARRAY_LEN(test_dup_obj_reject_forward),
1824 "Duplicates (ascending, DUPS_OBJ_REJECT)", test);
1826 test_dup_obj_reject_backward, ARRAY_LEN(test_dup_obj_reject_backward),
1827 "Duplicates (descending, DUPS_OBJ_REJECT)", test);
1829 ao2_t_ref(c1, -1,
"bye c1");
1831 ao2_t_ref(c2, -1,
"bye c2");
1837 ast_test_status_update(test,
"Container c1 creation failed.\n");
1838 res = AST_TEST_FAIL;
1841 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c1(DUPS_REJECT)", test)) {
1842 res = AST_TEST_FAIL;
1845 if (insert_test_duplicates(c1, &destructor_count, duplicate_number,
"c1(DUPS_REJECT)", test)) {
1846 res = AST_TEST_FAIL;
1851 ast_test_status_update(test,
"Container c2 creation failed.\n");
1852 res = AST_TEST_FAIL;
1855 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial),
"c2(DUPS_REPLACE)", test)) {
1856 res = AST_TEST_FAIL;
1859 if (insert_test_duplicates(c2, &destructor_count, duplicate_number,
"c2(DUPS_REPLACE)", test)) {
1860 res = AST_TEST_FAIL;
1866 test_dup_replace, ARRAY_LEN(test_dup_replace),
1867 "Duplicates (ascending, DUPS_REPLACE)", test);
1869 test_dup_replace, ARRAY_LEN(test_dup_replace),
1870 "Duplicates (descending, DUPS_REPLACE)", test);
1875 ao2_t_ref(c1, -1,
"bye c1");
1878 ao2_t_ref(c2, -1,
"bye c2");
1881 if (destructor_count > 0) {
1882 ast_test_status_update(test,
1883 "all destructors were not called, destructor count is %d\n",
1885 res = AST_TEST_FAIL;
1886 }
else if (destructor_count < 0) {
1887 ast_test_status_update(test,
1888 "Destructor was called too many times, destructor count is %d\n",
1890 res = AST_TEST_FAIL;
1898 int res = AST_TEST_PASS;
1902 info->name =
"astobj2_test4";
1903 info->category =
"/main/astobj2/";
1904 info->summary =
"Test container traversal/iteration";
1906 "This test is to see if the container traversal/iteration works "
1907 "as intended for each supported container type.";
1908 return AST_TEST_NOT_RUN;
1924 enum test_container_type type,
unsigned int copt)
1930 int res = AST_TEST_PASS;
1937 case TEST_CONTAINER_HASH:
1939 test_hash_cb, test_sort_cb, test_cmp_cb);
1941 case TEST_CONTAINER_LIST:
1943 test_sort_cb, test_cmp_cb);
1945 case TEST_CONTAINER_RBTREE:
1947 test_sort_cb, test_cmp_cb);
1951 for (i = 0; i < OBJS; i++) {
1956 ast_test_status_update(test,
"Container c1 creation failed.\n");
1957 res = AST_TEST_FAIL;
1961 for (i = 0; i < OBJS; i++) {
1962 tobj[
i] = ao2_alloc(
sizeof(
struct test_obj), test_obj_destructor);
1964 ast_test_status_update(test,
"test object creation failed.\n");
1965 res = AST_TEST_FAIL;
1972 for (i = 0; i < OBJS; i++) {
1973 if ((!(tobj2 = ao2_find(c1, &i, OBJ_KEY)))) {
1974 ast_test_status_update(test,
"Should have found object %d in container.\n", i);
1975 res = AST_TEST_FAIL;
1983 for (i = 0; i < OBJS ; i++) {
1984 ao2_cleanup(tobj[i]);
1990 static enum ast_test_result_state testloop(
struct ast_test *test,
1991 enum test_container_type type,
int copt,
int iterations)
1993 int res = AST_TEST_PASS;
1995 int reportcount = iterations / 5;
1996 struct timeval start;
1999 for (i = 1 ; i <= iterations && res == AST_TEST_PASS ; i++) {
2000 if (i % reportcount == 0 && i != iterations) {
2001 ast_test_status_update(test,
"%5.2fK traversals, %9s\n",
2002 i / 1000.0, test_container2str(type));
2006 ast_test_status_update(test,
"%5.2fK traversals, %9s : %5lu ms\n",
2020 #define ITERATIONS 25000
2022 #define ITERATIONS 100000
2025 int res = AST_TEST_PASS;
2029 info->name =
"astobj2_test_perf";
2030 info->category =
"/main/astobj2/perf/";
2031 info->summary =
"Test container performance";
2033 "Runs container traversal tests.";
2034 return AST_TEST_NOT_RUN;
2039 res = testloop(test, TEST_CONTAINER_LIST, 0, ITERATIONS);
2043 res = testloop(test, TEST_CONTAINER_HASH, 0, ITERATIONS);
2047 res = testloop(test, TEST_CONTAINER_RBTREE, 0, ITERATIONS);
2052 static int unload_module(
void)
2054 AST_TEST_UNREGISTER(astobj2_test_1);
2055 AST_TEST_UNREGISTER(astobj2_test_2);
2056 AST_TEST_UNREGISTER(astobj2_test_3);
2057 AST_TEST_UNREGISTER(astobj2_test_4);
2058 AST_TEST_UNREGISTER(astobj2_test_perf);
2062 static int load_module(
void)
2064 AST_TEST_REGISTER(astobj2_test_1);
2065 AST_TEST_REGISTER(astobj2_test_2);
2066 AST_TEST_REGISTER(astobj2_test_3);
2067 AST_TEST_REGISTER(astobj2_test_4);
2068 AST_TEST_REGISTER(astobj2_test_perf);
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.
static int test_traversal_sorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
void( ao2_prnt_fn)(void *where, const char *fmt,...)
Print output.
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
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Allow objects with duplicate keys in container.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
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().
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.
Insert objects at the beginning of the container. (Otherwise it is the opposite; insert at the end...
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.
static void cleanup(void)
Clean up any old apps that we don't need any more.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
struct ao2_container * container
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)
Allocate and initialize a hash container with the desired number of buckets.
static int test_traversal_nonsorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
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)
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...
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Reject objects with duplicate keys in container.
AST_TEST_DEFINE(astobj2_test_perf)
#define AO2_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
#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.
#define ao2_link(container, obj)
Add an object to a container.