Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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
Definition: test_astobj2.c:44
@ TEST_CONTAINER_HASH
Definition: test_astobj2.c:43
@ TEST_CONTAINER_LIST
Definition: test_astobj2.c:42

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}
def info(msg)
@ 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)
Definition: test_astobj2.c:419

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, astobj2_test_1_helper(), sip_to_pjsip::info(), 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 *unused)
Definition: pbx_realtime.c:124
#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
Definition: test_astobj2.c:77
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static void test_obj_destructor(void *v_obj)
Definition: test_astobj2.c:87
static int test_cmp_cb(void *obj, void *arg, int flags)
Definition: test_astobj2.c:119
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, sip_to_pjsip::info(), 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, sip_to_pjsip::info(), 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, sip_to_pjsip::info(), 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, sip_to_pjsip::info(), 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[]
Definition: chan_ooh323.c:109
#define ast_test_debug(test, fmt,...)
Definition: test.h:130
static int multiple_cb(void *obj, void *arg, int flag)
Definition: test_astobj2.c:111
static int test_ao2_find_w_OBJ_POINTER(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
Definition: test_astobj2.c:315
static int test_ao2_find_w_OBJ_PARTIAL_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
Definition: test_astobj2.c:391
static int test_container_clone(int res, struct ao2_container *orig, struct ast_test *test)
Definition: test_astobj2.c:214
static int test_ao2_find_w_no_flags(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
Definition: test_astobj2.c:276
static int test_hash_cb(const void *obj, const int flags)
Definition: test_astobj2.c:139
static int test_ao2_find_w_OBJ_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
Definition: test_astobj2.c:354
static int all_but_one_cb(void *obj, void *arg, int flag)
Definition: test_astobj2.c:104
static int increment_cb(void *obj, void *arg, int flag)
Definition: test_astobj2.c:96
static int test_sort_cb(const void *obj_left, const void *obj_right, int flags)
Definition: test_astobj2.c:158
static const char * test_container2str(enum test_container_type type)
Definition: test_astobj2.c:56
long int ast_random(void)
Definition: utils.c:2312

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:501
Number structure.
Definition: app_followme.c:154
int dup_number
Definition: test_astobj2.c:81

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
Definition: test_astobj2.c:85

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(), 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)
Definition: test_astobj2.c:965
#define ARRAY_LEN(a)
Definition: utils.h:666

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)
Definition: test_astobj2.c:998

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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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().