CI: Add pre-build merge back in as RECURSIVE
[asterisk/asterisk.git] / tests / test_sorcery_astdb.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief Sorcery Unit Tests
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  */
26
27 /*** MODULEINFO
28         <depend>TEST_FRAMEWORK</depend>
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 #include "asterisk/test.h"
35 #include "asterisk/module.h"
36 #include "asterisk/sorcery.h"
37 #include "asterisk/astdb.h"
38 #include "asterisk/logger.h"
39
40 /*! \brief Dummy sorcery object */
41 struct test_sorcery_object {
42         SORCERY_OBJECT(details);
43         unsigned int bob;
44         unsigned int joe;
45 };
46
47 /*! \brief Internal function to allocate a test object */
48 static void *test_sorcery_object_alloc(const char *id)
49 {
50         return ast_sorcery_generic_alloc(sizeof(struct test_sorcery_object), NULL);
51 }
52
53 static struct ast_sorcery *alloc_and_initialize_sorcery(void)
54 {
55         struct ast_sorcery *sorcery;
56
57         if (!(sorcery = ast_sorcery_open())) {
58                 return NULL;
59         }
60
61         if ((ast_sorcery_apply_default(sorcery, "test", "astdb", "test") != AST_SORCERY_APPLY_SUCCESS) ||
62                 ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
63                 ast_sorcery_unref(sorcery);
64                 return NULL;
65         }
66
67         ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
68         ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
69
70         return sorcery;
71 }
72
73 static void deinitialize_sorcery(struct ast_sorcery *sorcery)
74 {
75         ast_db_deltree("test/test", NULL);
76         ast_sorcery_unref(sorcery);
77 }
78
79 AST_TEST_DEFINE(object_create)
80 {
81         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
82         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
83         char value[2];
84
85         switch (cmd) {
86         case TEST_INIT:
87                 info->name = "object_create";
88                 info->category = "/res/sorcery_astdb/";
89                 info->summary = "sorcery astdb object creation unit test";
90                 info->description =
91                         "Test object creation in sorcery using astdb wizard";
92                 return AST_TEST_NOT_RUN;
93         case TEST_EXECUTE:
94                 break;
95         }
96
97         if (!(sorcery = alloc_and_initialize_sorcery())) {
98                 ast_test_status_update(test, "Failed to open sorcery structure\n");
99                 return AST_TEST_FAIL;
100         }
101
102         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
103                 ast_test_status_update(test, "Failed to allocate a known object type\n");
104                 return AST_TEST_FAIL;
105         }
106
107         if (ast_sorcery_create(sorcery, obj)) {
108                 ast_test_status_update(test, "Failed to create object using astdb wizard\n");
109                 return AST_TEST_FAIL;
110         } else if (ast_db_get("test/test", "blah", value, sizeof(value))) {
111                 ast_test_status_update(test, "Object was apparently created but does not actually exist in astdb\n");
112                 return AST_TEST_FAIL;
113         }
114
115         return AST_TEST_PASS;
116 }
117
118 AST_TEST_DEFINE(object_retrieve_id)
119 {
120         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
121         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
122
123         switch (cmd) {
124         case TEST_INIT:
125                 info->name = "object_retrieve_id";
126                 info->category = "/res/sorcery_astdb/";
127                 info->summary = "sorcery object retrieval using id unit test";
128                 info->description =
129                         "Test object retrieval using id in sorcery with astdb wizard";
130                 return AST_TEST_NOT_RUN;
131         case TEST_EXECUTE:
132                 break;
133         }
134
135         if (!(sorcery = alloc_and_initialize_sorcery())) {
136                 ast_test_status_update(test, "Failed to open sorcery structure\n");
137                 return AST_TEST_FAIL;
138         }
139
140         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
141                 ast_test_status_update(test, "Failed to allocate a known object type\n");
142                 return AST_TEST_FAIL;
143         }
144
145         if (ast_sorcery_create(sorcery, obj)) {
146                 ast_test_status_update(test, "Failed to create object using astdb wizard\n");
147                 return AST_TEST_FAIL;
148         }
149
150         ao2_cleanup(obj);
151
152         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
153                 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
154                 return AST_TEST_FAIL;
155         }
156
157         if (ast_sorcery_create(sorcery, obj)) {
158                 ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
159                 return AST_TEST_FAIL;
160         }
161
162         ao2_cleanup(obj);
163
164         if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
165                 ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
166                 return AST_TEST_FAIL;
167         } else if (strcmp(ast_sorcery_object_get_id(obj), "blah")) {
168                 ast_test_status_update(test, "Retrieved object does not have correct id\n");
169                 return AST_TEST_FAIL;
170         }
171
172         return AST_TEST_PASS;
173 }
174
175 AST_TEST_DEFINE(object_retrieve_field)
176 {
177         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
178         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
179         RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "42", ""), ast_variables_destroy);
180
181         switch (cmd) {
182         case TEST_INIT:
183                 info->name = "object_retrieve_field";
184                 info->category = "/res/sorcery_astdb/";
185                 info->summary = "sorcery object retrieval using a specific field unit test";
186                 info->description =
187                         "Test object retrieval using a specific field in sorcery with astdb wizard";
188                 return AST_TEST_NOT_RUN;
189         case TEST_EXECUTE:
190                 break;
191         }
192
193         if (!fields) {
194                 ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
195                 return AST_TEST_FAIL;
196         }
197
198         if (!(sorcery = alloc_and_initialize_sorcery())) {
199                 ast_test_status_update(test, "Failed to open sorcery structure\n");
200                 return AST_TEST_FAIL;
201         }
202
203         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
204                 ast_test_status_update(test, "Failed to allocate a known object type\n");
205                 return AST_TEST_FAIL;
206         }
207
208         obj->joe = 42;
209
210         if (ast_sorcery_create(sorcery, obj)) {
211                 ast_test_status_update(test, "Failed to create object using astdb wizard\n");
212                 return AST_TEST_FAIL;
213         }
214
215         ao2_cleanup(obj);
216
217         if (!(obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
218                 ast_test_status_update(test, "Failed to retrieve properly created object using 'joe' field\n");
219                 return AST_TEST_FAIL;
220         }
221
222         ao2_cleanup(obj);
223         ast_variables_destroy(fields);
224
225         if (!(fields = ast_variable_new("joe", "49", ""))) {
226                 ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
227                 return AST_TEST_FAIL;
228         }
229
230         if ((obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
231                 ast_test_status_update(test, "Retrieved an object using a field with an in-correct value... that should not happen\n");
232                 return AST_TEST_FAIL;
233         }
234
235         return AST_TEST_PASS;
236 }
237
238 AST_TEST_DEFINE(object_retrieve_multiple_all)
239 {
240         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
241         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
242         RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
243
244         switch (cmd) {
245         case TEST_INIT:
246                 info->name = "object_retrieve_multiple_all";
247                 info->category = "/res/sorcery_astdb/";
248                 info->summary = "sorcery multiple object retrieval unit test";
249                 info->description =
250                         "Test multiple object retrieval in sorcery using astdb wizard";
251                 return AST_TEST_NOT_RUN;
252         case TEST_EXECUTE:
253                 break;
254         }
255
256         if (!(sorcery = alloc_and_initialize_sorcery())) {
257                 ast_test_status_update(test, "Failed to open sorcery structure\n");
258                 return AST_TEST_FAIL;
259         }
260
261         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
262                 ast_test_status_update(test, "Failed to allocate a known object type\n");
263                 return AST_TEST_FAIL;
264         }
265
266         if (ast_sorcery_create(sorcery, obj)) {
267                 ast_test_status_update(test, "Failed to create object using astdb wizard\n");
268                 return AST_TEST_FAIL;
269         }
270
271         ao2_cleanup(obj);
272
273         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
274                 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
275                 return AST_TEST_FAIL;
276         }
277
278         if (ast_sorcery_create(sorcery, obj)) {
279                 ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
280                 return AST_TEST_FAIL;
281         }
282
283         if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
284                 ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
285                 return AST_TEST_FAIL;
286         } else if (ao2_container_count(objects) != 2) {
287                 ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
288                 return AST_TEST_FAIL;
289         }
290
291         return AST_TEST_PASS;
292 }
293
294 AST_TEST_DEFINE(object_retrieve_multiple_field)
295 {
296         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
297         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
298         RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
299         RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe >=", "6", ""), ast_variables_destroy);
300
301         switch (cmd) {
302         case TEST_INIT:
303                 info->name = "object_retrieve_multiple_field";
304                 info->category = "/res/sorcery_astdb/";
305                 info->summary = "sorcery multiple object retrieval unit test";
306                 info->description =
307                         "Test multiple object retrieval in sorcery using fields using astdb wizard";
308                 return AST_TEST_NOT_RUN;
309         case TEST_EXECUTE:
310                 break;
311         }
312
313         if (!fields) {
314                 ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
315                 return AST_TEST_FAIL;
316         }
317
318         if (!(sorcery = alloc_and_initialize_sorcery())) {
319                 ast_test_status_update(test, "Failed to open sorcery structure\n");
320                 return AST_TEST_FAIL;
321         }
322
323         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
324                 ast_test_status_update(test, "Failed to allocate a known object type\n");
325                 return AST_TEST_FAIL;
326         }
327
328         obj->joe = 6;
329
330         if (ast_sorcery_create(sorcery, obj)) {
331                 ast_test_status_update(test, "Failed to create object using astdb wizard\n");
332                 return AST_TEST_FAIL;
333         }
334
335         if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
336                 ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
337                 return AST_TEST_FAIL;
338         } else if (ao2_container_count(objects) != 1) {
339                 ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
340                 return AST_TEST_FAIL;
341         }
342
343         ao2_cleanup(objects);
344         ast_variables_destroy(fields);
345
346         if (!(fields = ast_variable_new("joe <", "6", ""))) {
347                 ast_test_status_update(test, "Failed to create fields for multiple retrieval\n");
348                 return AST_TEST_FAIL;
349         } else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
350                 ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
351                 return AST_TEST_FAIL;
352         } else if (ao2_container_count(objects)) {
353                 ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
354                 return AST_TEST_FAIL;
355         }
356
357         return AST_TEST_PASS;
358 }
359
360 AST_TEST_DEFINE(object_retrieve_regex)
361 {
362         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
363         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
364         RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
365
366         switch (cmd) {
367         case TEST_INIT:
368                 info->name = "object_retrieve_regex";
369                 info->category = "/res/sorcery_astdb/";
370                 info->summary = "sorcery multiple object retrieval using regex unit test";
371                 info->description =
372                         "Test multiple object retrieval in sorcery using regular expression for matching using astdb wizard";
373                 return AST_TEST_NOT_RUN;
374         case TEST_EXECUTE:
375                 break;
376         }
377
378         if (!(sorcery = alloc_and_initialize_sorcery())) {
379                 ast_test_status_update(test, "Failed to open sorcery structure\n");
380                 return AST_TEST_FAIL;
381         }
382
383         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) {
384                 ast_test_status_update(test, "Failed to allocate a known object type\n");
385                 return AST_TEST_FAIL;
386         }
387
388         if (ast_sorcery_create(sorcery, obj)) {
389                 ast_test_status_update(test, "Failed to create object using astdb wizard\n");
390                 return AST_TEST_FAIL;
391         }
392
393         ao2_cleanup(obj);
394
395         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) {
396                 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
397                 return AST_TEST_FAIL;
398         }
399
400         if (ast_sorcery_create(sorcery, obj)) {
401                 ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
402                 return AST_TEST_FAIL;
403         }
404
405         ao2_cleanup(obj);
406
407         if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) {
408                 ast_test_status_update(test, "Failed to allocate third instance of a known object type\n");
409                 return AST_TEST_FAIL;
410         }
411
412         if (ast_sorcery_create(sorcery, obj)) {
413                 ast_test_status_update(test, "Failed to create third object using astdb wizard\n");
414                 return AST_TEST_FAIL;
415         }
416
417         if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "^blah-"))) {
418                 ast_test_status_update(test, "Failed to retrieve a container of objects\n");
419                 return AST_TEST_FAIL;
420         } else if (ao2_container_count(objects) != 2) {
421                 ast_test_status_update(test, "Received a container with incorrect number of objects in it\n");
422                 return AST_TEST_FAIL;
423         }
424
425         return AST_TEST_PASS;
426 }
427
428 AST_TEST_DEFINE(object_update)
429 {
430         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
431         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
432         RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
433
434         switch (cmd) {
435         case TEST_INIT:
436                 info->name = "object_update";
437                 info->category = "/res/sorcery_astdb/";
438                 info->summary = "sorcery object update unit test";
439                 info->description =
440                         "Test object updating in sorcery using astdb wizard";
441                 return AST_TEST_NOT_RUN;
442         case TEST_EXECUTE:
443                 break;
444         }
445
446         if (!(sorcery = alloc_and_initialize_sorcery())) {
447                 ast_test_status_update(test, "Failed to open sorcery structure\n");
448                 return AST_TEST_FAIL;
449         }
450
451         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
452                 ast_test_status_update(test, "Failed to allocate a known object type\n");
453                 return AST_TEST_FAIL;
454         }
455
456         if (ast_sorcery_create(sorcery, obj)) {
457                 ast_test_status_update(test, "Failed to create object using astdb wizard\n");
458                 return AST_TEST_FAIL;
459         }
460
461         if (!(obj2 = ast_sorcery_copy(sorcery, obj))) {
462                 ast_test_status_update(test, "Failed to allocate a known object type for updating\n");
463                 return AST_TEST_FAIL;
464         }
465
466         ao2_cleanup(obj);
467
468         obj2->bob = 1000;
469         obj2->joe = 2000;
470
471         if (ast_sorcery_update(sorcery, obj2)) {
472                 ast_test_status_update(test, "Failed to update sorcery with new object\n");
473                 return AST_TEST_FAIL;
474         }
475
476         if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
477                 ast_test_status_update(test, "Failed to retrieve properly updated object\n");
478                 return AST_TEST_FAIL;
479         } else if ((obj->bob != obj2->bob) || (obj->joe != obj2->joe)) {
480                 ast_test_status_update(test, "Object retrieved is not the updated object\n");
481                 return AST_TEST_FAIL;
482         }
483
484         return AST_TEST_PASS;
485 }
486
487 AST_TEST_DEFINE(object_update_uncreated)
488 {
489         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
490         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
491
492         switch (cmd) {
493         case TEST_INIT:
494                 info->name = "object_update_uncreated";
495                 info->category = "/res/sorcery_astdb/";
496                 info->summary = "sorcery object update unit test";
497                 info->description =
498                         "Test updating of an uncreated object in sorcery using astdb wizard";
499                 return AST_TEST_NOT_RUN;
500         case TEST_EXECUTE:
501                 break;
502         }
503
504         if (!(sorcery = alloc_and_initialize_sorcery())) {
505                 ast_test_status_update(test, "Failed to open sorcery structure\n");
506                 return AST_TEST_FAIL;
507         }
508
509         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
510                 ast_test_status_update(test, "Failed to allocate a known object type\n");
511                 return AST_TEST_FAIL;
512         }
513
514         if (!ast_sorcery_update(sorcery, obj)) {
515                 ast_test_status_update(test, "Successfully updated an object which has not been created yet\n");
516                 return AST_TEST_FAIL;
517         }
518
519         return AST_TEST_PASS;
520 }
521
522 AST_TEST_DEFINE(object_delete)
523 {
524         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
525         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
526
527         switch (cmd) {
528         case TEST_INIT:
529                 info->name = "object_delete";
530                 info->category = "/res/sorcery_astdb/";
531                 info->summary = "sorcery object deletion unit test";
532                 info->description =
533                         "Test object deletion in sorcery using astdb wizard";
534                 return AST_TEST_NOT_RUN;
535         case TEST_EXECUTE:
536                 break;
537         }
538
539         if (!(sorcery = alloc_and_initialize_sorcery())) {
540                 ast_test_status_update(test, "Failed to open sorcery structure\n");
541                 return AST_TEST_FAIL;
542         }
543
544         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
545                 ast_test_status_update(test, "Failed to allocate a known object type\n");
546                 return AST_TEST_FAIL;
547         }
548
549         if (ast_sorcery_create(sorcery, obj)) {
550                 ast_test_status_update(test, "Failed to create object using astdb wizard\n");
551                 return AST_TEST_FAIL;
552         }
553
554         if (ast_sorcery_delete(sorcery, obj)) {
555                 ast_test_status_update(test, "Failed to delete object using astdb wizard\n");
556                 return AST_TEST_FAIL;
557         }
558
559         ao2_cleanup(obj);
560
561         if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
562                 ast_test_status_update(test, "Retrieved deleted object that should not be there\n");
563                 return AST_TEST_FAIL;
564         }
565
566         return AST_TEST_PASS;
567 }
568
569 AST_TEST_DEFINE(object_delete_uncreated)
570 {
571         RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
572         RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
573
574         switch (cmd) {
575         case TEST_INIT:
576                 info->name = "object_delete_uncreated";
577                 info->category = "/res/sorcery_astdb/";
578                 info->summary = "sorcery object deletion unit test";
579                 info->description =
580                         "Test object deletion of an uncreated object in sorcery using astdb wizard";
581                 return AST_TEST_NOT_RUN;
582         case TEST_EXECUTE:
583                 break;
584         }
585
586         if (!(sorcery = alloc_and_initialize_sorcery())) {
587                 ast_test_status_update(test, "Failed to open sorcery structure\n");
588                 return AST_TEST_FAIL;
589         }
590
591         if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
592                 ast_test_status_update(test, "Failed to allocate a known object type\n");
593                 return AST_TEST_FAIL;
594         }
595
596         if (!ast_sorcery_delete(sorcery, obj)) {
597                 ast_test_status_update(test, "Successfully deleted an object which was never created\n");
598                 return AST_TEST_FAIL;
599         }
600
601         return AST_TEST_PASS;
602 }
603
604 static int unload_module(void)
605 {
606         AST_TEST_UNREGISTER(object_create);
607         AST_TEST_UNREGISTER(object_retrieve_id);
608         AST_TEST_UNREGISTER(object_retrieve_field);
609         AST_TEST_UNREGISTER(object_retrieve_multiple_all);
610         AST_TEST_UNREGISTER(object_retrieve_multiple_field);
611         AST_TEST_UNREGISTER(object_retrieve_regex);
612         AST_TEST_UNREGISTER(object_update);
613         AST_TEST_UNREGISTER(object_update_uncreated);
614         AST_TEST_UNREGISTER(object_delete);
615         AST_TEST_UNREGISTER(object_delete_uncreated);
616
617         return 0;
618 }
619
620 static int load_module(void)
621 {
622         AST_TEST_REGISTER(object_create);
623         AST_TEST_REGISTER(object_retrieve_id);
624         AST_TEST_REGISTER(object_retrieve_field);
625         AST_TEST_REGISTER(object_retrieve_multiple_all);
626         AST_TEST_REGISTER(object_retrieve_multiple_field);
627         AST_TEST_REGISTER(object_retrieve_regex);
628         AST_TEST_REGISTER(object_update);
629         AST_TEST_REGISTER(object_update_uncreated);
630         AST_TEST_REGISTER(object_delete);
631         AST_TEST_REGISTER(object_delete_uncreated);
632
633         return AST_MODULE_LOAD_SUCCESS;
634 }
635
636 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Sorcery astdb Wizard test module");