Asterisk - The Open Source Telephony Project GIT-master-f36a736
test_sorcery_realtime.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \brief Sorcery Unit Tests
22 *
23 * \author Joshua Colp <jcolp@digium.com>
24 *
25 */
26
27/*** MODULEINFO
28 <depend>TEST_FRAMEWORK</depend>
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/test.h"
35#include "asterisk/module.h"
36#include "asterisk/sorcery.h"
37#include "asterisk/astdb.h"
38#include "asterisk/logger.h"
39
40/*! \brief Configuration structure which contains all stored objects */
42
43static struct ast_variable *realtime_sorcery(const char *database, const char *table, const struct ast_variable *fields)
44{
45 char *object_id = NULL;
46
47 while ((object_id = ast_category_browse(realtime_objects, object_id))) {
48 if (!ast_variable_lists_match(ast_category_root(realtime_objects, object_id), fields, 0)) {
49 continue;
50 }
51
53 }
54
55 return NULL;
56}
57
58static struct ast_config *realtime_sorcery_multi(const char *database, const char *table, const struct ast_variable *fields)
59{
60 struct ast_config *objects;
61 char *object_id = NULL;
62
63 if (!(objects = ast_config_new())) {
64 return NULL;
65 }
66
67 while ((object_id = ast_category_browse(realtime_objects, object_id))) {
68 struct ast_category *object;
69 const struct ast_variable *object_fields = ast_category_root(realtime_objects, object_id);
70
71 if (!ast_variable_lists_match(object_fields, fields, 0)) {
72 continue;
73 }
74
75 if (!(object = ast_category_new("", "", 0))) {
76 ast_config_destroy(objects);
77 return NULL;
78 }
79
81 ast_category_append(objects, object);
82 }
83
84 return objects;
85}
86
87static int realtime_sorcery_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
88{
89 struct ast_category *object, *found;
90
91 if (!(found = ast_category_get(realtime_objects, entity, NULL))) {
92 return 0;
93 } else if (!(object = ast_category_new(entity, "", 0))) {
94 return -1;
95 }
96
98 ast_variable_append(object, ast_variables_dup((struct ast_variable*)fields));
99 ast_variable_append(object, ast_variable_new(keyfield, entity, ""));
101
102 return 1;
103}
104
105static int realtime_sorcery_store(const char *database, const char *table, const struct ast_variable *fields)
106{
107 /* The key field is explicit within res_sorcery_realtime */
108 const struct ast_variable *keyfield = ast_variable_find_variable_in_list(fields, "id");
109 struct ast_category *object;
110
111 if (!keyfield || ast_category_exist(realtime_objects, keyfield->value, NULL) || !(object = ast_category_new(keyfield->value, "", 0))) {
112 return -1;
113 }
114
115 ast_variable_append(object, ast_variables_dup((struct ast_variable*)fields));
117
118 return 1;
119}
120
121static int realtime_sorcery_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
122{
123 struct ast_category *found;
124 if (!(found = ast_category_get(realtime_objects, entity, NULL))) {
125 return 0;
126 }
127
129
130 return 1;
131}
132
134 .name = "sorcery_realtime_test",
135 .realtime_func = realtime_sorcery,
136 .realtime_multi_func = realtime_sorcery_multi,
137 .update_func = realtime_sorcery_update,
138 .store_func = realtime_sorcery_store,
139 .destroy_func = realtime_sorcery_destroy,
140};
141
142/*! \brief Dummy sorcery object */
143struct test_sorcery_object {
145 unsigned int bob;
146 unsigned int joe;
147};
148
149/*! \brief Internal function to allocate a test object */
150static void *test_sorcery_object_alloc(const char *id)
151{
152 return ast_sorcery_generic_alloc(sizeof(struct test_sorcery_object), NULL);
153}
154
156{
157 struct ast_sorcery *sorcery;
158
159 if (!(sorcery = ast_sorcery_open())) {
160 return NULL;
161 }
162
163 if ((ast_sorcery_apply_default(sorcery, "test", "realtime", table) != AST_SORCERY_APPLY_SUCCESS) ||
167 return NULL;
168 }
169
172
173 return sorcery;
174}
175
177{
181}
182
183AST_TEST_DEFINE(object_create)
184{
187
188 switch (cmd) {
189 case TEST_INIT:
190 info->name = "object_create";
191 info->category = "/res/sorcery_realtime/";
192 info->summary = "sorcery realtime object creation unit test";
193 info->description =
194 "Test object creation in sorcery using realtime wizard";
195 return AST_TEST_NOT_RUN;
196 case TEST_EXECUTE:
197 break;
198 }
199
200 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
201 ast_test_status_update(test, "Failed to open sorcery structure\n");
202 return AST_TEST_FAIL;
203 }
204
205 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
206 ast_test_status_update(test, "Failed to allocate a known object type\n");
207 return AST_TEST_FAIL;
208 }
209
210 if (ast_sorcery_create(sorcery, obj)) {
211 ast_test_status_update(test, "Failed to create object using realtime wizard\n");
212 return AST_TEST_FAIL;
213 }
214
215 return AST_TEST_PASS;
216}
217
218AST_TEST_DEFINE(object_retrieve_id)
219{
222
223 switch (cmd) {
224 case TEST_INIT:
225 info->name = "object_retrieve_id";
226 info->category = "/res/sorcery_realtime/";
227 info->summary = "sorcery object retrieval using id unit test";
228 info->description =
229 "Test object retrieval using id in sorcery with realtime wizard";
230 return AST_TEST_NOT_RUN;
231 case TEST_EXECUTE:
232 break;
233 }
234
235 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
236 ast_test_status_update(test, "Failed to open sorcery structure\n");
237 return AST_TEST_FAIL;
238 }
239
240 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
241 ast_test_status_update(test, "Failed to allocate a known object type\n");
242 return AST_TEST_FAIL;
243 }
244
245 if (ast_sorcery_create(sorcery, obj)) {
246 ast_test_status_update(test, "Failed to create object using astdb wizard\n");
247 return AST_TEST_FAIL;
248 }
249
250 ao2_cleanup(obj);
251
252 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
253 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
254 return AST_TEST_FAIL;
255 }
256
257 if (ast_sorcery_create(sorcery, obj)) {
258 ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
259 return AST_TEST_FAIL;
260 }
261
262 ao2_cleanup(obj);
263
264 if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
265 ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
266 return AST_TEST_FAIL;
267 } else if (strcmp(ast_sorcery_object_get_id(obj), "blah")) {
268 ast_test_status_update(test, "Retrieved object does not have correct id\n");
269 return AST_TEST_FAIL;
270 }
271
272 return AST_TEST_PASS;
273}
274
275AST_TEST_DEFINE(object_retrieve_field)
276{
279 RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "42", ""), ast_variables_destroy);
280
281 switch (cmd) {
282 case TEST_INIT:
283 info->name = "object_retrieve_field";
284 info->category = "/res/sorcery_realtime/";
285 info->summary = "sorcery object retrieval using a specific field unit test";
286 info->description =
287 "Test object retrieval using a specific field in sorcery with realtime wizard";
288 return AST_TEST_NOT_RUN;
289 case TEST_EXECUTE:
290 break;
291 }
292
293 if (!fields) {
294 ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
295 return AST_TEST_FAIL;
296 }
297
298 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
299 ast_test_status_update(test, "Failed to open sorcery structure\n");
300 return AST_TEST_FAIL;
301 }
302
303 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
304 ast_test_status_update(test, "Failed to allocate a known object type\n");
305 return AST_TEST_FAIL;
306 }
307
308 obj->joe = 42;
309
310 if (ast_sorcery_create(sorcery, obj)) {
311 ast_test_status_update(test, "Failed to create object using realtime wizard\n");
312 return AST_TEST_FAIL;
313 }
314
315 ao2_cleanup(obj);
316
318 ast_test_status_update(test, "Failed to retrieve properly created object using 'joe' field\n");
319 return AST_TEST_FAIL;
320 }
321
322 ao2_cleanup(obj);
323 ast_variables_destroy(fields);
324
325 if (!(fields = ast_variable_new("joe", "49", ""))) {
326 ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
327 return AST_TEST_FAIL;
328 }
329
331 ast_test_status_update(test, "Retrieved an object using a field with an in-correct value... that should not happen\n");
332 return AST_TEST_FAIL;
333 }
334
335 return AST_TEST_PASS;
336}
337
338AST_TEST_DEFINE(object_retrieve_multiple_all)
339{
342 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
343
344 switch (cmd) {
345 case TEST_INIT:
346 info->name = "object_retrieve_multiple_all";
347 info->category = "/res/sorcery_realtime/";
348 info->summary = "sorcery multiple object retrieval unit test";
349 info->description =
350 "Test multiple object retrieval in sorcery using realtime wizard";
351 return AST_TEST_NOT_RUN;
352 case TEST_EXECUTE:
353 break;
354 }
355
356 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
357 ast_test_status_update(test, "Failed to open sorcery structure\n");
358 return AST_TEST_FAIL;
359 }
360
361 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
362 ast_test_status_update(test, "Failed to allocate a known object type\n");
363 return AST_TEST_FAIL;
364 }
365
366 if (ast_sorcery_create(sorcery, obj)) {
367 ast_test_status_update(test, "Failed to create object using realtime wizard\n");
368 return AST_TEST_FAIL;
369 }
370
371 ao2_cleanup(obj);
372
373 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
374 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
375 return AST_TEST_FAIL;
376 }
377
378 if (ast_sorcery_create(sorcery, obj)) {
379 ast_test_status_update(test, "Failed to create second object using realtime wizard\n");
380 return AST_TEST_FAIL;
381 }
382
384 ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
385 return AST_TEST_FAIL;
386 } else if (ao2_container_count(objects) != 2) {
387 ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
388 return AST_TEST_FAIL;
389 }
390
391 return AST_TEST_PASS;
392}
393
394AST_TEST_DEFINE(object_retrieve_multiple_all_nofetch)
395{
398 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
399
400 switch (cmd) {
401 case TEST_INIT:
402 info->name = "object_retrieve_multiple_all_nofetch";
403 info->category = "/res/sorcery_realtime/";
404 info->summary = "sorcery multiple object retrieval unit test";
405 info->description =
406 "Test multiple object retrieval in sorcery using realtime wizard";
407 return AST_TEST_NOT_RUN;
408 case TEST_EXECUTE:
409 break;
410 }
411
412 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test,allow_unqualified_fetch=no"))) {
413 ast_test_status_update(test, "Failed to open sorcery structure\n");
414 return AST_TEST_FAIL;
415 }
416
417 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
418 ast_test_status_update(test, "Failed to allocate a known object type\n");
419 return AST_TEST_FAIL;
420 }
421
422 if (ast_sorcery_create(sorcery, obj)) {
423 ast_test_status_update(test, "Failed to create object using realtime wizard\n");
424 return AST_TEST_FAIL;
425 }
426
427 ao2_cleanup(obj);
428
429 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
430 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
431 return AST_TEST_FAIL;
432 }
433
434 if (ast_sorcery_create(sorcery, obj)) {
435 ast_test_status_update(test, "Failed to create second object using realtime wizard\n");
436 return AST_TEST_FAIL;
437 }
438
440 ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
441 return AST_TEST_FAIL;
442 } else if (ao2_container_count(objects) != 0) {
443 ast_test_status_update(test, "Received a container with objects in it when there should be none\n");
444 return AST_TEST_FAIL;
445 }
446
447 return AST_TEST_PASS;
448}
449
450
451AST_TEST_DEFINE(object_retrieve_multiple_field)
452{
455 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
456 RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "6", ""), ast_variables_destroy);
457
458 switch (cmd) {
459 case TEST_INIT:
460 info->name = "object_retrieve_multiple_field";
461 info->category = "/res/sorcery_realtime/";
462 info->summary = "sorcery multiple object retrieval unit test";
463 info->description =
464 "Test multiple object retrieval in sorcery using fields using realtime wizard";
465 return AST_TEST_NOT_RUN;
466 case TEST_EXECUTE:
467 break;
468 }
469
470 if (!fields) {
471 ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
472 return AST_TEST_FAIL;
473 }
474
475 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
476 ast_test_status_update(test, "Failed to open sorcery structure\n");
477 return AST_TEST_FAIL;
478 }
479
480 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
481 ast_test_status_update(test, "Failed to allocate a known object type\n");
482 return AST_TEST_FAIL;
483 }
484
485 obj->joe = 6;
486
487 if (ast_sorcery_create(sorcery, obj)) {
488 ast_test_status_update(test, "Failed to create object using realtime wizard\n");
489 return AST_TEST_FAIL;
490 }
491
492 if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
493 ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
494 return AST_TEST_FAIL;
495 } else if (ao2_container_count(objects) != 1) {
496 ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
497 return AST_TEST_FAIL;
498 }
499
500 ao2_cleanup(objects);
501 ast_variables_destroy(fields);
502
503 if (!(fields = ast_variable_new("joe", "7", ""))) {
504 ast_test_status_update(test, "Failed to create fields for multiple retrieval\n");
505 return AST_TEST_FAIL;
506 } else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
507 ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
508 return AST_TEST_FAIL;
509 } else if (ao2_container_count(objects)) {
510 ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
511 return AST_TEST_FAIL;
512 }
513
514 return AST_TEST_PASS;
515}
516
517AST_TEST_DEFINE(object_retrieve_regex)
518{
521 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
522
523 switch (cmd) {
524 case TEST_INIT:
525 info->name = "object_retrieve_regex";
526 info->category = "/res/sorcery_realtime/";
527 info->summary = "sorcery multiple object retrieval using regex unit test";
528 info->description =
529 "Test multiple object retrieval in sorcery using regular expression for matching using realtime wizard";
530 return AST_TEST_NOT_RUN;
531 case TEST_EXECUTE:
532 break;
533 }
534
535 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
536 ast_test_status_update(test, "Failed to open sorcery structure\n");
537 return AST_TEST_FAIL;
538 }
539
540 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) {
541 ast_test_status_update(test, "Failed to allocate a known object type\n");
542 return AST_TEST_FAIL;
543 }
544
545 if (ast_sorcery_create(sorcery, obj)) {
546 ast_test_status_update(test, "Failed to create object using realtime wizard\n");
547 return AST_TEST_FAIL;
548 }
549
550 ao2_cleanup(obj);
551
552 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) {
553 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
554 return AST_TEST_FAIL;
555 }
556
557 if (ast_sorcery_create(sorcery, obj)) {
558 ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
559 return AST_TEST_FAIL;
560 }
561
562 ao2_cleanup(obj);
563
564 if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) {
565 ast_test_status_update(test, "Failed to allocate third instance of a known object type\n");
566 return AST_TEST_FAIL;
567 }
568
569 if (ast_sorcery_create(sorcery, obj)) {
570 ast_test_status_update(test, "Failed to create third object using astdb wizard\n");
571 return AST_TEST_FAIL;
572 }
573
574 if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "blah-"))) {
575 ast_test_status_update(test, "Failed to retrieve a container of objects\n");
576 return AST_TEST_FAIL;
577 } else if (ao2_container_count(objects) != 2) {
578 ast_test_status_update(test, "Received a container with incorrect number of objects in it: %d instead of 2\n", ao2_container_count(objects));
579 return AST_TEST_FAIL;
580 }
581
582 return AST_TEST_PASS;
583}
584
585AST_TEST_DEFINE(object_retrieve_regex_nofetch)
586{
589 RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
590
591 switch (cmd) {
592 case TEST_INIT:
593 info->name = "object_retrieve_regex_nofetch";
594 info->category = "/res/sorcery_realtime/";
595 info->summary = "sorcery multiple object retrieval using regex unit test";
596 info->description =
597 "Test multiple object retrieval in sorcery using regular expression for matching using realtime wizard";
598 return AST_TEST_NOT_RUN;
599 case TEST_EXECUTE:
600 break;
601 }
602
603 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test,allow_unqualified_fetch=no"))) {
604 ast_test_status_update(test, "Failed to open sorcery structure\n");
605 return AST_TEST_FAIL;
606 }
607
608 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) {
609 ast_test_status_update(test, "Failed to allocate a known object type\n");
610 return AST_TEST_FAIL;
611 }
612
613 if (ast_sorcery_create(sorcery, obj)) {
614 ast_test_status_update(test, "Failed to create object using realtime wizard\n");
615 return AST_TEST_FAIL;
616 }
617
618 ao2_cleanup(obj);
619
620 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) {
621 ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
622 return AST_TEST_FAIL;
623 }
624
625 if (ast_sorcery_create(sorcery, obj)) {
626 ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
627 return AST_TEST_FAIL;
628 }
629
630 ao2_cleanup(obj);
631
632 if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) {
633 ast_test_status_update(test, "Failed to allocate third instance of a known object type\n");
634 return AST_TEST_FAIL;
635 }
636
637 if (ast_sorcery_create(sorcery, obj)) {
638 ast_test_status_update(test, "Failed to create third object using astdb wizard\n");
639 return AST_TEST_FAIL;
640 }
641
642 if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", ""))) {
643 ast_test_status_update(test, "Failed to retrieve a container of objects\n");
644 return AST_TEST_FAIL;
645 } else if (ao2_container_count(objects) != 0) {
646 ast_test_status_update(test, "Received a container with incorrect number of objects in it: %d instead of 0\n", ao2_container_count(objects));
647 return AST_TEST_FAIL;
648 }
649
650 return AST_TEST_PASS;
651}
652
653AST_TEST_DEFINE(object_update)
654{
658
659 switch (cmd) {
660 case TEST_INIT:
661 info->name = "object_update";
662 info->category = "/res/sorcery_realtime/";
663 info->summary = "sorcery object update unit test";
664 info->description =
665 "Test object updating in sorcery using realtime wizard";
666 return AST_TEST_NOT_RUN;
667 case TEST_EXECUTE:
668 break;
669 }
670
671 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
672 ast_test_status_update(test, "Failed to open sorcery structure\n");
673 return AST_TEST_FAIL;
674 }
675
676 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
677 ast_test_status_update(test, "Failed to allocate a known object type\n");
678 return AST_TEST_FAIL;
679 }
680
681 if (ast_sorcery_create(sorcery, obj)) {
682 ast_test_status_update(test, "Failed to create object using realtime wizard\n");
683 return AST_TEST_FAIL;
684 }
685
686 if (!(obj2 = ast_sorcery_copy(sorcery, obj))) {
687 ast_test_status_update(test, "Failed to allocate a known object type for updating\n");
688 return AST_TEST_FAIL;
689 }
690
691 ao2_cleanup(obj);
692
693 obj2->bob = 1000;
694 obj2->joe = 2000;
695
696 if (ast_sorcery_update(sorcery, obj2)) {
697 ast_test_status_update(test, "Failed to update sorcery with new object\n");
698 return AST_TEST_FAIL;
699 }
700
701 if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
702 ast_test_status_update(test, "Failed to retrieve properly updated object\n");
703 return AST_TEST_FAIL;
704 } else if ((obj->bob != obj2->bob) || (obj->joe != obj2->joe)) {
705 ast_test_status_update(test, "Object retrieved is not the updated object\n");
706 return AST_TEST_FAIL;
707 }
708
709 return AST_TEST_PASS;
710}
711
712AST_TEST_DEFINE(object_delete)
713{
716
717 switch (cmd) {
718 case TEST_INIT:
719 info->name = "object_delete";
720 info->category = "/res/sorcery_realtime/";
721 info->summary = "sorcery object deletion unit test";
722 info->description =
723 "Test object deletion in sorcery using realtime wizard";
724 return AST_TEST_NOT_RUN;
725 case TEST_EXECUTE:
726 break;
727 }
728
729 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
730 ast_test_status_update(test, "Failed to open sorcery structure\n");
731 return AST_TEST_FAIL;
732 }
733
734 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
735 ast_test_status_update(test, "Failed to allocate a known object type\n");
736 return AST_TEST_FAIL;
737 }
738
739 if (ast_sorcery_create(sorcery, obj)) {
740 ast_test_status_update(test, "Failed to create object using realtime wizard\n");
741 return AST_TEST_FAIL;
742 }
743
744 if (ast_sorcery_delete(sorcery, obj)) {
745 ast_test_status_update(test, "Failed to delete object using realtime wizard\n");
746 return AST_TEST_FAIL;
747 }
748
749 ao2_cleanup(obj);
750
751 if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
752 ast_test_status_update(test, "Retrieved deleted object that should not be there\n");
753 return AST_TEST_FAIL;
754 }
755
756 return AST_TEST_PASS;
757}
758
759AST_TEST_DEFINE(object_delete_uncreated)
760{
763
764 switch (cmd) {
765 case TEST_INIT:
766 info->name = "object_delete_uncreated";
767 info->category = "/res/sorcery_realtime/";
768 info->summary = "sorcery object deletion unit test";
769 info->description =
770 "Test object deletion of an uncreated object in sorcery using realtime wizard";
771 return AST_TEST_NOT_RUN;
772 case TEST_EXECUTE:
773 break;
774 }
775
776 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
777 ast_test_status_update(test, "Failed to open sorcery structure\n");
778 return AST_TEST_FAIL;
779 }
780
781 if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
782 ast_test_status_update(test, "Failed to allocate a known object type\n");
783 return AST_TEST_FAIL;
784 }
785
786 if (!ast_sorcery_delete(sorcery, obj)) {
787 ast_test_status_update(test, "Successfully deleted an object which was never created\n");
788 return AST_TEST_FAIL;
789 }
790
791 return AST_TEST_PASS;
792}
793
794AST_TEST_DEFINE(object_allocate_on_retrieval)
795{
798 struct ast_category *cat;
799
800 switch (cmd) {
801 case TEST_INIT:
802 info->name = "object_allocate_on_retrieval";
803 info->category = "/res/sorcery_realtime/";
804 info->summary = "sorcery object allocation upon retrieval unit test";
805 info->description =
806 "This test creates data in a realtime backend, not through sorcery. Sorcery is then\n"
807 "instructed to retrieve an object with the id of the object that was created in the\n"
808 "realtime backend. Sorcery should be able to allocate the object appropriately";
809 return AST_TEST_NOT_RUN;
810 case TEST_EXECUTE:
811 break;
812 }
813
814 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
815 ast_test_status_update(test, "Failed to open sorcery structure\n");
816 return AST_TEST_FAIL;
817 }
818
819 cat = ast_category_new("blah", "", 0);
820 ast_variable_append(cat, ast_variable_new("id", "blah", ""));
821 ast_variable_append(cat, ast_variable_new("bob", "42", ""));
822 ast_variable_append(cat, ast_variable_new("joe", "93", ""));
824
825 if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
826 ast_test_status_update(test, "Failed to allocate object 'blah' base on realtime data\n");
827 return AST_TEST_FAIL;
828 }
829
830 if (obj->bob != 42) {
831 ast_test_status_update(test, "Object's 'bob' field does not have expected value: %u != 42\n",
832 obj->bob);
833 return AST_TEST_FAIL;
834 } else if (obj->joe != 93) {
835 ast_test_status_update(test, "Object's 'joe' field does not have expected value: %u != 93\n",
836 obj->joe);
837 return AST_TEST_FAIL;
838 }
839
840 return AST_TEST_PASS;
841}
842
843
844AST_TEST_DEFINE(object_filter)
845{
848 struct ast_category *cat;
849
850 switch (cmd) {
851 case TEST_INIT:
852 info->name = "object_filter";
853 info->category = "/res/sorcery_realtime/";
854 info->summary = "sorcery object field filter unit test";
855 info->description =
856 "This test creates data in a realtime backend, not through sorcery. In addition to\n"
857 "the object fields that have been registered with sorcery, there is data in the\n"
858 "realtime backend that is unknown to sorcery. When sorcery attempts to retrieve\n"
859 "the object from the realtime backend, the data unknown to sorcery should be\n"
860 "filtered out of the returned objectset, and the object should be successfully\n"
861 "allocated by sorcery";
862 return AST_TEST_NOT_RUN;
863 case TEST_EXECUTE:
864 break;
865 }
866
867 if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
868 ast_test_status_update(test, "Failed to open sorcery structure\n");
869 return AST_TEST_FAIL;
870 }
871
872 cat = ast_category_new("blah", "", 0);
873 ast_variable_append(cat, ast_variable_new("id", "blah", ""));
874 ast_variable_append(cat, ast_variable_new("bob", "42", ""));
875 ast_variable_append(cat, ast_variable_new("joe", "93", ""));
876 ast_variable_append(cat, ast_variable_new("fred", "50", ""));
878
879 if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
880 ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
881 return AST_TEST_FAIL;
882 }
883
884 if (obj->bob != 42) {
885 ast_test_status_update(test, "Object's 'bob' field does not have expected value: %u != 42\n",
886 obj->bob);
887 return AST_TEST_FAIL;
888 } else if (obj->joe != 93) {
889 ast_test_status_update(test, "Object's 'joe' field does not have expected value: %u != 93\n",
890 obj->joe);
891 return AST_TEST_FAIL;
892 }
893 return AST_TEST_PASS;
894}
895
896static int unload_module(void)
897{
899 AST_TEST_UNREGISTER(object_create);
900 AST_TEST_UNREGISTER(object_retrieve_id);
901 AST_TEST_UNREGISTER(object_retrieve_field);
902 AST_TEST_UNREGISTER(object_retrieve_multiple_all);
903 AST_TEST_UNREGISTER(object_retrieve_multiple_all_nofetch);
904 AST_TEST_UNREGISTER(object_retrieve_multiple_field);
905 AST_TEST_UNREGISTER(object_retrieve_regex);
906 AST_TEST_UNREGISTER(object_retrieve_regex_nofetch);
907 AST_TEST_UNREGISTER(object_update);
908 AST_TEST_UNREGISTER(object_delete);
909 AST_TEST_UNREGISTER(object_delete_uncreated);
910 AST_TEST_UNREGISTER(object_allocate_on_retrieval);
911 AST_TEST_UNREGISTER(object_filter);
912
913 return 0;
914}
915
916static int load_module(void)
917{
919 ast_realtime_append_mapping("sorcery_realtime_test", "sorcery_realtime_test", "test", "test", 1);
920 AST_TEST_REGISTER(object_create);
921 AST_TEST_REGISTER(object_retrieve_id);
922 AST_TEST_REGISTER(object_retrieve_field);
923 AST_TEST_REGISTER(object_retrieve_multiple_all);
924 AST_TEST_REGISTER(object_retrieve_multiple_all_nofetch);
925 AST_TEST_REGISTER(object_retrieve_multiple_field);
926 AST_TEST_REGISTER(object_retrieve_regex);
927 AST_TEST_REGISTER(object_retrieve_regex_nofetch);
928 AST_TEST_REGISTER(object_update);
929 AST_TEST_REGISTER(object_delete);
930 AST_TEST_REGISTER(object_delete_uncreated);
931 AST_TEST_REGISTER(object_allocate_on_retrieval);
932 AST_TEST_REGISTER(object_filter);
933
935}
936
937AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Sorcery Realtime Wizard test module");
Persistent data storage (akin to *doze registry)
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
static char * table
Definition: cdr_odbc.c:55
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
struct ast_category * ast_category_delete(struct ast_config *cfg, struct ast_category *cat)
Delete a category.
Definition: main/config.c:1582
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3274
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Definition: extconf.c:2833
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: extconf.c:1177
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
Definition: extconf.c:2788
#define ast_variable_new(name, value, filename)
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
Definition: main/config.c:3188
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Definition: main/config.c:544
struct ast_variable * ast_category_root(struct ast_config *config, char *cat)
returns the root ast_variable of a config
Definition: main/config.c:1260
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
int ast_category_exist(const struct ast_config *config, const char *category_name, const char *filter)
Check for category duplicates.
Definition: main/config.c:1159
int ast_variable_lists_match(const struct ast_variable *left, const struct ast_variable *right, int exact_match)
Tests 2 variable lists to see if they match.
Definition: main/config.c:870
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
const struct ast_variable * ast_variable_find_variable_in_list(const struct ast_variable *list, const char *variable_name)
Gets a variable from a variable list by name.
Definition: main/config.c:838
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
Definition: main/config.c:3172
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:1120
Support for logging to various files, console and syslog Configuration in file logger....
static int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
Definition: main/config.c:3055
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
static struct ast_sorcery * sorcery
#define NULL
Definition: resample.c:96
Sorcery Data Access Layer API.
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
#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
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition: sorcery.h:120
@ AST_RETRIEVE_FLAG_DEFAULT
Default retrieval flags.
Definition: sorcery.h:117
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition: sorcery.h:123
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2062
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
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:1954
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
Definition: sorcery.h:867
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2150
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
#define ast_sorcery_open()
Open a new sorcery structure.
Definition: sorcery.h:406
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
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2238
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition: sorcery.c:1778
@ AST_SORCERY_APPLY_SUCCESS
Definition: sorcery.h:427
Generic container type.
Configuration engine structure, used to define realtime drivers.
Full structure for sorcery.
Definition: sorcery.c:230
Structure for variables, used for configurations and for channel variables.
Dummy sorcery object.
Definition: test_sorcery.c:44
unsigned int bob
Definition: test_sorcery.c:46
unsigned int joe
Definition: test_sorcery.c:47
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
static void * test_sorcery_object_alloc(const char *id)
Internal function to allocate a test object.
static struct ast_config * realtime_objects
Configuration structure which contains all stored objects.
static int realtime_sorcery_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
static void deinitialize_sorcery(struct ast_sorcery *sorcery)
static int realtime_sorcery_store(const char *database, const char *table, const struct ast_variable *fields)
struct ast_config_engine sorcery_config_engine
static struct ast_variable * realtime_sorcery(const char *database, const char *table, const struct ast_variable *fields)
static struct ast_config * realtime_sorcery_multi(const char *database, const char *table, const struct ast_variable *fields)
static int load_module(void)
static int unload_module(void)
static struct ast_sorcery * alloc_and_initialize_sorcery(char *table)
AST_TEST_DEFINE(object_create)
static int realtime_sorcery_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941