Asterisk - The Open Source Telephony Project GIT-master-a63eec2
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions | Variables
test_astobj2.c File Reference

astobj2 test module More...

#include "asterisk.h"
#include "asterisk/utils.h"
#include "asterisk/module.h"
#include "asterisk/test.h"
#include "asterisk/astobj2.h"
Include dependency graph for test_astobj2.c:

Go to the source code of this file.

Data Structures

struct  test_obj
 

Macros

#define ITERATIONS   100000
 
#define OBJS   73
 

Enumerations

enum  test_container_type { TEST_CONTAINER_LIST , TEST_CONTAINER_HASH , TEST_CONTAINER_RBTREE }
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int all_but_one_cb (void *obj, void *arg, int flag)
 
static AO2_GLOBAL_OBJ_STATIC (astobj2_holder)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_TEST_DEFINE (astobj2_test_1)
 
 AST_TEST_DEFINE (astobj2_test_2)
 
 AST_TEST_DEFINE (astobj2_test_3)
 
 AST_TEST_DEFINE (astobj2_test_4)
 
 AST_TEST_DEFINE (astobj2_test_perf)
 
static int astobj2_test_1_helper (int tst_num, enum test_container_type type, int use_sort, unsigned int lim, struct ast_test *test)
 
static int increment_cb (void *obj, void *arg, int flag)
 
static int insert_test_duplicates (struct ao2_container *container, int *destroy_counter, int number, const char *prefix, struct ast_test *test)
 
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 int load_module (void)
 
static int multiple_cb (void *obj, void *arg, int flag)
 
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 int test_ao2_find_w_no_flags (int res, struct ao2_container *look_in, int limit, struct ast_test *test)
 
static int test_ao2_find_w_OBJ_KEY (int res, struct ao2_container *look_in, int limit, struct ast_test *test)
 
static int test_ao2_find_w_OBJ_PARTIAL_KEY (int res, struct ao2_container *look_in, int limit, struct ast_test *test)
 
static int test_ao2_find_w_OBJ_POINTER (int res, struct ao2_container *look_in, int limit, struct ast_test *test)
 
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)
 
static int test_cmp_cb (void *obj, void *arg, int flags)
 
static const char * test_container2str (enum test_container_type type)
 
static int test_container_clone (int res, struct ao2_container *orig, struct ast_test *test)
 
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)
 
static int test_hash_cb (const void *obj, const int flags)
 
static struct ao2_containertest_make_nonsorted (enum test_container_type type, int options)
 
static struct ao2_containertest_make_sorted (enum test_container_type type, int options)
 
static void test_obj_destructor (void *v_obj)
 
static enum ast_test_result_state test_performance (struct ast_test *test, enum test_container_type type, unsigned int copt)
 
static int test_sort_cb (const void *obj_left, const void *obj_right, int flags)
 
static int test_traversal_nonsorted (int res, int tst_num, enum test_container_type type, struct ast_test *test)
 
static int test_traversal_sorted (int res, int tst_num, enum test_container_type type, struct ast_test *test)
 
static enum ast_test_result_state testloop (struct ast_test *test, enum test_container_type type, int copt, int iterations)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "ASTOBJ2 Unit Tests" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
int partial_key_match_range
 

Detailed Description

astobj2 test module

Author
David Vossel dvoss.nosp@m.el@d.nosp@m.igium.nosp@m..com

Definition in file test_astobj2.c.

Macro Definition Documentation

◆ ITERATIONS

#define ITERATIONS   100000

◆ OBJS

#define OBJS   73

Enumeration Type Documentation

◆ test_container_type

Enumerator
TEST_CONTAINER_LIST 
TEST_CONTAINER_HASH 
TEST_CONTAINER_RBTREE 

Definition at line 41 of file test_astobj2.c.

41 {
45};
@ TEST_CONTAINER_RBTREE
@ TEST_CONTAINER_HASH
@ TEST_CONTAINER_LIST

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2072 of file test_astobj2.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2072 of file test_astobj2.c.

◆ all_but_one_cb()

static int all_but_one_cb ( void *  obj,
void *  arg,
int  flag 
)
static

Definition at line 104 of file test_astobj2.c.

105{
106 struct test_obj *cmp_obj = (struct test_obj *) obj;
107
108 return (cmp_obj->i) ? CMP_MATCH : 0;
109}
@ CMP_MATCH
Definition astobj2.h:1027

References CMP_MATCH, and test_obj::i.

Referenced by astobj2_test_1_helper().

◆ AO2_GLOBAL_OBJ_STATIC()

static AO2_GLOBAL_OBJ_STATIC ( astobj2_holder  )
static

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 2072 of file test_astobj2.c.

◆ AST_TEST_DEFINE() [1/5]

AST_TEST_DEFINE ( astobj2_test_1  )

Definition at line 646 of file test_astobj2.c.

647{
648 int res = AST_TEST_PASS;
649
650 switch (cmd) {
651 case TEST_INIT:
652 info->name = "astobj2_test1";
653 info->category = "/main/astobj2/";
654 info->summary = "Test ao2 objects, containers, callbacks, and iterators";
655 info->description =
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;
660 case TEST_EXECUTE:
661 break;
662 }
663
664 /* Test number, container_type, use_sort, number of objects. */
665 if ((res = astobj2_test_1_helper(1, TEST_CONTAINER_LIST, 0, 50, test)) == AST_TEST_FAIL) {
666 return res;
667 }
668
669 if ((res = astobj2_test_1_helper(2, TEST_CONTAINER_LIST, 1, 50, test)) == AST_TEST_FAIL) {
670 return res;
671 }
672
673 if ((res = astobj2_test_1_helper(3, TEST_CONTAINER_HASH, 0, 1000, test)) == AST_TEST_FAIL) {
674 return res;
675 }
676
677 if ((res = astobj2_test_1_helper(4, TEST_CONTAINER_HASH, 1, 1000, test)) == AST_TEST_FAIL) {
678 return res;
679 }
680
681 if ((res = astobj2_test_1_helper(4, TEST_CONTAINER_RBTREE, 1, 1000, test)) == AST_TEST_FAIL) {
682 return res;
683 }
684
685 return res;
686}
@ TEST_INIT
Definition test.h:200
@ TEST_EXECUTE
Definition test.h:201
@ AST_TEST_PASS
Definition test.h:195
@ AST_TEST_FAIL
Definition test.h:196
@ AST_TEST_NOT_RUN
Definition test.h:194
static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int use_sort, unsigned int lim, struct ast_test *test)

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, astobj2_test_1_helper(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, TEST_EXECUTE, and TEST_INIT.

◆ AST_TEST_DEFINE() [2/5]

AST_TEST_DEFINE ( astobj2_test_2  )

Definition at line 688 of file test_astobj2.c.

689{
690 int res = AST_TEST_PASS;
691 struct ao2_container *c;
692 struct ao2_iterator i;
693 struct test_obj *obj;
694 int num;
695 static const int NUM_OBJS = 5;
696 int destructor_count = NUM_OBJS;
697 struct test_obj tmp_obj = { 0, };
698
699 switch (cmd) {
700 case TEST_INIT:
701 info->name = "astobj2_test2";
702 info->category = "/main/astobj2/";
703 info->summary = "Test a certain scenario using ao2 iterators";
704 info->description =
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;
709 case TEST_EXECUTE:
710 break;
711 }
712
714 if (!c) {
715 ast_test_status_update(test, "ao2_container_alloc_list failed.\n");
716 res = AST_TEST_FAIL;
717 goto cleanup;
718 }
719
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");
723 res = AST_TEST_FAIL;
724 goto cleanup;
725 }
727 obj->i = num;
728 ao2_link(c, obj);
729 ao2_ref(obj, -1);
730 if (ao2_container_count(c) != num) {
731 ast_test_status_update(test, "container did not link correctly\n");
732 res = AST_TEST_FAIL;
733 }
734 }
735 if (ao2_container_check(c, 0)) {
736 ast_test_status_update(test, "container integrity check failed\n");
737 res = AST_TEST_FAIL;
738 goto cleanup;
739 }
740
741 /*
742 * Iteration take 1. Just make sure we see all NUM_OBJS objects.
743 */
744 num = 0;
745 i = ao2_iterator_init(c, 0);
746 while ((obj = ao2_iterator_next(&i))) {
747 num++;
748 ao2_ref(obj, -1);
749 }
751
752 if (num != NUM_OBJS) {
753 ast_test_status_update(test, "iterate take 1, expected '%d', only saw '%d' objects\n",
754 NUM_OBJS, num);
755 res = AST_TEST_FAIL;
756 }
757
758 /*
759 * Iteration take 2. Do a find for the last object, then iterate and make
760 * sure we find all NUM_OBJS objects.
761 */
762 tmp_obj.i = NUM_OBJS;
763 obj = ao2_find(c, &tmp_obj, OBJ_POINTER);
764 if (!obj) {
765 ast_test_status_update(test, "ao2_find() failed.\n");
766 res = AST_TEST_FAIL;
767 } else {
768 ao2_ref(obj, -1);
769 }
770
771 num = 0;
772 i = ao2_iterator_init(c, 0);
773 while ((obj = ao2_iterator_next(&i))) {
774 num++;
775 ao2_ref(obj, -1);
776 }
778
779 if (num != NUM_OBJS) {
780 ast_test_status_update(test, "iterate take 2, expected '%d', only saw '%d' objects\n",
781 NUM_OBJS, num);
782 res = AST_TEST_FAIL;
783 }
784
785 /*
786 * Iteration take 3. Do a find for an object while in the middle
787 * of iterating;
788 */
789 num = 0;
790 i = ao2_iterator_init(c, 0);
791 while ((obj = ao2_iterator_next(&i))) {
792 if (num == 1) {
793 struct test_obj *obj2;
794 tmp_obj.i = NUM_OBJS - 1;
795 obj2 = ao2_find(c, &tmp_obj, OBJ_POINTER);
796 if (!obj2) {
797 ast_test_status_update(test, "ao2_find() failed.\n");
798 res = AST_TEST_FAIL;
799 } else {
800 ao2_ref(obj2, -1);
801 }
802 }
803 num++;
804 ao2_ref(obj, -1);
805 }
807
808 if (num != NUM_OBJS) {
809 ast_test_status_update(test, "iterate take 3, expected '%d', only saw '%d' objects\n",
810 NUM_OBJS, num);
811 res = AST_TEST_FAIL;
812 }
813
814
815cleanup:
816 if (c) {
817 ao2_ref(c, -1);
818 }
819
820 return res;
821}
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
#define OBJ_POINTER
Definition astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition res_stasis.c:327
#define NULL
Definition resample.c:96
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
int * destructor_count
#define ast_test_status_update(a, b, c...)
Definition test.h:129
static void test_obj_destructor(void *v_obj)
static int test_cmp_cb(void *obj, void *arg, int flags)
static struct test_val c

