diff --git a/main/astobj2.c b/main/astobj2.c index 5f4cda91eb..5e61d5e5f1 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -734,10 +734,6 @@ static void *internal_ao2_callback(struct ao2_container *c, } ast_free(cur); /* free the link record */ } - if ((match) && (!(flags & OBJ_UNLINK))) { - AST_LIST_REMOVE_CURRENT(entry); - AST_LIST_INSERT_HEAD(&c->buckets[i], cur, entry); - } if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) { /* We found our only (or last) match, so force an exit from diff --git a/tests/test_astobj2.c b/tests/test_astobj2.c index f76f2185eb..12632c63af 100644 --- a/tests/test_astobj2.c +++ b/tests/test_astobj2.c @@ -364,16 +364,148 @@ AST_TEST_DEFINE(astobj2_test_1) return res; } +AST_TEST_DEFINE(astobj2_test_2) +{ + int res = AST_TEST_PASS; + struct ao2_container *c; + struct ao2_iterator i; + struct test_obj *obj; + int num; + static const int NUM_OBJS = 5; + int destructor_count = NUM_OBJS; + struct test_obj tmp_obj = { "", }; + + switch (cmd) { + case TEST_INIT: + info->name = "astobj2_test2"; + info->category = "/main/astobj2/"; + info->summary = "Test a certain scenario using ao2 iterators"; + info->description = + "This test is aimed at testing for a specific regression that occurred. " + "Add some objects into a container. Mix finds and iteration and make " + "sure that the iterator still sees all objects."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + c = ao2_container_alloc(1, NULL, test_cmp_cb); + if (!c) { + ast_test_status_update(test, "ao2_container_alloc failed.\n"); + res = AST_TEST_FAIL; + goto cleanup; + } + + for (num = 1; num <= NUM_OBJS; num++) { + if (!(obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor))) { + ast_test_status_update(test, "ao2_alloc failed.\n"); + res = AST_TEST_FAIL; + goto cleanup; + } + obj->destructor_count = &destructor_count; + obj->i = num; + ao2_link(c, obj); + ao2_ref(obj, -1); + if (ao2_container_count(c) != num) { + ast_test_status_update(test, "container did not link correctly\n"); + res = AST_TEST_FAIL; + } + } + + /* + * Iteration take 1. Just make sure we see all NUM_OBJS objects. + */ + num = 0; + i = ao2_iterator_init(c, 0); + while ((obj = ao2_iterator_next(&i))) { + num++; + ao2_ref(obj, -1); + } + ao2_iterator_destroy(&i); + + if (num != NUM_OBJS) { + ast_test_status_update(test, "iterate take 1, expected '%d', only saw '%d' objects\n", + NUM_OBJS, num); + res = AST_TEST_FAIL; + } + + /* + * Iteration take 2. Do a find for the last object, then iterate and make + * sure we find all NUM_OBJS objects. + */ + tmp_obj.i = NUM_OBJS; + obj = ao2_find(c, &tmp_obj, OBJ_POINTER); + if (!obj) { + ast_test_status_update(test, "ao2_find() failed.\n"); + res = AST_TEST_FAIL; + } else { + ao2_ref(obj, -1); + } + + num = 0; + i = ao2_iterator_init(c, 0); + while ((obj = ao2_iterator_next(&i))) { + num++; + ao2_ref(obj, -1); + } + ao2_iterator_destroy(&i); + + if (num != NUM_OBJS) { + ast_test_status_update(test, "iterate take 2, expected '%d', only saw '%d' objects\n", + NUM_OBJS, num); + res = AST_TEST_FAIL; + } + + /* + * Iteration take 3. Do a find for an object while in the middle + * of iterating; + */ + num = 0; + i = ao2_iterator_init(c, 0); + while ((obj = ao2_iterator_next(&i))) { + if (num == 1) { + struct test_obj *obj2; + tmp_obj.i = NUM_OBJS - 1; + obj2 = ao2_find(c, &tmp_obj, OBJ_POINTER); + if (!obj2) { + ast_test_status_update(test, "ao2_find() failed.\n"); + res = AST_TEST_FAIL; + } else { + ao2_ref(obj2, -1); + } + } + num++; + ao2_ref(obj, -1); + } + ao2_iterator_destroy(&i); + + if (num != NUM_OBJS) { + ast_test_status_update(test, "iterate take 3, expected '%d', only saw '%d' objects\n", + NUM_OBJS, num); + res = AST_TEST_FAIL; + } + + +cleanup: + if (c) { + ao2_ref(c, -1); + } + + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(astobj2_test_1); + AST_TEST_UNREGISTER(astobj2_test_2); return 0; } static int load_module(void) { AST_TEST_REGISTER(astobj2_test_1); + AST_TEST_REGISTER(astobj2_test_2); return AST_MODULE_LOAD_SUCCESS; } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ASTOBJ2 Unit Test"); +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ASTOBJ2 Unit Tests");