38 static int destructor_called;
39 static int weakproxydestroyed;
41 static void test_obj_destructor(
void *obj)
46 static void weakproxy_destructor(
void *obj)
51 static void test_obj_destroy_notify(
void *obj,
void *data)
71 int notify0_called = 0;
72 int notify1_called = 0;
73 int notify2_called = 0;
74 int notify3_called = 0;
78 info->name =
"astobj2_weak1";
79 info->category =
"/main/astobj2/";
80 info->summary =
"Test ao2 weak objects";
81 info->description =
"Test ao2 weak objects.";
82 return AST_TEST_NOT_RUN;
87 destructor_called = weakproxydestroyed = 0;
88 obj1 = ao2_t_alloc(0, test_obj_destructor,
"obj1");
93 weakref1 = ao2_t_weakproxy_alloc(
sizeof(*weakref1), weakproxy_destructor,
"weakref1");
95 ast_test_status_update(
test,
"Failed to allocate weakref1.\n");
101 ast_test_status_update(
test,
"Failed to subscribe to weakref1.\n");
104 if (!notify0_called) {
105 ast_test_status_update(
test,
"Subscribe failed to immediately run callback for empty weakproxy.\n");
109 if (ao2_t_weakproxy_set_object(weakref1, obj1, 0,
"set weakref1 to obj1")) {
110 ast_test_status_update(
test,
"Failed to set obj1 on weakref1.\n");
115 ast_test_status_update(
test,
"Failed to add a subscription to weakref1.\n");
119 weakref2 = ao2_t_get_weakproxy(obj1,
"get weakref2 from obj1");
120 if (weakref1 != weakref2) {
121 ast_test_status_update(
test,
"weakref1 != weakref2.\n");
126 ast_test_status_update(
test,
"Failed to add a subscription to weakref2.\n");
131 ast_test_status_update(
test,
"Failed to add a duplicate subscription to weakref2.\n");
136 ast_test_status_update(
test,
"Failed to add a second duplicate subscription to weakref2.\n");
141 ast_test_status_update(
test,
"Failed to remove a subscription to weakref2.\n");
145 ao2_t_cleanup(weakref1,
"weakref1");
146 ao2_t_cleanup(weakref2,
"weakref2");
148 weakref2 = ao2_t_get_weakproxy(obj1,
"get weakref2 from obj1");
149 if (weakref1 != weakref2) {
151 ast_test_status_update(
test,
"weakref1 != weakref2.\n");
156 obj2 = ao2_t_alloc(0, NULL,
"obj2");
158 int ret = ao2_t_weakproxy_set_object(weakref2, obj2, 0,
"set weakref2 to obj2");
162 ast_test_status_update(
test,
"Set obj2 to weakref2 when it already had an object.\n");
168 ast_test_status_update(
test,
"Failed to add a subscription to weakref2.\n");
173 ast_test_status_update(
test,
"Failed to add a duplicate subscription to weakref2.\n");
178 ast_test_status_update(
test,
"Failed to remove the correct number of subscriptions to weakref2.\n");
182 if (destructor_called || notify1_called || notify2_called || notify3_called) {
183 ast_test_status_update(
test,
"Destructor or notifications called early.\n");
187 strong1 = ao2_t_weakproxy_get_object(weakref2, 0,
"get strong1 from weakref2");
188 ao2_t_cleanup(strong1,
"strong1");
190 if (obj1 != strong1) {
191 ast_test_status_update(
test,
"obj1 != strong1.\n");
195 if (destructor_called || notify1_called || notify2_called || notify3_called) {
196 ast_test_status_update(
test,
"Destructor or notification called early.\n");
200 ao2_t_ref(obj1, -1,
"obj1");
203 if (destructor_called != 1 || notify1_called != 1 || notify2_called != 2 || notify3_called != 0) {
204 ast_test_status_update(
test,
"Destructor or notification not called the expected number of times.\n");
208 if (ao2_t_weakproxy_get_object(weakref2, 0,
"impossible get of weakref2") != NULL) {
209 ast_test_status_update(
test,
"Get object on weakref2 worked when it shouldn't\n");
213 obj3 = ao2_t_alloc(0, test_obj_destructor,
"obj3");
215 ast_test_status_update(
test,
"Failed to allocate obj3.\n");
219 if (ao2_t_weakproxy_set_object(weakref2, obj3, 0,
"set weakref2 to obj3")) {
220 ast_test_status_update(
test,
"Failed to set obj3 to weakref2.\n");
224 if (ao2_t_weakproxy_ref_object(obj3, +1, 0,
"ao2_ref should never see this") != -2) {
225 ast_test_status_update(
test,
226 "Expected -2 from ao2_t_weakproxy_ref_object against normal ao2 object.\n");
230 if (ao2_t_weakproxy_ref_object(weakref2, +1, 0,
"weakref2 ref_object") != 2) {
231 ast_test_status_update(
test,
"Expected 2 from weakref2 ref_object.\n");
235 if (ao2_t_ref(obj3, -1,
"balance weakref2 ref_object") != 3) {
236 ast_test_status_update(
test,
"Expected 3 from obj3 ao2_t_ref.\n");
243 ast_test_status_update(
test,
"Expected -1 from weakref2 ref_object because obj3 is gone.\n");
247 ao2_t_ref(weakref2, -1,
"weakref2");
249 if (!weakproxydestroyed) {
250 ast_test_status_update(
test,
"Destructor never called for weakproxy, likely a leak.\n");
251 return AST_TEST_FAIL;
254 return AST_TEST_PASS;
259 ao2_cleanup(weakref1);
260 ao2_cleanup(weakref2);
262 return AST_TEST_FAIL;
276 struct strong_str *strong = ao2_t_alloc(
sizeof(*strong), NULL, value);
279 if (!weak || !strong) {
283 strcpy(weak->value, value);
284 strong->value = weak->value;
290 if (!
ao2_link(weakcontainer, weak)) {
308 #define ITERATOR_CHECK_NEXT(iter, var, expected) \
310 var = ao2_iterator_next(iter); \
311 ast_test_validate_cleanup(test, var == expected, ret, cleanup); \
315 #define WEAKFIND_CHECK(c, key, var, expected) \
317 var = ao2_weakproxy_find(c, key, OBJ_SEARCH_KEY, ""); \
318 ast_test_validate_cleanup(test, var == expected, ret, cleanup); \
324 int ret = AST_TEST_FAIL;
339 info->name =
"astobj2_weak_container";
340 info->category =
"/main/astobj2/";
341 info->summary =
"Test ao2 weak containers";
342 info->description =
"Test ao2 weak containers.";
343 return AST_TEST_NOT_RUN;
349 weakproxy_str_hash_fn, NULL, weakproxy_str_cmp_fn);
351 strong_str_sort_fn, NULL);
353 if (!weakcontainer || !dupcontainer) {
357 strong1 = alloc_str(weakcontainer,
"obj1");
358 strong2 = alloc_str(weakcontainer,
"obj2");
359 strong3 = alloc_str(weakcontainer,
"obj3");
361 if (!strong1 || !strong2 || !strong3) {
370 ITERATOR_CHECK_NEXT(&iter, strong, strong1);
371 ITERATOR_CHECK_NEXT(&iter, strong, strong2);
372 ITERATOR_CHECK_NEXT(&iter, strong, strong3);
373 ITERATOR_CHECK_NEXT(&iter, strong, NULL);
374 ao2_iterator_cleanup(&iter);
378 WEAKFIND_CHECK(weakcontainer,
"obj1", strong, strong1);
379 WEAKFIND_CHECK(weakcontainer,
"obj2", strong, strong2);
380 WEAKFIND_CHECK(weakcontainer,
"obj3", strong, strong3);
381 WEAKFIND_CHECK(weakcontainer,
"unknown", strong, NULL);
390 ast_test_validate_cleanup(
test,
396 ITERATOR_CHECK_NEXT(&iter, strong, strong1);
397 ITERATOR_CHECK_NEXT(&iter, strong, strong3);
398 ITERATOR_CHECK_NEXT(&iter, strong, NULL);
399 ao2_iterator_cleanup(&iter);
401 WEAKFIND_CHECK(weakcontainer,
"obj1", strong, strong1);
402 WEAKFIND_CHECK(weakcontainer,
"obj2", strong, NULL);
403 WEAKFIND_CHECK(weakcontainer,
"obj3", strong, strong3);
404 WEAKFIND_CHECK(weakcontainer,
"unknown", strong, NULL);
409 ao2_cleanup(strong1);
410 ao2_cleanup(strong2);
411 ao2_cleanup(strong3);
413 ao2_cleanup(weakcontainer);
414 ao2_cleanup(dupcontainer);
421 static int unload_module(
void)
423 AST_TEST_UNREGISTER(astobj2_weak1);
424 AST_TEST_UNREGISTER(astobj2_weak_container);
429 static int load_module(
void)
431 AST_TEST_REGISTER(astobj2_weak1);
432 AST_TEST_REGISTER(astobj2_weak_container);
437 AST_MODULE_INFO_STANDARD(
ASTERISK_GPL_KEY,
"ASTOBJ2 Weak Reference Unit Tests");
#define ao2_weakproxy_set_object(weakproxy, obj, flags)
Associate weakproxy with obj.
Asterisk main include file. File version handling, generic pbx functions.
AO2_STRING_FIELD_HASH_FN(transport_monitor, key)
Hashing function for struct transport_monitor.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_weakproxy_ref_object(weakproxy, delta, flags)
Run ao2_t_ref on the object associated with weakproxy.
int ao2_weakproxy_unsubscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags)
Remove notification of real object destruction.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
int ao2_container_dup_weakproxy_objs(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy object references associated with src container weakproxies into the dest container.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
AO2_STRING_FIELD_CMP_FN(transport_monitor, key)
Comparison function for struct transport_monitor.
int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags)
Request notification when weakproxy points to NULL.
static void cleanup(void)
Clean up any old apps that we don't need any more.
#define ao2_weakproxy_alloc(data_size, destructor_fn)
Allocate an ao2_weakproxy object.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#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.
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
#define AST_TEST_DEFINE(hdr)
AO2_STRING_FIELD_SORT_FN(transport_monitor, key)
Sort function for struct transport_monitor.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_link(container, obj)
Add an object to a container.