References ao2_alloc, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_list, ao2_container_check(), ao2_container_count(), ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, c, cleanup(), test_obj::destructor_count, test_obj::i, NULL, OBJ_POINTER, test_cmp_cb(), TEST_EXECUTE, TEST_INIT, and test_obj_destructor().

◆ AST_TEST_DEFINE() [3/5]

AST_TEST_DEFINE ( astobj2_test_3  )

Definition at line 825 of file test_astobj2.c.

826{
827 int res = AST_TEST_PASS;
828 int destructor_count = 0;
829 int num_objects = 0;
830 struct test_obj *obj = NULL;
831 struct test_obj *obj2 = NULL;
832 struct test_obj *obj3 = NULL;
833
834 switch (cmd) {
835 case TEST_INIT:
836 info->name = "astobj2_test3";
837 info->category = "/main/astobj2/";
838 info->summary = "Test global ao2 holder";
839 info->description =
840 "This test is to see if the global ao2 holder works as intended.";
841 return AST_TEST_NOT_RUN;
842 case TEST_EXECUTE:
843 break;
844 }
845
846 /* Put an object in the holder */
847 obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
848 if (!obj) {
849 ast_test_status_update(test, "ao2_alloc failed.\n");
850 res = AST_TEST_FAIL;
851 goto cleanup;
852 }
854 obj->i = ++num_objects;
855 obj2 = ao2_t_global_obj_replace(astobj2_holder, obj, "Save object in the holder");
856 if (obj2) {
857 ast_test_status_update(test, "Returned object not expected.\n");
858 res = AST_TEST_FAIL;
859 goto cleanup;
860 }
861 /* Save object for next check. */
862 obj3 = obj;
863
864 /* Replace an object in the holder */
865 obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
866 if (!obj) {
867 ast_test_status_update(test, "ao2_alloc failed.\n");
868 res = AST_TEST_FAIL;
869 goto cleanup;
870 }
872 obj->i = ++num_objects;
873 obj2 = ao2_t_global_obj_replace(astobj2_holder, obj, "Replace object in the holder");
874 if (!obj2) {
875 ast_test_status_update(test, "Expected an object.\n");
876 res = AST_TEST_FAIL;
877 goto cleanup;
878 }
879 if (obj2 != obj3) {
880 ast_test_status_update(test, "Replaced object not expected object.\n");
881 res = AST_TEST_FAIL;
882 goto cleanup;
883 }
884 ao2_ref(obj3, -1);
885 obj3 = NULL;
886 ao2_ref(obj2, -1);
887 obj2 = NULL;
888 ao2_ref(obj, -1);
889
890 /* Replace with unref of an object in the holder */
891 obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
892 if (!obj) {
893 ast_test_status_update(test, "ao2_alloc failed.\n");
894 res = AST_TEST_FAIL;
895 goto cleanup;
896 }
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");
901 res = AST_TEST_FAIL;
902 goto cleanup;
903 }
904 /* Save object for next check. */
905 obj3 = obj;
906
907 /* Get reference to held object. */
908 obj = ao2_t_global_obj_ref(astobj2_holder, "Get a held object reference");
909 if (!obj) {
910 ast_test_status_update(test, "Expected an object.\n");
911 res = AST_TEST_FAIL;
912 goto cleanup;
913 }
914 if (obj != obj3) {
915 ast_test_status_update(test, "Referenced object not expected object.\n");
916 res = AST_TEST_FAIL;
917 goto cleanup;
918 }
919 ao2_ref(obj3, -1);
920 obj3 = NULL;
921 ao2_ref(obj, -1);
922 obj = NULL;
923
924 /* Release the object in the global holder. */
925 ao2_t_global_obj_release(astobj2_holder, "Check release all objects");
926 destructor_count += num_objects;
927 if (0 < destructor_count) {
929 "all destructors were not called, destructor count is %d\n",
931 res = AST_TEST_FAIL;
932 } else if (destructor_count < 0) {
934 "Destructor was called too many times, destructor count is %d\n",
936 res = AST_TEST_FAIL;
937 }
938
939cleanup:
940 if (obj) {
941 ao2_t_ref(obj, -1, "Test cleanup external object 1");
942 }
943 if (obj2) {
944 ao2_t_ref(obj2, -1, "Test cleanup external object 2");
945 }
946 if (obj3) {
947 ao2_t_ref(obj3, -1, "Test cleanup external object 3");
948 }
949 ao2_t_global_obj_release(astobj2_holder, "Test cleanup holder");
950
951 return res;
952}
#define ao2_t_ref(o, delta, tag)
Definition astobj2.h:460
#define ao2_t_global_obj_replace_unref(holder, obj, tag)
Definition astobj2.h:904
#define ao2_t_global_obj_replace(holder, obj, tag)
Definition astobj2.h:881
#define ao2_t_global_obj_release(holder, tag)
Definition astobj2.h:861
#define ao2_t_global_obj_ref(holder, tag)
Definition astobj2.h:921

References ao2_alloc, ao2_ref, ao2_t_global_obj_ref, ao2_t_global_obj_release, ao2_t_global_obj_replace, ao2_t_global_obj_replace_unref, ao2_t_ref, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, cleanup(), test_obj::destructor_count, test_obj::i, NULL, TEST_EXECUTE, TEST_INIT, and test_obj_destructor().

◆ AST_TEST_DEFINE() [4/5]

AST_TEST_DEFINE ( astobj2_test_4  )

Definition at line 1896 of file test_astobj2.c.

1897{
1898 int res = AST_TEST_PASS;
1899
1900 switch (cmd) {
1901 case TEST_INIT:
1902 info->name = "astobj2_test4";
1903 info->category = "/main/astobj2/";
1904 info->summary = "Test container traversal/iteration";
1905 info->description =
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;
1909 case TEST_EXECUTE:
1910 break;
1911 }
1912
1915
1919
1920 return res;
1921}
static int test_traversal_sorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
static int test_traversal_nonsorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)

References AST_TEST_NOT_RUN, AST_TEST_PASS, TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, TEST_EXECUTE, TEST_INIT, test_traversal_nonsorted(), and test_traversal_sorted().

◆ AST_TEST_DEFINE() [5/5]

AST_TEST_DEFINE ( astobj2_test_perf  )

The number of iteration of testloop to be performed.

Note
In order to keep the elapsed time sane, if AO2_DEBUG is defined in menuselect, only 25000 iterations are performed. Otherwise 100000.

Definition at line 2011 of file test_astobj2.c.

2012{
2013/*!
2014 * \brief The number of iteration of testloop to be performed.
2015 * \note
2016 * In order to keep the elapsed time sane, if AO2_DEBUG is defined in menuselect,
2017 * only 25000 iterations are performed. Otherwise 100000.
2018 */
2019#ifdef AO2_DEBUG
2020#define ITERATIONS 25000
2021#else
2022#define ITERATIONS 100000
2023#endif
2024
2025 int res = AST_TEST_PASS;
2026
2027 switch (cmd) {
2028 case TEST_INIT:
2029 info->name = "astobj2_test_perf";
2030 info->category = "/main/astobj2/perf/";
2031 info->summary = "Test container performance";
2032 info->description =
2033 "Runs container traversal tests.";
2034 return AST_TEST_NOT_RUN;
2035 case TEST_EXECUTE:
2036 break;
2037 }
2038
2040 if (!res) {
2041 return res;
2042 }
2044 if (!res) {
2045 return res;
2046 }
2048
2049 return res;
2050}
#define ITERATIONS
static enum ast_test_result_state testloop(struct ast_test *test, enum test_container_type type, int copt, int iterations)

