Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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 */
44 struct test_sorcery_object {
45  SORCERY_OBJECT(details);
46  unsigned int bob;
47  unsigned int joe;
48  struct ast_variable *jim;
49  struct ast_variable *jack;
50 };
51 
52 /*! \brief Internal function to destroy a test object */
53 static 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 */
61 static 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 */
93 static 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 */
104 static 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 */
111 static 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 */
121 static 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 */
143  struct test_sorcery_object object;
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 */
171 static 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 */
178 static struct sorcery_test_caching cache = { 0, };
179 
180 /*! \brief Global scope observer structure for testing */
182 
183 static void *wizard2_data;
184 
185 static void *sorcery_test_open(const char *data)
186 {
187  wizard2_data = (void *)data;
188  return wizard2_data;
189 }
190 
191 static void sorcery_test_close(void *data)
192 {
193 
194 }
195 
196 static 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 
204 static void *sorcery_test_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
205 {
206  return (cache.created && !cache.deleted) ? ast_sorcery_alloc(sorcery, type, id) : NULL;
207 }
208 
209 static int sorcery_test_update(const struct ast_sorcery *sorcery, void *data, void *object)
210 {
211  cache.updated = 1;
212  return 0;
213 }
214 
215 static int sorcery_test_delete(const struct ast_sorcery *sorcery, void *data, void *object)
216 {
217  cache.deleted = 1;
218  return 0;
219 }
220 
221 static 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 
247 static void sorcery_observer_created(const void *object)
248 {
250  observer.created = object;
252 }
253 
254 static void sorcery_observer_updated(const void *object)
255 {
257  observer.updated = object;
259 }
260 
261 static void sorcery_observer_deleted(const void *object)
262 {
264  observer.deleted = object;
266 }
267 
268 static void sorcery_observer_loaded(const char *object_type)
269 {
271  observer.loaded = 1;
273 }
274 
275 /*! \brief Test sorcery observer implementation */
276 static 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*/
284 static 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 */
294 static 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, ","))) {
302  ast_variable_list_append(&tobj->jack, ast_variable_new("jack", val, ""));
303  }
304  return 0;
305 }
306 
307 static 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 
316 static 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  }
326  ast_str_truncate(str, -1);
327  *buf = ast_strdup(ast_str_buffer(str));
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 
340  if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
342  ast_sorcery_unref(sorcery);
343  return NULL;
344  }
345 
346  ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
347  ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
348  ast_sorcery_object_field_register_custom_nodoc(sorcery, "test", "jim", "444", jim_handler, NULL, jim_vl, 0, 0);
349  ast_sorcery_object_field_register_custom_nodoc(sorcery, "test", "jack", "888,999", jack_handler, jack_str, NULL, 0, 0);
350 
351  return sorcery;
352 }
353 
354 AST_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 
368  if (ast_sorcery_wizard_register(&test_wizard)) {
369  ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
370  return AST_TEST_FAIL;
371  }
372 
373  if (!ast_sorcery_wizard_register(&test_wizard)) {
374  ast_test_status_update(test, "Successfully registered a sorcery wizard twice, which is bad\n");
375  return AST_TEST_FAIL;
376  }
377 
378  if (ast_sorcery_wizard_unregister(&test_wizard)) {
379  ast_test_status_update(test, "Failed to unregister a perfectly valid sorcery wizard\n");
380  return AST_TEST_FAIL;
381  }
382 
383  if (!ast_sorcery_wizard_unregister(&test_wizard)) {
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 
391 AST_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 
419  if (!(sorcery2 = ast_sorcery_retrieve_by_module_name(AST_MODULE))) {
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 
465 AST_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 
486  if (ast_sorcery_apply_default(sorcery, "test", "dummy", NULL) != AST_SORCERY_APPLY_FAIL) {
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 {
506  struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
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");
529  ast_config_destroy(config);
530  return AST_TEST_NOT_RUN;
531  }
532 
533  ast_config_destroy(config);
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 
548 AST_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 
587 AST_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 
616 AST_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 
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 
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 
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 
665 AST_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 
714 AST_TEST_DEFINE(object_alloc_with_id)
715 {
716  int res = AST_TEST_PASS;
718  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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;
740  } else if (ast_strlen_zero(ast_sorcery_object_get_id(obj))) {
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;
746  } else if (ast_strlen_zero(ast_sorcery_object_get_type(obj))) {
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 
760 AST_TEST_DEFINE(object_alloc_without_id)
761 {
762  int res = AST_TEST_PASS;
764  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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;
786  } else if (ast_strlen_zero(ast_sorcery_object_get_id(obj))) {
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 
795 AST_TEST_DEFINE(object_copy)
796 {
797  int res = AST_TEST_PASS;
799  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 ogirinal '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 
862 AST_TEST_DEFINE(object_copy_native)
863 {
864  int res = AST_TEST_PASS;
866  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
919 AST_TEST_DEFINE(object_diff)
920 {
922  RAII_VAR(struct test_sorcery_object *, obj1, NULL, ao2_cleanup);
923  RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
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 
1003 AST_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 
1069 AST_TEST_DEFINE(objectset_create)
1070 {
1071  int res = AST_TEST_PASS;
1073  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1134 AST_TEST_DEFINE(objectset_json_create)
1135 {
1136  int res = AST_TEST_PASS;
1138  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1201 AST_TEST_DEFINE(objectset_create_regex)
1202 {
1203  int res = AST_TEST_PASS;
1205  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1259 AST_TEST_DEFINE(objectset_apply)
1260 {
1261  int res = AST_TEST_PASS;
1263  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1302 AST_TEST_DEFINE(objectset_apply_handler)
1303 {
1304  int res = AST_TEST_PASS;
1306  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1356 AST_TEST_DEFINE(objectset_apply_invalid)
1357 {
1359  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1398 AST_TEST_DEFINE(objectset_transform)
1399 {
1401  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1421  if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
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 
1463 AST_TEST_DEFINE(objectset_apply_fields)
1464 {
1465  int res = AST_TEST_PASS;
1467  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1514 AST_TEST_DEFINE(extended_fields)
1515 {
1516  int res = AST_TEST_PASS;
1518  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1579 AST_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 
1650 AST_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);
1654  RAII_VAR(struct ast_variable *, same, 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 
1716 AST_TEST_DEFINE(object_create)
1717 {
1719  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1751 AST_TEST_DEFINE(object_retrieve_id)
1752 {
1754  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1808 AST_TEST_DEFINE(object_retrieve_field)
1809 {
1811  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1863  if ((obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
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 
1871 AST_TEST_DEFINE(object_retrieve_multiple_all)
1872 {
1874  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1927 AST_TEST_DEFINE(object_retrieve_multiple_field)
1928 {
1930  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
1993 AST_TEST_DEFINE(object_retrieve_regex)
1994 {
1996  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2061 AST_TEST_DEFINE(object_update)
2062 {
2064  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2117 AST_TEST_DEFINE(object_update_uncreated)
2118 {
2120  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2152 AST_TEST_DEFINE(object_delete)
2153 {
2155  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2199 AST_TEST_DEFINE(object_delete_uncreated)
2200 {
2202  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2234 AST_TEST_DEFINE(object_is_stale)
2235 {
2237  RAII_VAR(struct ast_sorcery_wizard *, wizard1, &test_wizard, ast_sorcery_wizard_unregister);
2238  RAII_VAR(struct ast_sorcery_wizard *, wizard2, &test_wizard2, ast_sorcery_wizard_unregister);
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 
2255  if (ast_sorcery_wizard_register(&test_wizard)) {
2256  ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
2257  return AST_TEST_FAIL;
2258  }
2259 
2260  if (ast_sorcery_wizard_register(&test_wizard2)) {
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 
2270  if ((ast_sorcery_apply_default(sorcery, "test", "test", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
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 
2312 AST_TEST_DEFINE(caching_wizard_behavior)
2313 {
2314  struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2315  struct ast_config *config;
2317  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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");
2340  ast_config_destroy(config);
2341  return AST_TEST_NOT_RUN;
2342  }
2343 
2344  ast_config_destroy(config);
2345 
2346  if (ast_sorcery_wizard_register(&test_wizard)) {
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 
2413 end:
2415  sorcery = NULL;
2416 
2417  if (ast_sorcery_wizard_unregister(&test_wizard)) {
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 
2425 AST_TEST_DEFINE(object_type_observer)
2426 {
2428  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2453  if (ast_sorcery_observer_add(sorcery, "test", &test_observer)) {
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 
2465  observer.created = NULL;
2466  observer.updated = NULL;
2467  observer.deleted = NULL;
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 
2560 end:
2561  observer.created = NULL;
2562  observer.updated = NULL;
2563  observer.deleted = NULL;
2566 
2567  return res;
2568 }
2569 
2570 AST_TEST_DEFINE(configuration_file_wizard)
2571 {
2572  struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2573  struct ast_config *config;
2575  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2594  ast_config_destroy(config);
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 
2633 AST_TEST_DEFINE(configuration_file_wizard_with_file_integrity)
2634 {
2635  struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2636  struct ast_config *config;
2638  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2657  ast_config_destroy(config);
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 
2687 AST_TEST_DEFINE(configuration_file_wizard_with_criteria)
2688 {
2689  struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2690  struct ast_config *config;
2692  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2711  ast_config_destroy(config);
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 
2745 AST_TEST_DEFINE(configuration_file_wizard_retrieve_field)
2746 {
2747  struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
2748  struct ast_config *config;
2750  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2770  ast_config_destroy(config);
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 
2803 AST_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 
2828  ast_config_destroy(config);
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 
2880 AST_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 
2904  ast_config_destroy(config);
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 
2937 AST_TEST_DEFINE(dialplan_function)
2938 {
2940  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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 
2977  ast_str_reset(buf);
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 
2985  ast_str_reset(buf);
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 
2993  ast_str_reset(buf);
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 
3001  ast_str_reset(buf);
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 
3009  ast_str_reset(buf);
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 
3022  ast_str_reset(buf);
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 
3035  ast_str_reset(buf);
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 
3047  ast_str_reset(buf);
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 
3060  ast_str_reset(buf);
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 
3073  ast_str_reset(buf);
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 
3086  ast_str_reset(buf);
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 
3094  ast_str_reset(buf);
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 
3107 AST_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 
3149 static int event_observed;
3150 
3151 static 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 
3158 static void instance_observer(const char *name, struct ast_sorcery *sorcery)
3159 {
3160  if (!strcmp(name, "test_sorcery")) {
3161  event_observed = 1;
3162  }
3163 }
3164 
3165 AST_TEST_DEFINE(global_observation)
3166 {
3167  RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
3169  const struct ast_sorcery_global_observer 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;
3209  ast_sorcery_wizard_register(&test_wizard);
3210  ast_test_validate(test, (event_observed == 0), "Observer removed failed");
3211 
3212  return AST_TEST_PASS;
3213 }
3214 
3215 static void instance_loaded_observer(const char *name, const struct ast_sorcery *sorcery,
3216  int reloaded)
3217 {
3218  if (!strcmp(name, "test_sorcery") && !reloaded) {
3219  event_observed++;
3220  }
3221 }
3222 
3223 static void instance_reloaded_observer(const char *name,
3224  const struct ast_sorcery *sorcery, int reloaded)
3225 {
3226  if (!strcmp(name, "test_sorcery") && reloaded) {
3227  event_observed++;
3228  }
3229 }
3230 
3231 static 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")) {
3237  event_observed++;
3238  }
3239 }
3240 
3241 static void object_type_registered_observer(const char *name,
3242  struct ast_sorcery *sorcery, const char *object_type)
3243 {
3244  if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")) {
3245  event_observed++;
3246  }
3247 }
3248 
3249 static 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) {
3254  event_observed++;
3255  }
3256 }
3257 
3258 static 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) {
3263  event_observed++;
3264  }
3265 }
3266 
3267 AST_TEST_DEFINE(instance_observation)
3268 {
3270  struct ast_sorcery_instance_observer 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  }
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 */
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;
3321  ast_sorcery_internal_object_register(sorcery, "test_object_type",
3323  ast_test_validate(test, (event_observed == 1), "Object type registered failed");
3324 
3325  /* Test object type load */
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 */
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 
3357 static 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) {
3362  event_observed++;
3363  }
3364 }
3365 
3366 static void sorcery_test_load(void *data, const struct ast_sorcery *sorcery, const char *type)
3367 {
3368  return;
3369 }
3370 
3371 static 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) {
3376  event_observed++;
3377  }
3378 }
3379 
3380 AST_TEST_DEFINE(wizard_observation)
3381 {
3383  RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
3384  struct ast_sorcery_wizard_observer 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 */
3406  ast_sorcery_wizard_observer_add(wizard, &observer);
3407  ast_sorcery_wizard_observer_remove(wizard, &observer);
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);
3420  ast_sorcery_internal_object_register(sorcery, "test_object_type",
3422 
3423  /* Test wizard loading and loaded */
3424  ast_sorcery_wizard_observer_add(wizard, &observer);
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");
3432  ast_sorcery_wizard_observer_remove(wizard, &observer);
3433  ast_test_validate(test, (event_observed == 0), "Wizard reloaded failed");
3434 
3435  /* Test wizard reloading and reloaded */
3438  ast_sorcery_wizard_observer_add(wizard, &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");
3446  ast_sorcery_wizard_observer_remove(wizard, &observer);
3447  ast_test_validate(test, (event_observed == 2), "Wizard reloaded failed");
3448 
3449  return AST_TEST_PASS;
3450 }
3451 
3452 AST_TEST_DEFINE(wizard_apply_and_insert)
3453 {
3455  RAII_VAR(struct ast_sorcery_wizard *, wizard1, &test_wizard, ast_sorcery_wizard_unregister);
3456  RAII_VAR(struct ast_sorcery_wizard *, wizard2, &test_wizard2, ast_sorcery_wizard_unregister);
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 
3483  ast_sorcery_wizard_register(wizard1);
3484  ast_sorcery_wizard_register(wizard2);
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 
3569 AST_TEST_DEFINE(wizard_read_only)
3570 {
3572  RAII_VAR(struct ast_sorcery_wizard *, wizard_read_only, &test_read_only_wizard, ast_sorcery_wizard_unregister);
3573  RAII_VAR(struct ast_sorcery_wizard *, wizard1, &test_wizard, ast_sorcery_wizard_unregister);
3574  RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
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);
3598  ast_sorcery_wizard_register(wizard1);
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,
3610  ast_sorcery_object_type_apply_wizard(sorcery, "test_object_type",
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 
3631 static 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 
3688 static 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 
3742  return AST_MODULE_LOAD_SUCCESS;
3743 }
3744 
static void object_type_registered_observer(const char *name, struct ast_sorcery *sorcery, const char *object_type)
#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:679
static int jack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition: test_sorcery.c:294
struct ast_variable * next
static const char type[]
Definition: chan_ooh323.c:109
const void * updated
Pointer to the update object.
Definition: test_sorcery.c:158
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
static struct ast_variable * test_sorcery_transform(struct ast_variable *set)
Internal function for object set transformation.
Definition: test_sorcery.c:67
#define ast_sorcery_remove_wizard_mapping(sorcery, type, name)
Remove an object wizard mapping.
Definition: sorcery.h:758
#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
Asterisk main include file. File version handling, generic pbx functions.
Dummy sorcery object.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void test_sorcery_object_destroy(void *obj)
Internal function to destroy a test object.
Definition: test_sorcery.c:53
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
#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:647
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
Definition: ast_expr2.c:325
char * config
Definition: conf2ael.c:66
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
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)
Interface for the global sorcery observer.
Definition: sorcery.h:220
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
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 int jim_vl(const void *obj, struct ast_variable **fields)
Definition: test_sorcery.c:307
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
Iterator for JSON object key/values.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static int unload_module(void)
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:429
static int tmp()
Definition: bt_open.c:389
ast_cond_t cond
Condition for notification.
Definition: test_sorcery.c:152
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:3154
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
void(* created)(const void *object)
Callback for when an object is created.
Definition: sorcery.h:334
Test Framework API.
Perform no matching, return all objects.
Definition: sorcery.h:123
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
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
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
Full structure for sorcery.
Definition: sorcery.c:230
Type for a default handler that should do nothing.
void(* wizard_registered)(const char *name, const struct ast_sorcery_wizard *wizard)
Callback after an wizard is registered.
Definition: sorcery.h:225
static void instance_observer(const char *name, struct ast_sorcery *sorcery)
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:1091
#define ast_cond_init(cond, attr)
Definition: lock.h:199
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
static int copy(char *infile, char *outfile)
Utility function to copy a file.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#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:1040
#define ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:456
Return all matching objects.
Definition: sorcery.h:120
#define ast_mutex_lock(a)
Definition: lock.h:187
static void object_type_reloaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * str
Definition: app_jack.c:147
static int jim_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition: test_sorcery.c:284
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
const char * args
#define NULL
Definition: resample.c:96
static void sorcery_observer_deleted(const void *object)
Definition: test_sorcery.c:261
char * end
Definition: eagi_proxy.c:73
#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:563
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
int value
Definition: syslog.c:37
const char * name
Name of the wizard.
Definition: sorcery.h:278
int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
Add a global observer to sorcery.
Definition: sorcery.c:498
unsigned int updated
Whether the object has been updated in the cache or not.
Definition: test_sorcery.c:134
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
#define ast_cond_signal(cond)
Definition: lock.h:201
static void * wizard2_data
Definition: test_sorcery.c:183
static void sorcery_observer_loaded(const char *object_type)
Definition: test_sorcery.c:268
static int event_observed
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
void(* instance_loaded)(const char *name, const struct ast_sorcery *sorcery, int reloaded)
Callback after instance is loaded/reloaded.
Definition: sorcery.h:243
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2324
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:738
pthread_cond_t ast_cond_t
Definition: lock.h:176
#define ast_strlen_zero(foo)
Definition: strings.h:52
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
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1502
void(* wizard_mapped)(const char *name, struct ast_sorcery *sorcery, const char *object_type, struct ast_sorcery_wizard *wizard, const char *wizard_args, void *wizard_data)
Callback after a wizard is mapped to an object_type.
Definition: sorcery.h:247
const void * deleted
Pointer to the deleted object.
Definition: test_sorcery.c:161
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
void(* wizard_loaded)(const char *name, const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
Callback after a wizard is loaded/reloaded for any type.
Definition: sorcery.h:271
unsigned int is_stale
Whether the object is stale or not.
Definition: test_sorcery.c:140
void ast_sorcery_global_observer_remove(const struct ast_sorcery_global_observer *callbacks)
Remove a global observer from sorcery.
Definition: sorcery.c:514
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
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
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
static int jack_str(const void *obj, const intptr_t *args, char **buf)
Definition: test_sorcery.c:316
Structure for registered object type.
Definition: sorcery.c:148
Asterisk JSON abstraction layer.
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:587
void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *wizard, const struct ast_sorcery_wizard_observer *callbacks)
Remove an observer from a sorcery wizard.
Definition: sorcery.c:568
struct ast_json * ast_json_object_iter_value(struct ast_json_iter *iter)
Get the value from an iterator.
Definition: json.c:445
#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:911
Type for default option handler for unsigned integers.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
Interface for the sorcery instance observer.
Definition: sorcery.h:237
unsigned int joe
Definition: test_sorcery.c:47
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
ast_mutex_t lock
Definition: app_meetme.c:1091
Test structure for observer.
Definition: test_sorcery.c:147
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
struct ast_variable * jack
Definition: test_sorcery.c:49
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static int apply_handler_called
Global scope apply handler integer to make sure it executed.
Definition: test_sorcery.c:168
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
const char * ast_json_object_iter_key(struct ast_json_iter *iter)
Get the key from an iterator.
Definition: json.c:441
static void * sorcery_test_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Definition: test_sorcery.c:204
#define ast_variable_new(name, value, filename)
const void * created
Pointer to the created object.
Definition: test_sorcery.c:155
static void * sorcery_test_open(const char *data)
Definition: test_sorcery.c:185
Core PBX routines and definitions.
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
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
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
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
Default retrieval flags.
Definition: sorcery.h:117
Test structure for caching.
Definition: test_sorcery.c:129
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
Definition: sorcery.h:383
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2233
static void * test_sorcery_object_alloc(const char *id)
Internal function to allocate a test object.
Definition: test_sorcery.c:61
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
Definition: sorcery.h:868
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
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
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
static int sorcery_test_create(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_sorcery.c:196
Interface for a sorcery object type observer.
Definition: sorcery.h:332
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
def info(msg)
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:477
static void instance_reloaded_observer(const char *name, const struct ast_sorcery *sorcery, int reloaded)
static struct ast_sorcery * alloc_and_initialize_sorcery(void)
Definition: test_sorcery.c:332
#define ast_cond_destroy(cond)
Definition: lock.h:200
static struct sorcery_test_observer observer
Global scope observer structure for testing.
Definition: test_sorcery.c:181
void(* wizard_loading)(const char *name, const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
Callback before a wizard is loaded/reloaded for any type.
Definition: sorcery.h:267
static int sorcery_test_delete(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_sorcery.c:215
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
unsigned int bob
Definition: test_sorcery.c:46
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1136
static void wizard_reloaded_observer(const char *name, const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
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
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
static int sorcery_test_update(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_sorcery.c:209
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
#define ast_sorcery_object_type_remove_wizard(sorcery, object_type_name, wizard_type_name, wizard_args)
Remove an object wizard mapping.
Definition: sorcery.h:725
static void object_type_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
static const struct ast_sorcery_observer test_observer
Test sorcery observer implementation.
Definition: test_sorcery.c:276
static void wizard_loaded_observer(const char *name, const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
Structure used to handle boolean flags.
Definition: utils.h:199
Support for logging to various files, console and syslog Configuration in file logger.conf.
static void sorcery_test_load(void *data, const struct ast_sorcery *sorcery, const char *type)
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
Interface for a sorcery wizard.
Definition: sorcery.h:276
void ast_sorcery_load(const struct ast_sorcery *sorcery)
Inform any wizards to load persistent objects.
Definition: sorcery.c:1377
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:653
static struct ast_sorcery_wizard test_read_only_wizard
void ast_sorcery_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects.
Definition: sorcery.c:1408
void(* object_type_loaded)(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
Callback after any object_type is loaded/reloaded.
Definition: sorcery.h:260
char * strsep(char **str, const char *delims)
static void wizard_observer(const char *name, const struct ast_sorcery_wizard *wizard)
static struct ast_sorcery * sorcery
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 ao2_cleanup(obj)
Definition: astobj2.h:1958
Interface for the sorcery wizard observer.
Definition: sorcery.h:265
#define AST_MODULE
static void sorcery_test_close(void *data)
Definition: test_sorcery.c:191
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition: sorcery.c:1778
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
unsigned int loaded
Whether the type has been loaded.
Definition: test_sorcery.c:164
#define ast_sorcery_open()
Definition: sorcery.h:408
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
Abstract JSON element (object, array, string, int, ...).
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
unsigned int created
Whether the object has been created in the cache or not.
Definition: test_sorcery.c:131
static void sorcery_observer_created(const void *object)
Definition: test_sorcery.c:247
#define ast_mutex_init(pmutex)
Definition: lock.h:184
Generic container type.
static int apply_config(struct aco_info *info)
static struct sorcery_test_caching cache
Global scope caching structure for testing.
Definition: test_sorcery.c:178
#define ast_mutex_destroy(a)
Definition: lock.h:186
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:1022
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
AST_TEST_DEFINE(wizard_registration)
Definition: test_sorcery.c:354
struct ast_variable * jim
Definition: test_sorcery.c:48
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
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
Asterisk module definitions.
void(* instance_loading)(const char *name, const struct ast_sorcery *sorcery, int reloaded)
Callback before instance is loaded/reloaded.
Definition: sorcery.h:239
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
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Definition: main/config.c:545
ast_mutex_t lock
Lock for notification.
Definition: test_sorcery.c:149
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:204
#define ast_variable_list_append(head, new_var)
struct ast_sorcery * ast_sorcery_retrieve_by_module_name(const char *module)
Retrieves an existing sorcery instance by module name.
Definition: sorcery.c:672
Structure for mutex and tracking information.
Definition: lock.h:135
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
static int load_module(void)
static struct ast_sorcery_wizard test_wizard2
Definition: test_sorcery.c:236
void(* object_type_loading)(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
Callback before any object_type is loaded/reloaded.
Definition: sorcery.h:256
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
Sorcery Data Access Layer API.
#define ast_mutex_unlock(a)
Definition: lock.h:188
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2145
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:437
unsigned int deleted
Whether the object has been deleted from the cache or not.
Definition: test_sorcery.c:137
static int sorcery_test_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_sorcery.c:221