Asterisk - The Open Source Telephony Project GIT-master-0deac78
test_sorcery.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2012 - 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 <depend>func_sorcery</depend>
30 <support_level>core</support_level>
31 ***/
32
33#include "asterisk.h"
34
35#include "asterisk/test.h"
36#include "asterisk/module.h"
37#include "asterisk/astobj2.h"
38#include "asterisk/pbx.h"
39#include "asterisk/sorcery.h"
40#include "asterisk/logger.h"
41#include "asterisk/json.h"
42
43/*! \brief Dummy sorcery object */
46 unsigned int bob;
47 unsigned int joe;
50};
51
52/*! \brief Internal function to destroy a test object */
53static void test_sorcery_object_destroy(void *obj)
54{
55 struct test_sorcery_object *tobj = obj;
58}
59
60/*! \brief Internal function to allocate a test object */
61static void *test_sorcery_object_alloc(const char *id)
62{
64}
65
66/*! \brief Internal function for object set transformation */
68{
69 struct ast_variable *field, *transformed = NULL;
70
71 for (field = set; field; field = field->next) {
72 struct ast_variable *transformed_field;
73
74 if (!strcmp(field->name, "joe")) {
75 transformed_field = ast_variable_new(field->name, "5000", "");
76 } else {
77 transformed_field = ast_variable_new(field->name, field->value, "");
78 }
79
80 if (!transformed_field) {
81 ast_variables_destroy(transformed);
82 return NULL;
83 }
84
85 transformed_field->next = transformed;
86 transformed = transformed_field;
87 }
88
89 return transformed;
90}
91
92/*! \brief Internal function which copies pre-defined data into an object, natively */
93static int test_sorcery_copy(const void *src, void *dst)
94{
95 struct test_sorcery_object *obj = dst;
96 obj->bob = 10;
97 obj->joe = 20;
98 obj->jim = ast_variable_new("jim", "444", "");
99 obj->jack = ast_variable_new("jack", "999,000", "");
100 return 0;
101}
102
103/*! \brief Internal function which creates a pre-defined diff natively */
104static int test_sorcery_diff(const void *original, const void *modified, struct ast_variable **changes)
105{
106 *changes = ast_variable_new("yes", "itworks", "");
107 return 0;
108}
109
110/*! \brief Internal function which sets some values */
111static int test_sorcery_regex_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
112{
113 struct test_sorcery_object *test = obj;
114
115 test->bob = 256;
116
117 return 0;
118}
119
120/*! \brief Internal function which creates some ast_variable structures */
121static int test_sorcery_regex_fields(const void *obj, struct ast_variable **fields)
122{
123 *fields = ast_variable_new("toast-bob", "10", "");
124
125 return 0;
126}
127
128/*! \brief Test structure for caching */
130 /*! \brief Whether the object has been created in the cache or not */
131 unsigned int created:1;
132
133 /*! \brief Whether the object has been updated in the cache or not */
134 unsigned int updated:1;
135
136 /*! \brief Whether the object has been deleted from the cache or not */
137 unsigned int deleted:1;
138
139 /*! \brief Whether the object is stale or not */
140 unsigned int is_stale:1;
141
142 /*! \brief Object to return when asked */
144};
145
146/*! \brief Test structure for observer */
148 /*! \brief Lock for notification */
150
151 /*! \brief Condition for notification */
153
154 /*! \brief Pointer to the created object */
155 const void *created;
156
157 /*! \brief Pointer to the update object */
158 const void *updated;
159
160 /*! \brief Pointer to the deleted object */
161 const void *deleted;
162
163 /*! \brief Whether the type has been loaded */
164 unsigned int loaded:1;
165};
166
167/*! \brief Global scope apply handler integer to make sure it executed */
169
170/*! \brief Simple apply handler which sets global scope integer to 1 if called */
171static int test_apply_handler(const struct ast_sorcery *sorcery, void *obj)
172{
174 return 0;
175}
176
177/*! \brief Global scope caching structure for testing */
178static struct sorcery_test_caching cache = { 0, };
179
180/*! \brief Global scope observer structure for testing */
182
183static void *wizard2_data;
184
185static void *sorcery_test_open(const char *data)
186{
187 wizard2_data = (void *)data;
188 return wizard2_data;
189}
190
191static void sorcery_test_close(void *data)
192{
193
194}
195
196static int sorcery_test_create(const struct ast_sorcery *sorcery, void *data, void *object)
197{
198 cache.created = 1;
199 cache.updated = 0;
200 cache.deleted = 0;
201 return 0;
202}
203
204static void *sorcery_test_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
205{
207}
208
209static int sorcery_test_update(const struct ast_sorcery *sorcery, void *data, void *object)
210{
211 cache.updated = 1;
212 return 0;
213}
214
215static int sorcery_test_delete(const struct ast_sorcery *sorcery, void *data, void *object)
216{
217 cache.deleted = 1;
218 return 0;
219}
220
221static int sorcery_test_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
222{
223 cache.is_stale = 1;
224 return 1;
225}
226
227/*! \brief Dummy sorcery wizards, not actually used so we only populate the name and nothing else */
229 .name = "test",
230 .create = sorcery_test_create,
231 .retrieve_id = sorcery_test_retrieve_id,
232 .update = sorcery_test_update,
233 .delete = sorcery_test_delete,
234};
235
237 .name = "test2",
238 .open = sorcery_test_open,
239 .close = sorcery_test_close,
240 .create = sorcery_test_create,
241 .retrieve_id = sorcery_test_retrieve_id,
242 .update = sorcery_test_update,
243 .delete = sorcery_test_delete,
244 .is_stale = sorcery_test_is_stale,
245};
246
247static void sorcery_observer_created(const void *object)
248{
250 observer.created = object;
252}
253
254static void sorcery_observer_updated(const void *object)
255{
257 observer.updated = object;
259}
260
261static void sorcery_observer_deleted(const void *object)
262{
264 observer.deleted = object;
266}
267
268static void sorcery_observer_loaded(const char *object_type)
269{
271 observer.loaded = 1;
273}
274
275/*! \brief Test sorcery observer implementation */
276static const struct ast_sorcery_observer test_observer = {
278 .updated = sorcery_observer_updated,
279 .deleted = sorcery_observer_deleted,
280 .loaded = sorcery_observer_loaded,
281};
282
283/* This handler takes a simple value and creates new list entry for it*/
284static int jim_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
285{
286 struct test_sorcery_object *tobj = obj;
287
289
290 return 0;
291}
292
293/* This handler takes a CSV string and creates new a new list entry for each value */
294static int jack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
295{
296 struct test_sorcery_object *tobj = obj;
297
298 char *jacks = ast_strdupa(var->value);
299 char *val;
300
301 while ((val = strsep(&jacks, ","))) {
303 }
304 return 0;
305}
306
307static int jim_vl(const void *obj, struct ast_variable **fields)
308{
309 const struct test_sorcery_object *tobj = obj;
310 if (tobj->jim) {
311 *fields = ast_variables_dup(tobj->jim);
312 }
313 return 0;
314}
315
316static int jack_str(const void *obj, const intptr_t *args, char **buf)
317{
318 const struct test_sorcery_object *tobj = obj;
319 struct ast_variable *curr = tobj->jack;
320 RAII_VAR(struct ast_str *, str, ast_str_create(128), ast_free);
321
322 while(curr) {
323 ast_str_append(&str, 0, "%s,", curr->value);
324 curr = curr->next;
325 }
328 str = NULL;
329 return 0;
330}
331
333{
334 struct ast_sorcery *sorcery;
335
336 if (!(sorcery = ast_sorcery_open())) {
337 return NULL;
338 }
339
343 return NULL;
344 }
345
350
351 return sorcery;
352}
353
354AST_TEST_DEFINE(wizard_registration)
355{
356 switch (cmd) {
357 case TEST_INIT:
358 info->name = "wizard_registration";
359 info->category = "/main/sorcery/";
360 info->summary = "sorcery wizard registration and unregistration unit test";
361 info->description =
362 "Test registration and unregistration of a sorcery wizard";
363 return AST_TEST_NOT_RUN;
364 case TEST_EXECUTE:
365 break;
366 }
367
369 ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
370 return AST_TEST_FAIL;
371 }
372
374 ast_test_status_update(test, "Successfully registered a sorcery wizard twice, which is bad\n");
375 return AST_TEST_FAIL;
376 }
377
379 ast_test_status_update(test, "Failed to unregister a perfectly valid sorcery wizard\n");
380 return AST_TEST_FAIL;
381 }
382
384 ast_test_status_update(test, "Successfully unregistered a sorcery wizard twice, which is bad\n");
385 return AST_TEST_FAIL;
386 }
387
388 return AST_TEST_PASS;
389}
390
391AST_TEST_DEFINE(sorcery_open)
392{
394 RAII_VAR(struct ast_sorcery *, sorcery2, NULL, ast_sorcery_unref);
395 int refcount;
396
397 switch (cmd) {
398 case TEST_INIT:
399 info->name = "open";
400 info->category = "/main/sorcery/";
401 info->summary = "sorcery open/close unit test";
402 info->description =
403 "Test opening of sorcery and registry operations";
404 return AST_TEST_NOT_RUN;
405 case TEST_EXECUTE:
406 break;
407 }
408
410 ast_test_status_update(test, "There should NOT have been an existing sorcery instance\n");
411 return AST_TEST_FAIL;
412 }
413
414 if (!(sorcery = ast_sorcery_open())) {
415 ast_test_status_update(test, "Failed to open new sorcery structure\n");
416 return AST_TEST_FAIL;
417 }
418
420 ast_test_status_update(test, "Failed to find sorcery structure in registry\n");
421 return AST_TEST_FAIL;
422 }
423
424 if (sorcery2 != sorcery) {
425 ast_test_status_update(test, "Should have gotten same sorcery on retrieve\n");
426 return AST_TEST_FAIL;
427 }
428 ast_sorcery_unref(sorcery2);
429
430 if ((refcount = ao2_ref(sorcery, 0)) != 2) {
431 ast_test_status_update(test, "Should have been 2 references to sorcery instead of %d\n", refcount);
432 return AST_TEST_FAIL;
433 }
434
435 if (!(sorcery2 = ast_sorcery_open())) {
436 ast_test_status_update(test, "Failed to open second sorcery structure\n");
437 return AST_TEST_FAIL;
438 }
439
440 if (sorcery2 != sorcery) {
441 ast_test_status_update(test, "Should have gotten same sorcery on 2nd open\n");
442 return AST_TEST_FAIL;
443 }
444
445 if ((refcount = ao2_ref(sorcery, 0)) != 3) {
446 ast_test_status_update(test, "Should have been 3 references to sorcery instead of %d\n", refcount);
447 return AST_TEST_FAIL;
448 }
449
451 ast_sorcery_unref(sorcery2);
452
453 sorcery2 = NULL;
454
457 sorcery = NULL;
458 ast_test_status_update(test, "Should NOT have found sorcery structure in registry\n");
459 return AST_TEST_FAIL;
460 }
461
462 return AST_TEST_PASS;
463}
464
465AST_TEST_DEFINE(apply_default)
466{
468
469 switch (cmd) {
470 case TEST_INIT:
471 info->name = "apply_default";
472 info->category = "/main/sorcery/";
473 info->summary = "sorcery default wizard unit test";
474 info->description =
475 "Test setting default type wizard in sorcery";
476 return AST_TEST_NOT_RUN;
477 case TEST_EXECUTE:
478 break;
479 }
480
481 if (!(sorcery = ast_sorcery_open())) {
482 ast_test_status_update(test, "Failed to open sorcery structure\n");
483 return AST_TEST_FAIL;
484 }
485
487 ast_test_status_update(test, "Successfully set a default wizard that doesn't exist\n");
488 return AST_TEST_FAIL;
489 }
490
492 ast_test_status_update(test, "Failed to set a known wizard as a default\n");
493 return AST_TEST_FAIL;
494 }
495
497 ast_test_status_update(test, "Successfully set a default wizard on a type twice\n");
498 return AST_TEST_FAIL;
499 }
500
501 return AST_TEST_PASS;
502}
503
505{
507 struct ast_config *config;
509
510 switch (cmd) {
511 case TEST_INIT:
512 info->name = "apply_config";
513 info->category = "/main/sorcery/";
514 info->summary = "sorcery object mapping configuration unit test";
515 info->description =
516 "Test configured object mapping in sorcery";
517 return AST_TEST_NOT_RUN;
518 case TEST_EXECUTE:
519 break;
520 }
521
522 if (!(config = ast_config_load2("sorcery.conf", "test_sorcery", flags))) {
523 ast_test_status_update(test, "Sorcery configuration file not present - skipping apply_config test\n");
524 return AST_TEST_NOT_RUN;
525 }
526
527 if (!ast_category_get(config, "test_sorcery_section", NULL)) {
528 ast_test_status_update(test, "Sorcery configuration file does not have test_sorcery section\n");
530 return AST_TEST_NOT_RUN;
531 }
532
534
535 if (!(sorcery = ast_sorcery_open())) {
536 ast_test_status_update(test, "Failed to open sorcery structure\n");
537 return AST_TEST_FAIL;
538 }
539
540 if (ast_sorcery_apply_config(sorcery, "test_sorcery_section") != AST_SORCERY_APPLY_SUCCESS) {
541 ast_test_status_update(test, "Failed to apply configured object mappings\n");
542 return AST_TEST_FAIL;
543 }
544
545 return AST_TEST_PASS;
546}
547
548AST_TEST_DEFINE(object_register)
549{
551
552 switch (cmd) {
553 case TEST_INIT:
554 info->name = "object_register";
555 info->category = "/main/sorcery/";
556 info->summary = "sorcery object type registration unit test";
557 info->description =
558 "Test object type registration in sorcery";
559 return AST_TEST_NOT_RUN;
560 case TEST_EXECUTE:
561 break;
562 }
563
564 if (!(sorcery = ast_sorcery_open())) {
565 ast_test_status_update(test, "Failed to open structure\n");
566 return AST_TEST_FAIL;
567 }
568
570 ast_test_status_update(test, "Failed to set a known wizard as a default\n");
571 return AST_TEST_FAIL;
572 }
573
575 ast_test_status_update(test, "Failed to register object type\n");
576 return AST_TEST_FAIL;
577 }
578
580 ast_test_status_update(test, "Registered object type a second time, despite it being registered already\n");
581 return AST_TEST_FAIL;
582 }
583
584 return AST_TEST_PASS;
585}
586
587AST_TEST_DEFINE(object_register_without_mapping)
588{
590
591 switch (cmd) {
592 case TEST_INIT:
593 info->name = "object_register_without_mapping";
594 info->category = "/main/sorcery/";
595 info->summary = "sorcery object type registration (without mapping) unit test";
596 info->description =
597 "Test object type registration when no mapping exists in sorcery";
598 return AST_TEST_NOT_RUN;
599 case TEST_EXECUTE:
600 break;
601 }
602
603 if (!(sorcery = ast_sorcery_open())) {
604 ast_test_status_update(test, "Failed to open sorcery structure\n");
605 return AST_TEST_FAIL;
606 }
607
609 ast_test_status_update(test, "Registered object type when no object mapping exists\n");
610 return AST_TEST_FAIL;
611 }
612
613 return AST_TEST_PASS;
614}
615
616AST_TEST_DEFINE(object_field_register)
617{
619
620 switch (cmd) {
621 case TEST_INIT:
622 info->name = "object_field_register";
623 info->category = "/main/sorcery/";
624 info->summary = "sorcery object field registration unit test";
625 info->description =
626 "Test object field registration in sorcery with a provided id";
627 return AST_TEST_NOT_RUN;
628 case TEST_EXECUTE:
629 break;
630 }
631
632 if (!(sorcery = ast_sorcery_open())) {
633 ast_test_status_update(test, "Failed to open sorcery structure\n");
634 return AST_TEST_FAIL;
635 }
636
637 if (!ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob))) {
638 ast_test_status_update(test, "Registered an object field successfully when no mappings or object types exist\n");
639 return AST_TEST_FAIL;
640 }
641
643 ast_test_status_update(test, "Failed to set a known wizard as a default\n");
644 return AST_TEST_FAIL;
645 }
646
647 if (!ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob))) {
648 ast_test_status_update(test, "Registered an object field successfully when object type does not exist\n");
649 return AST_TEST_FAIL;
650 }
651
653 ast_test_status_update(test, "Failed to register object type\n");
654 return AST_TEST_FAIL;
655 }
656
657 if (ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob))) {
658 ast_test_status_update(test, "Could not successfully register object field when mapping and object type exists\n");
659 return AST_TEST_FAIL;
660 }
661
662 return AST_TEST_PASS;
663}
664
665AST_TEST_DEFINE(object_fields_register)
666{
668
669 switch (cmd) {
670 case TEST_INIT:
671 info->name = "object_fields_register";
672 info->category = "/main/sorcery/";
673 info->summary = "sorcery object regex fields registration unit test";
674 info->description =
675 "Test object regex fields registration in sorcery with a provided id";
676 return AST_TEST_NOT_RUN;
677 case TEST_EXECUTE:
678 break;
679 }
680
681 if (!(sorcery = ast_sorcery_open())) {
682 ast_test_status_update(test, "Failed to open sorcery structure\n");
683 return AST_TEST_FAIL;
684 }
685
687 ast_test_status_update(test, "Registered a regex object field successfully when no mappings or object types exist\n");
688 return AST_TEST_FAIL;
689 }
690
692 ast_test_status_update(test, "Failed to set a known wizard as a default\n");
693 return AST_TEST_FAIL;
694 }
695
697 ast_test_status_update(test, "Registered a regex object field successfully when object type does not exist\n");
698 return AST_TEST_FAIL;
699 }
700
702 ast_test_status_update(test, "Failed to register object type\n");
703 return AST_TEST_FAIL;
704 }
705
707 ast_test_status_update(test, "Registered a regex object field successfully when no mappings or object types exist\n");
708 return AST_TEST_FAIL;
709 }
710
711 return AST_TEST_PASS;
712}
713
714AST_TEST_DEFINE(object_alloc_with_id)
715{
716 int res = AST_TEST_PASS;
719
720 switch (cmd) {
721 case TEST_INIT:
722 info->name = "object_alloc_with_id";
723 info->category = "/main/sorcery/";
724 info->summary = "sorcery object allocation (with id) unit test";
725 info->description =
726 "Test object allocation in sorcery with a provided id";
727 return AST_TEST_NOT_RUN;
728 case TEST_EXECUTE:
729 break;
730 }
731
733 ast_test_status_update(test, "Failed to open sorcery structure\n");
734 return AST_TEST_FAIL;
735 }
736
737 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
738 ast_test_status_update(test, "Failed to allocate a known object type\n");
739 res = AST_TEST_FAIL;
741 ast_test_status_update(test, "Allocated object has empty id when it should not\n");
742 res = AST_TEST_FAIL;
743 } else if (strcmp(ast_sorcery_object_get_id(obj), "blah")) {
744 ast_test_status_update(test, "Allocated object does not have correct id\n");
745 res = AST_TEST_FAIL;
747 ast_test_status_update(test, "Allocated object has empty type when it should not\n");
748 res = AST_TEST_FAIL;
749 } else if (strcmp(ast_sorcery_object_get_type(obj), "test")) {
750 ast_test_status_update(test, "Allocated object does not have correct type\n");
751 res = AST_TEST_FAIL;
752 } else if ((obj->bob != 5) || (obj->joe != 10)) {
753 ast_test_status_update(test, "Allocated object does not have defaults set as it should\n");
754 res = AST_TEST_FAIL;
755 }
756
757 return res;
758}
759
760AST_TEST_DEFINE(object_alloc_without_id)
761{
762 int res = AST_TEST_PASS;
765
766 switch (cmd) {
767 case TEST_INIT:
768 info->name = "object_alloc_without_id";
769 info->category = "/main/sorcery/";
770 info->summary = "sorcery object allocation (without id) unit test";
771 info->description =
772 "Test object allocation in sorcery with no provided id";
773 return AST_TEST_NOT_RUN;
774 case TEST_EXECUTE:
775 break;
776 }
777
779 ast_test_status_update(test, "Failed to open sorcery structure\n");
780 return AST_TEST_FAIL;
781 }
782
783 if (!(obj = ast_sorcery_alloc(sorcery, "test", NULL))) {
784 ast_test_status_update(test, "Failed to allocate a known object type\n");
785 res = AST_TEST_FAIL;
787 ast_test_status_update(test, "Allocated object has empty id when it should not\n");
788 res = AST_TEST_FAIL;
789 }
790
791 return res;
792}
793
794
795AST_TEST_DEFINE(object_copy)
796{
797 int res = AST_TEST_PASS;
801
802 switch (cmd) {
803 case TEST_INIT:
804 info->name = "object_copy";
805 info->category = "/main/sorcery/";
806 info->summary = "sorcery object copy unit test";
807 info->description =
808 "Test object copy in sorcery";
809 return AST_TEST_NOT_RUN;
810 case TEST_EXECUTE:
811 break;
812 }
813
815 ast_test_status_update(test, "Failed to open sorcery structure\n");
816 return AST_TEST_FAIL;
817 }
818
819 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
820 ast_test_status_update(test, "Failed to allocate a known object type\n");
821 return AST_TEST_FAIL;
822 }
823
824 obj->bob = 50;
825 obj->joe = 100;
826 jim_handler(NULL, ast_variable_new("jim", "444", ""), obj);
827 jim_handler(NULL, ast_variable_new("jim", "555", ""), obj);
828
829 if (!(copy = ast_sorcery_copy(sorcery, obj))) {
830 ast_test_status_update(test, "Failed to create a copy of a known valid object\n");
831 res = AST_TEST_FAIL;
832 } else if (copy == obj) {
833 ast_test_status_update(test, "Created copy is actually the original object\n");
834 res = AST_TEST_FAIL;
835 } else if (copy->bob != obj->bob) {
836 ast_test_status_update(test, "Value of 'bob' on newly created copy is not the same as original\n");
837 res = AST_TEST_FAIL;
838 } else if (copy->joe != obj->joe) {
839 ast_test_status_update(test, "Value of 'joe' on newly created copy is not the same as original\n");
840 res = AST_TEST_FAIL;
841 } else if (!copy->jim) {
842 ast_test_status_update(test, "A new ast_variable was not created for 'jim'\n");
843 res = AST_TEST_FAIL;
844 } else if (copy->jim == obj->jim) {
845 ast_test_status_update(test, "Created copy of 'jim' is actually the original 'jim'\n");
846 res = AST_TEST_FAIL;
847 } else if (strcmp(copy->jim->value, obj->jim->value)) {
848 ast_test_status_update(test, "Value of 1st 'jim' on newly created copy is not the same as original\n");
849 res = AST_TEST_FAIL;
850 } else if (!copy->jim->next) {
851 ast_test_status_update(test, "A new ast_variable was not created for 2nd 'jim'\n");
852 res = AST_TEST_FAIL;
853 } else if (strcmp(copy->jim->next->value, obj->jim->next->value)) {
854 ast_test_status_update(test, "Value of 2nd 'jim' (%s %s) on newly created copy is not the same as original (%s %s)\n",
855 copy->jim->value, copy->jim->next->value, obj->jim->value, obj->jim->next->value);
856 res = AST_TEST_FAIL;
857 }
858
859 return res;
860}
861
862AST_TEST_DEFINE(object_copy_native)
863{
864 int res = AST_TEST_PASS;
868
869 switch (cmd) {
870 case TEST_INIT:
871 info->name = "object_copy_native";
872 info->category = "/main/sorcery/";
873 info->summary = "sorcery object native copy unit test";
874 info->description =
875 "Test object native copy in sorcery";
876 return AST_TEST_NOT_RUN;
877 case TEST_EXECUTE:
878 break;
879 }
880
882 ast_test_status_update(test, "Failed to open sorcery structure\n");
883 return AST_TEST_FAIL;
884 }
885
887
888 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
889 ast_test_status_update(test, "Failed to allocate a known object type\n");
890 return AST_TEST_FAIL;
891 }
892
893 obj->bob = 50;
894 obj->joe = 100;
895
896 if (!(copy = ast_sorcery_copy(sorcery, obj))) {
897 ast_test_status_update(test, "Failed to create a copy of a known valid object\n");
898 res = AST_TEST_FAIL;
899 } else if (copy == obj) {
900 ast_test_status_update(test, "Created copy is actually the original object\n");
901 res = AST_TEST_FAIL;
902 } else if (copy->bob != 10) {
903 ast_test_status_update(test, "Value of 'bob' on newly created copy is not the predefined native copy value\n");
904 res = AST_TEST_FAIL;
905 } else if (copy->joe != 20) {
906 ast_test_status_update(test, "Value of 'joe' on newly created copy is not the predefined native copy value\n");
907 res = AST_TEST_FAIL;
908 } else if (!copy->jim) {
909 ast_test_status_update(test, "A new ast_variable was not created for 'jim'\n");
910 res = AST_TEST_FAIL;
911 } else if (strcmp(copy->jim->value, "444")) {
912 ast_test_status_update(test, "Value of 'jim' on newly created copy is not the predefined native copy value\n");
913 res = AST_TEST_FAIL;
914 }
915
916 return res;
917}
918
919AST_TEST_DEFINE(object_diff)
920{
924 RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
925 struct ast_variable *field;
926 int res = AST_TEST_PASS;
927 int jims = 0;
928
929 switch (cmd) {
930 case TEST_INIT:
931 info->name = "object_diff";
932 info->category = "/main/sorcery/";
933 info->summary = "sorcery object diff unit test";
934 info->description =
935 "Test object diffing in sorcery";
936 return AST_TEST_NOT_RUN;
937 case TEST_EXECUTE:
938 break;
939 }
940
942 ast_test_status_update(test, "Failed to open sorcery structure\n");
943 return AST_TEST_FAIL;
944 }
945
946 if (!(obj1 = ast_sorcery_alloc(sorcery, "test", "blah"))) {
947 ast_test_status_update(test, "Failed to allocate a known object type\n");
948 return AST_TEST_FAIL;
949 }
950
951 obj1->bob = 99;
952 obj1->joe = 55;
953 jim_handler(NULL, ast_variable_new("jim", "444", ""), obj1);
954 jim_handler(NULL, ast_variable_new("jim", "555", ""), obj1);
955
956 if (!(obj2 = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
957 ast_test_status_update(test, "Failed to allocate a second known object type\n");
958 return AST_TEST_FAIL;
959 }
960
961 obj2->bob = 99;
962 obj2->joe = 42;
963 jim_handler(NULL, ast_variable_new("jim", "444", ""), obj2);
964 jim_handler(NULL, ast_variable_new("jim", "666", ""), obj2);
965 jim_handler(NULL, ast_variable_new("jim", "777", ""), obj2);
966
967 if (ast_sorcery_diff(sorcery, obj1, obj2, &changes)) {
968 ast_test_status_update(test, "Failed to diff obj1 and obj2\n");
969 } else if (!changes) {
970 ast_test_status_update(test, "Failed to produce a diff of two objects, despite there being differences\n");
971 return AST_TEST_FAIL;
972 }
973
974 for (field = changes; field; field = field->next) {
975 if (!strcmp(field->name, "joe")) {
976 if (strcmp(field->value, "42")) {
978 "Object diff produced unexpected value '%s' for joe\n", field->value);
979 res = AST_TEST_FAIL;
980 }
981 } else if (!strcmp(field->name, "jim")) {
982 jims++;
983 if (!strcmp(field->value, "555")) {
985 "Object diff produced unexpected value '%s' for jim\n", field->value);
986 res = AST_TEST_FAIL;
987 }
988 } else {
989 ast_test_status_update(test, "Object diff produced unexpected field '%s'\n",
990 field->name);
991 res = AST_TEST_FAIL;
992 }
993 }
994
995 if (jims != 2) {
996 ast_test_status_update(test, "Object diff didn't produce 2 jims\n");
997 res = AST_TEST_FAIL;
998 }
999
1000 return res;
1001}
1002
1003AST_TEST_DEFINE(object_diff_native)
1004{
1006 RAII_VAR(struct test_sorcery_object *, obj1, NULL, ao2_cleanup);
1007 RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
1008 RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
1009 struct ast_variable *field;
1010 int res = AST_TEST_PASS;
1011
1012 switch (cmd) {
1013 case TEST_INIT:
1014 info->name = "object_diff_native";
1015 info->category = "/main/sorcery/";
1016 info->summary = "sorcery object native diff unit test";
1017 info->description =
1018 "Test native object diffing in sorcery";
1019 return AST_TEST_NOT_RUN;
1020 case TEST_EXECUTE:
1021 break;
1022 }
1023
1025 ast_test_status_update(test, "Failed to open sorcery structure\n");
1026 return AST_TEST_FAIL;
1027 }
1028
1030
1031 if (!(obj1 = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1032 ast_test_status_update(test, "Failed to allocate a known object type\n");
1033 return AST_TEST_FAIL;
1034 }
1035
1036 obj1->bob = 99;
1037 obj1->joe = 55;
1038
1039 if (!(obj2 = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
1040 ast_test_status_update(test, "Failed to allocate a second known object type\n");
1041 return AST_TEST_FAIL;
1042 }
1043
1044 obj2->bob = 99;
1045 obj2->joe = 42;
1046
1047 if (ast_sorcery_diff(sorcery, obj1, obj2, &changes)) {
1048 ast_test_status_update(test, "Failed to diff obj1 and obj2\n");
1049 } else if (!changes) {
1050 ast_test_status_update(test, "Failed to produce a diff of two objects, despite there being differences\n");
1051 return AST_TEST_FAIL;
1052 }
1053
1054 for (field = changes; field; field = field->next) {
1055 if (!strcmp(field->name, "yes")) {
1056 if (strcmp(field->value, "itworks")) {
1057 ast_test_status_update(test, "Object diff produced unexpected value '%s' for joe\n", field->value);
1058 res = AST_TEST_FAIL;
1059 }
1060 } else {
1061 ast_test_status_update(test, "Object diff produced unexpected field '%s'\n", field->name);
1062 res = AST_TEST_FAIL;
1063 }
1064 }
1065
1066 return res;
1067}
1068
1069AST_TEST_DEFINE(objectset_create)
1070{
1071 int res = AST_TEST_PASS;
1074 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
1075 struct ast_variable *field;
1076
1077 switch (cmd) {
1078 case TEST_INIT:
1079 info->name = "objectset_create";
1080 info->category = "/main/sorcery/";
1081 info->summary = "sorcery object set creation unit test";
1082 info->description =
1083 "Test object set creation in sorcery";
1084 return AST_TEST_NOT_RUN;
1085 case TEST_EXECUTE:
1086 break;
1087 }
1088
1090 ast_test_status_update(test, "Failed to open sorcery structure\n");
1091 return AST_TEST_FAIL;
1092 }
1093
1094 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1095 ast_test_status_update(test, "Failed to allocate a known object type\n");
1096 return AST_TEST_FAIL;
1097 }
1098
1099 if (!(objset = ast_sorcery_objectset_create(sorcery, obj))) {
1100 ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
1101 return AST_TEST_FAIL;
1102 }
1103
1104 for (field = objset; field; field = field->next) {
1105 if (!strcmp(field->name, "bob")) {
1106 if (strcmp(field->value, "5")) {
1107 ast_test_status_update(test, "Object set failed to create proper value for 'bob'\n");
1108 res = AST_TEST_FAIL;
1109 }
1110 } else if (!strcmp(field->name, "joe")) {
1111 if (strcmp(field->value, "10")) {
1112 ast_test_status_update(test, "Object set failed to create proper value for 'joe'\n");
1113 res = AST_TEST_FAIL;
1114 }
1115 } else if (!strcmp(field->name, "jim")) {
1116 if (strcmp(field->value, "444")) {
1117 ast_test_status_update(test, "Object set failed to create proper value for 'jim'\n");
1118 res = AST_TEST_FAIL;
1119 }
1120 } else if (!strcmp(field->name, "jack")) {
1121 if (strcmp(field->value, "888,999")) {
1122 ast_test_status_update(test, "Object set failed to create proper value (%s) for 'jack'\n", field->value);
1123 res = AST_TEST_FAIL;
1124 }
1125 } else {
1126 ast_test_status_update(test, "Object set created field '%s' which is unknown\n", field->name);
1127 res = AST_TEST_FAIL;
1128 }
1129 }
1130
1131 return res;
1132}
1133
1134AST_TEST_DEFINE(objectset_json_create)
1135{
1136 int res = AST_TEST_PASS;
1139 RAII_VAR(struct ast_json *, objset, NULL, ast_json_unref);
1140 struct ast_json_iter *field;
1141
1142 switch (cmd) {
1143 case TEST_INIT:
1144 info->name = "objectset_json_create";
1145 info->category = "/main/sorcery/";
1146 info->summary = "sorcery json object set creation unit test";
1147 info->description =
1148 "Test object set creation (for JSON format) in sorcery";
1149 return AST_TEST_NOT_RUN;
1150 case TEST_EXECUTE:
1151 break;
1152 }
1153
1155 ast_test_status_update(test, "Failed to open sorcery structure\n");
1156 return AST_TEST_FAIL;
1157 }
1158
1159 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1160 ast_test_status_update(test, "Failed to allocate a known object type\n");
1161 return AST_TEST_FAIL;
1162 }
1163
1164 if (!(objset = ast_sorcery_objectset_json_create(sorcery, obj))) {
1165 ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
1166 return AST_TEST_FAIL;
1167 }
1168
1169 for (field = ast_json_object_iter(objset); field; field = ast_json_object_iter_next(objset, field)) {
1170 struct ast_json *value = ast_json_object_iter_value(field);
1171
1172 if (!strcmp(ast_json_object_iter_key(field), "bob")) {
1173 if (strcmp(ast_json_string_get(value), "5")) {
1174 ast_test_status_update(test, "Object set failed to create proper value for 'bob'\n");
1175 res = AST_TEST_FAIL;
1176 }
1177 } else if (!strcmp(ast_json_object_iter_key(field), "joe")) {
1178 if (strcmp(ast_json_string_get(value), "10")) {
1179 ast_test_status_update(test, "Object set failed to create proper value for 'joe'\n");
1180 res = AST_TEST_FAIL;
1181 }
1182 } else if (!strcmp(ast_json_object_iter_key(field), "jim")) {
1183 if (strcmp(ast_json_string_get(value), "444")) {
1184 ast_test_status_update(test, "Object set failed to create proper value for 'jim'\n");
1185 res = AST_TEST_FAIL;
1186 }
1187 } else if (!strcmp(ast_json_object_iter_key(field), "jack")) {
1188 if (strcmp(ast_json_string_get(value), "888,999")) {
1189 ast_test_status_update(test, "Object set failed to create proper value for 'jack'\n");
1190 res = AST_TEST_FAIL;
1191 }
1192 } else {
1193 ast_test_status_update(test, "Object set created field '%s' which is unknown\n", ast_json_object_iter_key(field));
1194 res = AST_TEST_FAIL;
1195 }
1196 }
1197
1198 return res;
1199}
1200
1201AST_TEST_DEFINE(objectset_create_regex)
1202{
1203 int res = AST_TEST_PASS;
1206 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
1207 struct ast_variable *field;
1208
1209 switch (cmd) {
1210 case TEST_INIT:
1211 info->name = "objectset_create_regex";
1212 info->category = "/main/sorcery/";
1213 info->summary = "sorcery object set creation with regex fields unit test";
1214 info->description =
1215 "Test object set creation with regex fields in sorcery";
1216 return AST_TEST_NOT_RUN;
1217 case TEST_EXECUTE:
1218 break;
1219 }
1220
1221 if (!(sorcery = ast_sorcery_open())) {
1222 ast_test_status_update(test, "Failed to open sorcery structure\n");
1223 return AST_TEST_FAIL;
1224 }
1225
1226 if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
1228 ast_test_status_update(test, "Failed to register 'test' object type\n");
1229 return AST_TEST_FAIL;
1230 }
1231
1233
1234 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1235 ast_test_status_update(test, "Failed to allocate a known object type\n");
1236 return AST_TEST_FAIL;
1237 }
1238
1239 if (!(objset = ast_sorcery_objectset_create(sorcery, obj))) {
1240 ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
1241 return AST_TEST_FAIL;
1242 }
1243
1244 for (field = objset; field; field = field->next) {
1245 if (!strcmp(field->name, "toast-bob")) {
1246 if (strcmp(field->value, "10")) {
1247 ast_test_status_update(test, "Object set failed to create proper value for 'bob'\n");
1248 res = AST_TEST_FAIL;
1249 }
1250 } else {
1251 ast_test_status_update(test, "Object set created field '%s' which is unknown\n", field->name);
1252 res = AST_TEST_FAIL;
1253 }
1254 }
1255
1256 return res;
1257}
1258
1259AST_TEST_DEFINE(objectset_apply)
1260{
1261 int res = AST_TEST_PASS;
1264 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
1265
1266 switch (cmd) {
1267 case TEST_INIT:
1268 info->name = "objectset_apply";
1269 info->category = "/main/sorcery/";
1270 info->summary = "sorcery object apply unit test";
1271 info->description =
1272 "Test object set applying in sorcery";
1273 return AST_TEST_NOT_RUN;
1274 case TEST_EXECUTE:
1275 break;
1276 }
1277
1279 ast_test_status_update(test, "Failed to open sorcery structure\n");
1280 return AST_TEST_FAIL;
1281 }
1282
1283 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1284 ast_test_status_update(test, "Failed to allocate a known object type\n");
1285 return AST_TEST_FAIL;
1286 }
1287
1288 if (!(objset = ast_variable_new("joe", "25", ""))) {
1289 ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
1290 res = AST_TEST_FAIL;
1291 } else if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
1292 ast_test_status_update(test, "Failed to apply valid object set to object\n");
1293 res = AST_TEST_FAIL;
1294 } else if (obj->joe != 25) {
1295 ast_test_status_update(test, "Object set was not actually applied to object despite it returning success\n");
1296 res = AST_TEST_FAIL;
1297 }
1298
1299 return res;
1300}
1301
1302AST_TEST_DEFINE(objectset_apply_handler)
1303{
1304 int res = AST_TEST_PASS;
1307 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
1308
1309 switch (cmd) {
1310 case TEST_INIT:
1311 info->name = "objectset_apply_handler";
1312 info->category = "/main/sorcery/";
1313 info->summary = "sorcery object apply handler unit test";
1314 info->description =
1315 "Test object set apply handler call in sorcery";
1316 return AST_TEST_NOT_RUN;
1317 case TEST_EXECUTE:
1318 break;
1319 }
1320
1321 if (!(sorcery = ast_sorcery_open())) {
1322 ast_test_status_update(test, "Failed to open sorcery structure\n");
1323 return AST_TEST_FAIL;
1324 }
1325
1326 if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
1328 ast_test_status_update(test, "Failed to register 'test' object type\n");
1329 return AST_TEST_FAIL;
1330 }
1331
1334
1335 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1336 ast_test_status_update(test, "Failed to allocate a known object type\n");
1337 return AST_TEST_FAIL;
1338 }
1339
1341
1342 if (!(objset = ast_variable_new("joe", "25", ""))) {
1343 ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
1344 res = AST_TEST_FAIL;
1345 } else if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
1346 ast_test_status_update(test, "Failed to apply valid object set to object\n");
1347 res = AST_TEST_FAIL;
1348 } else if (!apply_handler_called) {
1349 ast_test_status_update(test, "Apply handler was not called when it should have been\n");
1350 res = AST_TEST_FAIL;
1351 }
1352
1353 return res;
1354}
1355
1356AST_TEST_DEFINE(objectset_apply_invalid)
1357{
1360 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
1361
1362 switch (cmd) {
1363 case TEST_INIT:
1364 info->name = "objectset_apply_invalid";
1365 info->category = "/main/sorcery/";
1366 info->summary = "sorcery object invalid apply unit test";
1367 info->description =
1368 "Test object set applying of an invalid set in sorcery";
1369 return AST_TEST_NOT_RUN;
1370 case TEST_EXECUTE:
1371 break;
1372 }
1373
1375 ast_test_status_update(test, "Failed to open sorcery structure\n");
1376 return AST_TEST_FAIL;
1377 }
1378
1379 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1380 ast_test_status_update(test, "Failed to allocate a known object type\n");
1381 return AST_TEST_FAIL;
1382 }
1383
1384 if (!(objset = ast_variable_new("fred", "99", ""))) {
1385 ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
1386 return AST_TEST_FAIL;
1387 } else if (!ast_sorcery_objectset_apply(sorcery, obj, objset)) {
1388 ast_test_status_update(test, "Successfully applied an invalid object set\n");
1389 return AST_TEST_FAIL;
1390 } else if ((obj->bob != 5) || (obj->joe != 10)) {
1391 ast_test_status_update(test, "Object set modified object fields when it should not have\n");
1392 return AST_TEST_FAIL;
1393 }
1394
1395 return AST_TEST_PASS;
1396}
1397
1398AST_TEST_DEFINE(objectset_transform)
1399{
1402 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
1403
1404 switch (cmd) {
1405 case TEST_INIT:
1406 info->name = "objectset_transform";
1407 info->category = "/main/sorcery/";
1408 info->summary = "sorcery object set transformation unit test";
1409 info->description =
1410 "Test object set transformation in sorcery";
1411 return AST_TEST_NOT_RUN;
1412 case TEST_EXECUTE:
1413 break;
1414 }
1415
1416 if (!(sorcery = ast_sorcery_open())) {
1417 ast_test_status_update(test, "Failed to open sorcery structure\n");
1418 return AST_TEST_FAIL;
1419 }
1420
1422 ast_test_status_update(test, "Failed to set a known wizard as a default\n");
1423 return AST_TEST_FAIL;
1424 }
1425
1427 ast_test_status_update(test, "Failed to register object type\n");
1428 return AST_TEST_FAIL;
1429 }
1430
1433
1434 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1435 ast_test_status_update(test, "Failed to allocate a known object type\n");
1436 return AST_TEST_FAIL;
1437 }
1438
1439 if (!(objset = ast_sorcery_objectset_create(sorcery, obj))) {
1440 ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
1441 return AST_TEST_FAIL;
1442 }
1443
1444 if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
1445 ast_test_status_update(test, "Failed to apply properly created object set against object\n");
1446 return AST_TEST_FAIL;
1447 }
1448
1449 if (obj->bob != 5) {
1450 ast_test_status_update(test, "Application of object set produced incorrect value on 'bob'\n");
1451 return AST_TEST_FAIL;
1452 } else if (obj->joe == 10) {
1453 ast_test_status_update(test, "Transformation callback did not change value of 'joe' from provided value\n");
1454 return AST_TEST_FAIL;
1455 } else if (obj->joe != 5000) {
1456 ast_test_status_update(test, "Value of 'joe' differs from default AND from transformation value\n");
1457 return AST_TEST_FAIL;
1458 }
1459
1460 return AST_TEST_PASS;
1461}
1462
1463AST_TEST_DEFINE(objectset_apply_fields)
1464{
1465 int res = AST_TEST_PASS;
1468 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
1469
1470 switch (cmd) {
1471 case TEST_INIT:
1472 info->name = "objectset_apply_fields";
1473 info->category = "/main/sorcery/";
1474 info->summary = "sorcery object apply regex fields unit test";
1475 info->description =
1476 "Test object set apply with regex fields in sorcery";
1477 return AST_TEST_NOT_RUN;
1478 case TEST_EXECUTE:
1479 break;
1480 }
1481
1482 if (!(sorcery = ast_sorcery_open())) {
1483 ast_test_status_update(test, "Failed to open sorcery structure\n");
1484 return AST_TEST_FAIL;
1485 }
1486
1487 if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
1489 ast_test_status_update(test, "Failed to register 'test' object type\n");
1490 return AST_TEST_FAIL;
1491 }
1492
1494
1495 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1496 ast_test_status_update(test, "Failed to allocate a known object type\n");
1497 return AST_TEST_FAIL;
1498 }
1499
1500 if (!(objset = ast_variable_new("toast-bob", "20", ""))) {
1501 ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
1502 res = AST_TEST_FAIL;
1503 } else if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
1504 ast_test_status_update(test, "Failed to apply valid object set to object\n");
1505 res = AST_TEST_FAIL;
1506 } else if (obj->bob != 256) {
1507 ast_test_status_update(test, "Regex field handler was not called when it should have been\n");
1508 res = AST_TEST_FAIL;
1509 }
1510
1511 return res;
1512}
1513
1514AST_TEST_DEFINE(extended_fields)
1515{
1516 int res = AST_TEST_PASS;
1519 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
1520 const char *value;
1521
1522 switch (cmd) {
1523 case TEST_INIT:
1524 info->name = "extended_fields";
1525 info->category = "/main/sorcery/";
1526 info->summary = "sorcery object extended fields unit test";
1527 info->description =
1528 "Test extended fields support in sorcery";
1529 return AST_TEST_NOT_RUN;
1530 case TEST_EXECUTE:
1531 break;
1532 }
1533
1535 ast_test_status_update(test, "Failed to open sorcery structure\n");
1536 return AST_TEST_FAIL;
1537 }
1538
1539 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1540 ast_test_status_update(test, "Failed to allocate a known object type\n");
1541 return AST_TEST_FAIL;
1542 }
1543
1544 if (!(objset = ast_variable_new("@testing", "toast", ""))) {
1545 ast_test_status_update(test, "Failed to create an object set, test could not occur\n");
1546 res = AST_TEST_FAIL;
1547 } else if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
1548 ast_test_status_update(test, "Failed to apply valid object set to object\n");
1549 res = AST_TEST_FAIL;
1550 } else if (!(value = ast_sorcery_object_get_extended(obj, "testing"))) {
1551 ast_test_status_update(test, "Extended field, which was set using object set, could not be found\n");
1552 res = AST_TEST_FAIL;
1553 } else if (strcmp(value, "toast")) {
1554 ast_test_status_update(test, "Extended field does not contain expected value\n");
1555 res = AST_TEST_FAIL;
1556 } else if (ast_sorcery_object_set_extended(obj, "@tacos", "supreme")) {
1557 ast_test_status_update(test, "Extended field could not be set\n");
1558 res = AST_TEST_FAIL;
1559 } else if (!(value = ast_sorcery_object_get_extended(obj, "tacos"))) {
1560 ast_test_status_update(test, "Extended field, which was set using the API, could not be found\n");
1561 res = AST_TEST_FAIL;
1562 } else if (strcmp(value, "supreme")) {
1563 ast_test_status_update(test, "Extended field does not contain expected value\n");
1564 res = AST_TEST_FAIL;
1565 } else if (ast_sorcery_object_set_extended(obj, "@tacos", "canadian")) {
1566 ast_test_status_update(test, "Extended field could not be set a second time\n");
1567 res = AST_TEST_FAIL;
1568 } else if (!(value = ast_sorcery_object_get_extended(obj, "tacos"))) {
1569 ast_test_status_update(test, "Extended field, which was set using the API, could not be found\n");
1570 res = AST_TEST_FAIL;
1571 } else if (strcmp(value, "canadian")) {
1572 ast_test_status_update(test, "Extended field does not contain expected value\n");
1573 res = AST_TEST_FAIL;
1574 }
1575
1576 return res;
1577}
1578
1579AST_TEST_DEFINE(changeset_create)
1580{
1581 int res = AST_TEST_PASS;
1582 RAII_VAR(struct ast_variable *, original, NULL, ast_variables_destroy);
1583 RAII_VAR(struct ast_variable *, modified, NULL, ast_variables_destroy);
1584 RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
1585 struct ast_variable *tmp;
1586
1587 switch (cmd) {
1588 case TEST_INIT:
1589 info->name = "changeset_create";
1590 info->category = "/main/sorcery/";
1591 info->summary = "sorcery changeset creation unit test";
1592 info->description =
1593 "Test changeset creation in sorcery";
1594 return AST_TEST_NOT_RUN;
1595 case TEST_EXECUTE:
1596 break;
1597 }
1598
1599 if (!(tmp = ast_variable_new("bananas", "purple", ""))) {
1600 ast_test_status_update(test, "Failed to create first field for original objectset\n");
1601 return AST_TEST_FAIL;
1602 }
1603 tmp->next = original;
1604 original = tmp;
1605
1606 if (!(tmp = ast_variable_new("apples", "orange", ""))) {
1607 ast_test_status_update(test, "Failed to create second field for original objectset\n");
1608 return AST_TEST_FAIL;
1609 }
1610 tmp->next = original;
1611 original = tmp;
1612
1613 if (!(tmp = ast_variable_new("bananas", "green", ""))) {
1614 ast_test_status_update(test, "Failed to create first field for modified objectset\n");
1615 return AST_TEST_FAIL;
1616 }
1617 tmp->next = modified;
1618 modified = tmp;
1619
1620 if (!(tmp = ast_variable_new("apples", "orange", ""))) {
1621 ast_test_status_update(test, "Failed to create second field for modified objectset\n");
1622 return AST_TEST_FAIL;
1623 }
1624 tmp->next = modified;
1625 modified = tmp;
1626
1627 if (ast_sorcery_changeset_create(original, modified, &changes)) {
1628 ast_test_status_update(test, "Failed to create a changeset due to an error\n");
1629 return AST_TEST_FAIL;
1630 } else if (!changes) {
1631 ast_test_status_update(test, "Failed to produce a changeset when there should be one\n");
1632 return AST_TEST_FAIL;
1633 }
1634
1635 for (tmp = changes; tmp; tmp = tmp->next) {
1636 if (!strcmp(tmp->name, "bananas")) {
1637 if (strcmp(tmp->value, "green")) {
1638 ast_test_status_update(test, "Changeset produced had unexpected value '%s' for bananas\n", tmp->value);
1639 res = AST_TEST_FAIL;
1640 }
1641 } else {
1642 ast_test_status_update(test, "Changeset produced had unexpected field '%s'\n", tmp->name);
1643 res = AST_TEST_FAIL;
1644 }
1645 }
1646
1647 return res;
1648}
1649
1650AST_TEST_DEFINE(changeset_create_unchanged)
1651{
1652 RAII_VAR(struct ast_variable *, original, NULL, ast_variables_destroy);
1653 RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
1655 struct ast_variable *tmp;
1656
1657 switch (cmd) {
1658 case TEST_INIT:
1659 info->name = "changeset_create_unchanged";
1660 info->category = "/main/sorcery/";
1661 info->summary = "sorcery changeset creation unit test when no changes exist";
1662 info->description =
1663 "Test changeset creation in sorcery when no changes actually exist";
1664 return AST_TEST_NOT_RUN;
1665 case TEST_EXECUTE:
1666 break;
1667 }
1668
1669 if (!(tmp = ast_variable_new("bananas", "purple", ""))) {
1670 ast_test_status_update(test, "Failed to create first field for original objectset\n");
1671 return AST_TEST_FAIL;
1672 }
1673 tmp->next = original;
1674 original = tmp;
1675
1676 if (!(tmp = ast_variable_new("apples", "orange", ""))) {
1677 ast_test_status_update(test, "Failed to create second field for original objectset\n");
1678 return AST_TEST_FAIL;
1679 }
1680 tmp->next = original;
1681 original = tmp;
1682
1683 if (ast_sorcery_changeset_create(original, original, &changes)) {
1684 ast_test_status_update(test, "Failed to create a changeset due to an error\n");
1685 return AST_TEST_FAIL;
1686 } else if (changes) {
1687 ast_test_status_update(test, "Created a changeset when no changes actually exist\n");
1688 return AST_TEST_FAIL;
1689 }
1690
1691 if (!(tmp = ast_variable_new("bananas", "purple", ""))) {
1692 ast_test_status_update(test, "Failed to create first field for same objectset\n");
1693 return AST_TEST_FAIL;
1694 }
1695 tmp->next = same;
1696 same = tmp;
1697
1698 if (!(tmp = ast_variable_new("apples", "orange", ""))) {
1699 ast_test_status_update(test, "Failed to create second field for same objectset\n");
1700 return AST_TEST_FAIL;
1701 }
1702 tmp->next = same;
1703 same = tmp;
1704
1705 if (ast_sorcery_changeset_create(original, same, &changes)) {
1706 ast_test_status_update(test, "Failed to create a changeset due to an error\n");
1707 return AST_TEST_FAIL;
1708 } else if (changes) {
1709 ast_test_status_update(test, "Created a changeset between two different objectsets when no changes actually exist\n");
1710 return AST_TEST_FAIL;
1711 }
1712
1713 return AST_TEST_PASS;
1714}
1715
1716AST_TEST_DEFINE(object_create)
1717{
1720
1721 switch (cmd) {
1722 case TEST_INIT:
1723 info->name = "object_create";
1724 info->category = "/main/sorcery/";
1725 info->summary = "sorcery object creation unit test";
1726 info->description =
1727 "Test object creation in sorcery";
1728 return AST_TEST_NOT_RUN;
1729 case TEST_EXECUTE:
1730 break;
1731 }
1732
1734 ast_test_status_update(test, "Failed to open sorcery structure\n");
1735 return AST_TEST_FAIL;
1736 }
1737
1738 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1739 ast_test_status_update(test, "Failed to allocate a known object type\n");
1740 return AST_TEST_FAIL;
1741 }
1742
1743 if (ast_sorcery_create(sorcery, obj)) {
1744 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
1745 return AST_TEST_FAIL;
1746 }
1747
1748 return AST_TEST_PASS;
1749}
1750
1751AST_TEST_DEFINE(object_retrieve_id)
1752{
1755
1756 switch (cmd) {
1757 case TEST_INIT:
1758 info->name = "object_retrieve_id";
1759 info->category = "/main/sorcery/";
1760 info->summary = "sorcery object retrieval using id unit test";
1761 info->description =
1762 "Test object retrieval using id in sorcery";
1763 return AST_TEST_NOT_RUN;
1764 case TEST_EXECUTE:
1765 break;
1766 }
1767
1769 ast_test_status_update(test, "Failed to open sorcery structure\n");
1770 return AST_TEST_FAIL;
1771 }
1772
1773 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1774 ast_test_status_update(test, "Failed to allocate a known object type\n");
1775 return AST_TEST_FAIL;
1776 }
1777
1778 if (ast_sorcery_create(sorcery, obj)) {
1779 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
1780 return AST_TEST_FAIL;
1781 }
1782
1783 ao2_cleanup(obj);
1784
1785 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
1786 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
1787 return AST_TEST_FAIL;
1788 }
1789
1790 if (ast_sorcery_create(sorcery, obj)) {
1791 ast_test_status_update(test, "Failed to create second object using in-memory wizard\n");
1792 return AST_TEST_FAIL;
1793 }
1794
1795 ao2_cleanup(obj);
1796
1797 if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
1798 ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
1799 return AST_TEST_FAIL;
1800 } else if (strcmp(ast_sorcery_object_get_id(obj), "blah")) {
1801 ast_test_status_update(test, "Retrieved object does not have correct id\n");
1802 return AST_TEST_FAIL;
1803 }
1804
1805 return AST_TEST_PASS;
1806}
1807
1808AST_TEST_DEFINE(object_retrieve_field)
1809{
1812 RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "42", ""), ast_variables_destroy);
1813
1814 switch (cmd) {
1815 case TEST_INIT:
1816 info->name = "object_retrieve_field";
1817 info->category = "/main/sorcery/";
1818 info->summary = "sorcery object retrieval using a specific field unit test";
1819 info->description =
1820 "Test object retrieval using a specific field in sorcery";
1821 return AST_TEST_NOT_RUN;
1822 case TEST_EXECUTE:
1823 break;
1824 }
1825
1826 if (!fields) {
1827 ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
1828 return AST_TEST_FAIL;
1829 }
1830
1832 ast_test_status_update(test, "Failed to open sorcery structure\n");
1833 return AST_TEST_FAIL;
1834 }
1835
1836 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1837 ast_test_status_update(test, "Failed to allocate a known object type\n");
1838 return AST_TEST_FAIL;
1839 }
1840
1841 obj->joe = 42;
1842
1843 if (ast_sorcery_create(sorcery, obj)) {
1844 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
1845 return AST_TEST_FAIL;
1846 }
1847
1848 ao2_cleanup(obj);
1849
1850 if (!(obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
1851 ast_test_status_update(test, "Failed to retrieve properly created object using 'joe' field\n");
1852 return AST_TEST_FAIL;
1853 }
1854
1855 ao2_cleanup(obj);
1856 ast_variables_destroy(fields);
1857
1858 if (!(fields = ast_variable_new("joe", "49", ""))) {
1859 ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
1860 return AST_TEST_FAIL;
1861 }
1862
1864 ast_test_status_update(test, "Retrieved an object using a field with an in-correct value... that should not happen\n");
1865 return AST_TEST_FAIL;
1866 }
1867
1868 return AST_TEST_PASS;
1869}
1870
1871AST_TEST_DEFINE(object_retrieve_multiple_all)
1872{
1875 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
1876
1877 switch (cmd) {
1878 case TEST_INIT:
1879 info->name = "object_retrieve_multiple_all";
1880 info->category = "/main/sorcery/";
1881 info->summary = "sorcery multiple object retrieval unit test";
1882 info->description =
1883 "Test multiple object retrieval in sorcery";
1884 return AST_TEST_NOT_RUN;
1885 case TEST_EXECUTE:
1886 break;
1887 }
1888
1890 ast_test_status_update(test, "Failed to open sorcery structure\n");
1891 return AST_TEST_FAIL;
1892 }
1893
1894 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1895 ast_test_status_update(test, "Failed to allocate a known object type\n");
1896 return AST_TEST_FAIL;
1897 }
1898
1899 if (ast_sorcery_create(sorcery, obj)) {
1900 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
1901 return AST_TEST_FAIL;
1902 }
1903
1904 ao2_cleanup(obj);
1905
1906 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
1907 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
1908 return AST_TEST_FAIL;
1909 }
1910
1911 if (ast_sorcery_create(sorcery, obj)) {
1912 ast_test_status_update(test, "Failed to create second object using in-memory wizard\n");
1913 return AST_TEST_FAIL;
1914 }
1915
1917 ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
1918 return AST_TEST_FAIL;
1919 } else if (ao2_container_count(objects) != 2) {
1920 ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
1921 return AST_TEST_FAIL;
1922 }
1923
1924 return AST_TEST_PASS;
1925}
1926
1927AST_TEST_DEFINE(object_retrieve_multiple_field)
1928{
1931 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
1932 RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "6", ""), ast_variables_destroy);
1933
1934 switch (cmd) {
1935 case TEST_INIT:
1936 info->name = "object_retrieve_multiple_field";
1937 info->category = "/main/sorcery/";
1938 info->summary = "sorcery multiple object retrieval unit test";
1939 info->description =
1940 "Test multiple object retrieval in sorcery using fields";
1941 return AST_TEST_NOT_RUN;
1942 case TEST_EXECUTE:
1943 break;
1944 }
1945
1946 if (!fields) {
1947 ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
1948 return AST_TEST_FAIL;
1949 }
1950
1952 ast_test_status_update(test, "Failed to open sorcery structure\n");
1953 return AST_TEST_FAIL;
1954 }
1955
1956 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
1957 ast_test_status_update(test, "Failed to allocate a known object type\n");
1958 return AST_TEST_FAIL;
1959 }
1960
1961 obj->joe = 6;
1962
1963 if (ast_sorcery_create(sorcery, obj)) {
1964 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
1965 return AST_TEST_FAIL;
1966 }
1967
1968 if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
1969 ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
1970 return AST_TEST_FAIL;
1971 } else if (ao2_container_count(objects) != 1) {
1972 ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
1973 return AST_TEST_FAIL;
1974 }
1975
1976 ao2_cleanup(objects);
1977 ast_variables_destroy(fields);
1978
1979 if (!(fields = ast_variable_new("joe", "7", ""))) {
1980 ast_test_status_update(test, "Failed to create fields for multiple retrieval\n");
1981 return AST_TEST_FAIL;
1982 } else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
1983 ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
1984 return AST_TEST_FAIL;
1985 } else if (ao2_container_count(objects)) {
1986 ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
1987 return AST_TEST_FAIL;
1988 }
1989
1990 return AST_TEST_PASS;
1991}
1992
1993AST_TEST_DEFINE(object_retrieve_regex)
1994{
1997 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
1998
1999 switch (cmd) {
2000 case TEST_INIT:
2001 info->name = "object_retrieve_regex";
2002 info->category = "/main/sorcery/";
2003 info->summary = "sorcery multiple object retrieval using regex unit test";
2004 info->description =
2005 "Test multiple object retrieval in sorcery using regular expression for matching";
2006 return AST_TEST_NOT_RUN;
2007 case TEST_EXECUTE:
2008 break;
2009 }
2010
2012 ast_test_status_update(test, "Failed to open sorcery structure\n");
2013 return AST_TEST_FAIL;
2014 }
2015
2016 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) {
2017 ast_test_status_update(test, "Failed to allocate a known object type\n");
2018 return AST_TEST_FAIL;
2019 }
2020
2021 if (ast_sorcery_create(sorcery, obj)) {
2022 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
2023 return AST_TEST_FAIL;
2024 }
2025
2026 ao2_cleanup(obj);
2027
2028 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) {
2029 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
2030 return AST_TEST_FAIL;
2031 }
2032
2033 if (ast_sorcery_create(sorcery, obj)) {
2034 ast_test_status_update(test, "Failed to create second object using in-memory wizard\n");
2035 return AST_TEST_FAIL;
2036 }
2037
2038 ao2_cleanup(obj);
2039
2040 if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) {
2041 ast_test_status_update(test, "Failed to allocate third instance of a known object type\n");
2042 return AST_TEST_FAIL;
2043 }
2044
2045 if (ast_sorcery_create(sorcery, obj)) {
2046 ast_test_status_update(test, "Failed to create third object using in-memory wizard\n");
2047 return AST_TEST_FAIL;
2048 }
2049
2050 if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "^blah-"))) {
2051 ast_test_status_update(test, "Failed to retrieve a container of objects\n");
2052 return AST_TEST_FAIL;
2053 } else if (ao2_container_count(objects) != 2) {
2054 ast_test_status_update(test, "Received a container with incorrect number of objects in it\n");
2055 return AST_TEST_FAIL;
2056 }
2057
2058 return AST_TEST_PASS;
2059}
2060
2061AST_TEST_DEFINE(object_update)
2062{
2065 RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
2066
2067 switch (cmd) {
2068 case TEST_INIT:
2069 info->name = "object_update";
2070 info->category = "/main/sorcery/";
2071 info->summary = "sorcery object update unit test";
2072 info->description =
2073 "Test object updating in sorcery";
2074 return AST_TEST_NOT_RUN;
2075 case TEST_EXECUTE:
2076 break;
2077 }
2078
2080 ast_test_status_update(test, "Failed to open sorcery structure\n");
2081 return AST_TEST_FAIL;
2082 }
2083
2084 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2085 ast_test_status_update(test, "Failed to allocate a known object type\n");
2086 return AST_TEST_FAIL;
2087 }
2088
2089 if (ast_sorcery_create(sorcery, obj)) {
2090 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
2091 return AST_TEST_FAIL;
2092 }
2093
2094 if (!(obj2 = ast_sorcery_copy(sorcery, obj))) {
2095 ast_test_status_update(test, "Failed to allocate a known object type for updating\n");
2096 return AST_TEST_FAIL;
2097 }
2098
2099 ao2_cleanup(obj);
2100
2101 if (ast_sorcery_update(sorcery, obj2)) {
2102 ast_test_status_update(test, "Failed to update sorcery with new object\n");
2103 return AST_TEST_FAIL;
2104 }
2105
2106 if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
2107 ast_test_status_update(test, "Failed to retrieve properly updated object\n");
2108 return AST_TEST_FAIL;
2109 } else if (obj != obj2) {
2110 ast_test_status_update(test, "Object retrieved is not the updated object\n");
2111 return AST_TEST_FAIL;
2112 }
2113
2114 return AST_TEST_PASS;
2115}
2116
2117AST_TEST_DEFINE(object_update_uncreated)
2118{
2121
2122 switch (cmd) {
2123 case TEST_INIT:
2124 info->name = "object_update_uncreated";
2125 info->category = "/main/sorcery/";
2126 info->summary = "sorcery object update unit test";
2127 info->description =
2128 "Test updating of an uncreated object in sorcery";
2129 return AST_TEST_NOT_RUN;
2130 case TEST_EXECUTE:
2131 break;
2132 }
2133
2135 ast_test_status_update(test, "Failed to open sorcery structure\n");
2136 return AST_TEST_FAIL;
2137 }
2138
2139 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2140 ast_test_status_update(test, "Failed to allocate a known object type\n");
2141 return AST_TEST_FAIL;
2142 }
2143
2145 if (!ast_sorcery_update(sorcery, obj)) {
2146 ast_test_status_update(test, "Successfully updated an object which has not been created yet\n");
2147 return AST_TEST_FAIL;
2148 }
2149
2151 if (ast_sorcery_update(sorcery, obj)) {
2152 ast_test_status_update(test, "Failed to create object when update() finds no object in a backend\n");
2153 return AST_TEST_FAIL;
2154 }
2155
2156 return AST_TEST_PASS;
2157}
2158
2159AST_TEST_DEFINE(object_delete)
2160{
2163
2164 switch (cmd) {
2165 case TEST_INIT:
2166 info->name = "object_delete";
2167 info->category = "/main/sorcery/";
2168 info->summary = "sorcery object deletion unit test";
2169 info->description =
2170 "Test object deletion in sorcery";
2171 return AST_TEST_NOT_RUN;
2172 case TEST_EXECUTE:
2173 break;
2174 }
2175
2177 ast_test_status_update(test, "Failed to open sorcery structure\n");
2178 return AST_TEST_FAIL;
2179 }
2180
2181 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2182 ast_test_status_update(test, "Failed to allocate a known object type\n");
2183 return AST_TEST_FAIL;
2184 }
2185
2186 if (ast_sorcery_create(sorcery, obj)) {
2187 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
2188 return AST_TEST_FAIL;
2189 }
2190
2191 if (ast_sorcery_delete(sorcery, obj)) {
2192 ast_test_status_update(test, "Failed to delete object using in-memory wizard\n");
2193 return AST_TEST_FAIL;
2194 }
2195
2196 ao2_cleanup(obj);
2197
2198 if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
2199 ast_test_status_update(test, "Retrieved deleted object that should not be there\n");
2200 return AST_TEST_FAIL;
2201 }
2202
2203 return AST_TEST_PASS;
2204}
2205
2206AST_TEST_DEFINE(object_delete_uncreated)
2207{
2210
2211 switch (cmd) {
2212 case TEST_INIT:
2213 info->name = "object_delete_uncreated";
2214 info->category = "/main/sorcery/";
2215 info->summary = "sorcery object deletion unit test";
2216 info->description =
2217 "Test object deletion of an uncreated object in sorcery";
2218 return AST_TEST_NOT_RUN;
2219 case TEST_EXECUTE:
2220 break;
2221 }
2222
2224 ast_test_status_update(test, "Failed to open sorcery structure\n");
2225 return AST_TEST_FAIL;
2226 }
2227
2228 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2229 ast_test_status_update(test, "Failed to allocate a known object type\n");
2230 return AST_TEST_FAIL;
2231 }
2232
2233 if (!ast_sorcery_delete(sorcery, obj)) {
2234 ast_test_status_update(test, "Successfully deleted an object which was never created\n");
2235 return AST_TEST_FAIL;
2236 }
2237
2238 return AST_TEST_PASS;
2239}
2240
2241AST_TEST_DEFINE(object_is_stale)
2242{
2246 RAII_VAR(struct test_sorcery_object *, obj1, NULL, ao2_cleanup);
2247 RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
2248
2249 switch (cmd) {
2250 case TEST_INIT:
2251 info->name = "object_is_stale";
2252 info->category = "/main/sorcery/";
2253 info->summary = "sorcery object staleness unit test";
2254 info->description =
2255 "Test whether sorcery will query a wizard correctly if asked\n"
2256 "if an object is stale.";
2257 return AST_TEST_NOT_RUN;
2258 case TEST_EXECUTE:
2259 break;
2260 }
2261
2263 ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
2264 return AST_TEST_FAIL;
2265 }
2266
2268 ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
2269 return AST_TEST_FAIL;
2270 }
2271
2272 if (!(sorcery = ast_sorcery_open())) {
2273 ast_test_status_update(test, "Failed to open sorcery structure\n");
2274 return AST_TEST_FAIL;
2275 }
2276
2279 return AST_TEST_FAIL;
2280 }
2281
2286
2287
2288 if ((ast_sorcery_apply_default(sorcery, "test2", "test2", "test2data") != AST_SORCERY_APPLY_SUCCESS) ||
2290 return AST_TEST_FAIL;
2291 }
2292
2297
2298
2299 if (!(obj1 = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2300 ast_test_status_update(test, "Failed to allocate a known object type\n");
2301 return AST_TEST_FAIL;
2302 }
2303
2304 if (!(obj2 = ast_sorcery_alloc(sorcery, "test2", "blah"))) {
2305 ast_test_status_update(test, "Failed to allocate a known object type\n");
2306 return AST_TEST_FAIL;
2307 }
2308
2309 /* The 'test' wizard has no is_stale callback */
2310 ast_test_validate(test, ast_sorcery_is_stale(sorcery, obj1) == 0);
2311
2312 /* The 'test2' wizard should return stale */
2313 ast_test_validate(test, ast_sorcery_is_stale(sorcery, obj2) == 1);
2314 ast_test_validate(test, cache.is_stale == 1);
2315
2316 return AST_TEST_PASS;
2317}
2318
2319AST_TEST_DEFINE(caching_wizard_behavior)
2320{
2321 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2322 struct ast_config *config;
2325 RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
2326 int res = AST_TEST_FAIL;
2327
2328 switch (cmd) {
2329 case TEST_INIT:
2330 info->name = "caching_wizard_behavior";
2331 info->category = "/main/sorcery/";
2332 info->summary = "sorcery caching wizard behavior unit test";
2333 info->description =
2334 "Test internal behavior of caching wizards";
2335 return AST_TEST_NOT_RUN;
2336 case TEST_EXECUTE:
2337 break;
2338 }
2339
2340 if (!(config = ast_config_load2("sorcery.conf", "test_sorcery_cache", flags))) {
2341 ast_test_status_update(test, "Sorcery configuration file not present - skipping caching_wizard_behavior test\n");
2342 return AST_TEST_NOT_RUN;
2343 }
2344
2345 if (!ast_category_get(config, "test_sorcery_cache", NULL)) {
2346 ast_test_status_update(test, "Sorcery configuration file does not contain 'test_sorcery_cache' section\n");
2348 return AST_TEST_NOT_RUN;
2349 }
2350
2352
2354 ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
2355 return AST_TEST_FAIL;
2356 }
2357
2358 if (!(sorcery = ast_sorcery_open())) {
2359 ast_test_status_update(test, "Failed to open sorcery structure\n");
2360 goto end;
2361 }
2362
2363 if (ast_sorcery_apply_config(sorcery, "test_sorcery_cache") != AST_SORCERY_APPLY_SUCCESS) {
2364 ast_test_status_update(test, "Failed to apply configured object mappings\n");
2365 goto end;
2366 }
2367
2369 ast_test_status_update(test, "Failed to register object type\n");
2370 goto end;
2371 }
2372
2373 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2374 ast_test_status_update(test, "Failed to allocate a known object type\n");
2375 goto end;
2376 }
2377
2378 if (ast_sorcery_create(sorcery, obj)) {
2379 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
2380 goto end;
2381 }
2382
2383 ao2_cleanup(obj);
2384
2385 if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
2386 ast_test_status_update(test, "Failed to retrieve just created object\n");
2387 goto end;
2388 } else if (!cache.created) {
2389 ast_test_status_update(test, "Caching wizard was not told to cache just created object\n");
2390 goto end;
2391 } else if (!(obj2 = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
2392 ast_test_status_update(test, "Failed to retrieve just cached object\n");
2393 goto end;
2394 } else if (obj == obj2) {
2395 ast_test_status_update(test, "Returned object is *NOT* a cached object\n");
2396 goto end;
2397 } else if (ast_sorcery_update(sorcery, obj)) {
2398 ast_test_status_update(test, "Failed to update a known stored object\n");
2399 goto end;
2400 } else if (!cache.updated) {
2401 ast_test_status_update(test, "Caching wizard was not told to update object\n");
2402 goto end;
2403 } else if (ast_sorcery_delete(sorcery, obj)) {
2404 ast_test_status_update(test, "Failed to delete a known stored object\n");
2405 goto end;
2406 } else if (!cache.deleted) {
2407 ast_test_status_update(test, "Caching wizard was not told to delete object\n");
2408 goto end;
2409 }
2410
2411 ao2_cleanup(obj2);
2412
2413 if ((obj2 = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
2414 ast_test_status_update(test, "Retrieved an object that should have been deleted\n");
2415 goto end;
2416 }
2417
2418 res = AST_TEST_PASS;
2419
2420end:
2422 sorcery = NULL;
2423
2425 ast_test_status_update(test, "Failed to unregister test sorcery wizard\n");
2426 return AST_TEST_FAIL;
2427 }
2428
2429 return res;
2430}
2431
2432AST_TEST_DEFINE(object_type_observer)
2433{
2436 int res = AST_TEST_FAIL;
2437
2438 switch (cmd) {
2439 case TEST_INIT:
2440 info->name = "object_type_observer";
2441 info->category = "/main/sorcery/";
2442 info->summary = "sorcery object type observer unit test";
2443 info->description =
2444 "Test that object type observers get called when they should";
2445 return AST_TEST_NOT_RUN;
2446 case TEST_EXECUTE:
2447 break;
2448 }
2449
2451 ast_test_status_update(test, "Failed to open sorcery structure\n");
2452 return AST_TEST_FAIL;
2453 }
2454
2455 if (!ast_sorcery_observer_add(sorcery, "test", NULL)) {
2456 ast_test_status_update(test, "Successfully added a NULL observer when it should not be possible\n");
2457 return AST_TEST_FAIL;
2458 }
2459
2461 ast_test_status_update(test, "Failed to add a proper observer\n");
2462 return AST_TEST_FAIL;
2463 }
2464
2465 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2466 ast_test_status_update(test, "Failed to allocate a known object type\n");
2467 goto end;
2468 }
2469
2475
2476 if (ast_sorcery_create(sorcery, obj)) {
2477 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
2478 goto end;
2479 }
2480
2482 while (!observer.created) {
2483 struct timeval start = ast_tvnow();
2484 struct timespec end = {
2485 .tv_sec = start.tv_sec + 10,
2486 .tv_nsec = start.tv_usec * 1000,
2487 };
2488 if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
2489 break;
2490 }
2491 }
2493
2494 if (!observer.created) {
2495 ast_test_status_update(test, "Failed to receive observer notification for object creation within suitable timeframe\n");
2496 goto end;
2497 }
2498
2499 if (ast_sorcery_update(sorcery, obj)) {
2500 ast_test_status_update(test, "Failed to update object using in-memory wizard\n");
2501 goto end;
2502 }
2503
2505 while (!observer.updated) {
2506 struct timeval start = ast_tvnow();
2507 struct timespec end = {
2508 .tv_sec = start.tv_sec + 10,
2509 .tv_nsec = start.tv_usec * 1000,
2510 };
2511 if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
2512 break;
2513 }
2514 }
2516
2517 if (!observer.updated) {
2518 ast_test_status_update(test, "Failed to receive observer notification for object updating within suitable timeframe\n");
2519 goto end;
2520 }
2521
2522 if (ast_sorcery_delete(sorcery, obj)) {
2523 ast_test_status_update(test, "Failed to delete object using in-memory wizard\n");
2524 goto end;
2525 }
2526
2528 while (!observer.deleted) {
2529 struct timeval start = ast_tvnow();
2530 struct timespec end = {
2531 .tv_sec = start.tv_sec + 10,
2532 .tv_nsec = start.tv_usec * 1000,
2533 };
2534 if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
2535 break;
2536 }
2537 }
2539
2540 if (!observer.deleted) {
2541 ast_test_status_update(test, "Failed to receive observer notification for object deletion within suitable timeframe\n");
2542 goto end;
2543 }
2544
2546
2548 while (!observer.loaded) {
2549 struct timeval start = ast_tvnow();
2550 struct timespec end = {
2551 .tv_sec = start.tv_sec + 10,
2552 .tv_nsec = start.tv_usec * 1000,
2553 };
2554 if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
2555 break;
2556 }
2557 }
2559
2560 if (!observer.loaded) {
2561 ast_test_status_update(test, "Failed to receive observer notification for object type load within suitable timeframe\n");
2562 goto end;
2563 }
2564
2565 res = AST_TEST_PASS;
2566
2567end:
2573
2574 return res;
2575}
2576
2577AST_TEST_DEFINE(configuration_file_wizard)
2578{
2579 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2580 struct ast_config *config;
2583
2584 switch (cmd) {
2585 case TEST_INIT:
2586 info->name = "configuration_file_wizard";
2587 info->category = "/main/sorcery/";
2588 info->summary = "sorcery configuration file wizard unit test";
2589 info->description =
2590 "Test the configuration file wizard in sorcery";
2591 return AST_TEST_NOT_RUN;
2592 case TEST_EXECUTE:
2593 break;
2594 }
2595
2596 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2597 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard test\n");
2598 return AST_TEST_NOT_RUN;
2599 }
2600
2602
2603 if (!(sorcery = ast_sorcery_open())) {
2604 ast_test_status_update(test, "Failed to open sorcery structure\n");
2605 return AST_TEST_FAIL;
2606 }
2607
2608 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
2609 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2610 return AST_TEST_NOT_RUN;
2611 }
2612
2614 ast_test_status_update(test, "Failed to register object type\n");
2615 return AST_TEST_FAIL;
2616 }
2617
2620
2622
2623 if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey2"))) {
2624 ast_test_status_update(test, "Retrieved object which has an unknown field\n");
2625 return AST_TEST_FAIL;
2626 } else if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey"))) {
2627 ast_test_status_update(test, "Failed to retrieve a known object that has been configured in the configuration file\n");
2628 return AST_TEST_FAIL;
2629 } else if (obj->bob != 98) {
2630 ast_test_status_update(test, "Value of 'bob' on object is not what is configured in configuration file\n");
2631 return AST_TEST_FAIL;
2632 } else if (obj->joe != 41) {
2633 ast_test_status_update(test, "Value of 'joe' on object is not what is configured in configuration file\n");
2634 return AST_TEST_FAIL;
2635 }
2636
2637 return AST_TEST_PASS;
2638}
2639
2640AST_TEST_DEFINE(configuration_file_wizard_with_file_integrity)
2641{
2642 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2643 struct ast_config *config;
2646
2647 switch (cmd) {
2648 case TEST_INIT:
2649 info->name = "configuration_file_wizard_with_file_integrity";
2650 info->category = "/main/sorcery/";
2651 info->summary = "sorcery configuration file wizard file integrity unit test";
2652 info->description =
2653 "Test the configuration file wizard with file integrity turned on in sorcery";
2654 return AST_TEST_NOT_RUN;
2655 case TEST_EXECUTE:
2656 break;
2657 }
2658
2659 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2660 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_with_file_integrity test\n");
2661 return AST_TEST_NOT_RUN;
2662 }
2663
2665
2666 if (!(sorcery = ast_sorcery_open())) {
2667 ast_test_status_update(test, "Failed to open sorcery structure\n");
2668 return AST_TEST_FAIL;
2669 }
2670
2671 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,integrity=file") != AST_SORCERY_APPLY_SUCCESS) {
2672 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2673 return AST_TEST_NOT_RUN;
2674 }
2675
2677 ast_test_status_update(test, "Failed to register object type\n");
2678 return AST_TEST_FAIL;
2679 }
2680
2683
2685
2686 if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey"))) {
2687 ast_test_status_update(test, "Retrieved object which has an unknown field\n");
2688 return AST_TEST_FAIL;
2689 }
2690
2691 return AST_TEST_PASS;
2692}
2693
2694AST_TEST_DEFINE(configuration_file_wizard_with_criteria)
2695{
2696 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2697 struct ast_config *config;
2700
2701 switch (cmd) {
2702 case TEST_INIT:
2703 info->name = "configuration_file_wizard_with_criteria";
2704 info->category = "/main/sorcery/";
2705 info->summary = "sorcery configuration file wizard with criteria unit test";
2706 info->description =
2707 "Test the configuration file wizard with criteria matching in sorcery";
2708 return AST_TEST_NOT_RUN;
2709 case TEST_EXECUTE:
2710 break;
2711 }
2712
2713 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2714 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_with_criteria test\n");
2715 return AST_TEST_NOT_RUN;
2716 }
2717
2719
2720 if (!(sorcery = ast_sorcery_open())) {
2721 ast_test_status_update(test, "Failed to open sorcery structure\n");
2722 return AST_TEST_FAIL;
2723 }
2724
2725 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,criteria=type=zombies") != AST_SORCERY_APPLY_SUCCESS) {
2726 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2727 return AST_TEST_NOT_RUN;
2728 }
2729
2731 ast_test_status_update(test, "Failed to register object type\n");
2732 return AST_TEST_FAIL;
2733 }
2734
2738
2740
2741 if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey"))) {
2742 ast_test_status_update(test, "Retrieved object which did not match criteria\n");
2743 return AST_TEST_FAIL;
2744 } else if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey2"))) {
2745 ast_test_status_update(test, "Failed to retrieve a known object which matches criteria\n");
2746 return AST_TEST_FAIL;
2747 }
2748
2749 return AST_TEST_PASS;
2750}
2751
2752AST_TEST_DEFINE(configuration_file_wizard_retrieve_field)
2753{
2754 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2755 struct ast_config *config;
2758 RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "41", ""), ast_variables_destroy);
2759
2760 switch (cmd) {
2761 case TEST_INIT:
2762 info->name = "configuration_file_wizard_retrieve_field";
2763 info->category = "/main/sorcery/";
2764 info->summary = "sorcery configuration file wizard field retrieval unit test";
2765 info->description =
2766 "Test the configuration file wizard retrieval using field in sorcery";
2767 return AST_TEST_NOT_RUN;
2768 case TEST_EXECUTE:
2769 break;
2770 }
2771
2772 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2773 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_retrieve_field test\n");
2774 return AST_TEST_NOT_RUN;
2775 }
2776
2778
2779 if (!(sorcery = ast_sorcery_open())) {
2780 ast_test_status_update(test, "Failed to open sorcery structure\n");
2781 return AST_TEST_FAIL;
2782 }
2783
2784 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
2785 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2786 return AST_TEST_NOT_RUN;
2787 }
2788
2790 ast_test_status_update(test, "Failed to register object type\n");
2791 return AST_TEST_FAIL;
2792 }
2793
2796
2798
2799 if (!(obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
2800 ast_test_status_update(test, "Failed to retrieve a known object that has been configured with the correct field\n");
2801 return AST_TEST_FAIL;
2802 } else if (strcmp(ast_sorcery_object_get_id(obj), "hey")) {
2803 ast_test_status_update(test, "Retrieved object has incorrect object id of '%s'\n", ast_sorcery_object_get_id(obj));
2804 return AST_TEST_FAIL;
2805 }
2806
2807 return AST_TEST_PASS;
2808}
2809
2810AST_TEST_DEFINE(configuration_file_wizard_retrieve_multiple)
2811{
2812 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2813 struct ast_config *config;
2815 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
2816 RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "99", ""), ast_variables_destroy);
2817
2818 switch (cmd) {
2819 case TEST_INIT:
2820 info->name = "configuration_file_wizard_retrieve_multiple";
2821 info->category = "/main/sorcery/";
2822 info->summary = "sorcery configuration file wizard multiple retrieval unit test";
2823 info->description =
2824 "Test the configuration file wizard multiple retrieval in sorcery";
2825 return AST_TEST_NOT_RUN;
2826 case TEST_EXECUTE:
2827 break;
2828 }
2829
2830 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2831 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_retrieve_multiple test\n");
2832 return AST_TEST_NOT_RUN;
2833 }
2834
2836
2837 if (!fields) {
2838 ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
2839 return AST_TEST_FAIL;
2840 }
2841
2842 if (!(sorcery = ast_sorcery_open())) {
2843 ast_test_status_update(test, "Failed to open sorcery structure\n");
2844 return AST_TEST_FAIL;
2845 }
2846
2847 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
2848 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2849 return AST_TEST_NOT_RUN;
2850 }
2851
2853 ast_test_status_update(test, "Failed to register object type\n");
2854 return AST_TEST_FAIL;
2855 }
2856
2859
2861
2862 if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
2863 ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
2864 return AST_TEST_FAIL;
2865 } else if (ao2_container_count(objects)) {
2866 ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
2867 return AST_TEST_FAIL;
2868 }
2869
2870 ao2_cleanup(objects);
2871 ast_variables_destroy(fields);
2872
2873 if (!(fields = ast_variable_new("joe", "41", ""))) {
2874 ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
2875 return AST_TEST_FAIL;
2876 } else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
2877 ast_test_status_update(test, "Failed to retrieve a container when retrieving multiple\n");
2878 return AST_TEST_FAIL;
2879 } else if (ao2_container_count(objects) != 1) {
2880 ast_test_status_update(test, "Received a container with no objects in it when there should be\n");
2881 return AST_TEST_FAIL;
2882 }
2883
2884 return AST_TEST_PASS;
2885}
2886
2887AST_TEST_DEFINE(configuration_file_wizard_retrieve_multiple_all)
2888{
2889 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2890 struct ast_config *config;
2892 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
2893
2894 switch (cmd) {
2895 case TEST_INIT:
2896 info->name = "configuration_file_wizard_retrieve_multiple_all";
2897 info->category = "/main/sorcery/";
2898 info->summary = "sorcery configuration file wizard multiple retrieve all unit test";
2899 info->description =
2900 "Test the configuration file wizard multiple retrieve all in sorcery";
2901 return AST_TEST_NOT_RUN;
2902 case TEST_EXECUTE:
2903 break;
2904 }
2905
2906 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2907 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_retrieve_multiple_all test\n");
2908 return AST_TEST_NOT_RUN;
2909 }
2910
2912
2913 if (!(sorcery = ast_sorcery_open())) {
2914 ast_test_status_update(test, "Failed to open sorcery structure\n");
2915 return AST_TEST_FAIL;
2916 }
2917
2918 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
2919 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2920 return AST_TEST_NOT_RUN;
2921 }
2922
2924 ast_test_status_update(test, "Failed to register object type\n");
2925 return AST_TEST_FAIL;
2926 }
2927
2930
2932
2934 ast_test_status_update(test, "Failed to retrieve a container with all objects when there should be one\n");
2935 return AST_TEST_FAIL;
2936 } else if (ao2_container_count(objects) != 2) {
2937 ast_test_status_update(test, "Returned container does not have the correct number of objects in it\n");
2938 return AST_TEST_FAIL;
2939 }
2940
2941 return AST_TEST_PASS;
2942}
2943
2944AST_TEST_DEFINE(dialplan_function)
2945{
2948 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
2949 struct ast_str *buf;
2950 char expression[256];
2951
2952 switch (cmd) {
2953 case TEST_INIT:
2954 info->name = "dialplan_function";
2955 info->category = "/main/sorcery/";
2956 info->summary = "AST_SORCERY dialplan function";
2957 info->description =
2958 "Test the AST_SORCERY dialplan function";
2959 return AST_TEST_NOT_RUN;
2960 case TEST_EXECUTE:
2961 break;
2962 }
2963
2965 ast_test_status_update(test, "Failed to open sorcery structure\n");
2966 return AST_TEST_FAIL;
2967 }
2968
2969 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2970 ast_test_status_update(test, "Failed to allocate a known object type\n");
2971 return AST_TEST_FAIL;
2972 }
2973
2974 if (ast_sorcery_create(sorcery, obj)) {
2975 ast_test_status_update(test, "Failed to create a known object type\n");
2976 return AST_TEST_FAIL;
2977 }
2978
2979 if (!(buf = ast_str_create(16))) {
2980 ast_test_status_update(test, "Failed to allocate return buffer\n");
2981 return AST_TEST_FAIL;
2982 }
2983
2985 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "notest_sorcery", "test", "blah", "bob");
2986 if (!ast_func_read2(NULL, expression, &buf, 16)) {
2987 ast_free(buf);
2988 ast_test_status_update(test, "Retrieved a non-existent module\n");
2989 return AST_TEST_FAIL;
2990 }
2991
2993 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "notest", "blah", "bob");
2994 if (!ast_func_read2(NULL, expression, &buf, 16)) {
2995 ast_free(buf);
2996 ast_test_status_update(test, "Retrieved a non-existent type\n");
2997 return AST_TEST_FAIL;
2998 }
2999
3001 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "noid", "bob");
3002 if (!ast_func_read2(NULL, expression, &buf, 16)) {
3003 ast_free(buf);
3004 ast_test_status_update(test, "Retrieved a non-existent id\n");
3005 return AST_TEST_FAIL;
3006 }
3007
3009 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "nobob");
3010 if (!ast_func_read2(NULL, expression, &buf, 16)) {
3011 ast_free(buf);
3012 ast_test_status_update(test, "Retrieved a non-existent field\n");
3013 return AST_TEST_FAIL;
3014 }
3015
3017 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "bob");
3018 if (ast_func_read2(NULL, expression, &buf, 16)) {
3019 ast_free(buf);
3020 ast_test_status_update(test, "Failed retrieve field 'bob'\n");
3021 return AST_TEST_FAIL;
3022 }
3023 if (strcmp(ast_str_buffer(buf), "5")) {
3024 ast_free(buf);
3025 ast_test_status_update(test, "Failed retrieve field. Got '%u', should be '5'\n", obj->bob);
3026 return AST_TEST_FAIL;
3027 }
3028
3030 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,1)", "test_sorcery", "test", "blah", "bob");
3031 if (ast_func_read2(NULL, expression, &buf, 16)) {
3032 ast_free(buf);
3033 ast_test_status_update(test, "Failed retrieve field 'bob'\n");
3034 return AST_TEST_FAIL;
3035 }
3036 if (strcmp(ast_str_buffer(buf), "5")) {
3037 ast_free(buf);
3038 ast_test_status_update(test, "Failed retrieve field. Got '%u', should be '5'\n", obj->bob);
3039 return AST_TEST_FAIL;
3040 }
3041
3043 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "bob");
3044 if (!ast_func_read2(NULL, expression, &buf, 16)) {
3045 ast_free(buf);
3046 ast_test_status_update(test, "Got a second 'bob' and shouldn't have\n");
3047 return AST_TEST_FAIL;
3048 }
3049
3050 /* 444 is already the first item in the list */
3051 jim_handler(NULL, ast_variable_new("jim", "555", ""), obj);
3052 jim_handler(NULL, ast_variable_new("jim", "666", ""), obj);
3053
3055 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "jim");
3056 if (ast_func_read2(NULL, expression, &buf, 16)) {
3057 ast_free(buf);
3058 ast_test_status_update(test, "Couldn't retrieve 'jim'\n");
3059 return AST_TEST_FAIL;
3060 }
3061 if (strcmp(ast_str_buffer(buf), "444,555,666")) {
3062 ast_free(buf);
3063 ast_test_status_update(test, "Failed retrieve jim. Got '%s', should be '444,555,666'\n", ast_str_buffer(buf));
3064 return AST_TEST_FAIL;
3065 }
3066
3068 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "jim");
3069 if (ast_func_read2(NULL, expression, &buf, 16)) {
3070 ast_free(buf);
3071 ast_test_status_update(test, "Couldn't retrieve 2nd jim\n");
3072 return AST_TEST_FAIL;
3073 }
3074 if (strcmp(ast_str_buffer(buf), "555")) {
3075 ast_free(buf);
3076 ast_test_status_update(test, "Failed retrieve 2nd jim. Got '%s', should be '555'\n", ast_str_buffer(buf));
3077 return AST_TEST_FAIL;
3078 }
3079
3081 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,concat,|)", "test_sorcery", "test", "blah", "jim");
3082 if (ast_func_read2(NULL, expression, &buf, 16)) {
3083 ast_free(buf);
3084 ast_test_status_update(test, "Couldn't retrieve any 'jim'\n");
3085 return AST_TEST_FAIL;
3086 }
3087 if (strcmp(ast_str_buffer(buf), "444|555|666")) {
3088 ast_free(buf);
3089 ast_test_status_update(test, "Failed retrieve 'jim'. Got '%s', should be '444|555|666'\n", ast_str_buffer(buf));
3090 return AST_TEST_FAIL;
3091 }
3092
3094 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,noconcat,3)", "test_sorcery", "test", "blah", "jim");
3095 if (!ast_func_read2(NULL, expression, &buf, 16)) {
3096 ast_free(buf);
3097 ast_test_status_update(test, "Should have failed with invalid retrieval_type\n");
3098 return AST_TEST_FAIL;
3099 }
3100
3102 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,|)", "test_sorcery", "test", "blah", "jim");
3103 if (!ast_func_read2(NULL, expression, &buf, 16)) {
3104 ast_free(buf);
3105 ast_test_status_update(test, "Should have failed with invalid occurrence_number\n");
3106 return AST_TEST_FAIL;
3107 }
3108
3109 ast_free(buf);
3110
3111 return AST_TEST_PASS;
3112}
3113
3114AST_TEST_DEFINE(object_field_registered)
3115{
3117 RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
3118
3119 switch (cmd) {
3120 case TEST_INIT:
3121 info->name = "object_field_registered";
3122 info->category = "/main/sorcery/";
3123 info->summary = "ast_sorcery_is_object_field_registered unit test";
3124 info->description =
3125 "Test ast_sorcery_is_object_field_registered in sorcery";
3126 return AST_TEST_NOT_RUN;
3127 case TEST_EXECUTE:
3128 break;
3129 }
3130
3132 ast_test_status_update(test, "Failed to open sorcery structure\n");
3133 return AST_TEST_FAIL;
3134 }
3135
3136 object_type = ast_sorcery_get_object_type(sorcery, "test");
3137
3139
3140 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "joe"));
3141 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "bob"));
3142 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "@joebob"));
3143 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "prefix/goober"));
3144
3145 ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "joebob"));
3146 ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "prefix/"));
3147 ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "goober"));
3148
3150
3151 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "goober"));
3152
3153 return AST_TEST_PASS;
3154}
3155
3157
3158static void wizard_observer(const char *name, const struct ast_sorcery_wizard *wizard)
3159{
3160 if (!strcmp(wizard->name, "test")) {
3161 event_observed = 1;
3162 }
3163}
3164
3165static void instance_observer(const char *name, struct ast_sorcery *sorcery)
3166{
3167 if (!strcmp(name, "test_sorcery")) {
3168 event_observed = 1;
3169 }
3170}
3171
3172AST_TEST_DEFINE(global_observation)
3173{
3176 const struct ast_sorcery_global_observer observer = {
3177 .wizard_registered = wizard_observer,
3178 .instance_created = instance_observer,
3179 .wizard_unregistering = wizard_observer,
3180 .instance_destroying = instance_observer,
3181 };
3182
3183 switch (cmd) {
3184 case TEST_INIT:
3185 info->name = "global_observation";
3186 info->category = "/main/sorcery/";
3187 info->summary = "global sorcery observation test";
3188 info->description =
3189 "Test observation of sorcery (global)";
3190 return AST_TEST_NOT_RUN;
3191 case TEST_EXECUTE:
3192 break;
3193 }
3194
3196
3197 event_observed = 0;
3199 ast_test_validate(test, (event_observed == 1), "Wizard registered failed");
3200
3201 event_observed = 0;
3203 ast_test_validate(test, (event_observed == 1), "Wizard unregistered failed");
3204
3205 event_observed = 0;
3207 ast_test_validate(test, (event_observed == 1), "Instance created failed");
3208
3209 event_observed = 0;
3211 sorcery = NULL;
3212 ast_test_validate(test, (event_observed == 1), "Instance destroyed failed");
3213
3215 event_observed = 0;
3217 ast_test_validate(test, (event_observed == 0), "Observer removed failed");
3218
3219 return AST_TEST_PASS;
3220}
3221
3222static void instance_loaded_observer(const char *name, const struct ast_sorcery *sorcery,
3223 int reloaded)
3224{
3225 if (!strcmp(name, "test_sorcery") && !reloaded) {
3227 }
3228}
3229
3230static void instance_reloaded_observer(const char *name,
3231 const struct ast_sorcery *sorcery, int reloaded)
3232{
3233 if (!strcmp(name, "test_sorcery") && reloaded) {
3235 }
3236}
3237
3238static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery,
3239 const char *object_type, struct ast_sorcery_wizard *wizard,
3240 const char *wizard_args, void *wizard_data)
3241{
3242 if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
3243 && !strcmp(wizard->name, "memory") && !strcmp(wizard_args, "memwiz")) {
3245 }
3246}
3247
3249 struct ast_sorcery *sorcery, const char *object_type)
3250{
3251 if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")) {
3253 }
3254}
3255
3256static void object_type_loaded_observer(const char *name,
3257 const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
3258{
3259 if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
3260 && !reloaded) {
3262 }
3263}
3264
3265static void object_type_reloaded_observer(const char *name,
3266 const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
3267{
3268 if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
3269 && reloaded) {
3271 }
3272}
3273
3274AST_TEST_DEFINE(instance_observation)
3275{
3278 .wizard_mapped = wizard_mapped_observer,
3279 .object_type_registered = object_type_registered_observer,
3280 };
3281
3282 switch (cmd) {
3283 case TEST_INIT:
3284 info->name = "instance_observation";
3285 info->category = "/main/sorcery/";
3286 info->summary = "sorcery instance observation test";
3287 info->description =
3288 "Test observation of sorcery (instance)";
3289 return AST_TEST_NOT_RUN;
3290 case TEST_EXECUTE:
3291 break;
3292 }
3293
3294 /* Test instance load */
3295 if (!(sorcery = ast_sorcery_open())) {
3296 ast_test_status_update(test, "Failed to open a sorcery instance\n");
3297 return AST_TEST_FAIL;
3298 }
3299 observer.instance_loading = instance_loaded_observer;
3300 observer.instance_loaded = instance_loaded_observer;
3302 event_observed = 0;
3304 ast_test_validate(test, (event_observed == 2), "Instance loaded failed");
3305 event_observed = 0;
3307 ast_test_validate(test, (event_observed == 0), "Instance reloaded failed");
3308
3309 /* Test instance reload */
3311 observer.instance_loading = instance_reloaded_observer;
3312 observer.instance_loaded = instance_reloaded_observer;
3314 event_observed = 0;
3316 ast_test_validate(test, (event_observed == 0), "Instance loaded failed");
3317 event_observed = 0;
3319 ast_test_validate(test, (event_observed == 2), "Instance reloaded failed");
3320
3321 /* Test wizard mapping */
3322 event_observed = 0;
3323 ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
3324 ast_test_validate(test, (event_observed == 1), "Wizard mapping failed");
3325
3326 /* Test object type register */
3327 event_observed = 0;
3330 ast_test_validate(test, (event_observed == 1), "Object type registered failed");
3331
3332 /* Test object type load */
3334 observer.object_type_loading = object_type_loaded_observer;
3335 observer.object_type_loaded = object_type_loaded_observer;
3337 event_observed = 0;
3338 ast_sorcery_load_object(sorcery, "test_object_type");
3339 ast_test_validate(test, (event_observed == 2), "Object type loaded failed");
3340 event_observed = 0;
3341 ast_sorcery_reload_object(sorcery, "test_object_type");
3342 ast_test_validate(test, (event_observed == 0), "Object type reloaded failed");
3343
3344 /* Test object type reload */
3346 observer.object_type_loading = object_type_reloaded_observer;
3347 observer.object_type_loaded = object_type_reloaded_observer;
3349 event_observed = 0;
3350 ast_sorcery_load_object(sorcery, "test_object_type");
3351 ast_test_validate(test, (event_observed == 0), "Object type loaded failed");
3352 event_observed = 0;
3353 ast_sorcery_reload_object(sorcery, "test_object_type");
3354 ast_test_validate(test, (event_observed == 2), "Object type reloaded failed");
3355
3357 event_observed = 0;
3358 ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
3359 ast_test_validate(test, (event_observed == 0), "Observer remove failed");
3360
3361 return AST_TEST_PASS;
3362}
3363
3364static void wizard_loaded_observer(const char *name,
3365 const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
3366{
3367 if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
3368 && !reloaded) {
3370 }
3371}
3372
3373static void sorcery_test_load(void *data, const struct ast_sorcery *sorcery, const char *type)
3374{
3375 return;
3376}
3377
3378static void wizard_reloaded_observer(const char *name,
3379 const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
3380{
3381 if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
3382 && reloaded) {
3384 }
3385}
3386
3387AST_TEST_DEFINE(wizard_observation)
3388{
3392 .wizard_loading = wizard_loaded_observer,
3393 .wizard_loaded = wizard_loaded_observer,
3394 };
3395
3396 switch (cmd) {
3397 case TEST_INIT:
3398 info->name = "wizard_observation";
3399 info->category = "/main/sorcery/";
3400 info->summary = "sorcery wizard observation test";
3401 info->description =
3402 "Test observation of sorcery (wizard)";
3403 return AST_TEST_NOT_RUN;
3404 case TEST_EXECUTE:
3405 break;
3406 }
3407
3408 wizard->load = sorcery_test_load;
3409 wizard->reload = sorcery_test_load;
3410
3411 /* Test wizard observer remove and wizard unregister */
3415 event_observed = 0;
3417 ast_test_validate(test, (event_observed == 0), "Wizard observer removed failed");
3418
3419 /* Setup for test loaded and reloaded */
3420 if (!(sorcery = ast_sorcery_open())) {
3421 ast_test_status_update(test, "Failed to open a sorcery instance\n");
3422 return AST_TEST_FAIL;
3423 }
3424
3426 ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
3429
3430 /* Test wizard loading and loaded */
3432
3433 event_observed = 0;
3434 ast_sorcery_load_object(sorcery, "test_object_type");
3435 ast_test_validate(test, (event_observed == 2), "Wizard loaded failed");
3436
3437 event_observed = 0;
3438 ast_sorcery_reload_object(sorcery, "test_object_type");
3440 ast_test_validate(test, (event_observed == 0), "Wizard reloaded failed");
3441
3442 /* Test wizard reloading and reloaded */
3443 observer.wizard_loading = wizard_reloaded_observer;
3444 observer.wizard_loaded = wizard_reloaded_observer;
3446
3447 event_observed = 0;
3448 ast_sorcery_load_object(sorcery, "test_object_type");
3449 ast_test_validate(test, (event_observed == 0), "Wizard loaded failed");
3450
3451 event_observed = 0;
3452 ast_sorcery_reload_object(sorcery, "test_object_type");
3454 ast_test_validate(test, (event_observed == 2), "Wizard reloaded failed");
3455
3456 return AST_TEST_PASS;
3457}
3458
3459AST_TEST_DEFINE(wizard_apply_and_insert)
3460{
3464 RAII_VAR(struct ast_sorcery_wizard *, wizard, NULL, ao2_cleanup);
3465 void *data;
3466
3467 switch (cmd) {
3468 case TEST_INIT:
3469 info->name = "wizard_apply_and_insert";
3470 info->category = "/main/sorcery/";
3471 info->summary = "sorcery wizard apply and insert test";
3472 info->description =
3473 "sorcery wizard apply and insert test";
3474 return AST_TEST_NOT_RUN;
3475 case TEST_EXECUTE:
3476 break;
3477 }
3478
3479 wizard1->load = sorcery_test_load;
3480 wizard1->reload = sorcery_test_load;
3481
3482 wizard2->load = sorcery_test_load;
3483 wizard2->reload = sorcery_test_load;
3484
3485 if (!(sorcery = ast_sorcery_open())) {
3486 ast_test_status_update(test, "Failed to open a sorcery instance\n");
3487 return AST_TEST_FAIL;
3488 }
3489
3492
3493 /* test_object_type isn't registered yet so count should return error */
3494 ast_test_validate(test,
3495 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == -1);
3496
3497 ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
3498
3499 ast_test_validate(test,
3500 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
3501
3502 ast_test_validate(test,
3503 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, NULL) == 0);
3504 ast_test_validate(test, strcmp("test", wizard->name) == 0);
3505 ao2_ref(wizard, -1);
3506 wizard = NULL;
3507
3508 ast_test_validate(test,
3509 ast_sorcery_insert_wizard_mapping(sorcery, "test_object_type", "test2", "test2data", 0, 0) == 0);
3510
3511 ast_test_validate(test,
3512 ast_sorcery_insert_wizard_mapping(sorcery, "test_object_type", "test2", "test2data", 0, 0) != 0);
3513
3514 ast_test_validate(test,
3515 ast_sorcery_object_type_insert_wizard(sorcery, "test_object_type", "test2", "test2data2",
3517
3518 ast_test_validate(test,
3519 ast_sorcery_object_type_remove_wizard(sorcery, "test_object_type", "test2", "test2data2") == 0);
3520
3521 ast_test_validate(test,
3522 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, &data) == 0);
3523 ast_test_validate(test, strcmp("test2", wizard->name) == 0);
3524 ast_test_validate(test, strcmp("test2data", data) == 0);
3525 ao2_ref(wizard, -1);
3526 wizard = NULL;
3527
3528 ast_test_validate(test,
3529 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 1, &wizard, NULL) == 0);
3530 ast_test_validate(test, strcmp("test", wizard->name) == 0);
3531 ao2_ref(wizard, -1);
3532 wizard = NULL;
3533
3534 /* Test failures */
3535 ast_test_validate(test,
3536 ast_sorcery_get_wizard_mapping(sorcery, "non-existent-type", 0, &wizard, NULL) != 0);
3537
3538 ast_test_validate(test,
3539 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", -1, &wizard, &data) != 0);
3540
3541 ast_test_validate(test,
3542 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 2, &wizard, NULL) != 0);
3543
3544 ast_test_validate(test,
3545 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 2, NULL, NULL) != 0);
3546
3547 /* Test remove */
3548 /* Should fail */
3549 ast_test_validate(test,
3550 ast_sorcery_remove_wizard_mapping(sorcery, "non-existent-type", "somewizard") != 0);
3551 ast_test_validate(test,
3552 ast_sorcery_remove_wizard_mapping(sorcery, "test_object_type", "somewizard") != 0);
3553
3554 /* should work */
3555 ast_test_validate(test,
3556 ast_sorcery_remove_wizard_mapping(sorcery, "test_object_type", "test") == 0);
3557
3558 ast_test_validate(test,
3559 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
3560
3561 ast_test_validate(test,
3562 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, &data) == 0);
3563 ast_test_validate(test, strcmp("test2", wizard->name) == 0);
3564 ast_test_validate(test, strcmp("test2data", data) == 0);
3565 ao2_ref(wizard, -1);
3566 wizard = NULL;
3567
3568 return AST_TEST_PASS;
3569}
3570
3572 .name = "test-read-only",
3573 .retrieve_id = sorcery_test_retrieve_id,
3574};
3575
3576AST_TEST_DEFINE(wizard_read_only)
3577{
3582 struct ast_sorcery_wizard *wizard;
3583
3584 switch (cmd) {
3585 case TEST_INIT:
3586 info->name = "wizard_read_only";
3587 info->category = "/main/sorcery/";
3588 info->summary = "sorcery wizard read-only test";
3589 info->description =
3590 "sorcery wizard read-only test";
3591 return AST_TEST_NOT_RUN;
3592 case TEST_EXECUTE:
3593 break;
3594 }
3595
3596 wizard1->load = sorcery_test_load;
3597 wizard1->reload = sorcery_test_load;
3598
3599 if (!(sorcery = ast_sorcery_open())) {
3600 ast_test_status_update(test, "Failed to open a sorcery instance\n");
3601 return AST_TEST_FAIL;
3602 }
3603
3604 ast_sorcery_wizard_register(wizard_read_only);
3606
3607 if ((ast_sorcery_apply_default(sorcery, "test_object_type", "test-read-only", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
3609 ast_test_status_update(test, "Failed to apply object defaults\n");
3610 return AST_TEST_FAIL;
3611 }
3612
3613 ast_test_validate(test,
3614 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
3615
3616 ast_test_validate(test,
3618 "test", "test2data", AST_SORCERY_WIZARD_APPLY_READONLY, &wizard, NULL) == 0);
3619
3620 ast_test_validate(test, strcmp(wizard->name, wizard1->name) == 0);
3621
3622 ast_test_validate(test,
3623 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 2);
3624
3625 if (!(obj = ast_sorcery_alloc(sorcery, "test_object_type", "blah"))) {
3626 ast_test_status_update(test, "Failed to allocate a known object type\n");
3627 return AST_TEST_FAIL;
3628 }
3629
3630 if (ast_sorcery_create(sorcery, obj) == 0) {
3631 ast_test_status_update(test, "Should not have created object using read-only wizard\n");
3632 return AST_TEST_FAIL;
3633 }
3634
3635 return AST_TEST_PASS;
3636}
3637
3638static int unload_module(void)
3639{
3640 AST_TEST_UNREGISTER(wizard_registration);
3641 AST_TEST_UNREGISTER(sorcery_open);
3642 AST_TEST_UNREGISTER(apply_default);
3644 AST_TEST_UNREGISTER(object_register);
3645 AST_TEST_UNREGISTER(object_register_without_mapping);
3646 AST_TEST_UNREGISTER(object_field_register);
3647 AST_TEST_UNREGISTER(object_fields_register);
3648 AST_TEST_UNREGISTER(object_alloc_with_id);
3649 AST_TEST_UNREGISTER(object_alloc_without_id);
3650 AST_TEST_UNREGISTER(object_copy);
3651 AST_TEST_UNREGISTER(object_copy_native);
3652 AST_TEST_UNREGISTER(object_diff);
3653 AST_TEST_UNREGISTER(object_diff_native);
3654 AST_TEST_UNREGISTER(objectset_create);
3655 AST_TEST_UNREGISTER(objectset_json_create);
3656 AST_TEST_UNREGISTER(objectset_create_regex);
3657 AST_TEST_UNREGISTER(objectset_apply);
3658 AST_TEST_UNREGISTER(objectset_apply_handler);
3659 AST_TEST_UNREGISTER(objectset_apply_invalid);
3660 AST_TEST_UNREGISTER(objectset_transform);
3661 AST_TEST_UNREGISTER(objectset_apply_fields);
3662 AST_TEST_UNREGISTER(extended_fields);
3663 AST_TEST_UNREGISTER(changeset_create);
3664 AST_TEST_UNREGISTER(changeset_create_unchanged);
3665 AST_TEST_UNREGISTER(object_create);
3666 AST_TEST_UNREGISTER(object_retrieve_id);
3667 AST_TEST_UNREGISTER(object_retrieve_field);
3668 AST_TEST_UNREGISTER(object_retrieve_multiple_all);
3669 AST_TEST_UNREGISTER(object_retrieve_multiple_field);
3670 AST_TEST_UNREGISTER(object_retrieve_regex);
3671 AST_TEST_UNREGISTER(object_update);
3672 AST_TEST_UNREGISTER(object_update_uncreated);
3673 AST_TEST_UNREGISTER(object_delete);
3674 AST_TEST_UNREGISTER(object_delete_uncreated);
3675 AST_TEST_UNREGISTER(object_is_stale);
3676 AST_TEST_UNREGISTER(caching_wizard_behavior);
3677 AST_TEST_UNREGISTER(object_type_observer);
3678 AST_TEST_UNREGISTER(configuration_file_wizard);
3679 AST_TEST_UNREGISTER(configuration_file_wizard_with_file_integrity);
3680 AST_TEST_UNREGISTER(configuration_file_wizard_with_criteria);
3681 AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_field);
3682 AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple);
3683 AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple_all);
3684 AST_TEST_UNREGISTER(dialplan_function);
3685 AST_TEST_UNREGISTER(object_field_registered);
3686 AST_TEST_UNREGISTER(global_observation);
3687 AST_TEST_UNREGISTER(instance_observation);
3688 AST_TEST_UNREGISTER(wizard_observation);
3689 AST_TEST_UNREGISTER(wizard_apply_and_insert);
3690 AST_TEST_UNREGISTER(wizard_read_only);
3691
3692 return 0;
3693}
3694
3695static int load_module(void)
3696{
3697 AST_TEST_REGISTER(wizard_apply_and_insert);
3698 AST_TEST_REGISTER(wizard_registration);
3699 AST_TEST_REGISTER(sorcery_open);
3700 AST_TEST_REGISTER(apply_default);
3702 AST_TEST_REGISTER(object_register);
3703 AST_TEST_REGISTER(object_register_without_mapping);
3704 AST_TEST_REGISTER(object_field_register);
3705 AST_TEST_REGISTER(object_fields_register);
3706 AST_TEST_REGISTER(object_alloc_with_id);
3707 AST_TEST_REGISTER(object_alloc_without_id);
3708 AST_TEST_REGISTER(object_copy);
3709 AST_TEST_REGISTER(object_copy_native);
3710 AST_TEST_REGISTER(object_diff);
3711 AST_TEST_REGISTER(object_diff_native);
3712 AST_TEST_REGISTER(objectset_create);
3713 AST_TEST_REGISTER(objectset_json_create);
3714 AST_TEST_REGISTER(objectset_create_regex);
3715 AST_TEST_REGISTER(objectset_apply);
3716 AST_TEST_REGISTER(objectset_apply_handler);
3717 AST_TEST_REGISTER(objectset_apply_invalid);
3718 AST_TEST_REGISTER(objectset_transform);
3719 AST_TEST_REGISTER(objectset_apply_fields);
3720 AST_TEST_REGISTER(extended_fields);
3721 AST_TEST_REGISTER(changeset_create);
3722 AST_TEST_REGISTER(changeset_create_unchanged);
3723 AST_TEST_REGISTER(object_create);
3724 AST_TEST_REGISTER(object_retrieve_id);
3725 AST_TEST_REGISTER(object_retrieve_field);
3726 AST_TEST_REGISTER(object_retrieve_multiple_all);
3727 AST_TEST_REGISTER(object_retrieve_multiple_field);
3728 AST_TEST_REGISTER(object_retrieve_regex);
3729 AST_TEST_REGISTER(object_update);
3730 AST_TEST_REGISTER(object_update_uncreated);
3731 AST_TEST_REGISTER(object_delete);
3732 AST_TEST_REGISTER(object_delete_uncreated);
3733 AST_TEST_REGISTER(object_is_stale);
3734 AST_TEST_REGISTER(caching_wizard_behavior);
3735 AST_TEST_REGISTER(object_type_observer);
3736 AST_TEST_REGISTER(configuration_file_wizard);
3737 AST_TEST_REGISTER(configuration_file_wizard_with_file_integrity);
3738 AST_TEST_REGISTER(configuration_file_wizard_with_criteria);
3739 AST_TEST_REGISTER(configuration_file_wizard_retrieve_field);
3740 AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple);
3741 AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple_all);
3742 AST_TEST_REGISTER(dialplan_function);
3743 AST_TEST_REGISTER(object_field_registered);
3744 AST_TEST_REGISTER(global_observation);
3745 AST_TEST_REGISTER(instance_observation);
3746 AST_TEST_REGISTER(wizard_observation);
3747 AST_TEST_REGISTER(wizard_read_only);
3748
3750}
3751
#define AST_MODULE
const char * str
Definition: app_jack.c:150
ast_mutex_t lock
Definition: app_sla.c:337
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define var
Definition: ast_expr2f.c:605
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static const char type[]
Definition: chan_ooh323.c:109
static const char config[]
Definition: chan_ooh323.c:111
static int apply_config(struct aco_info *info)
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:266
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: main/config.c:3541
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Definition: main/config.c:629
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1287
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1260
@ CONFIG_FLAG_NOCACHE
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
Definition: main/config.c:1205
Support for logging to various files, console and syslog Configuration in file logger....
Asterisk JSON abstraction layer.
struct ast_json * ast_json_object_iter_value(struct ast_json_iter *iter)
Get the value from an iterator.
Definition: json.c:455
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json_iter * ast_json_object_iter_next(struct ast_json *object, struct ast_json_iter *iter)
Get the next iterator.
Definition: json.c:447
struct ast_json_iter * ast_json_object_iter(struct ast_json *object)
Get an iterator pointing to the first field in a JSON object.
Definition: json.c:439
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
const char * ast_json_object_iter_key(struct ast_json_iter *iter)
Get the key from an iterator.
Definition: json.c:451
#define ast_cond_destroy(cond)
Definition: lock.h:209
#define ast_cond_init(cond, attr)
Definition: lock.h:208
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:213
#define ast_mutex_init(pmutex)
Definition: lock.h:193
#define ast_mutex_unlock(a)
Definition: lock.h:197
pthread_cond_t ast_cond_t
Definition: lock.h:185
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:596
#define ast_mutex_destroy(a)
Definition: lock.h:195
#define ast_mutex_lock(a)
Definition: lock.h:196
#define ast_cond_signal(cond)
Definition: lock.h:210
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
Core PBX routines and definitions.
int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
executes a read operation on a function
static struct ast_sorcery * sorcery
#define NULL
Definition: resample.c:96
Sorcery Data Access Layer API.
#define ast_sorcery_object_type_insert_wizard(sorcery, object_type_name, wizard_type_name, wizard_args, flags, position, wizard, wizard_data)
Insert an additional object wizard mapping at a specific position in the wizard list returning wizard...
Definition: sorcery.h:646
const char * ast_sorcery_object_get_extended(const void *object, const char *name)
Get an extended field value from a sorcery object.
Definition: sorcery.c:2398
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2380
#define ast_sorcery_object_field_register_nodoc(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object without documentation.
Definition: sorcery.h:987
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:537
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1137
int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
Register a regex for multiple fields within an object.
Definition: sorcery.c:1223
#define ast_sorcery_object_field_register_custom_nodoc(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers without documentation.
Definition: sorcery.h:1041
int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
Set an extended field value on a sorcery object.
Definition: sorcery.c:2412
#define ast_sorcery_insert_wizard_mapping(sorcery, type, name, data, caching, position)
Insert an additional object wizard mapping at a specific position in the wizard list.
Definition: sorcery.h:562
void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Remove an observer from a sorcery instance.
Definition: sorcery.c:600
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition: sorcery.h:120
@ AST_RETRIEVE_FLAG_DEFAULT
Default retrieval flags.
Definition: sorcery.h:117
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition: sorcery.h:123
void ast_sorcery_load(const struct ast_sorcery *sorcery)
Inform any wizards to load persistent objects.
Definition: sorcery.c:1440
void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *interface, const struct ast_sorcery_wizard_observer *callbacks)
Remove an observer from a sorcery wizard.
Definition: sorcery.c:631
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2392
int ast_sorcery_update_or_create_on_update_miss
Global control for optional update->create fallback in backends.
Definition: sorcery.c:288
void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy)
Set the copy handler for an object type.
Definition: sorcery.c:1191
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2125
struct ast_sorcery_object_type * ast_sorcery_get_object_type(const struct ast_sorcery *sorcery, const char *type)
Get the sorcery object type given a type name.
Definition: sorcery.c:2557
int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
Create a changeset of two objects.
Definition: sorcery.c:1868
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1916
void ast_sorcery_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects.
Definition: sorcery.c:1471
int ast_sorcery_get_wizard_mapping_count(struct ast_sorcery *sorcery, const char *type)
Return the number of wizards mapped to an object type.
Definition: sorcery.c:841
struct ao2_container * ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
Retrieve multiple objects using a regular expression on their id.
Definition: sorcery.c:2017
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition: sorcery.c:2454
void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to load persistent objects.
Definition: sorcery.c:1456
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
Definition: sorcery.h:867
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1791
#define ast_sorcery_remove_wizard_mapping(sorcery, type, name)
Remove an object wizard mapping.
Definition: sorcery.h:757
#define ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:455
int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
Create a changeset given two object sets.
Definition: sorcery.c:1726
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
Definition: sorcery.h:383
int ast_sorcery_is_object_field_registered(const struct ast_sorcery_object_type *object_type, const char *field_name)
Determine if a particular object field has been registered with sorcery.
Definition: sorcery.c:2577
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1807
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2213
int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
Apply an object set (KVP list) to an object.
Definition: sorcery.c:1695
int ast_sorcery_get_wizard_mapping(struct ast_sorcery *sorcery, const char *type, int index, struct ast_sorcery_wizard **wizard, void **data)
By index, return a wizard mapped to an object type.
Definition: sorcery.c:853
int ast_sorcery_wizard_observer_add(struct ast_sorcery_wizard *wizard, const struct ast_sorcery_wizard_observer *callbacks)
Add an observer to a sorcery wizard.
Definition: sorcery.c:606
void ast_sorcery_global_observer_remove(const struct ast_sorcery_global_observer *callbacks)
Remove a global observer from sorcery.
Definition: sorcery.c:577
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
struct ast_json * ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
Create an object set in JSON format for an object.
Definition: sorcery.c:1628
int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
Add a global observer to sorcery.
Definition: sorcery.c:561
#define ast_sorcery_open()
Open a new sorcery structure.
Definition: sorcery.h:406
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
Definition: sorcery.c:1505
int ast_sorcery_is_stale(const struct ast_sorcery *sorcery, void *object)
Determine if a sorcery object is stale with respect to its backing datastore.
Definition: sorcery.c:2351
int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Add an observer to a sorcery instance.
Definition: sorcery.c:583
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1960
struct ast_sorcery * ast_sorcery_retrieve_by_module_name(const char *module_name)
Retrieves an existing sorcery instance by module name.
Definition: sorcery.c:735
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2301
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition: sorcery.c:1841
@ AST_SORCERY_WIZARD_APPLY_ALLOW_DUPLICATE
Definition: sorcery.h:583
@ AST_SORCERY_WIZARD_APPLY_READONLY
Definition: sorcery.h:581
#define ast_sorcery_object_type_remove_wizard(sorcery, object_type_name, wizard_type_name, wizard_args)
Remove an object wizard mapping.
Definition: sorcery.h:724
@ AST_SORCERY_APPLY_SUCCESS
Definition: sorcery.h:427
@ AST_SORCERY_APPLY_FAIL
Definition: sorcery.h:425
@ AST_SORCERY_APPLY_DEFAULT_UNNECESSARY
Definition: sorcery.h:431
void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff)
Set the diff handler for an object type.
Definition: sorcery.c:1202
#define ast_sorcery_object_type_apply_wizard(sorcery, object_type_name, wizard_type_name, wizard_args, flags, wizard, wizard_data)
Apply additional object wizard mappings returning wizard information.
Definition: sorcery.h:678
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
Generic container type.
Structure used to handle boolean flags.
Definition: utils.h:217
unsigned int flags
Definition: utils.h:218
Iterator for JSON object key/values.
Abstract JSON element (object, array, string, int, ...).
Structure for mutex and tracking information.
Definition: lock.h:142
Interface for the global sorcery observer.
Definition: sorcery.h:220
Interface for the sorcery instance observer.
Definition: sorcery.h:237
Structure for registered object type.
Definition: sorcery.c:149
Interface for a sorcery object type observer.
Definition: sorcery.h:332
void(* created)(const void *object)
Callback for when an object is created.
Definition: sorcery.h:334
Interface for the sorcery wizard observer.
Definition: sorcery.h:265
Interface for a sorcery wizard.
Definition: sorcery.h:276
const char * name
Name of the wizard.
Definition: sorcery.h:278
Full structure for sorcery.
Definition: sorcery.c:231
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Test structure for caching.
Definition: test_sorcery.c:129
unsigned int updated
Whether the object has been updated in the cache or not.
Definition: test_sorcery.c:134
struct test_sorcery_object object
Object to return when asked.
Definition: test_sorcery.c:143
unsigned int is_stale
Whether the object is stale or not.
Definition: test_sorcery.c:140
unsigned int deleted
Whether the object has been deleted from the cache or not.
Definition: test_sorcery.c:137
unsigned int created
Whether the object has been created in the cache or not.
Definition: test_sorcery.c:131
Test structure for observer.
Definition: test_sorcery.c:147
ast_cond_t cond
Condition for notification.
Definition: test_sorcery.c:152
const void * updated
Pointer to the update object.
Definition: test_sorcery.c:158
const void * created
Pointer to the created object.
Definition: test_sorcery.c:155
const void * deleted
Pointer to the deleted object.
Definition: test_sorcery.c:161
unsigned int loaded
Whether the type has been loaded.
Definition: test_sorcery.c:164
ast_mutex_t lock
Lock for notification.
Definition: test_sorcery.c:149
Dummy sorcery object.
Definition: test_sorcery.c:44
struct ast_variable * jack
Definition: test_sorcery.c:49
unsigned int bob
Definition: test_sorcery.c:46
unsigned int joe
Definition: test_sorcery.c:47
struct ast_variable * jim
Definition: test_sorcery.c:48
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
const char * args
static int event_observed
static void wizard_reloaded_observer(const char *name, const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
static void wizard_loaded_observer(const char *name, const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
static struct ast_sorcery * alloc_and_initialize_sorcery(void)
Definition: test_sorcery.c:332
static void object_type_reloaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
static void sorcery_observer_deleted(const void *object)
Definition: test_sorcery.c:261
static int sorcery_test_delete(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_sorcery.c:215
static struct ast_sorcery_wizard test_wizard2
Definition: test_sorcery.c:236
static void test_sorcery_object_destroy(void *obj)
Internal function to destroy a test object.
Definition: test_sorcery.c:53
static void * test_sorcery_object_alloc(const char *id)
Internal function to allocate a test object.
Definition: test_sorcery.c:61
static void sorcery_test_load(void *data, const struct ast_sorcery *sorcery, const char *type)
static void instance_loaded_observer(const char *name, const struct ast_sorcery *sorcery, int reloaded)
static void sorcery_observer_updated(const void *object)
Definition: test_sorcery.c:254
static struct ast_sorcery_wizard test_wizard
Dummy sorcery wizards, not actually used so we only populate the name and nothing else.
Definition: test_sorcery.c:228
AST_TEST_DEFINE(wizard_registration)
Definition: test_sorcery.c:354
static int jim_vl(const void *obj, struct ast_variable **fields)
Definition: test_sorcery.c:307
static void object_type_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
static int test_sorcery_copy(const void *src, void *dst)
Internal function which copies pre-defined data into an object, natively.
Definition: test_sorcery.c:93
static int test_sorcery_regex_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Internal function which sets some values.
Definition: test_sorcery.c:111
static struct sorcery_test_caching cache
Global scope caching structure for testing.
Definition: test_sorcery.c:178
static void * wizard2_data
Definition: test_sorcery.c:183
static int test_sorcery_diff(const void *original, const void *modified, struct ast_variable **changes)
Internal function which creates a pre-defined diff natively.
Definition: test_sorcery.c:104
static struct ast_sorcery_wizard test_read_only_wizard
static void object_type_registered_observer(const char *name, struct ast_sorcery *sorcery, const char *object_type)
static int sorcery_test_update(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_sorcery.c:209
static const struct ast_sorcery_observer test_observer
Test sorcery observer implementation.
Definition: test_sorcery.c:276
static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery, const char *object_type, struct ast_sorcery_wizard *wizard, const char *wizard_args, void *wizard_data)
static int jack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition: test_sorcery.c:294
static int sorcery_test_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_sorcery.c:221
static void wizard_observer(const char *name, const struct ast_sorcery_wizard *wizard)
static int apply_handler_called
Global scope apply handler integer to make sure it executed.
Definition: test_sorcery.c:168
static int jim_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition: test_sorcery.c:284
static void instance_observer(const char *name, struct ast_sorcery *sorcery)
static int load_module(void)
static void * sorcery_test_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Definition: test_sorcery.c:204
static int test_apply_handler(const struct ast_sorcery *sorcery, void *obj)
Simple apply handler which sets global scope integer to 1 if called.
Definition: test_sorcery.c:171
static void * sorcery_test_open(const char *data)
Definition: test_sorcery.c:185
static struct sorcery_test_observer observer
Global scope observer structure for testing.
Definition: test_sorcery.c:181
static struct ast_variable * test_sorcery_transform(struct ast_variable *set)
Internal function for object set transformation.
Definition: test_sorcery.c:67
static int unload_module(void)
static void sorcery_test_close(void *data)
Definition: test_sorcery.c:191
static void instance_reloaded_observer(const char *name, const struct ast_sorcery *sorcery, int reloaded)
static int sorcery_test_create(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_sorcery.c:196
static int test_sorcery_regex_fields(const void *obj, struct ast_variable **fields)
Internal function which creates some ast_variable structures.
Definition: test_sorcery.c:121
static int jack_str(const void *obj, const intptr_t *args, char **buf)
Definition: test_sorcery.c:316
static void sorcery_observer_created(const void *object)
Definition: test_sorcery.c:247
static void sorcery_observer_loaded(const char *object_type)
Definition: test_sorcery.c:268
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:978