References AST_TEST_NOT_RUN, AST_TEST_PASS, ITERATIONS, TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, TEST_EXECUTE, TEST_INIT, and testloop().

◆ astobj2_test_1_helper()

static int astobj2_test_1_helper ( int  tst_num,
enum test_container_type  type,
int  use_sort,
unsigned int  lim,
struct ast_test *  test 
)
static

Definition at line 419 of file test_astobj2.c.

420{
421 const char *c_type;
422 struct ao2_container *c1;
423 struct ao2_container *c2;
424 struct ao2_iterator it;
425 struct ao2_iterator *mult_it;
426 struct test_obj *obj;
427 int n_buckets = 0;
428 int increment = 0;
429 int destructor_count = 0;
430 int num;
431 int res = AST_TEST_PASS;
432
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");
436
437 c1 = NULL;
438 switch (type) {
440 /* Lists just have one bucket. */
441 n_buckets = 1;
443 use_sort ? test_sort_cb : NULL, test_cmp_cb, "test");
444 break;
446 n_buckets = (ast_random() % ((lim / 4) + 1)) + 1;
448 test_hash_cb, use_sort ? test_sort_cb : NULL, test_cmp_cb, "test");
449 break;
451 /* RBTrees just have one bucket. */
452 n_buckets = 1;
454 test_sort_cb, test_cmp_cb, "test");
455 break;
456 }
458
459 if (!c1 || !c2) {
460 ast_test_status_update(test, "ao2_container_alloc failed.\n");
461 res = AST_TEST_FAIL;
462 goto cleanup;
463 }
464
465 /* Create objects and link into container */
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");
469 res = AST_TEST_FAIL;
470 goto cleanup;
471 }
474 obj->i = num;
475 ao2_link(c1, obj);
476 ao2_t_ref(obj, -1, "test");
477 if (ao2_container_check(c1, 0)) {
478 ast_test_status_update(test, "container integrity check failed linking obj num:%d\n", num);
479 res = AST_TEST_FAIL;
480 goto cleanup;
481 }
482 if (ao2_container_count(c1) != num + 1) {
483 ast_test_status_update(test, "container did not link correctly\n");
484 res = AST_TEST_FAIL;
485 }
486 }
487
488 ast_test_status_update(test, "%s container created: buckets: %d, items: %u\n",
489 c_type, n_buckets, lim);
490
491 /* Testing ao2_container_clone */
492 res = test_container_clone(res, c1, test);
493
494 /* Testing ao2_find with no flags */
495 res = test_ao2_find_w_no_flags(res, c1, lim, test);
496
497 /* Testing ao2_find with OBJ_POINTER */
498 res = test_ao2_find_w_OBJ_POINTER(res, c1, lim, test);
499
500 /* Testing ao2_find with OBJ_KEY */
501 res = test_ao2_find_w_OBJ_KEY(res, c1, lim, test);
502
503 /* Testing ao2_find with OBJ_PARTIAL_KEY */
504 res = test_ao2_find_w_OBJ_PARTIAL_KEY(res, c1, lim, test);
505
506 /* Test Callback with no flags. */
507 increment = 0;
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);
511 res = AST_TEST_FAIL;
512 }
513
514 /* Test Callback with OBJ_NODATA. This should do nothing different than with no flags here. */
515 increment = 0;
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);
519 res = AST_TEST_FAIL;
520 }
521
522 /* Test OBJ_MULTIPLE with OBJ_UNLINK, add items back afterwards */
523 num = lim < 25 ? lim : 25;
524 if (!(mult_it = ao2_t_callback(c1, OBJ_MULTIPLE | OBJ_UNLINK, multiple_cb, &num, "test multiple"))) {
525 ast_test_status_update(test, "OBJ_MULTIPLE with OBJ_UNLINK test failed.\n");
526 res = AST_TEST_FAIL;
527 } else {
528 /* make sure num items unlinked is as expected */
529 if ((lim - ao2_container_count(c1)) != num) {
530 ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK test failed, did not unlink correct number of objects.\n");
531 res = AST_TEST_FAIL;
532 }
533 if (ao2_container_check(c1, 0)) {
534 ast_test_status_update(test, "container integrity check failed\n");
535 res = AST_TEST_FAIL;
536 goto cleanup;
537 }
538
539 /* link what was unlinked back into c1 */
540 while ((obj = ao2_t_iterator_next(mult_it, "test"))) {
541 ao2_t_link(c1, obj, "test");
542 ao2_t_ref(obj, -1, "test"); /* remove ref from iterator */
543 }
544 ao2_iterator_destroy(mult_it);
545 if (ao2_container_check(c1, 0)) {
546 ast_test_status_update(test, "container integrity check failed\n");
547 res = AST_TEST_FAIL;
548 goto cleanup;
549 }
550 }
551
552 /* Test OBJ_MULTIPLE without unlink and iterate the returned container */
553 num = 5;
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");
556 res = AST_TEST_FAIL;
557 } else {
558 while ((obj = ao2_t_iterator_next(mult_it, "test"))) {
559 ao2_t_ref(obj, -1, "test"); /* remove ref from iterator */
560 }
561 ao2_iterator_destroy(mult_it);
562 }
563
564 /* Test OBJ_MULTIPLE without unlink and no iterating */
565 num = 5;
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");
568 res = AST_TEST_FAIL;
569 } else {
570 ao2_iterator_destroy(mult_it);
571 }
572
573 /* Is the container count what we expect after all the finds and unlinks? */
574 if (ao2_container_count(c1) != lim) {
575 ast_test_status_update(test, "container count does not match what is expected after ao2_find tests.\n");
576 res = AST_TEST_FAIL;
577 }
578
579 /* Testing iterator. Unlink a single object and break. do not add item back */
580 it = ao2_iterator_init(c1, 0);
581 num = ast_random() % lim; /* remove a random object */
582 if (!num) {
583 /*
584 * Well we cannot remove object zero because of test with
585 * all_but_one_cb later.
586 */
587 num = 1;
588 }
589 while ((obj = ao2_t_iterator_next(&it, "test"))) {
590 if (obj->i == num) {
591 ao2_t_unlink(c1, obj, "test");
592 ao2_t_ref(obj, -1, "test");
593 break;
594 }
595 ao2_t_ref(obj, -1, "test");
596 }
598
599 /* Is the container count what we expect after removing a single item? */
600 if (ao2_container_count(c1) != (lim - 1)) {
601 ast_test_status_update(test, "unlink during iterator failed. Number %d was not removed.\n", num);
602 res = AST_TEST_FAIL;
603 }
604 if (ao2_container_check(c1, 0)) {
605 ast_test_status_update(test, "container integrity check failed\n");
606 res = AST_TEST_FAIL;
607 goto cleanup;
608 }
609
610 /* Test unlink all with OBJ_MULTIPLE, leave a single object for the container to destroy */
612 /* check to make sure all test_obj destructors were called except for 1 */
613 if (destructor_count != 1) {
614 ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA failed. destructor count %d\n", destructor_count);
615 res = AST_TEST_FAIL;
616 }
617 if (ao2_container_check(c1, 0)) {
618 ast_test_status_update(test, "container integrity check failed\n");
619 res = AST_TEST_FAIL;
620 }
621#if defined(TEST_CONTAINER_DEBUG_DUMP)
622 ao2_container_dump(c1, 0, "test_1 c1", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
623 ao2_container_stats(c1, 0, "test_1 c1", (void *) test, (ao2_prnt_fn *) ast_test_debug);
624#endif /* defined(TEST_CONTAINER_DEBUG_DUMP) */
625
626cleanup:
627 /* destroy containers */
628 if (c1) {
629 ao2_t_ref(c1, -1, "bye c1");
630 }
631 if (c2) {
632 ao2_t_ref(c2, -1, "bye c2");
633 }
634
635 if (destructor_count > 0) {
636 ast_test_status_update(test, "all destructors were not called, destructor count is %d\n", destructor_count);
637 res = AST_TEST_FAIL;
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);
640 res = AST_TEST_FAIL;
641 }
642
643 return res;
644}
#define ao2_t_iterator_next(iter, tag)
Definition astobj2.h:1909
#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag)
Definition astobj2.h:1352
#define ao2_t_link(container, obj, tag)
Definition astobj2.h:1534
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.
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag)
Definition astobj2.h:1330
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag)
Definition astobj2.h:1306
#define ao2_t_unlink(container, obj, tag)
Definition astobj2.h:1580
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.
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition astobj2.h:407
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_UNLINK
Definition astobj2.h:1039
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
Definition astobj2.h:1696
void() ao2_prnt_fn(void *where, const char *fmt,...)
Print output.
Definition astobj2.h:1435
static const char type[]
#define ast_test_debug(test, fmt,...)
Definition test.h:130
static int multiple_cb(void *obj, void *arg, int flag)
static int test_ao2_find_w_OBJ_POINTER(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
static int test_ao2_find_w_OBJ_PARTIAL_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
static int test_container_clone(int res, struct ao2_container *orig, struct ast_test *test)
static int test_ao2_find_w_no_flags(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
static int test_hash_cb(const void *obj, const int flags)
static int test_ao2_find_w_OBJ_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
static int all_but_one_cb(void *obj, void *arg, int flag)
static int increment_cb(void *obj, void *arg, int flag)
static int test_sort_cb(const void *obj_left, const void *obj_right, int flags)
static const char * test_container2str(enum test_container_type type)
long int ast_random(void)
Definition utils.c:2348

References all_but_one_cb(), AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_check(), ao2_container_count(), ao2_container_dump(), ao2_container_stats(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_link, ao2_t_alloc, ao2_t_callback, ao2_t_container_alloc_hash, ao2_t_container_alloc_list, ao2_t_container_alloc_rbtree, ao2_t_iterator_next, ao2_t_link, ao2_t_ref, ao2_t_unlink, ast_random(), ast_test_debug, AST_TEST_FAIL, AST_TEST_PASS, ast_test_status_update, cleanup(), test_obj::destructor_count, test_obj::i, increment_cb(), multiple_cb(), NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, test_ao2_find_w_no_flags(), test_ao2_find_w_OBJ_KEY(), test_ao2_find_w_OBJ_PARTIAL_KEY(), test_ao2_find_w_OBJ_POINTER(), test_cmp_cb(), test_container2str(), test_container_clone(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, test_hash_cb(), test_obj_destructor(), test_sort_cb(), and type.

Referenced by AST_TEST_DEFINE().

◆ increment_cb()

static int increment_cb ( void *  obj,
void *  arg,
int  flag 
)
static

Definition at line 96 of file test_astobj2.c.

97{
98 int *i = (int *) arg;
99
100 *i = *i + 1;
101 return 0;
102}

References test_obj::i.

Referenced by astobj2_test_1_helper().

◆ insert_test_duplicates()

static int insert_test_duplicates ( struct ao2_container container,
int *  destroy_counter,
int  number,
const char *  prefix,
struct ast_test *  test 
)
static

Definition at line 1090 of file test_astobj2.c.

1091{
1092 int count;
1093 struct test_obj *obj;
1094 struct test_obj *obj_dup;
1095
1096 /* Check if object already exists in the container. */
1097 obj = ao2_find(container, &number, OBJ_KEY);
1098 if (obj) {
1099 ast_test_status_update(test, "%s: Object %d already exists.\n", prefix, number);
1100 ao2_t_ref(obj, -1, "test");
1101 return -1;
1102 }
1103
1104 /* Add three duplicate keyed objects. */
1105 obj_dup = NULL;
1106 for (count = 0; count < 4; ++count) {
1107 obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
1108 if (!obj) {
1109 ast_test_status_update(test, "%s: ao2_alloc failed.\n", prefix);
1110 if (obj_dup) {
1111 ao2_t_ref(obj_dup, -1, "test");
1112 }
1113 return -1;
1114 }
1115 if (destroy_counter) {
1116 /* This object ultimately needs to be destroyed. */
1117 ++*destroy_counter;
1118 }
1119 obj->destructor_count = destroy_counter;
1120 obj->i = number;
1121 obj->dup_number = count;
1122 ao2_link(container, obj);
1123
1124 if (count == 2) {
1125 /* Duplicate this object. */
1126 obj_dup = obj;
1127 } else {
1128 ao2_t_ref(obj, -1, "test");
1129 }
1130
1132 ast_test_status_update(test, "%s: Container integrity check failed linking num:%d dup:%d\n",
1133 prefix, number, count);
1134 if (obj_dup) {
1135 ao2_t_ref(obj_dup, -1, "test");
1136 }
1137 return -1;
1138 }
1139 }
1140
1141 /* Add the duplicate object. */
1142 ao2_link(container, obj_dup);
1143 ao2_t_ref(obj_dup, -1, "test");
1144
1146 ast_test_status_update(test, "%s: Container integrity check failed linking obj_dup\n",
1147 prefix);
1148 return -1;
1149 }
1150
1151 return 0;
1152}
#define OBJ_KEY
Definition astobj2.h:1151
static char prefix[MAX_PREFIX]
Definition http.c:144
struct ao2_container * container
Definition res_fax.c:603
Number structure.
int dup_number

References ao2_alloc, ao2_container_check(), ao2_find, ao2_link, ao2_t_ref, ast_test_status_update, container, test_obj::destructor_count, test_obj::dup_number, test_obj::i, NULL, OBJ_KEY, prefix, and test_obj_destructor().

Referenced by test_traversal_sorted().

◆ insert_test_vector()

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

Definition at line 1038 of file test_astobj2.c.

1039{
1040 int idx;
1041 struct test_obj *obj;
1042
1043 for (idx = 0; idx < count; ++idx) {
1044 obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
1045 if (!obj) {
1046 ast_test_status_update(test, "%s: ao2_alloc failed.\n", prefix);
1047 return -1;
1048 }
1049 if (destroy_counter) {
1050 /* This object ultimately needs to be destroyed. */
1051 ++*destroy_counter;
1052 }
1053 obj->destructor_count = destroy_counter;
1054 obj->i = vector[idx];
1055 ao2_link(container, obj);
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]);
1060 return -1;
1061 }
1062
1063 if (ao2_container_count(container) != idx + 1) {
1065 "%s: Unexpected container count. Expected:%d Got:%d\n",
1067 return -1;
1068 }
1069 }
1070
1071 return 0;
1072}

