Asterisk - The Open Source Telephony Project GIT-master-a358458
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
2144 if (!ast_sorcery_update(sorcery, obj)) {
2145 ast_test_status_update(test, "Successfully updated an object which has not been created yet\n");
2146 return AST_TEST_FAIL;
2147 }
2148
2149 return AST_TEST_PASS;
2150}
2151
2152AST_TEST_DEFINE(object_delete)
2153{
2156
2157 switch (cmd) {
2158 case TEST_INIT:
2159 info->name = "object_delete";
2160 info->category = "/main/sorcery/";
2161 info->summary = "sorcery object deletion unit test";
2162 info->description =
2163 "Test object deletion in sorcery";
2164 return AST_TEST_NOT_RUN;
2165 case TEST_EXECUTE:
2166 break;
2167 }
2168
2170 ast_test_status_update(test, "Failed to open sorcery structure\n");
2171 return AST_TEST_FAIL;
2172 }
2173
2174 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2175 ast_test_status_update(test, "Failed to allocate a known object type\n");
2176 return AST_TEST_FAIL;
2177 }
2178
2179 if (ast_sorcery_create(sorcery, obj)) {
2180 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
2181 return AST_TEST_FAIL;
2182 }
2183
2184 if (ast_sorcery_delete(sorcery, obj)) {
2185 ast_test_status_update(test, "Failed to delete object using in-memory wizard\n");
2186 return AST_TEST_FAIL;
2187 }
2188
2189 ao2_cleanup(obj);
2190
2191 if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
2192 ast_test_status_update(test, "Retrieved deleted object that should not be there\n");
2193 return AST_TEST_FAIL;
2194 }
2195
2196 return AST_TEST_PASS;
2197}
2198
2199AST_TEST_DEFINE(object_delete_uncreated)
2200{
2203
2204 switch (cmd) {
2205 case TEST_INIT:
2206 info->name = "object_delete_uncreated";
2207 info->category = "/main/sorcery/";
2208 info->summary = "sorcery object deletion unit test";
2209 info->description =
2210 "Test object deletion of an uncreated object in sorcery";
2211 return AST_TEST_NOT_RUN;
2212 case TEST_EXECUTE:
2213 break;
2214 }
2215
2217 ast_test_status_update(test, "Failed to open sorcery structure\n");
2218 return AST_TEST_FAIL;
2219 }
2220
2221 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2222 ast_test_status_update(test, "Failed to allocate a known object type\n");
2223 return AST_TEST_FAIL;
2224 }
2225
2226 if (!ast_sorcery_delete(sorcery, obj)) {
2227 ast_test_status_update(test, "Successfully deleted an object which was never created\n");
2228 return AST_TEST_FAIL;
2229 }
2230
2231 return AST_TEST_PASS;
2232}
2233
2234AST_TEST_DEFINE(object_is_stale)
2235{
2239 RAII_VAR(struct test_sorcery_object *, obj1, NULL, ao2_cleanup);
2240 RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
2241
2242 switch (cmd) {
2243 case TEST_INIT:
2244 info->name = "object_is_stale";
2245 info->category = "/main/sorcery/";
2246 info->summary = "sorcery object staleness unit test";
2247 info->description =
2248 "Test whether sorcery will query a wizard correctly if asked\n"
2249 "if an object is stale.";
2250 return AST_TEST_NOT_RUN;
2251 case TEST_EXECUTE:
2252 break;
2253 }
2254
2256 ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
2257 return AST_TEST_FAIL;
2258 }
2259
2261 ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
2262 return AST_TEST_FAIL;
2263 }
2264
2265 if (!(sorcery = ast_sorcery_open())) {
2266 ast_test_status_update(test, "Failed to open sorcery structure\n");
2267 return AST_TEST_FAIL;
2268 }
2269
2272 return AST_TEST_FAIL;
2273 }
2274
2279
2280
2281 if ((ast_sorcery_apply_default(sorcery, "test2", "test2", "test2data") != AST_SORCERY_APPLY_SUCCESS) ||
2283 return AST_TEST_FAIL;
2284 }
2285
2290
2291
2292 if (!(obj1 = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2293 ast_test_status_update(test, "Failed to allocate a known object type\n");
2294 return AST_TEST_FAIL;
2295 }
2296
2297 if (!(obj2 = ast_sorcery_alloc(sorcery, "test2", "blah"))) {
2298 ast_test_status_update(test, "Failed to allocate a known object type\n");
2299 return AST_TEST_FAIL;
2300 }
2301
2302 /* The 'test' wizard has no is_stale callback */
2303 ast_test_validate(test, ast_sorcery_is_stale(sorcery, obj1) == 0);
2304
2305 /* The 'test2' wizard should return stale */
2306 ast_test_validate(test, ast_sorcery_is_stale(sorcery, obj2) == 1);
2307 ast_test_validate(test, cache.is_stale == 1);
2308
2309 return AST_TEST_PASS;
2310}
2311
2312AST_TEST_DEFINE(caching_wizard_behavior)
2313{
2314 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2315 struct ast_config *config;
2318 RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
2319 int res = AST_TEST_FAIL;
2320
2321 switch (cmd) {
2322 case TEST_INIT:
2323 info->name = "caching_wizard_behavior";
2324 info->category = "/main/sorcery/";
2325 info->summary = "sorcery caching wizard behavior unit test";
2326 info->description =
2327 "Test internal behavior of caching wizards";
2328 return AST_TEST_NOT_RUN;
2329 case TEST_EXECUTE:
2330 break;
2331 }
2332
2333 if (!(config = ast_config_load2("sorcery.conf", "test_sorcery_cache", flags))) {
2334 ast_test_status_update(test, "Sorcery configuration file not present - skipping caching_wizard_behavior test\n");
2335 return AST_TEST_NOT_RUN;
2336 }
2337
2338 if (!ast_category_get(config, "test_sorcery_cache", NULL)) {
2339 ast_test_status_update(test, "Sorcery configuration file does not contain 'test_sorcery_cache' section\n");
2341 return AST_TEST_NOT_RUN;
2342 }
2343
2345
2347 ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
2348 return AST_TEST_FAIL;
2349 }
2350
2351 if (!(sorcery = ast_sorcery_open())) {
2352 ast_test_status_update(test, "Failed to open sorcery structure\n");
2353 goto end;
2354 }
2355
2356 if (ast_sorcery_apply_config(sorcery, "test_sorcery_cache") != AST_SORCERY_APPLY_SUCCESS) {
2357 ast_test_status_update(test, "Failed to apply configured object mappings\n");
2358 goto end;
2359 }
2360
2362 ast_test_status_update(test, "Failed to register object type\n");
2363 goto end;
2364 }
2365
2366 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2367 ast_test_status_update(test, "Failed to allocate a known object type\n");
2368 goto end;
2369 }
2370
2371 if (ast_sorcery_create(sorcery, obj)) {
2372 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
2373 goto end;
2374 }
2375
2376 ao2_cleanup(obj);
2377
2378 if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
2379 ast_test_status_update(test, "Failed to retrieve just created object\n");
2380 goto end;
2381 } else if (!cache.created) {
2382 ast_test_status_update(test, "Caching wizard was not told to cache just created object\n");
2383 goto end;
2384 } else if (!(obj2 = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
2385 ast_test_status_update(test, "Failed to retrieve just cached object\n");
2386 goto end;
2387 } else if (obj == obj2) {
2388 ast_test_status_update(test, "Returned object is *NOT* a cached object\n");
2389 goto end;
2390 } else if (ast_sorcery_update(sorcery, obj)) {
2391 ast_test_status_update(test, "Failed to update a known stored object\n");
2392 goto end;
2393 } else if (!cache.updated) {
2394 ast_test_status_update(test, "Caching wizard was not told to update object\n");
2395 goto end;
2396 } else if (ast_sorcery_delete(sorcery, obj)) {
2397 ast_test_status_update(test, "Failed to delete a known stored object\n");
2398 goto end;
2399 } else if (!cache.deleted) {
2400 ast_test_status_update(test, "Caching wizard was not told to delete object\n");
2401 goto end;
2402 }
2403
2404 ao2_cleanup(obj2);
2405
2406 if ((obj2 = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
2407 ast_test_status_update(test, "Retrieved an object that should have been deleted\n");
2408 goto end;
2409 }
2410
2411 res = AST_TEST_PASS;
2412
2413end:
2415 sorcery = NULL;
2416
2418 ast_test_status_update(test, "Failed to unregister test sorcery wizard\n");
2419 return AST_TEST_FAIL;
2420 }
2421
2422 return res;
2423}
2424
2425AST_TEST_DEFINE(object_type_observer)
2426{
2429 int res = AST_TEST_FAIL;
2430
2431 switch (cmd) {
2432 case TEST_INIT:
2433 info->name = "object_type_observer";
2434 info->category = "/main/sorcery/";
2435 info->summary = "sorcery object type observer unit test";
2436 info->description =
2437 "Test that object type observers get called when they should";
2438 return AST_TEST_NOT_RUN;
2439 case TEST_EXECUTE:
2440 break;
2441 }
2442
2444 ast_test_status_update(test, "Failed to open sorcery structure\n");
2445 return AST_TEST_FAIL;
2446 }
2447
2448 if (!ast_sorcery_observer_add(sorcery, "test", NULL)) {
2449 ast_test_status_update(test, "Successfully added a NULL observer when it should not be possible\n");
2450 return AST_TEST_FAIL;
2451 }
2452
2454 ast_test_status_update(test, "Failed to add a proper observer\n");
2455 return AST_TEST_FAIL;
2456 }
2457
2458 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2459 ast_test_status_update(test, "Failed to allocate a known object type\n");
2460 goto end;
2461 }
2462
2468
2469 if (ast_sorcery_create(sorcery, obj)) {
2470 ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
2471 goto end;
2472 }
2473
2475 while (!observer.created) {
2476 struct timeval start = ast_tvnow();
2477 struct timespec end = {
2478 .tv_sec = start.tv_sec + 10,
2479 .tv_nsec = start.tv_usec * 1000,
2480 };
2481 if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
2482 break;
2483 }
2484 }
2486
2487 if (!observer.created) {
2488 ast_test_status_update(test, "Failed to receive observer notification for object creation within suitable timeframe\n");
2489 goto end;
2490 }
2491
2492 if (ast_sorcery_update(sorcery, obj)) {
2493 ast_test_status_update(test, "Failed to update object using in-memory wizard\n");
2494 goto end;
2495 }
2496
2498 while (!observer.updated) {
2499 struct timeval start = ast_tvnow();
2500 struct timespec end = {
2501 .tv_sec = start.tv_sec + 10,
2502 .tv_nsec = start.tv_usec * 1000,
2503 };
2504 if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
2505 break;
2506 }
2507 }
2509
2510 if (!observer.updated) {
2511 ast_test_status_update(test, "Failed to receive observer notification for object updating within suitable timeframe\n");
2512 goto end;
2513 }
2514
2515 if (ast_sorcery_delete(sorcery, obj)) {
2516 ast_test_status_update(test, "Failed to delete object using in-memory wizard\n");
2517 goto end;
2518 }
2519
2521 while (!observer.deleted) {
2522 struct timeval start = ast_tvnow();
2523 struct timespec end = {
2524 .tv_sec = start.tv_sec + 10,
2525 .tv_nsec = start.tv_usec * 1000,
2526 };
2527 if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
2528 break;
2529 }
2530 }
2532
2533 if (!observer.deleted) {
2534 ast_test_status_update(test, "Failed to receive observer notification for object deletion within suitable timeframe\n");
2535 goto end;
2536 }
2537
2539
2541 while (!observer.loaded) {
2542 struct timeval start = ast_tvnow();
2543 struct timespec end = {
2544 .tv_sec = start.tv_sec + 10,
2545 .tv_nsec = start.tv_usec * 1000,
2546 };
2547 if (ast_cond_timedwait(&observer.cond, &observer.lock, &end) == ETIMEDOUT) {
2548 break;
2549 }
2550 }
2552
2553 if (!observer.loaded) {
2554 ast_test_status_update(test, "Failed to receive observer notification for object type load within suitable timeframe\n");
2555 goto end;
2556 }
2557
2558 res = AST_TEST_PASS;
2559
2560end:
2566
2567 return res;
2568}
2569
2570AST_TEST_DEFINE(configuration_file_wizard)
2571{
2572 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2573 struct ast_config *config;
2576
2577 switch (cmd) {
2578 case TEST_INIT:
2579 info->name = "configuration_file_wizard";
2580 info->category = "/main/sorcery/";
2581 info->summary = "sorcery configuration file wizard unit test";
2582 info->description =
2583 "Test the configuration file wizard in sorcery";
2584 return AST_TEST_NOT_RUN;
2585 case TEST_EXECUTE:
2586 break;
2587 }
2588
2589 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2590 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard test\n");
2591 return AST_TEST_NOT_RUN;
2592 }
2593
2595
2596 if (!(sorcery = ast_sorcery_open())) {
2597 ast_test_status_update(test, "Failed to open sorcery structure\n");
2598 return AST_TEST_FAIL;
2599 }
2600
2601 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
2602 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2603 return AST_TEST_NOT_RUN;
2604 }
2605
2607 ast_test_status_update(test, "Failed to register object type\n");
2608 return AST_TEST_FAIL;
2609 }
2610
2613
2615
2616 if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey2"))) {
2617 ast_test_status_update(test, "Retrieved object which has an unknown field\n");
2618 return AST_TEST_FAIL;
2619 } else if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey"))) {
2620 ast_test_status_update(test, "Failed to retrieve a known object that has been configured in the configuration file\n");
2621 return AST_TEST_FAIL;
2622 } else if (obj->bob != 98) {
2623 ast_test_status_update(test, "Value of 'bob' on object is not what is configured in configuration file\n");
2624 return AST_TEST_FAIL;
2625 } else if (obj->joe != 41) {
2626 ast_test_status_update(test, "Value of 'joe' on object is not what is configured in configuration file\n");
2627 return AST_TEST_FAIL;
2628 }
2629
2630 return AST_TEST_PASS;
2631}
2632
2633AST_TEST_DEFINE(configuration_file_wizard_with_file_integrity)
2634{
2635 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2636 struct ast_config *config;
2639
2640 switch (cmd) {
2641 case TEST_INIT:
2642 info->name = "configuration_file_wizard_with_file_integrity";
2643 info->category = "/main/sorcery/";
2644 info->summary = "sorcery configuration file wizard file integrity unit test";
2645 info->description =
2646 "Test the configuration file wizard with file integrity turned on in sorcery";
2647 return AST_TEST_NOT_RUN;
2648 case TEST_EXECUTE:
2649 break;
2650 }
2651
2652 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2653 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_with_file_integrity test\n");
2654 return AST_TEST_NOT_RUN;
2655 }
2656
2658
2659 if (!(sorcery = ast_sorcery_open())) {
2660 ast_test_status_update(test, "Failed to open sorcery structure\n");
2661 return AST_TEST_FAIL;
2662 }
2663
2664 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,integrity=file") != AST_SORCERY_APPLY_SUCCESS) {
2665 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2666 return AST_TEST_NOT_RUN;
2667 }
2668
2670 ast_test_status_update(test, "Failed to register object type\n");
2671 return AST_TEST_FAIL;
2672 }
2673
2676
2678
2679 if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey"))) {
2680 ast_test_status_update(test, "Retrieved object which has an unknown field\n");
2681 return AST_TEST_FAIL;
2682 }
2683
2684 return AST_TEST_PASS;
2685}
2686
2687AST_TEST_DEFINE(configuration_file_wizard_with_criteria)
2688{
2689 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2690 struct ast_config *config;
2693
2694 switch (cmd) {
2695 case TEST_INIT:
2696 info->name = "configuration_file_wizard_with_criteria";
2697 info->category = "/main/sorcery/";
2698 info->summary = "sorcery configuration file wizard with criteria unit test";
2699 info->description =
2700 "Test the configuration file wizard with criteria matching in sorcery";
2701 return AST_TEST_NOT_RUN;
2702 case TEST_EXECUTE:
2703 break;
2704 }
2705
2706 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2707 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_with_criteria test\n");
2708 return AST_TEST_NOT_RUN;
2709 }
2710
2712
2713 if (!(sorcery = ast_sorcery_open())) {
2714 ast_test_status_update(test, "Failed to open sorcery structure\n");
2715 return AST_TEST_FAIL;
2716 }
2717
2718 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,criteria=type=zombies") != AST_SORCERY_APPLY_SUCCESS) {
2719 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2720 return AST_TEST_NOT_RUN;
2721 }
2722
2724 ast_test_status_update(test, "Failed to register object type\n");
2725 return AST_TEST_FAIL;
2726 }
2727
2731
2733
2734 if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey"))) {
2735 ast_test_status_update(test, "Retrieved object which did not match criteria\n");
2736 return AST_TEST_FAIL;
2737 } else if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "hey2"))) {
2738 ast_test_status_update(test, "Failed to retrieve a known object which matches criteria\n");
2739 return AST_TEST_FAIL;
2740 }
2741
2742 return AST_TEST_PASS;
2743}
2744
2745AST_TEST_DEFINE(configuration_file_wizard_retrieve_field)
2746{
2747 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2748 struct ast_config *config;
2751 RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "41", ""), ast_variables_destroy);
2752
2753 switch (cmd) {
2754 case TEST_INIT:
2755 info->name = "configuration_file_wizard_retrieve_field";
2756 info->category = "/main/sorcery/";
2757 info->summary = "sorcery configuration file wizard field retrieval unit test";
2758 info->description =
2759 "Test the configuration file wizard retrieval using field in sorcery";
2760 return AST_TEST_NOT_RUN;
2761 case TEST_EXECUTE:
2762 break;
2763 }
2764
2765 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2766 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_retrieve_field test\n");
2767 return AST_TEST_NOT_RUN;
2768 }
2769
2771
2772 if (!(sorcery = ast_sorcery_open())) {
2773 ast_test_status_update(test, "Failed to open sorcery structure\n");
2774 return AST_TEST_FAIL;
2775 }
2776
2777 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
2778 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2779 return AST_TEST_NOT_RUN;
2780 }
2781
2783 ast_test_status_update(test, "Failed to register object type\n");
2784 return AST_TEST_FAIL;
2785 }
2786
2789
2791
2792 if (!(obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
2793 ast_test_status_update(test, "Failed to retrieve a known object that has been configured with the correct field\n");
2794 return AST_TEST_FAIL;
2795 } else if (strcmp(ast_sorcery_object_get_id(obj), "hey")) {
2796 ast_test_status_update(test, "Retrieved object has incorrect object id of '%s'\n", ast_sorcery_object_get_id(obj));
2797 return AST_TEST_FAIL;
2798 }
2799
2800 return AST_TEST_PASS;
2801}
2802
2803AST_TEST_DEFINE(configuration_file_wizard_retrieve_multiple)
2804{
2805 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2806 struct ast_config *config;
2808 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
2809 RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "99", ""), ast_variables_destroy);
2810
2811 switch (cmd) {
2812 case TEST_INIT:
2813 info->name = "configuration_file_wizard_retrieve_multiple";
2814 info->category = "/main/sorcery/";
2815 info->summary = "sorcery configuration file wizard multiple retrieval unit test";
2816 info->description =
2817 "Test the configuration file wizard multiple retrieval in sorcery";
2818 return AST_TEST_NOT_RUN;
2819 case TEST_EXECUTE:
2820 break;
2821 }
2822
2823 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2824 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_retrieve_multiple test\n");
2825 return AST_TEST_NOT_RUN;
2826 }
2827
2829
2830 if (!fields) {
2831 ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
2832 return AST_TEST_FAIL;
2833 }
2834
2835 if (!(sorcery = ast_sorcery_open())) {
2836 ast_test_status_update(test, "Failed to open sorcery structure\n");
2837 return AST_TEST_FAIL;
2838 }
2839
2840 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
2841 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2842 return AST_TEST_NOT_RUN;
2843 }
2844
2846 ast_test_status_update(test, "Failed to register object type\n");
2847 return AST_TEST_FAIL;
2848 }
2849
2852
2854
2855 if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
2856 ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
2857 return AST_TEST_FAIL;
2858 } else if (ao2_container_count(objects)) {
2859 ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
2860 return AST_TEST_FAIL;
2861 }
2862
2863 ao2_cleanup(objects);
2864 ast_variables_destroy(fields);
2865
2866 if (!(fields = ast_variable_new("joe", "41", ""))) {
2867 ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
2868 return AST_TEST_FAIL;
2869 } else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
2870 ast_test_status_update(test, "Failed to retrieve a container when retrieving multiple\n");
2871 return AST_TEST_FAIL;
2872 } else if (ao2_container_count(objects) != 1) {
2873 ast_test_status_update(test, "Received a container with no objects in it when there should be\n");
2874 return AST_TEST_FAIL;
2875 }
2876
2877 return AST_TEST_PASS;
2878}
2879
2880AST_TEST_DEFINE(configuration_file_wizard_retrieve_multiple_all)
2881{
2882 struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2883 struct ast_config *config;
2885 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
2886
2887 switch (cmd) {
2888 case TEST_INIT:
2889 info->name = "configuration_file_wizard_retrieve_multiple_all";
2890 info->category = "/main/sorcery/";
2891 info->summary = "sorcery configuration file wizard multiple retrieve all unit test";
2892 info->description =
2893 "Test the configuration file wizard multiple retrieve all in sorcery";
2894 return AST_TEST_NOT_RUN;
2895 case TEST_EXECUTE:
2896 break;
2897 }
2898
2899 if (!(config = ast_config_load2("test_sorcery.conf", "test_sorcery", flags))) {
2900 ast_test_status_update(test, "Test sorcery configuration file wizard file not present - skipping configuration_file_wizard_retrieve_multiple_all test\n");
2901 return AST_TEST_NOT_RUN;
2902 }
2903
2905
2906 if (!(sorcery = ast_sorcery_open())) {
2907 ast_test_status_update(test, "Failed to open sorcery structure\n");
2908 return AST_TEST_FAIL;
2909 }
2910
2911 if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
2912 ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
2913 return AST_TEST_NOT_RUN;
2914 }
2915
2917 ast_test_status_update(test, "Failed to register object type\n");
2918 return AST_TEST_FAIL;
2919 }
2920
2923
2925
2927 ast_test_status_update(test, "Failed to retrieve a container with all objects when there should be one\n");
2928 return AST_TEST_FAIL;
2929 } else if (ao2_container_count(objects) != 2) {
2930 ast_test_status_update(test, "Returned container does not have the correct number of objects in it\n");
2931 return AST_TEST_FAIL;
2932 }
2933
2934 return AST_TEST_PASS;
2935}
2936
2937AST_TEST_DEFINE(dialplan_function)
2938{
2941 RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
2942 struct ast_str *buf;
2943 char expression[256];
2944
2945 switch (cmd) {
2946 case TEST_INIT:
2947 info->name = "dialplan_function";
2948 info->category = "/main/sorcery/";
2949 info->summary = "AST_SORCERY dialplan function";
2950 info->description =
2951 "Test the AST_SORCERY dialplan function";
2952 return AST_TEST_NOT_RUN;
2953 case TEST_EXECUTE:
2954 break;
2955 }
2956
2958 ast_test_status_update(test, "Failed to open sorcery structure\n");
2959 return AST_TEST_FAIL;
2960 }
2961
2962 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
2963 ast_test_status_update(test, "Failed to allocate a known object type\n");
2964 return AST_TEST_FAIL;
2965 }
2966
2967 if (ast_sorcery_create(sorcery, obj)) {
2968 ast_test_status_update(test, "Failed to create a known object type\n");
2969 return AST_TEST_FAIL;
2970 }
2971
2972 if (!(buf = ast_str_create(16))) {
2973 ast_test_status_update(test, "Failed to allocate return buffer\n");
2974 return AST_TEST_FAIL;
2975 }
2976
2978 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "notest_sorcery", "test", "blah", "bob");
2979 if (!ast_func_read2(NULL, expression, &buf, 16)) {
2980 ast_free(buf);
2981 ast_test_status_update(test, "Retrieved a non-existent module\n");
2982 return AST_TEST_FAIL;
2983 }
2984
2986 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "notest", "blah", "bob");
2987 if (!ast_func_read2(NULL, expression, &buf, 16)) {
2988 ast_free(buf);
2989 ast_test_status_update(test, "Retrieved a non-existent type\n");
2990 return AST_TEST_FAIL;
2991 }
2992
2994 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "noid", "bob");
2995 if (!ast_func_read2(NULL, expression, &buf, 16)) {
2996 ast_free(buf);
2997 ast_test_status_update(test, "Retrieved a non-existent id\n");
2998 return AST_TEST_FAIL;
2999 }
3000
3002 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "nobob");
3003 if (!ast_func_read2(NULL, expression, &buf, 16)) {
3004 ast_free(buf);
3005 ast_test_status_update(test, "Retrieved a non-existent field\n");
3006 return AST_TEST_FAIL;
3007 }
3008
3010 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "bob");
3011 if (ast_func_read2(NULL, expression, &buf, 16)) {
3012 ast_free(buf);
3013 ast_test_status_update(test, "Failed retrieve field 'bob'\n");
3014 return AST_TEST_FAIL;
3015 }
3016 if (strcmp(ast_str_buffer(buf), "5")) {
3017 ast_free(buf);
3018 ast_test_status_update(test, "Failed retrieve field. Got '%u', should be '5'\n", obj->bob);
3019 return AST_TEST_FAIL;
3020 }
3021
3023 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,1)", "test_sorcery", "test", "blah", "bob");
3024 if (ast_func_read2(NULL, expression, &buf, 16)) {
3025 ast_free(buf);
3026 ast_test_status_update(test, "Failed retrieve field 'bob'\n");
3027 return AST_TEST_FAIL;
3028 }
3029 if (strcmp(ast_str_buffer(buf), "5")) {
3030 ast_free(buf);
3031 ast_test_status_update(test, "Failed retrieve field. Got '%u', should be '5'\n", obj->bob);
3032 return AST_TEST_FAIL;
3033 }
3034
3036 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "bob");
3037 if (!ast_func_read2(NULL, expression, &buf, 16)) {
3038 ast_free(buf);
3039 ast_test_status_update(test, "Got a second 'bob' and shouldn't have\n");
3040 return AST_TEST_FAIL;
3041 }
3042
3043 /* 444 is already the first item in the list */
3044 jim_handler(NULL, ast_variable_new("jim", "555", ""), obj);
3045 jim_handler(NULL, ast_variable_new("jim", "666", ""), obj);
3046
3048 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s)", "test_sorcery", "test", "blah", "jim");
3049 if (ast_func_read2(NULL, expression, &buf, 16)) {
3050 ast_free(buf);
3051 ast_test_status_update(test, "Couldn't retrieve 'jim'\n");
3052 return AST_TEST_FAIL;
3053 }
3054 if (strcmp(ast_str_buffer(buf), "444,555,666")) {
3055 ast_free(buf);
3056 ast_test_status_update(test, "Failed retrieve jim. Got '%s', should be '444,555,666'\n", ast_str_buffer(buf));
3057 return AST_TEST_FAIL;
3058 }
3059
3061 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,2)", "test_sorcery", "test", "blah", "jim");
3062 if (ast_func_read2(NULL, expression, &buf, 16)) {
3063 ast_free(buf);
3064 ast_test_status_update(test, "Couldn't retrieve 2nd jim\n");
3065 return AST_TEST_FAIL;
3066 }
3067 if (strcmp(ast_str_buffer(buf), "555")) {
3068 ast_free(buf);
3069 ast_test_status_update(test, "Failed retrieve 2nd jim. Got '%s', should be '555'\n", ast_str_buffer(buf));
3070 return AST_TEST_FAIL;
3071 }
3072
3074 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,concat,|)", "test_sorcery", "test", "blah", "jim");
3075 if (ast_func_read2(NULL, expression, &buf, 16)) {
3076 ast_free(buf);
3077 ast_test_status_update(test, "Couldn't retrieve any 'jim'\n");
3078 return AST_TEST_FAIL;
3079 }
3080 if (strcmp(ast_str_buffer(buf), "444|555|666")) {
3081 ast_free(buf);
3082 ast_test_status_update(test, "Failed retrieve 'jim'. Got '%s', should be '444|555|666'\n", ast_str_buffer(buf));
3083 return AST_TEST_FAIL;
3084 }
3085
3087 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,noconcat,3)", "test_sorcery", "test", "blah", "jim");
3088 if (!ast_func_read2(NULL, expression, &buf, 16)) {
3089 ast_free(buf);
3090 ast_test_status_update(test, "Should have failed with invalid retrieval_type\n");
3091 return AST_TEST_FAIL;
3092 }
3093
3095 snprintf(expression, sizeof(expression), "AST_SORCERY(%s,%s,%s,%s,single,|)", "test_sorcery", "test", "blah", "jim");
3096 if (!ast_func_read2(NULL, expression, &buf, 16)) {
3097 ast_free(buf);
3098 ast_test_status_update(test, "Should have failed with invalid occurrence_number\n");
3099 return AST_TEST_FAIL;
3100 }
3101
3102 ast_free(buf);
3103
3104 return AST_TEST_PASS;
3105}
3106
3107AST_TEST_DEFINE(object_field_registered)
3108{
3110 RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
3111
3112 switch (cmd) {
3113 case TEST_INIT:
3114 info->name = "object_field_registered";
3115 info->category = "/main/sorcery/";
3116 info->summary = "ast_sorcery_is_object_field_registered unit test";
3117 info->description =
3118 "Test ast_sorcery_is_object_field_registered in sorcery";
3119 return AST_TEST_NOT_RUN;
3120 case TEST_EXECUTE:
3121 break;
3122 }
3123
3125 ast_test_status_update(test, "Failed to open sorcery structure\n");
3126 return AST_TEST_FAIL;
3127 }
3128
3129 object_type = ast_sorcery_get_object_type(sorcery, "test");
3130
3132
3133 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "joe"));
3134 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "bob"));
3135 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "@joebob"));
3136 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "prefix/goober"));
3137
3138 ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "joebob"));
3139 ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "prefix/"));
3140 ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "goober"));
3141
3143
3144 ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "goober"));
3145
3146 return AST_TEST_PASS;
3147}
3148
3150
3151static void wizard_observer(const char *name, const struct ast_sorcery_wizard *wizard)
3152{
3153 if (!strcmp(wizard->name, "test")) {
3154 event_observed = 1;
3155 }
3156}
3157
3158static void instance_observer(const char *name, struct ast_sorcery *sorcery)
3159{
3160 if (!strcmp(name, "test_sorcery")) {
3161 event_observed = 1;
3162 }
3163}
3164
3165AST_TEST_DEFINE(global_observation)
3166{
3169 const struct ast_sorcery_global_observer observer = {
3170 .wizard_registered = wizard_observer,
3171 .instance_created = instance_observer,
3172 .wizard_unregistering = wizard_observer,
3173 .instance_destroying = instance_observer,
3174 };
3175
3176 switch (cmd) {
3177 case TEST_INIT:
3178 info->name = "global_observation";
3179 info->category = "/main/sorcery/";
3180 info->summary = "global sorcery observation test";
3181 info->description =
3182 "Test observation of sorcery (global)";
3183 return AST_TEST_NOT_RUN;
3184 case TEST_EXECUTE:
3185 break;
3186 }
3187
3189
3190 event_observed = 0;
3192 ast_test_validate(test, (event_observed == 1), "Wizard registered failed");
3193
3194 event_observed = 0;
3196 ast_test_validate(test, (event_observed == 1), "Wizard unregistered failed");
3197
3198 event_observed = 0;
3200 ast_test_validate(test, (event_observed == 1), "Instance created failed");
3201
3202 event_observed = 0;
3204 sorcery = NULL;
3205 ast_test_validate(test, (event_observed == 1), "Instance destroyed failed");
3206
3208 event_observed = 0;
3210 ast_test_validate(test, (event_observed == 0), "Observer removed failed");
3211
3212 return AST_TEST_PASS;
3213}
3214
3215static void instance_loaded_observer(const char *name, const struct ast_sorcery *sorcery,
3216 int reloaded)
3217{
3218 if (!strcmp(name, "test_sorcery") && !reloaded) {
3220 }
3221}
3222
3223static void instance_reloaded_observer(const char *name,
3224 const struct ast_sorcery *sorcery, int reloaded)
3225{
3226 if (!strcmp(name, "test_sorcery") && reloaded) {
3228 }
3229}
3230
3231static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery,
3232 const char *object_type, struct ast_sorcery_wizard *wizard,
3233 const char *wizard_args, void *wizard_data)
3234{
3235 if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
3236 && !strcmp(wizard->name, "memory") && !strcmp(wizard_args, "memwiz")) {
3238 }
3239}
3240
3242 struct ast_sorcery *sorcery, const char *object_type)
3243{
3244 if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")) {
3246 }
3247}
3248
3249static void object_type_loaded_observer(const char *name,
3250 const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
3251{
3252 if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
3253 && !reloaded) {
3255 }
3256}
3257
3258static void object_type_reloaded_observer(const char *name,
3259 const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
3260{
3261 if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
3262 && reloaded) {
3264 }
3265}
3266
3267AST_TEST_DEFINE(instance_observation)
3268{
3271 .wizard_mapped = wizard_mapped_observer,
3272 .object_type_registered = object_type_registered_observer,
3273 };
3274
3275 switch (cmd) {
3276 case TEST_INIT:
3277 info->name = "instance_observation";
3278 info->category = "/main/sorcery/";
3279 info->summary = "sorcery instance observation test";
3280 info->description =
3281 "Test observation of sorcery (instance)";
3282 return AST_TEST_NOT_RUN;
3283 case TEST_EXECUTE:
3284 break;
3285 }
3286
3287 /* Test instance load */
3288 if (!(sorcery = ast_sorcery_open())) {
3289 ast_test_status_update(test, "Failed to open a sorcery instance\n");
3290 return AST_TEST_FAIL;
3291 }
3292 observer.instance_loading = instance_loaded_observer;
3293 observer.instance_loaded = instance_loaded_observer;
3295 event_observed = 0;
3297 ast_test_validate(test, (event_observed == 2), "Instance loaded failed");
3298 event_observed = 0;
3300 ast_test_validate(test, (event_observed == 0), "Instance reloaded failed");
3301
3302 /* Test instance reload */
3304 observer.instance_loading = instance_reloaded_observer;
3305 observer.instance_loaded = instance_reloaded_observer;
3307 event_observed = 0;
3309 ast_test_validate(test, (event_observed == 0), "Instance loaded failed");
3310 event_observed = 0;
3312 ast_test_validate(test, (event_observed == 2), "Instance reloaded failed");
3313
3314 /* Test wizard mapping */
3315 event_observed = 0;
3316 ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
3317 ast_test_validate(test, (event_observed == 1), "Wizard mapping failed");
3318
3319 /* Test object type register */
3320 event_observed = 0;
3323 ast_test_validate(test, (event_observed == 1), "Object type registered failed");
3324
3325 /* Test object type load */
3327 observer.object_type_loading = object_type_loaded_observer;
3328 observer.object_type_loaded = object_type_loaded_observer;
3330 event_observed = 0;
3331 ast_sorcery_load_object(sorcery, "test_object_type");
3332 ast_test_validate(test, (event_observed == 2), "Object type loaded failed");
3333 event_observed = 0;
3334 ast_sorcery_reload_object(sorcery, "test_object_type");
3335 ast_test_validate(test, (event_observed == 0), "Object type reloaded failed");
3336
3337 /* Test object type reload */
3339 observer.object_type_loading = object_type_reloaded_observer;
3340 observer.object_type_loaded = object_type_reloaded_observer;
3342 event_observed = 0;
3343 ast_sorcery_load_object(sorcery, "test_object_type");
3344 ast_test_validate(test, (event_observed == 0), "Object type loaded failed");
3345 event_observed = 0;
3346 ast_sorcery_reload_object(sorcery, "test_object_type");
3347 ast_test_validate(test, (event_observed == 2), "Object type reloaded failed");
3348
3350 event_observed = 0;
3351 ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
3352 ast_test_validate(test, (event_observed == 0), "Observer remove failed");
3353
3354 return AST_TEST_PASS;
3355}
3356
3357static void wizard_loaded_observer(const char *name,
3358 const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
3359{
3360 if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
3361 && !reloaded) {
3363 }
3364}
3365
3366static void sorcery_test_load(void *data, const struct ast_sorcery *sorcery, const char *type)
3367{
3368 return;
3369}
3370
3371static void wizard_reloaded_observer(const char *name,
3372 const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
3373{
3374 if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
3375 && reloaded) {
3377 }
3378}
3379
3380AST_TEST_DEFINE(wizard_observation)
3381{
3385 .wizard_loading = wizard_loaded_observer,
3386 .wizard_loaded = wizard_loaded_observer,
3387 };
3388
3389 switch (cmd) {
3390 case TEST_INIT:
3391 info->name = "wizard_observation";
3392 info->category = "/main/sorcery/";
3393 info->summary = "sorcery wizard observation test";
3394 info->description =
3395 "Test observation of sorcery (wizard)";
3396 return AST_TEST_NOT_RUN;
3397 case TEST_EXECUTE:
3398 break;
3399 }
3400
3401 wizard->load = sorcery_test_load;
3402 wizard->reload = sorcery_test_load;
3403
3404 /* Test wizard observer remove and wizard unregister */
3408 event_observed = 0;
3410 ast_test_validate(test, (event_observed == 0), "Wizard observer removed failed");
3411
3412 /* Setup for test loaded and reloaded */
3413 if (!(sorcery = ast_sorcery_open())) {
3414 ast_test_status_update(test, "Failed to open a sorcery instance\n");
3415 return AST_TEST_FAIL;
3416 }
3417
3419 ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
3422
3423 /* Test wizard loading and loaded */
3425
3426 event_observed = 0;
3427 ast_sorcery_load_object(sorcery, "test_object_type");
3428 ast_test_validate(test, (event_observed == 2), "Wizard loaded failed");
3429
3430 event_observed = 0;
3431 ast_sorcery_reload_object(sorcery, "test_object_type");
3433 ast_test_validate(test, (event_observed == 0), "Wizard reloaded failed");
3434
3435 /* Test wizard reloading and reloaded */
3436 observer.wizard_loading = wizard_reloaded_observer;
3437 observer.wizard_loaded = wizard_reloaded_observer;
3439
3440 event_observed = 0;
3441 ast_sorcery_load_object(sorcery, "test_object_type");
3442 ast_test_validate(test, (event_observed == 0), "Wizard loaded failed");
3443
3444 event_observed = 0;
3445 ast_sorcery_reload_object(sorcery, "test_object_type");
3447 ast_test_validate(test, (event_observed == 2), "Wizard reloaded failed");
3448
3449 return AST_TEST_PASS;
3450}
3451
3452AST_TEST_DEFINE(wizard_apply_and_insert)
3453{
3457 RAII_VAR(struct ast_sorcery_wizard *, wizard, NULL, ao2_cleanup);
3458 void *data;
3459
3460 switch (cmd) {
3461 case TEST_INIT:
3462 info->name = "wizard_apply_and_insert";
3463 info->category = "/main/sorcery/";
3464 info->summary = "sorcery wizard apply and insert test";
3465 info->description =
3466 "sorcery wizard apply and insert test";
3467 return AST_TEST_NOT_RUN;
3468 case TEST_EXECUTE:
3469 break;
3470 }
3471
3472 wizard1->load = sorcery_test_load;
3473 wizard1->reload = sorcery_test_load;
3474
3475 wizard2->load = sorcery_test_load;
3476 wizard2->reload = sorcery_test_load;
3477
3478 if (!(sorcery = ast_sorcery_open())) {
3479 ast_test_status_update(test, "Failed to open a sorcery instance\n");
3480 return AST_TEST_FAIL;
3481 }
3482
3485
3486 /* test_object_type isn't registered yet so count should return error */
3487 ast_test_validate(test,
3488 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == -1);
3489
3490 ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
3491
3492 ast_test_validate(test,
3493 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
3494
3495 ast_test_validate(test,
3496 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, NULL) == 0);
3497 ast_test_validate(test, strcmp("test", wizard->name) == 0);
3498 ao2_ref(wizard, -1);
3499 wizard = NULL;
3500
3501 ast_test_validate(test,
3502 ast_sorcery_insert_wizard_mapping(sorcery, "test_object_type", "test2", "test2data", 0, 0) == 0);
3503
3504 ast_test_validate(test,
3505 ast_sorcery_insert_wizard_mapping(sorcery, "test_object_type", "test2", "test2data", 0, 0) != 0);
3506
3507 ast_test_validate(test,
3508 ast_sorcery_object_type_insert_wizard(sorcery, "test_object_type", "test2", "test2data2",
3510
3511 ast_test_validate(test,
3512 ast_sorcery_object_type_remove_wizard(sorcery, "test_object_type", "test2", "test2data2") == 0);
3513
3514 ast_test_validate(test,
3515 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, &data) == 0);
3516 ast_test_validate(test, strcmp("test2", wizard->name) == 0);
3517 ast_test_validate(test, strcmp("test2data", data) == 0);
3518 ao2_ref(wizard, -1);
3519 wizard = NULL;
3520
3521 ast_test_validate(test,
3522 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 1, &wizard, NULL) == 0);
3523 ast_test_validate(test, strcmp("test", wizard->name) == 0);
3524 ao2_ref(wizard, -1);
3525 wizard = NULL;
3526
3527 /* Test failures */
3528 ast_test_validate(test,
3529 ast_sorcery_get_wizard_mapping(sorcery, "non-existent-type", 0, &wizard, NULL) != 0);
3530
3531 ast_test_validate(test,
3532 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", -1, &wizard, &data) != 0);
3533
3534 ast_test_validate(test,
3535 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 2, &wizard, NULL) != 0);
3536
3537 ast_test_validate(test,
3538 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 2, NULL, NULL) != 0);
3539
3540 /* Test remove */
3541 /* Should fail */
3542 ast_test_validate(test,
3543 ast_sorcery_remove_wizard_mapping(sorcery, "non-existent-type", "somewizard") != 0);
3544 ast_test_validate(test,
3545 ast_sorcery_remove_wizard_mapping(sorcery, "test_object_type", "somewizard") != 0);
3546
3547 /* should work */
3548 ast_test_validate(test,
3549 ast_sorcery_remove_wizard_mapping(sorcery, "test_object_type", "test") == 0);
3550
3551 ast_test_validate(test,
3552 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
3553
3554 ast_test_validate(test,
3555 ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, &data) == 0);
3556 ast_test_validate(test, strcmp("test2", wizard->name) == 0);
3557 ast_test_validate(test, strcmp("test2data", data) == 0);
3558 ao2_ref(wizard, -1);
3559 wizard = NULL;
3560
3561 return AST_TEST_PASS;
3562}
3563
3565 .name = "test-read-only",
3566 .retrieve_id = sorcery_test_retrieve_id,
3567};
3568
3569AST_TEST_DEFINE(wizard_read_only)
3570{
3575 struct ast_sorcery_wizard *wizard;
3576
3577 switch (cmd) {
3578 case TEST_INIT:
3579 info->name = "wizard_read_only";
3580 info->category = "/main/sorcery/";
3581 info->summary = "sorcery wizard read-only test";
3582 info->description =
3583 "sorcery wizard read-only test";
3584 return AST_TEST_NOT_RUN;
3585 case TEST_EXECUTE:
3586 break;
3587 }
3588
3589 wizard1->load = sorcery_test_load;
3590 wizard1->reload = sorcery_test_load;
3591
3592 if (!(sorcery = ast_sorcery_open())) {
3593 ast_test_status_update(test, "Failed to open a sorcery instance\n");
3594 return AST_TEST_FAIL;
3595 }
3596
3597 ast_sorcery_wizard_register(wizard_read_only);
3599
3600 if ((ast_sorcery_apply_default(sorcery, "test_object_type", "test-read-only", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
3602 ast_test_status_update(test, "Failed to apply object defaults\n");
3603 return AST_TEST_FAIL;
3604 }
3605
3606 ast_test_validate(test,
3607 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
3608
3609 ast_test_validate(test,
3611 "test", "test2data", AST_SORCERY_WIZARD_APPLY_READONLY, &wizard, NULL) == 0);
3612
3613 ast_test_validate(test, strcmp(wizard->name, wizard1->name) == 0);
3614
3615 ast_test_validate(test,
3616 ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 2);
3617
3618 if (!(obj = ast_sorcery_alloc(sorcery, "test_object_type", "blah"))) {
3619 ast_test_status_update(test, "Failed to allocate a known object type\n");
3620 return AST_TEST_FAIL;
3621 }
3622
3623 if (ast_sorcery_create(sorcery, obj) == 0) {
3624 ast_test_status_update(test, "Should not have created object using read-only wizard\n");
3625 return AST_TEST_FAIL;
3626 }
3627
3628 return AST_TEST_PASS;
3629}
3630
3631static int unload_module(void)
3632{
3633 AST_TEST_UNREGISTER(wizard_registration);
3634 AST_TEST_UNREGISTER(sorcery_open);
3635 AST_TEST_UNREGISTER(apply_default);
3637 AST_TEST_UNREGISTER(object_register);
3638 AST_TEST_UNREGISTER(object_register_without_mapping);
3639 AST_TEST_UNREGISTER(object_field_register);
3640 AST_TEST_UNREGISTER(object_fields_register);
3641 AST_TEST_UNREGISTER(object_alloc_with_id);
3642 AST_TEST_UNREGISTER(object_alloc_without_id);
3643 AST_TEST_UNREGISTER(object_copy);
3644 AST_TEST_UNREGISTER(object_copy_native);
3645 AST_TEST_UNREGISTER(object_diff);
3646 AST_TEST_UNREGISTER(object_diff_native);
3647 AST_TEST_UNREGISTER(objectset_create);
3648 AST_TEST_UNREGISTER(objectset_json_create);
3649 AST_TEST_UNREGISTER(objectset_create_regex);
3650 AST_TEST_UNREGISTER(objectset_apply);
3651 AST_TEST_UNREGISTER(objectset_apply_handler);
3652 AST_TEST_UNREGISTER(objectset_apply_invalid);
3653 AST_TEST_UNREGISTER(objectset_transform);
3654 AST_TEST_UNREGISTER(objectset_apply_fields);
3655 AST_TEST_UNREGISTER(extended_fields);
3656 AST_TEST_UNREGISTER(changeset_create);
3657 AST_TEST_UNREGISTER(changeset_create_unchanged);
3658 AST_TEST_UNREGISTER(object_create);
3659 AST_TEST_UNREGISTER(object_retrieve_id);
3660 AST_TEST_UNREGISTER(object_retrieve_field);
3661 AST_TEST_UNREGISTER(object_retrieve_multiple_all);
3662 AST_TEST_UNREGISTER(object_retrieve_multiple_field);
3663 AST_TEST_UNREGISTER(object_retrieve_regex);
3664 AST_TEST_UNREGISTER(object_update);
3665 AST_TEST_UNREGISTER(object_update_uncreated);
3666 AST_TEST_UNREGISTER(object_delete);
3667 AST_TEST_UNREGISTER(object_delete_uncreated);
3668 AST_TEST_UNREGISTER(object_is_stale);
3669 AST_TEST_UNREGISTER(caching_wizard_behavior);
3670 AST_TEST_UNREGISTER(object_type_observer);
3671 AST_TEST_UNREGISTER(configuration_file_wizard);
3672 AST_TEST_UNREGISTER(configuration_file_wizard_with_file_integrity);
3673 AST_TEST_UNREGISTER(configuration_file_wizard_with_criteria);
3674 AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_field);
3675 AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple);
3676 AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple_all);
3677 AST_TEST_UNREGISTER(dialplan_function);
3678 AST_TEST_UNREGISTER(object_field_registered);
3679 AST_TEST_UNREGISTER(global_observation);
3680 AST_TEST_UNREGISTER(instance_observation);
3681 AST_TEST_UNREGISTER(wizard_observation);
3682 AST_TEST_UNREGISTER(wizard_apply_and_insert);
3683 AST_TEST_UNREGISTER(wizard_read_only);
3684
3685 return 0;
3686}
3687
3688static int load_module(void)
3689{
3690 AST_TEST_REGISTER(wizard_apply_and_insert);
3691 AST_TEST_REGISTER(wizard_registration);
3692 AST_TEST_REGISTER(sorcery_open);
3693 AST_TEST_REGISTER(apply_default);
3695 AST_TEST_REGISTER(object_register);
3696 AST_TEST_REGISTER(object_register_without_mapping);
3697 AST_TEST_REGISTER(object_field_register);
3698 AST_TEST_REGISTER(object_fields_register);
3699 AST_TEST_REGISTER(object_alloc_with_id);
3700 AST_TEST_REGISTER(object_alloc_without_id);
3701 AST_TEST_REGISTER(object_copy);
3702 AST_TEST_REGISTER(object_copy_native);
3703 AST_TEST_REGISTER(object_diff);
3704 AST_TEST_REGISTER(object_diff_native);
3705 AST_TEST_REGISTER(objectset_create);
3706 AST_TEST_REGISTER(objectset_json_create);
3707 AST_TEST_REGISTER(objectset_create_regex);
3708 AST_TEST_REGISTER(objectset_apply);
3709 AST_TEST_REGISTER(objectset_apply_handler);
3710 AST_TEST_REGISTER(objectset_apply_invalid);
3711 AST_TEST_REGISTER(objectset_transform);
3712 AST_TEST_REGISTER(objectset_apply_fields);
3713 AST_TEST_REGISTER(extended_fields);
3714 AST_TEST_REGISTER(changeset_create);
3715 AST_TEST_REGISTER(changeset_create_unchanged);
3716 AST_TEST_REGISTER(object_create);
3717 AST_TEST_REGISTER(object_retrieve_id);
3718 AST_TEST_REGISTER(object_retrieve_field);
3719 AST_TEST_REGISTER(object_retrieve_multiple_all);
3720 AST_TEST_REGISTER(object_retrieve_multiple_field);
3721 AST_TEST_REGISTER(object_retrieve_regex);
3722 AST_TEST_REGISTER(object_update);
3723 AST_TEST_REGISTER(object_update_uncreated);
3724 AST_TEST_REGISTER(object_delete);
3725 AST_TEST_REGISTER(object_delete_uncreated);
3726 AST_TEST_REGISTER(object_is_stale);
3727 AST_TEST_REGISTER(caching_wizard_behavior);
3728 AST_TEST_REGISTER(object_type_observer);
3729 AST_TEST_REGISTER(configuration_file_wizard);
3730 AST_TEST_REGISTER(configuration_file_wizard_with_file_integrity);
3731 AST_TEST_REGISTER(configuration_file_wizard_with_criteria);
3732 AST_TEST_REGISTER(configuration_file_wizard_retrieve_field);
3733 AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple);
3734 AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple_all);
3735 AST_TEST_REGISTER(dialplan_function);
3736 AST_TEST_REGISTER(object_field_registered);
3737 AST_TEST_REGISTER(global_observation);
3738 AST_TEST_REGISTER(instance_observation);
3739 AST_TEST_REGISTER(wizard_observation);
3740 AST_TEST_REGISTER(wizard_read_only);
3741
3743}
3744
#define AST_MODULE
const char * str
Definition: app_jack.c:147
ast_mutex_t lock
Definition: app_sla.c:331
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define var
Definition: ast_expr2f.c:605
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 int tmp()
Definition: bt_open.c:389
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:238
char * strsep(char **str, const char *delims)
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:3321
#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:543
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
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:1111
@ CONFIG_FLAG_NOCACHE
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:202
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:206
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
pthread_cond_t ast_cond_t
Definition: lock.h:178
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:589
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:189
#define ast_cond_signal(cond)
Definition: lock.h:203
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
#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:2330
#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:2312
#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:474
#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:1160
#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:2344
#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:537
@ 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:1377
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:568
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2324
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:1128
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2057
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:2489
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:1805
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:1853
void ast_sorcery_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects.
Definition: sorcery.c:1408
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:778
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:1949
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:2386
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:1393
#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:1728
#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:1663
#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:2509
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2145
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:1632
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:790
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:543
void ast_sorcery_global_observer_remove(const struct ast_sorcery_global_observer *callbacks)
Remove a global observer from sorcery.
Definition: sorcery.c:514
#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:1565
int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
Add a global observer to sorcery.
Definition: sorcery.c:498
#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:1442
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:2283
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:520
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:1897
struct ast_sorcery * ast_sorcery_retrieve_by_module_name(const char *module_name)
Retrieves an existing sorcery instance by module name.
Definition: sorcery.c:672
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2233
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition: sorcery.c:1778
@ 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:1139
#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:199
unsigned int flags
Definition: utils.h:200
Iterator for JSON object key/values.
Abstract JSON element (object, array, string, int, ...).
Structure for mutex and tracking information.
Definition: lock.h:135
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:148
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:230
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:941