References ao2_alloc, ao2_container_check(), ao2_container_count(), ao2_link, ao2_t_ref, ast_test_status_update, container, test_obj::destructor_count, test_obj::i, prefix, and test_obj_destructor().

Referenced by test_traversal_nonsorted(), and test_traversal_sorted().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2062 of file test_astobj2.c.

2063{
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);
2070}
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
#define AST_TEST_REGISTER(cb)
Definition test.h:127

References AST_MODULE_LOAD_SUCCESS, and AST_TEST_REGISTER.

◆ multiple_cb()

static int multiple_cb ( void *  obj,
void *  arg,
int  flag 
)
static

Definition at line 111 of file test_astobj2.c.

112{
113 int *i = (int *) arg;
114 struct test_obj *cmp_obj = (struct test_obj *) obj;
115
116 return (cmp_obj->i < *i) ? CMP_MATCH : 0;
117}

References CMP_MATCH, and test_obj::i.

Referenced by astobj2_test_1_helper().

◆ test_ao2_callback_traversal()

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

Definition at line 1230 of file test_astobj2.c.

1233{
1234 struct ao2_iterator *mult_iter;
1235 struct test_obj *obj;
1236 int idx;
1237
1238 mult_iter = ao2_callback(container, flags | OBJ_MULTIPLE, cmp_fn, arg);
1239 if (!mult_iter) {
1240 ast_test_status_update(test, "%s: Did not return iterator.\n", prefix);
1241 return AST_TEST_FAIL;
1242 }
1243
1244 /* Check matching objects against the given vector. */
1245 for (idx = 0; idx < count; ++idx) {
1246 obj = ao2_iterator_next(mult_iter);
1247 if (!obj) {
1248 ast_test_status_update(test, "%s: Too few objects found.\n", prefix);
1249 res = AST_TEST_FAIL;
1250 break;
1251 }
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;
1256 }
1257 ao2_ref(obj, -1); /* remove ref from iterator */
1258 }
1259 obj = ao2_iterator_next(mult_iter);
1260 if (obj) {
1261 ast_test_status_update(test, "%s: Too many objects found. Object %d\n",
1262 prefix, obj->i);
1263 ao2_ref(obj, -1); /* remove ref from iterator */
1264 res = AST_TEST_FAIL;
1265 }
1266 ao2_iterator_destroy(mult_iter);
1267
1268 return res;
1269}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693

References ao2_callback, ao2_iterator_destroy(), ao2_iterator_next, ao2_ref, AST_TEST_FAIL, ast_test_status_update, container, test_obj::i, OBJ_MULTIPLE, and prefix.

Referenced by test_traversal_nonsorted(), and test_traversal_sorted().

◆ test_ao2_find_w_no_flags()

static int test_ao2_find_w_no_flags ( int  res,
struct ao2_container look_in,
int  limit,
struct ast_test *  test 
)
static

Definition at line 276 of file test_astobj2.c.

277{
278 int i;
279 int num;
280 struct test_obj tmp_obj = { 0, };
281 struct test_obj *obj;
282
283 for (num = 100; num--;) {
284 i = ast_random() % limit; /* find a random object */
285
286 tmp_obj.i = i;
287 obj = ao2_find(look_in, &tmp_obj, 0);
288 if (!obj) {
289 ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with no flags failed.\n", i);
290 res = AST_TEST_FAIL;
291 } else {
292 if (obj->i != i) {
293 ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
294 res = AST_TEST_FAIL;
295 }
296 ao2_t_ref(obj, -1, "test");
297 }
298 }
299
300 return res;
301}

References ao2_find, ao2_t_ref, ast_random(), AST_TEST_FAIL, ast_test_status_update, and test_obj::i.

Referenced by astobj2_test_1_helper().

◆ test_ao2_find_w_OBJ_KEY()

static int test_ao2_find_w_OBJ_KEY ( int  res,
struct ao2_container look_in,
int  limit,
struct ast_test *  test 
)
static

Definition at line 354 of file test_astobj2.c.

355{
356 int i;
357 int num;
358 struct test_obj *obj;
359
360 for (num = 75; num--;) {
361 i = ast_random() % limit; /* find a random object */
362
363 obj = ao2_find(look_in, &i, OBJ_KEY);
364 if (!obj) {
365 ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_KEY flag failed.\n", i);
366 res = AST_TEST_FAIL;
367 } else {
368 if (obj->i != i) {
369 ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
370 res = AST_TEST_FAIL;
371 }
372 ao2_t_ref(obj, -1, "test");
373 }
374 }
375
376 return res;
377}

References ao2_find, ao2_t_ref, ast_random(), AST_TEST_FAIL, ast_test_status_update, test_obj::i, and OBJ_KEY.

Referenced by astobj2_test_1_helper().

◆ test_ao2_find_w_OBJ_PARTIAL_KEY()

static int test_ao2_find_w_OBJ_PARTIAL_KEY ( int  res,
struct ao2_container look_in,
int  limit,
struct ast_test *  test 
)
static

Definition at line 391 of file test_astobj2.c.

392{
393 int i;
394 int num;
395 struct test_obj *obj;
396
397 /* Set partial match to find exactly. */
399
400 for (num = 100; num--;) {
401 i = ast_random() % limit; /* find a random object */
402
403 obj = ao2_find(look_in, &i, OBJ_PARTIAL_KEY);
404 if (!obj) {
405 ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_PARTIAL_KEY flag failed.\n", i);
406 res = AST_TEST_FAIL;
407 } else {
408 if (obj->i != i) {
409 ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
410 res = AST_TEST_FAIL;
411 }
412 ao2_t_ref(obj, -1, "test");
413 }
414 }
415
416 return res;
417}
#define OBJ_PARTIAL_KEY
Definition astobj2.h:1152
int partial_key_match_range

References ao2_find, ao2_t_ref, ast_random(), AST_TEST_FAIL, ast_test_status_update, test_obj::i, OBJ_PARTIAL_KEY, and partial_key_match_range.

Referenced by astobj2_test_1_helper().

◆ test_ao2_find_w_OBJ_POINTER()

static int test_ao2_find_w_OBJ_POINTER ( int  res,
struct ao2_container look_in,
int  limit,
struct ast_test *  test 
)
static

Definition at line 315 of file test_astobj2.c.

316{
317 int i;
318 int num;
319 struct test_obj tmp_obj = { 0, };
320 struct test_obj *obj;
321
322 for (num = 75; num--;) {
323 i = ast_random() % limit; /* find a random object */
324
325 tmp_obj.i = i;
326 obj = ao2_find(look_in, &tmp_obj, OBJ_POINTER);
327 if (!obj) {
328 ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_POINTER flag failed.\n", i);
329 res = AST_TEST_FAIL;
330 } else {
331 if (obj->i != i) {
332 ast_test_status_update(test, "object %d does not match %d\n", obj->i, i);
333 res = AST_TEST_FAIL;
334 }
335 ao2_t_ref(obj, -1, "test");
336 }
337 }
338
339 return res;
340}

References ao2_find, ao2_t_ref, ast_random(), AST_TEST_FAIL, ast_test_status_update, test_obj::i, and OBJ_POINTER.

Referenced by astobj2_test_1_helper().

◆ test_ao2_iteration()

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 
)
static

Definition at line 1169 of file test_astobj2.c.

1172{
1173 struct ao2_iterator iter;
1174 struct test_obj *obj;
1175 int idx;
1176
1177 if (ao2_container_count(container) != count) {
1178 ast_test_status_update(test, "%s: Container count doesn't match vector count.\n",
1179 prefix);
1180 res = AST_TEST_FAIL;
1181 }
1182
1183 iter = ao2_iterator_init(container, flags);
1184
1185 /* Check iterated objects against the given vector. */
1186 for (idx = 0; idx < count; ++idx) {
1187 obj = ao2_iterator_next(&iter);
1188 if (!obj) {
1189 ast_test_status_update(test, "%s: Too few objects found.\n", prefix);
1190 res = AST_TEST_FAIL;
1191 break;
1192 }
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;
1197 }
1198 ao2_ref(obj, -1); /* remove ref from iterator */
1199 }
1200 obj = ao2_iterator_next(&iter);
1201 if (obj) {
1202 ast_test_status_update(test, "%s: Too many objects found. Object %d\n",
1203 prefix, obj->i);
1204 ao2_ref(obj, -1); /* remove ref from iterator */
1205 res = AST_TEST_FAIL;
1206 }
1207
1208 ao2_iterator_destroy(&iter);
1209
1210 return res;
1211}

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_TEST_FAIL, ast_test_status_update, container, test_obj::i, and prefix.

Referenced by test_traversal_nonsorted(), and test_traversal_sorted().

◆ test_cmp_cb()

static int test_cmp_cb ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 119 of file test_astobj2.c.

120{
121 struct test_obj *cmp_obj = (struct test_obj *) obj;
122
123 if (flags & OBJ_KEY) {
124 int *i = (int *) arg;
125
126 return (cmp_obj->i == *i) ? CMP_MATCH : 0;
127 } else if (flags & OBJ_PARTIAL_KEY) {
128 int *i = (int *) arg;
129
130 return (*i - partial_key_match_range <= cmp_obj->i
131 && cmp_obj->i <= *i + partial_key_match_range) ? CMP_MATCH : 0;
132 } else {
133 struct test_obj *arg_obj = (struct test_obj *) arg;
134
135 return (cmp_obj->i == arg_obj->i) ? CMP_MATCH : 0;
136 }
137}

References CMP_MATCH, test_obj::i, OBJ_KEY, OBJ_PARTIAL_KEY, and partial_key_match_range.

Referenced by AST_TEST_DEFINE(), astobj2_test_1_helper(), test_make_nonsorted(), test_make_sorted(), test_performance(), test_traversal_nonsorted(), and test_traversal_sorted().

◆ test_container2str()

static const char * test_container2str ( enum test_container_type  type)
static

Definition at line 56 of file test_astobj2.c.

57{
58 const char *c_type;
59
60 c_type = "Unknown";
61 switch (type) {
63 c_type = "List";
64 break;
66 c_type = "Hash";
67 break;
69 c_type = "RBTree";
70 break;
71 }
72 return c_type;
73}

References TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, and type.

Referenced by astobj2_test_1_helper(), test_traversal_nonsorted(), test_traversal_sorted(), and testloop().

◆ test_container_clone()

static int test_container_clone ( int  res,
struct ao2_container orig,
struct ast_test *  test 
)
static

Definition at line 214 of file test_astobj2.c.

215{
216 struct ao2_container *clone;
217 struct test_obj *obj;
218 struct test_obj *obj2;
219 struct ao2_iterator iter;
220
221 clone = ao2_container_clone(orig, 0);
222 if (!clone) {
223 ast_test_status_update(test, "ao2_container_clone failed.\n");
224 return AST_TEST_FAIL;
225 }
226 if (ao2_container_check(clone, 0)) {
227 ast_test_status_update(test, "container integrity check failed\n");
228 res = AST_TEST_FAIL;
229 } else if (ao2_container_count(orig) != ao2_container_count(clone)) {
230 ast_test_status_update(test, "Cloned container does not have the same number of objects.\n");
231 res = AST_TEST_FAIL;
232 } else {
233 iter = ao2_iterator_init(orig, 0);
234 for (; (obj = ao2_t_iterator_next(&iter, "test orig")); ao2_t_ref(obj, -1, "test orig")) {
235 /*
236 * Unlink the matching object from the cloned container to make
237 * the next search faster. This is a big speed optimization!
238 */
240 "test clone");
241 if (obj2) {
242 ao2_t_ref(obj2, -1, "test clone");
243 continue;
244 }
246 "Orig container has an object %p not in the clone container.\n", obj);
247 res = AST_TEST_FAIL;
248 }
250 if (ao2_container_count(clone)) {
251 ast_test_status_update(test, "Cloned container still has objects.\n");
252 res = AST_TEST_FAIL;
253 }
254 if (ao2_container_check(clone, 0)) {
255 ast_test_status_update(test, "container integrity check failed\n");
256 res = AST_TEST_FAIL;
257 }
258 }
259 ao2_t_ref(clone, -1, "bye clone");
260
261 return res;
262}
int ao2_match_by_addr(void *obj, void *arg, int flags)
A common ao2_callback is one that matches by address.
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
Definition astobj2.h:1419

References ao2_container_check(), ao2_container_clone, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_match_by_addr(), ao2_t_callback, ao2_t_iterator_next, ao2_t_ref, AST_TEST_FAIL, ast_test_status_update, OBJ_POINTER, and OBJ_UNLINK.

Referenced by astobj2_test_1_helper().

◆ test_expected_duplicates()

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 
)
static

Definition at line 1287 of file test_astobj2.c.

1290{
1291 struct ao2_iterator *mult_iter;
1292 struct test_obj *obj;
1293 int idx;
1294
1295 mult_iter = ao2_find(container, &number, flags | OBJ_MULTIPLE | OBJ_KEY);
1296 if (!mult_iter) {
1297 ast_test_status_update(test, "%s: Did not return iterator.\n", prefix);
1298 return AST_TEST_FAIL;
1299 }
1300
1301 /* Check matching objects against the given vector. */
1302 for (idx = 0; idx < count; ++idx) {
1303 obj = ao2_iterator_next(mult_iter);
1304 if (!obj) {
1305 ast_test_status_update(test, "%s: Too few objects found.\n", prefix);
1306 res = AST_TEST_FAIL;
1307 break;
1308 }
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;
1313 }
1314 if (vector[idx] != obj->dup_number) {
1315 ast_test_status_update(test, "%s: Object dup id %d != vector[%d] %d.\n",
1316 prefix, obj->dup_number, idx, vector[idx]);
1317 res = AST_TEST_FAIL;
1318 }
1319 ao2_ref(obj, -1); /* remove ref from iterator */
1320 }
1321 obj = ao2_iterator_next(mult_iter);
1322 if (obj) {
1324 "%s: Too many objects found. Object %d, dup id %d\n",
1325 prefix, obj->i, obj->dup_number);
1326 ao2_ref(obj, -1); /* remove ref from iterator */
1327 res = AST_TEST_FAIL;
1328 }
1329 ao2_iterator_destroy(mult_iter);
1330
1331 return res;
1332}

References ao2_find, ao2_iterator_destroy(), ao2_iterator_next, ao2_ref, AST_TEST_FAIL, ast_test_status_update, container, test_obj::dup_number, test_obj::i, OBJ_KEY, OBJ_MULTIPLE, and prefix.

Referenced by test_traversal_sorted().

◆ test_hash_cb()

static int test_hash_cb ( const void *  obj,
const int  flags 
)
static

Definition at line 139 of file test_astobj2.c.

140{
141 if (flags & OBJ_KEY) {
142 const int *i = obj;
143
144 return *i;
145 } else if (flags & OBJ_PARTIAL_KEY) {
146 /* This is absolutely wrong to be called with this flag value. */
147 abort();
148 /* Just in case abort() doesn't work or something else super silly */
149 *((int *) 0) = 0;
150 return 0;
151 } else {
152 const struct test_obj *hash_obj = obj;
153
154 return hash_obj->i;
155 }
156}

References test_obj::i, OBJ_KEY, and OBJ_PARTIAL_KEY.

Referenced by astobj2_test_1_helper(), test_make_nonsorted(), test_make_sorted(), and test_performance().

◆ test_make_nonsorted()

static struct ao2_container * test_make_nonsorted ( enum test_container_type  type,
int  options 
)
static

Definition at line 965 of file test_astobj2.c.

966{
967 struct ao2_container *container;
968
969 container = NULL;
970 switch (type) {
974 break;
978 break;
980 /* Container type must be sorted. */
981 break;
982 }
983
984 return container;
985}
#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.
Definition astobj2.h:1303
static struct test_options options

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ao2_container_alloc_list, container, NULL, options, test_cmp_cb(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, test_hash_cb(), and type.

Referenced by test_traversal_nonsorted().

◆ test_make_sorted()

static struct ao2_container * test_make_sorted ( enum test_container_type  type,
int  options 
)
static

◆ test_obj_destructor()

static void test_obj_destructor ( void *  v_obj)
static

Definition at line 87 of file test_astobj2.c.

88{
89 struct test_obj *obj = (struct test_obj *) v_obj;
90
91 if (obj->destructor_count) {
92 --*obj->destructor_count;
93 }
94}

References test_obj::destructor_count.

Referenced by AST_TEST_DEFINE(), AST_TEST_DEFINE(), astobj2_test_1_helper(), insert_test_duplicates(), insert_test_vector(), and test_performance().

◆ test_performance()

static enum ast_test_result_state test_performance ( struct ast_test *  test,
enum test_container_type  type,
unsigned int  copt 
)
static

The number of objects inserted and searched for in the container under test.

Definition at line 1923 of file test_astobj2.c.

1925{
1926/*!
1927 * \brief The number of objects inserted and searched for in the container under test.
1928 */
1929#define OBJS 73
1930 int res = AST_TEST_PASS;
1931 struct ao2_container *c1 = NULL;
1932 struct test_obj *tobj[OBJS];
1933 struct test_obj *tobj2;
1934 int i;
1935
1936 switch (type) {
1940 break;
1944 break;
1948 break;
1949 }
1950
1951 for (i = 0; i < OBJS; i++) {
1952 tobj[i] = NULL;
1953 }
1954
1955 if (!c1) {
1956 ast_test_status_update(test, "Container c1 creation failed.\n");
1957 res = AST_TEST_FAIL;
1958 goto test_cleanup;
1959 }
1960
1961 for (i = 0; i < OBJS; i++) {
1962 tobj[i] = ao2_alloc(sizeof(struct test_obj), test_obj_destructor);
1963 if (!tobj[i]) {
1964 ast_test_status_update(test, "test object creation failed.\n");
1965 res = AST_TEST_FAIL;
1966 goto test_cleanup;
1967 }
1968 tobj[i]->i = i;
1969 ao2_link(c1, tobj[i]);
1970 }
1971
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;
1976 goto test_cleanup;
1977 }
1978 ao2_ref(tobj2, -1);
1979 tobj2 = NULL;
1980 }
1981
1982test_cleanup:
1983 for (i = 0; i < OBJS ; i++) {
1984 ao2_cleanup(tobj[i]);
1985 }
1986 ao2_cleanup(c1);
1987 return res;
1988}
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition astobj2.h:1349
#define OBJS

References ao2_alloc, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_cleanup, ao2_container_alloc_hash, ao2_container_alloc_list, ao2_container_alloc_rbtree, ao2_find, ao2_link, ao2_ref, AST_TEST_FAIL, AST_TEST_PASS, ast_test_status_update, test_obj::i, NULL, OBJ_KEY, OBJS, test_cmp_cb(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, test_hash_cb(), test_obj_destructor(), test_sort_cb(), and type.

Referenced by testloop().

◆ test_sort_cb()

static int test_sort_cb ( const void *  obj_left,
const void *  obj_right,
int  flags 
)
static

Definition at line 158 of file test_astobj2.c.

159{
160 const struct test_obj *test_left = obj_left;
161
162 if (flags & OBJ_KEY) {
163 const int *i = obj_right;
164
165 return test_left->i - *i;
166 } else if (flags & OBJ_PARTIAL_KEY) {
167 int *i = (int *) obj_right;
168
169 if (*i - partial_key_match_range <= test_left->i
170 && test_left->i <= *i + partial_key_match_range) {
171 return 0;
172 }
173
174 return test_left->i - *i;
175 } else {
176 const struct test_obj *test_right = obj_right;
177
178 return test_left->i - test_right->i;
179 }
180}

References test_obj::i, OBJ_KEY, OBJ_PARTIAL_KEY, and partial_key_match_range.

Referenced by astobj2_test_1_helper(), test_make_sorted(), and test_performance().

◆ test_traversal_nonsorted()

static int test_traversal_nonsorted ( int  res,
int  tst_num,
enum test_container_type  type,
struct ast_test *  test 
)
static

Container object insertion vector.

Container object insertion vector reversed.

Definition at line 1346 of file test_astobj2.c.

1347{
1348 struct ao2_container *c1;
1349 struct ao2_container *c2 = NULL;
1350 int partial;
1351 int destructor_count = 0;
1352
1353 /*! Container object insertion vector. */
1354 static const int test_initial[] = {
1355 1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1356 };
1357
1358 /*! Container object insertion vector reversed. */
1359 static const int test_reverse[] = {
1360 8, 9, 3, 5, 7, 4, 6, 2, 0, 1
1361 };
1362 static const int test_list_partial_forward[] = {
1363 6, 7, 5
1364 };
1365 static const int test_list_partial_backward[] = {
1366 5, 7, 6
1367 };
1368
1369 /* The hash orders assume that there are 5 buckets. */
1370 static const int test_hash_end_forward[] = {
1371 0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1372 };
1373 static const int test_hash_end_backward[] = {
1374 9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1375 };
1376 static const int test_hash_begin_forward[] = {
1377 5, 0, 6, 1, 7, 2, 8, 3, 9, 4
1378 };
1379 static const int test_hash_begin_backward[] = {
1380 4, 9, 3, 8, 2, 7, 1, 6, 0, 5
1381 };
1382 static const int test_hash_partial_forward[] = {
1383 5, 6, 7
1384 };
1385 static const int test_hash_partial_backward[] = {
1386 7, 6, 5
1387 };
1388
1389 ast_test_status_update(test, "Test %d, %s containers.\n",
1390 tst_num, test_container2str(type));
1391
1392 /* Create container that inserts objects at the end. */
1393 c1 = test_make_nonsorted(type, 0);
1394 if (!c1) {
1395 ast_test_status_update(test, "Container c1 creation failed.\n");
1396 res = AST_TEST_FAIL;
1397 goto test_cleanup;
1398 }
1399 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1", test)) {
1400 res = AST_TEST_FAIL;
1401 goto test_cleanup;
1402 }
1403
1404 /* Create container that inserts objects at the beginning. */
1406 if (!c2) {
1407 ast_test_status_update(test, "Container c2 creation failed.\n");
1408 res = AST_TEST_FAIL;
1409 goto test_cleanup;
1410 }
1411 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2", test)) {
1412 res = AST_TEST_FAIL;
1413 goto test_cleanup;
1414 }
1415
1416 /* Check container iteration directions */
1417 switch (type) {
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);
1425
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);
1432 break;
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);
1440
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);
1447 break;
1449 break;
1450 }
1451
1452 /* Check container traversal directions */
1453 switch (type) {
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);
1461
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);
1468 break;
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);
1476
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);
1483 break;
1485 break;
1486 }
1487
1488 /* Check traversal with OBJ_PARTIAL_KEY search range. */
1489 partial = 6;
1491 switch (type) {
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);
1501 break;
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);
1511 break;
1513 break;
1514 }
1515
1516test_cleanup:
1517 /* destroy containers */
1518 if (c1) {
1519 ao2_t_ref(c1, -1, "bye c1");
1520 }
1521 if (c2) {
1522 ao2_t_ref(c2, -1, "bye c2");
1523 }
1524
1525 if (destructor_count > 0) {
1527 "all destructors were not called, destructor count is %d\n",
1528 destructor_count);
1529 res = AST_TEST_FAIL;
1530 } else if (destructor_count < 0) {
1532 "Destructor was called too many times, destructor count is %d\n",
1533 destructor_count);
1534 res = AST_TEST_FAIL;
1535 }
1536
1537 return res;
1538}
@ AO2_ITERATOR_DESCENDING
Definition astobj2.h:1875
@ OBJ_ORDER_DESCENDING
Traverse in descending order (Last to first container object)
Definition astobj2.h:1123
@ OBJ_ORDER_ASCENDING
Traverse in ascending order (First to last container object)
Definition astobj2.h:1121
@ AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN
Insert objects at the beginning of the container. (Otherwise it is the opposite; insert at the end....
Definition astobj2.h:1172
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)
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 int insert_test_vector(struct ao2_container *container, int *destroy_counter, const int *vector, int count, const char *prefix, struct ast_test *test)
static struct ao2_container * test_make_nonsorted(enum test_container_type type, int options)
#define ARRAY_LEN(a)
Definition utils.h:703

References AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN, AO2_ITERATOR_DESCENDING, ao2_t_ref, ARRAY_LEN, AST_TEST_FAIL, ast_test_status_update, insert_test_vector(), NULL, OBJ_ORDER_ASCENDING, OBJ_ORDER_DESCENDING, OBJ_PARTIAL_KEY, partial_key_match_range, test_ao2_callback_traversal(), test_ao2_iteration(), test_cmp_cb(), test_container2str(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, test_make_nonsorted(), and type.

Referenced by AST_TEST_DEFINE().

◆ test_traversal_sorted()

static int test_traversal_sorted ( int  res,
int  tst_num,
enum test_container_type  type,
struct ast_test *  test 
)
static

Container object insertion vector.

Container forward traversal/iteration.

Container backward traversal/iteration.

Definition at line 1552 of file test_astobj2.c.

1553{
1554 struct ao2_container *c1;
1555 struct ao2_container *c2 = NULL;
1556 int partial;
1557 int destructor_count = 0;
1558 int duplicate_number = 100;
1559
1560 /*! Container object insertion vector. */
1561 static const int test_initial[] = {
1562 1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1563 };
1564
1565 /*! Container forward traversal/iteration. */
1566 static const int test_forward[] = {
1567 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
1568 };
1569 /*! Container backward traversal/iteration. */
1570 static const int test_backward[] = {
1571 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
1572 };
1573
1574 static const int test_partial_forward[] = {
1575 5, 6, 7
1576 };
1577 static const int test_partial_backward[] = {
1578 7, 6, 5
1579 };
1580
1581 /* The hash orders assume that there are 5 buckets. */
1582 static const int test_hash_forward[] = {
1583 0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1584 };
1585 static const int test_hash_backward[] = {
1586 9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1587 };
1588 static const int test_hash_partial_forward[] = {
1589 5, 6, 7
1590 };
1591 static const int test_hash_partial_backward[] = {
1592 7, 6, 5
1593 };
1594
1595 /* Duplicate identifier order */
1596 static const int test_dup_allow_forward[] = {
1597 0, 1, 2, 3, 2
1598 };
1599 static const int test_dup_allow_backward[] = {
1600 2, 3, 2, 1, 0
1601 };
1602 static const int test_dup_reject[] = {
1603 0
1604 };
1605 static const int test_dup_obj_reject_forward[] = {
1606 0, 1, 2, 3
1607 };
1608 static const int test_dup_obj_reject_backward[] = {
1609 3, 2, 1, 0
1610 };
1611 static const int test_dup_replace[] = {
1612 2
1613 };
1614
1615 ast_test_status_update(test, "Test %d, %s containers.\n",
1616 tst_num, test_container2str(type));
1617
1618 /* Create container that inserts duplicate objects after matching objects. */
1620 if (!c1) {
1621 ast_test_status_update(test, "Container c1 creation failed.\n");
1622 res = AST_TEST_FAIL;
1623 goto test_cleanup;
1624 }
1625 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_ALLOW)", test)) {
1626 res = AST_TEST_FAIL;
1627 goto test_cleanup;
1628 }
1629
1630 /* Create container that inserts duplicate objects before matching objects. */
1632 if (!c2) {
1633 ast_test_status_update(test, "Container c2 creation failed.\n");
1634 res = AST_TEST_FAIL;
1635 goto test_cleanup;
1636 }
1637 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_ALLOW)", test)) {
1638 res = AST_TEST_FAIL;
1639 goto test_cleanup;
1640 }
1641
1642#if defined(TEST_CONTAINER_DEBUG_DUMP)
1643 ao2_container_dump(c1, 0, "c1(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
1644 ao2_container_stats(c1, 0, "c1(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug);
1645 ao2_container_dump(c2, 0, "c2(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
1646 ao2_container_stats(c2, 0, "c2(DUPS_ALLOW)", (void *) test, (ao2_prnt_fn *) ast_test_debug);
1647#endif /* defined(TEST_CONTAINER_DEBUG_DUMP) */
1648
1649 /* Check container iteration directions */
1650 switch (type) {
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);
1659 break;
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);
1667 break;
1668 }
1669
1670 /* Check container traversal directions */
1671 switch (type) {
1675 test_forward, ARRAY_LEN(test_forward),
1676 "Traversal (ascending)", test);
1678 test_backward, ARRAY_LEN(test_backward),
1679 "Traversal (descending)", test);
1680 break;
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);
1688 break;
1689 }
1690
1691 /* Check traversal with OBJ_PARTIAL_KEY search range. */
1692 partial = 6;
1694 switch (type) {
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);
1705 break;
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);
1715 break;
1716 }
1717
1718 /* Add duplicates to initial containers that allow duplicates */
1719 if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_ALLOW)", test)) {
1720 res = AST_TEST_FAIL;
1721 goto test_cleanup;
1722 }
1723 if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_ALLOW)", test)) {
1724 res = AST_TEST_FAIL;
1725 goto test_cleanup;
1726 }
1727
1728#if defined(TEST_CONTAINER_DEBUG_DUMP)
1729 ao2_container_dump(c1, 0, "c1(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
1730 ao2_container_stats(c1, 0, "c1(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug);
1731 ao2_container_dump(c2, 0, "c2(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug, test_prnt_obj);
1732 ao2_container_stats(c2, 0, "c2(DUPS_ALLOW) w/ dups", (void *) test, (ao2_prnt_fn *) ast_test_debug);
1733#endif /* defined(TEST_CONTAINER_DEBUG_DUMP) */
1734
1735 /* Check duplicates in containers that allow duplicates. */
1736 res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
1737 test_dup_allow_forward, ARRAY_LEN(test_dup_allow_forward),
1738 "Duplicates (ascending, DUPS_ALLOW)", test);
1739 res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
1740 test_dup_allow_backward, ARRAY_LEN(test_dup_allow_backward),
1741 "Duplicates (descending, DUPS_ALLOW)", test);
1742
1743 ao2_t_ref(c1, -1, "bye c1");
1744 c1 = NULL;
1745 ao2_t_ref(c2, -1, "bye c2");
1746 c2 = NULL;
1747
1748 /* Create containers that reject duplicate keyed objects. */
1750 if (!c1) {
1751 ast_test_status_update(test, "Container c1 creation failed.\n");
1752 res = AST_TEST_FAIL;
1753 goto test_cleanup;
1754 }
1755 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_REJECT)", test)) {
1756 res = AST_TEST_FAIL;
1757 goto test_cleanup;
1758 }
1759 if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_REJECT)", test)) {
1760 res = AST_TEST_FAIL;
1761 goto test_cleanup;
1762 }
1764 if (!c2) {
1765 ast_test_status_update(test, "Container c2 creation failed.\n");
1766 res = AST_TEST_FAIL;
1767 goto test_cleanup;
1768 }
1769 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_REJECT)", test)) {
1770 res = AST_TEST_FAIL;
1771 goto test_cleanup;
1772 }
1773 if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_REJECT)", test)) {
1774 res = AST_TEST_FAIL;
1775 goto test_cleanup;
1776 }
1777
1778 /* Check duplicates in containers that reject duplicate keyed objects. */
1779 res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
1780 test_dup_reject, ARRAY_LEN(test_dup_reject),
1781 "Duplicates (ascending, DUPS_REJECT)", test);
1782 res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
1783 test_dup_reject, ARRAY_LEN(test_dup_reject),
1784 "Duplicates (descending, DUPS_REJECT)", test);
1785
1786 ao2_t_ref(c1, -1, "bye c1");
1787 c1 = NULL;
1788 ao2_t_ref(c2, -1, "bye c2");
1789 c2 = NULL;
1790
1791 /* Create containers that reject duplicate objects. */
1793 if (!c1) {
1794 ast_test_status_update(test, "Container c1 creation failed.\n");
1795 res = AST_TEST_FAIL;
1796 goto test_cleanup;
1797 }
1798 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_OBJ_REJECT)", test)) {
1799 res = AST_TEST_FAIL;
1800 goto test_cleanup;
1801 }
1802 if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_OBJ_REJECT)", test)) {
1803 res = AST_TEST_FAIL;
1804 goto test_cleanup;
1805 }
1807 if (!c2) {
1808 ast_test_status_update(test, "Container c2 creation failed.\n");
1809 res = AST_TEST_FAIL;
1810 goto test_cleanup;
1811 }
1812 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_OBJ_REJECT)", test)) {
1813 res = AST_TEST_FAIL;
1814 goto test_cleanup;
1815 }
1816 if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_OBJ_REJECT)", test)) {
1817 res = AST_TEST_FAIL;
1818 goto test_cleanup;
1819 }
1820
1821 /* Check duplicates in containers that reject duplicate objects. */
1822 res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
1823 test_dup_obj_reject_forward, ARRAY_LEN(test_dup_obj_reject_forward),
1824 "Duplicates (ascending, DUPS_OBJ_REJECT)", test);
1825 res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
1826 test_dup_obj_reject_backward, ARRAY_LEN(test_dup_obj_reject_backward),
1827 "Duplicates (descending, DUPS_OBJ_REJECT)", test);
1828
1829 ao2_t_ref(c1, -1, "bye c1");
1830 c1 = NULL;
1831 ao2_t_ref(c2, -1, "bye c2");
1832 c2 = NULL;
1833
1834 /* Create container that replaces duplicate keyed objects. */
1836 if (!c1) {
1837 ast_test_status_update(test, "Container c1 creation failed.\n");
1838 res = AST_TEST_FAIL;
1839 goto test_cleanup;
1840 }
1841 if (insert_test_vector(c1, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c1(DUPS_REJECT)", test)) {
1842 res = AST_TEST_FAIL;
1843 goto test_cleanup;
1844 }
1845 if (insert_test_duplicates(c1, &destructor_count, duplicate_number, "c1(DUPS_REJECT)", test)) {
1846 res = AST_TEST_FAIL;
1847 goto test_cleanup;
1848 }
1850 if (!c2) {
1851 ast_test_status_update(test, "Container c2 creation failed.\n");
1852 res = AST_TEST_FAIL;
1853 goto test_cleanup;
1854 }
1855 if (insert_test_vector(c2, &destructor_count, test_initial, ARRAY_LEN(test_initial), "c2(DUPS_REPLACE)", test)) {
1856 res = AST_TEST_FAIL;
1857 goto test_cleanup;
1858 }
1859 if (insert_test_duplicates(c2, &destructor_count, duplicate_number, "c2(DUPS_REPLACE)", test)) {
1860 res = AST_TEST_FAIL;
1861 goto test_cleanup;
1862 }
1863
1864 /* Check duplicates in containers that replaces duplicate keyed objects. */
1865 res = test_expected_duplicates(res, c1, OBJ_ORDER_ASCENDING, duplicate_number,
1866 test_dup_replace, ARRAY_LEN(test_dup_replace),
1867 "Duplicates (ascending, DUPS_REPLACE)", test);
1868 res = test_expected_duplicates(res, c1, OBJ_ORDER_DESCENDING, duplicate_number,
1869 test_dup_replace, ARRAY_LEN(test_dup_replace),
1870 "Duplicates (descending, DUPS_REPLACE)", test);
1871
1872test_cleanup:
1873 /* destroy containers */
1874 if (c1) {
1875 ao2_t_ref(c1, -1, "bye c1");
1876 }
1877 if (c2) {
1878 ao2_t_ref(c2, -1, "bye c2");
1879 }
1880
1881 if (destructor_count > 0) {
1883 "all destructors were not called, destructor count is %d\n",
1884 destructor_count);
1885 res = AST_TEST_FAIL;
1886 } else if (destructor_count < 0) {
1888 "Destructor was called too many times, destructor count is %d\n",
1889 destructor_count);
1890 res = AST_TEST_FAIL;
1891 }
1892
1893 return res;
1894}
@ AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT
Reject duplicate objects in container.
Definition astobj2.h:1201
@ AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW
Allow objects with duplicate keys in container.
Definition astobj2.h:1181
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition astobj2.h:1188
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE
Replace objects with duplicate keys in container.
Definition astobj2.h:1211
static int insert_test_duplicates(struct ao2_container *container, int *destroy_counter, int number, const char *prefix, struct ast_test *test)
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)
static struct ao2_container * test_make_sorted(enum test_container_type type, int options)

References AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW, AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN, ao2_container_dump(), ao2_container_stats(), AO2_ITERATOR_DESCENDING, ao2_t_ref, ARRAY_LEN, ast_test_debug, AST_TEST_FAIL, ast_test_status_update, insert_test_duplicates(), insert_test_vector(), NULL, OBJ_ORDER_ASCENDING, OBJ_ORDER_DESCENDING, OBJ_PARTIAL_KEY, partial_key_match_range, test_ao2_callback_traversal(), test_ao2_iteration(), test_cmp_cb(), test_container2str(), TEST_CONTAINER_HASH, TEST_CONTAINER_LIST, TEST_CONTAINER_RBTREE, test_expected_duplicates(), test_make_sorted(), and type.

Referenced by AST_TEST_DEFINE().

◆ testloop()

static enum ast_test_result_state testloop ( struct ast_test *  test,
enum test_container_type  type,
int  copt,
int  iterations 
)
static

Definition at line 1990 of file test_astobj2.c.

1992{
1993 int res = AST_TEST_PASS;
1994 int i;
1995 int reportcount = iterations / 5;
1996 struct timeval start;
1997
1998 start = ast_tvnow();
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));
2003 }
2004 res = test_performance(test, type, copt);
2005 }
2006 ast_test_status_update(test, "%5.2fK traversals, %9s : %5lu ms\n",
2007 iterations / 1000.0, test_container2str(type), (unsigned long)ast_tvdiff_ms(ast_tvnow(), start));
2008 return res;
2009}
static enum ast_test_result_state test_performance(struct ast_test *test, enum test_container_type type, unsigned int copt)
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

References AST_TEST_PASS, ast_test_status_update, ast_tvdiff_ms(), ast_tvnow(), test_obj::i, test_container2str(), test_performance(), and type.

Referenced by AST_TEST_DEFINE().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2052 of file test_astobj2.c.

2053{
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);
2059 return 0;
2060}
#define AST_TEST_UNREGISTER(cb)
Definition test.h:128

References AST_TEST_UNREGISTER.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "ASTOBJ2 Unit Tests" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 2072 of file test_astobj2.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2072 of file test_astobj2.c.

◆ partial_key_match_range

int partial_key_match_range

Partial search key +/- matching range.

Definition at line 85 of file test_astobj2.c.

Referenced by test_ao2_find_w_OBJ_PARTIAL_KEY(), test_cmp_cb(), test_sort_cb(), test_traversal_nonsorted(), and test_traversal_sorted().