Asterisk - The Open Source Telephony Project  GIT-master-e8cda4b
test_bucket.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 Bucket 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 <sys/stat.h>
35 
36 #include "asterisk/test.h"
37 #include "asterisk/module.h"
38 #include "asterisk/bucket.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/json.h"
41 #include "asterisk/file.h"
42 
43 /*! \brief Test state structure for scheme wizards */
45  /*! \brief Whether the object has been created or not */
46  unsigned int created:1;
47  /*! \brief Whether the object has been updated or not */
48  unsigned int updated:1;
49  /*! \brief Whether the object has been deleted or not */
50  unsigned int deleted:1;
51  /*! \brief Whether the object is stale or not */
52  unsigned int is_stale:1;
53 };
54 
55 /*! \brief Global scope structure for testing bucket wizards */
57 
58 static void bucket_test_wizard_clear(void)
59 {
64 }
65 
66 static int bucket_test_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
67 {
69  return -1;
70  }
71 
73 
74  return 0;
75 }
76 
77 static int bucket_test_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
78 {
80  return -1;
81  }
82 
84 
85  return 0;
86 }
87 
88 static void *bucket_test_wizard_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type,
89  const char *id)
90 {
91  if (!strcmp(type, "bucket")) {
92  return ast_bucket_alloc(id);
93  } else if (!strcmp(type, "file")) {
94  return ast_bucket_file_alloc(id);
95  } else {
96  return NULL;
97  }
98 }
99 
100 static int bucket_test_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
101 {
103  return -1;
104  }
105 
107 
108  return 0;
109 }
110 
111 static int bucket_test_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
112 {
114 }
115 
117  .name = "test",
118  .create = bucket_test_wizard_create,
119  .retrieve_id = bucket_test_wizard_retrieve_id,
120  .delete = bucket_test_wizard_delete,
121  .is_stale = bucket_test_wizard_is_stale,
122 };
123 
125  .name = "test",
126  .create = bucket_test_wizard_create,
127  .update = bucket_test_wizard_update,
128  .retrieve_id = bucket_test_wizard_retrieve_id,
129  .delete = bucket_test_wizard_delete,
130  .is_stale = bucket_test_wizard_is_stale,
131 };
132 
133 AST_TEST_DEFINE(bucket_scheme_register)
134 {
135  switch (cmd) {
136  case TEST_INIT:
137  info->name = "bucket_scheme_register_unregister";
138  info->category = "/main/bucket/";
139  info->summary = "bucket scheme registration/unregistration unit test";
140  info->description =
141  "Test registration and unregistration of bucket scheme";
142  return AST_TEST_NOT_RUN;
143  case TEST_EXECUTE:
144  break;
145  }
146 
148  ast_test_status_update(test, "Successfully registered a Bucket scheme without name or wizards\n");
149  return AST_TEST_FAIL;
150  }
151 
152  if (!ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard, NULL, NULL)) {
153  ast_test_status_update(test, "Successfully registered a Bucket scheme twice\n");
154  return AST_TEST_FAIL;
155  }
156 
157  return AST_TEST_PASS;
158 }
159 
161 {
162  RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
163 
164  switch (cmd) {
165  case TEST_INIT:
166  info->name = "bucket_alloc";
167  info->category = "/main/bucket/";
168  info->summary = "bucket allocation unit test";
169  info->description =
170  "Test allocation of buckets";
171  return AST_TEST_NOT_RUN;
172  case TEST_EXECUTE:
173  break;
174  }
175 
176  if ((bucket = ast_bucket_alloc(""))) {
177  ast_test_status_update(test, "Allocated a bucket with no URI provided\n");
178  return AST_TEST_FAIL;
179  }
180 
181  if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
182  ast_test_status_update(test, "Failed to allocate bucket\n");
183  return AST_TEST_FAIL;
184  }
185 
186  if (strcmp(ast_sorcery_object_get_id(bucket), "test:///tmp/bob")) {
187  ast_test_status_update(test, "URI within allocated bucket is '%s' and should be test:///tmp/bob\n",
188  ast_sorcery_object_get_id(bucket));
189  return AST_TEST_FAIL;
190  }
191 
192  if (strcmp(bucket->scheme, "test")) {
193  ast_test_status_update(test, "Scheme within allocated bucket is '%s' and should be test\n",
194  bucket->scheme);
195  return AST_TEST_FAIL;
196  }
197 
198  return AST_TEST_PASS;
199 }
200 
201 AST_TEST_DEFINE(bucket_create)
202 {
203  RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
204 
205  switch (cmd) {
206  case TEST_INIT:
207  info->name = "bucket_create";
208  info->category = "/main/bucket/";
209  info->summary = "bucket creation unit test";
210  info->description =
211  "Test creation of buckets";
212  return AST_TEST_NOT_RUN;
213  case TEST_EXECUTE:
214  break;
215  }
216 
217  if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
218  ast_test_status_update(test, "Failed to allocate bucket\n");
219  return AST_TEST_FAIL;
220  }
221 
223 
224  if (ast_bucket_create(bucket)) {
225  ast_test_status_update(test, "Failed to create bucket with URI '%s'\n",
226  ast_sorcery_object_get_id(bucket));
227  return AST_TEST_FAIL;
228  }
229 
231  ast_test_status_update(test, "Bucket creation returned success but scheme implementation never actually created it\n");
232  return AST_TEST_FAIL;
233  }
234 
235  if (!ast_bucket_create(bucket)) {
236  ast_test_status_update(test, "Successfully created bucket with URI '%s' twice\n",
237  ast_sorcery_object_get_id(bucket));
238  return AST_TEST_FAIL;
239  }
240 
241  return AST_TEST_PASS;
242 }
243 
244 AST_TEST_DEFINE(bucket_clone)
245 {
246  RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
247  RAII_VAR(struct ast_bucket *, clone, NULL, ao2_cleanup);
248 
249  switch (cmd) {
250  case TEST_INIT:
251  info->name = "bucket_clone";
252  info->category = "/main/bucket/";
253  info->summary = "bucket clone unit test";
254  info->description =
255  "Test cloning a bucket";
256  return AST_TEST_NOT_RUN;
257  case TEST_EXECUTE:
258  break;
259  }
260 
261  if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
262  ast_test_status_update(test, "Failed to allocate bucket\n");
263  return AST_TEST_FAIL;
264  }
265 
267 
268  if (ast_bucket_create(bucket)) {
269  ast_test_status_update(test, "Failed to create bucket with URI '%s'\n",
270  ast_sorcery_object_get_id(bucket));
271  return AST_TEST_FAIL;
272  }
273 
274  clone = ast_bucket_clone(bucket);
275  if (!clone) {
276  ast_test_status_update(test, "Failed to clone bucket with URI '%s'\n",
277  ast_sorcery_object_get_id(bucket));
278  return AST_TEST_FAIL;
279  }
280 
281  ast_test_validate(test, strcmp(ast_sorcery_object_get_id(bucket), ast_sorcery_object_get_id(clone)) == 0);
282  ast_test_validate(test, bucket->scheme_impl == clone->scheme_impl);
283  ast_test_validate(test, strcmp(bucket->scheme, clone->scheme) == 0);
284 
285  return AST_TEST_PASS;
286 }
287 
288 AST_TEST_DEFINE(bucket_delete)
289 {
290  RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
291 
292  switch (cmd) {
293  case TEST_INIT:
294  info->name = "bucket_delete";
295  info->category = "/main/bucket/";
296  info->summary = "bucket deletion unit test";
297  info->description =
298  "Test deletion of buckets";
299  return AST_TEST_NOT_RUN;
300  case TEST_EXECUTE:
301  break;
302  }
303 
304  if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
305  ast_test_status_update(test, "Failed to allocate bucket\n");
306  return AST_TEST_FAIL;
307  }
308 
310 
311  if (ast_bucket_delete(bucket)) {
312  ast_test_status_update(test, "Failed to delete bucket with URI '%s'\n",
313  ast_sorcery_object_get_id(bucket));
314  return AST_TEST_FAIL;
315  }
316 
318  ast_test_status_update(test, "Bucket deletion returned success but scheme implementation never actually deleted it\n");
319  return AST_TEST_FAIL;
320  }
321 
322  if (!ast_bucket_delete(bucket)) {
323  ast_test_status_update(test, "Successfully deleted bucket with URI '%s' twice\n",
324  ast_sorcery_object_get_id(bucket));
325  return AST_TEST_FAIL;
326  }
327 
328  return AST_TEST_PASS;
329 }
330 
331 AST_TEST_DEFINE(bucket_is_stale)
332 {
333  RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
334 
335  switch (cmd) {
336  case TEST_INIT:
337  info->name = "bucket_is_stale";
338  info->category = "/main/bucket/";
339  info->summary = "bucket staleness unit test";
340  info->description =
341  "Test if staleness of a bucket is reported correctly";
342  return AST_TEST_NOT_RUN;
343  case TEST_EXECUTE:
344  break;
345  }
346 
347  if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
348  ast_test_status_update(test, "Failed to allocate bucket\n");
349  return AST_TEST_FAIL;
350  }
351 
353 
354  ast_test_validate(test, ast_bucket_is_stale(bucket) == 0);
355 
357 
358  ast_test_validate(test, ast_bucket_is_stale(bucket) == 1);
359 
360  return AST_TEST_PASS;
361 }
362 
363 AST_TEST_DEFINE(bucket_json)
364 {
365  RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
366  RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
367  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
368 
369  switch (cmd) {
370  case TEST_INIT:
371  info->name = "bucket_json";
372  info->category = "/main/bucket/";
373  info->summary = "bucket json unit test";
374  info->description =
375  "Test creation of JSON for a bucket";
376  return AST_TEST_NOT_RUN;
377  case TEST_EXECUTE:
378  break;
379  }
380 
381  if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
382  ast_test_status_update(test, "Failed to allocate bucket\n");
383  return AST_TEST_FAIL;
384  }
385 
386  ast_str_container_add(bucket->buckets, "test:///tmp/bob/joe");
387  ast_str_container_add(bucket->files, "test:///tmp/bob/recording.wav");
388 
389  expected = ast_json_pack("{s: s, s: s, s: [s], s: s, s: [s], s: s}",
390  "modified", "0.000000", "created", "0.000000",
391  "buckets", "test:///tmp/bob/joe",
392  "scheme", "test",
393  "files", "test:///tmp/bob/recording.wav",
394  "id", "test:///tmp/bob");
395  if (!expected) {
396  ast_test_status_update(test, "Could not produce JSON for expected bucket value\n");
397  return AST_TEST_FAIL;
398  }
399 
400  json = ast_bucket_json(bucket);
401  if (!json) {
402  ast_test_status_update(test, "Could not produce JSON for a valid bucket\n");
403  return AST_TEST_FAIL;
404  }
405 
406  if (!ast_json_equal(json, expected)) {
407  ast_test_status_update(test, "Bucket JSON does not match expected output\n");
408  return AST_TEST_FAIL;
409  }
410 
411  return AST_TEST_PASS;
412 }
413 
414 AST_TEST_DEFINE(bucket_retrieve)
415 {
416  RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
417 
418  switch (cmd) {
419  case TEST_INIT:
420  info->name = "bucket_retrieve";
421  info->category = "/main/bucket/";
422  info->summary = "bucket retrieval unit test";
423  info->description =
424  "Test retrieval of buckets";
425  return AST_TEST_NOT_RUN;
426  case TEST_EXECUTE:
427  break;
428  }
429 
430  if (!(bucket = ast_bucket_retrieve("test://tmp/bob"))) {
431  ast_test_status_update(test, "Failed to retrieve known valid bucket\n");
432  return AST_TEST_FAIL;
433  }
434 
435  return AST_TEST_PASS;
436 }
437 
439 {
441 
442  switch (cmd) {
443  case TEST_INIT:
444  info->name = "bucket_file_alloc";
445  info->category = "/main/bucket/";
446  info->summary = "bucket file allocation unit test";
447  info->description =
448  "Test allocation of bucket files";
449  return AST_TEST_NOT_RUN;
450  case TEST_EXECUTE:
451  break;
452  }
453 
454  if ((file = ast_bucket_file_alloc(""))) {
455  ast_test_status_update(test, "Allocated a file with no URI provided\n");
456  return AST_TEST_FAIL;
457  }
458 
459  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
460  ast_test_status_update(test, "Failed to allocate file\n");
461  return AST_TEST_FAIL;
462  }
463 
464  if (ast_strlen_zero(file->path)) {
465  ast_test_status_update(test, "Expected temporary path in allocated file");
466  return AST_TEST_FAIL;
467  }
468 
469  if (strcmp(ast_sorcery_object_get_id(file), "test:///tmp/bob")) {
470  ast_test_status_update(test, "URI within allocated file is '%s' and should be test:///tmp/bob\n",
472  return AST_TEST_FAIL;
473  }
474 
475  if (strcmp(file->scheme, "test")) {
476  ast_test_status_update(test, "Scheme within allocated file is '%s' and should be test\n",
477  file->scheme);
478  return AST_TEST_FAIL;
479  }
480 
481  return AST_TEST_PASS;
482 }
483 
484 AST_TEST_DEFINE(bucket_file_create)
485 {
487 
488  switch (cmd) {
489  case TEST_INIT:
490  info->name = "bucket_file_create";
491  info->category = "/main/bucket/";
492  info->summary = "file creation unit test";
493  info->description =
494  "Test creation of files";
495  return AST_TEST_NOT_RUN;
496  case TEST_EXECUTE:
497  break;
498  }
499 
500  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
501  ast_test_status_update(test, "Failed to allocate file\n");
502  return AST_TEST_FAIL;
503  }
504 
506 
508  ast_test_status_update(test, "Failed to create file with URI '%s'\n",
510  return AST_TEST_FAIL;
511  }
512 
514  ast_test_status_update(test, "Bucket file creation returned success but scheme implementation never actually created it\n");
515  return AST_TEST_FAIL;
516  }
517 
519  ast_test_status_update(test, "Successfully created file with URI '%s' twice\n",
521  return AST_TEST_FAIL;
522  }
523 
524  return AST_TEST_PASS;
525 }
526 
527 AST_TEST_DEFINE(bucket_file_clone)
528 {
530  RAII_VAR(struct ast_bucket_file *, clone, NULL, ao2_cleanup);
531 
532  switch (cmd) {
533  case TEST_INIT:
534  info->name = "bucket_file_clone";
535  info->category = "/main/bucket/";
536  info->summary = "file clone unit test";
537  info->description =
538  "Test cloning a file";
539  return AST_TEST_NOT_RUN;
540  case TEST_EXECUTE:
541  break;
542  }
543 
544  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
545  ast_test_status_update(test, "Failed to allocate file\n");
546  return AST_TEST_FAIL;
547  }
548 
550 
552  ast_test_status_update(test, "Failed to create file with URI '%s'\n",
554  return AST_TEST_FAIL;
555  }
556  ast_bucket_file_metadata_set(file, "bob", "joe");
557 
558  clone = ast_bucket_file_clone(file);
559  if (!clone) {
560  ast_test_status_update(test, "Failed to clone file with URI '%s'\n",
562  return AST_TEST_FAIL;
563  }
564 
565  ast_test_validate(test, strcmp(ast_sorcery_object_get_id(file), ast_sorcery_object_get_id(clone)) == 0);
566  ast_test_validate(test, file->scheme_impl == clone->scheme_impl);
567  ast_test_validate(test, strcmp(file->scheme, clone->scheme) == 0);
568  ast_test_validate(test, ao2_container_count(file->metadata) == ao2_container_count(clone->metadata));
569 
570  return AST_TEST_PASS;
571 }
572 
573 AST_TEST_DEFINE(bucket_file_copy)
574 {
577  FILE *temporary;
578  struct stat old, new;
579  RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
580 
581  switch (cmd) {
582  case TEST_INIT:
583  info->name = "bucket_file_copy";
584  info->category = "/main/bucket/";
585  info->summary = "bucket file copying unit test";
586  info->description =
587  "Test copying of bucket files";
588  return AST_TEST_NOT_RUN;
589  case TEST_EXECUTE:
590  break;
591  }
592 
593  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
594  ast_test_status_update(test, "Failed to allocate file\n");
595  return AST_TEST_FAIL;
596  }
597 
598  ast_bucket_file_metadata_set(file, "bob", "joe");
599 
600  if (!(temporary = fopen(file->path, "w"))) {
601  ast_test_status_update(test, "Failed to open temporary file '%s'\n", file->path);
602  return AST_TEST_FAIL;
603  }
604 
605  fprintf(temporary, "bob");
606  fclose(temporary);
607 
608  if (!(copy = ast_bucket_file_copy(file, "test:///tmp/bob2"))) {
609  ast_test_status_update(test, "Failed to copy file '%s' to test:///tmp/bob2\n",
611  return AST_TEST_FAIL;
612  }
613 
614  if (stat(file->path, &old)) {
615  ast_test_status_update(test, "Failed to retrieve information on old file '%s'\n", file->path);
616  return AST_TEST_FAIL;
617  }
618 
619  if (stat(copy->path, &new)) {
620  ast_test_status_update(test, "Failed to retrieve information on copy file '%s'\n", copy->path);
621  return AST_TEST_FAIL;
622  }
623 
624  if (old.st_size != new.st_size) {
625  ast_test_status_update(test, "Copying of underlying temporary file failed\n");
626  return AST_TEST_FAIL;
627  }
628 
629  if (ao2_container_count(file->metadata) != ao2_container_count(copy->metadata)) {
630  ast_test_status_update(test, "Number of metadata entries does not match original\n");
631  return AST_TEST_FAIL;
632  }
633 
634  metadata = ast_bucket_file_metadata_get(copy, "bob");
635  if (!metadata) {
636  ast_test_status_update(test, "Copy of file does not have expected metadata\n");
637  return AST_TEST_FAIL;
638  }
639 
640  if (strcmp(metadata->value, "joe")) {
641  ast_test_status_update(test, "Copy of file contains metadata for 'bob' but value is not what it should be\n");
642  return AST_TEST_FAIL;
643  }
644 
645  return AST_TEST_PASS;
646 }
647 
648 AST_TEST_DEFINE(bucket_file_retrieve)
649 {
651 
652  switch (cmd) {
653  case TEST_INIT:
654  info->name = "bucket_file_retrieve";
655  info->category = "/main/bucket/";
656  info->summary = "file retrieval unit test";
657  info->description =
658  "Test retrieval of files";
659  return AST_TEST_NOT_RUN;
660  case TEST_EXECUTE:
661  break;
662  }
663 
664  if (!(file = ast_bucket_file_retrieve("test://tmp/bob"))) {
665  ast_test_status_update(test, "Failed to retrieve known valid file\n");
666  return AST_TEST_FAIL;
667  }
668 
669  return AST_TEST_PASS;
670 }
671 
672 AST_TEST_DEFINE(bucket_file_update)
673 {
675 
676  switch (cmd) {
677  case TEST_INIT:
678  info->name = "bucket_file_update";
679  info->category = "/main/bucket/";
680  info->summary = "file updating unit test";
681  info->description =
682  "Test updating of files";
683  return AST_TEST_NOT_RUN;
684  case TEST_EXECUTE:
685  break;
686  }
687 
688  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
689  ast_test_status_update(test, "Failed to allocate file\n");
690  return AST_TEST_FAIL;
691  }
692 
694 
696  ast_test_status_update(test, "Failed to update file with URI '%s'\n",
698  return AST_TEST_FAIL;
699  }
700 
702  ast_test_status_update(test, "Successfully returned file was updated, but it was not\n");
703  return AST_TEST_FAIL;
704  }
705 
707  ast_test_status_update(test, "Successfully updated file with URI '%s' twice\n",
709  return AST_TEST_FAIL;
710  }
711 
712  return AST_TEST_PASS;
713 }
714 
715 AST_TEST_DEFINE(bucket_file_delete)
716 {
718 
719  switch (cmd) {
720  case TEST_INIT:
721  info->name = "bucket_file_delete";
722  info->category = "/main/bucket/";
723  info->summary = "file deletion unit test";
724  info->description =
725  "Test deletion of files";
726  return AST_TEST_NOT_RUN;
727  case TEST_EXECUTE:
728  break;
729  }
730 
731  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
732  ast_test_status_update(test, "Failed to allocate file\n");
733  return AST_TEST_FAIL;
734  }
735 
737 
739  ast_test_status_update(test, "Failed to delete file with URI '%s'\n",
741  return AST_TEST_FAIL;
742  }
743 
745  ast_test_status_update(test, "Bucket file deletion returned success but scheme implementation never actually deleted it\n");
746  return AST_TEST_FAIL;
747  }
748 
750  ast_test_status_update(test, "Successfully deleted file with URI '%s' twice\n",
752  return AST_TEST_FAIL;
753  }
754 
755  return AST_TEST_PASS;
756 }
757 
758 AST_TEST_DEFINE(bucket_file_is_stale)
759 {
761 
762  switch (cmd) {
763  case TEST_INIT:
764  info->name = "bucket_file_is_stale";
765  info->category = "/main/bucket/";
766  info->summary = "file staleness unit test";
767  info->description =
768  "Test if staleness of a bucket file is reported correctly";
769  return AST_TEST_NOT_RUN;
770  case TEST_EXECUTE:
771  break;
772  }
773 
774  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
775  ast_test_status_update(test, "Failed to allocate file\n");
776  return AST_TEST_FAIL;
777  }
778 
780 
781  ast_test_validate(test, ast_bucket_file_is_stale(file) == 0);
782 
784 
785  ast_test_validate(test, ast_bucket_file_is_stale(file) == 1);
786 
787  return AST_TEST_PASS;
788 }
789 
790 AST_TEST_DEFINE(bucket_file_metadata_set)
791 {
793  RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
794 
795  switch (cmd) {
796  case TEST_INIT:
797  info->name = "bucket_file_metadata_set";
798  info->category = "/main/bucket/";
799  info->summary = "file metadata setting unit test";
800  info->description =
801  "Test setting of metadata on files";
802  return AST_TEST_NOT_RUN;
803  case TEST_EXECUTE:
804  break;
805  }
806 
807  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
808  ast_test_status_update(test, "Failed to allocate file\n");
809  return AST_TEST_FAIL;
810  }
811 
812  if (ao2_container_count(file->metadata) != 0) {
813  ast_test_status_update(test, "Newly allocated file has metadata count of '%d' when should be 0\n",
814  ao2_container_count(file->metadata));
815  return AST_TEST_FAIL;
816  }
817 
818  if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
819  ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
820  return AST_TEST_FAIL;
821  }
822 
823  if (!(metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
824  ast_test_status_update(test, "Failed to find set metadata 'bob' on newly allocated file\n");
825  return AST_TEST_FAIL;
826  }
827 
828  if (strcmp(metadata->value, "joe")) {
829  ast_test_status_update(test, "Metadata has value '%s' when should be 'joe'\n",
830  metadata->value);
831  return AST_TEST_FAIL;
832  }
833 
834  ao2_cleanup(metadata);
835  metadata = NULL;
836 
837  if (ast_bucket_file_metadata_set(file, "bob", "fred")) {
838  ast_test_status_update(test, "Failed to overwrite metadata 'bob' with new value 'fred'\n");
839  return AST_TEST_FAIL;
840  }
841 
842  if (!(metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
843  ast_test_status_update(test, "Failed to find overwritten metadata 'bob' on newly allocated file\n");
844  return AST_TEST_FAIL;
845  }
846 
847  if (strcmp(metadata->value, "fred")) {
848  ast_test_status_update(test, "Metadata has value '%s' when should be 'fred'\n",
849  metadata->value);
850  return AST_TEST_FAIL;
851  }
852 
853  return AST_TEST_PASS;
854 }
855 
856 AST_TEST_DEFINE(bucket_file_metadata_unset)
857 {
859  RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
860 
861  switch (cmd) {
862  case TEST_INIT:
863  info->name = "bucket_file_metadata_unset";
864  info->category = "/main/bucket/";
865  info->summary = "file metadata unsetting unit test";
866  info->description =
867  "Test unsetting of metadata on files";
868  return AST_TEST_NOT_RUN;
869  case TEST_EXECUTE:
870  break;
871  }
872 
873  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
874  ast_test_status_update(test, "Failed to allocate file\n");
875  return AST_TEST_FAIL;
876  }
877 
878  if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
879  ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
880  return AST_TEST_FAIL;
881  }
882 
883  if (ast_bucket_file_metadata_unset(file, "bob")) {
884  ast_test_status_update(test, "Failed to unset metadata 'bob' on newly allocated file\n");
885  return AST_TEST_FAIL;
886  }
887 
888  if ((metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
889  ast_test_status_update(test, "Metadata 'bob' was unset, but can still be found\n");
890  return AST_TEST_FAIL;
891  }
892 
893  return AST_TEST_PASS;
894 }
895 
896 AST_TEST_DEFINE(bucket_file_metadata_get)
897 {
899  RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
900 
901  switch (cmd) {
902  case TEST_INIT:
903  info->name = "bucket_file_metadata_get";
904  info->category = "/main/bucket/";
905  info->summary = "file metadata getting unit test";
906  info->description =
907  "Test getting of metadata on files";
908  return AST_TEST_NOT_RUN;
909  case TEST_EXECUTE:
910  break;
911  }
912 
913  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
914  ast_test_status_update(test, "Failed to allocate file\n");
915  return AST_TEST_FAIL;
916  }
917 
918  if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
919  ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
920  return AST_TEST_FAIL;
921  }
922 
923  if (!(metadata = ast_bucket_file_metadata_get(file, "bob"))) {
924  ast_test_status_update(test, "Failed to retrieve metadata 'bob' that was just set\n");
925  return AST_TEST_FAIL;
926  }
927 
928  if (strcmp(metadata->value, "joe")) {
929  ast_test_status_update(test, "Retrieved metadata value is '%s' while it should be 'joe'\n",
930  metadata->value);
931  return AST_TEST_FAIL;
932  }
933 
934  return AST_TEST_PASS;
935 }
936 
937 AST_TEST_DEFINE(bucket_file_json)
938 {
940  RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
941  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
942 
943  switch (cmd) {
944  case TEST_INIT:
945  info->name = "bucket_file_json";
946  info->category = "/main/bucket/";
947  info->summary = "file json unit test";
948  info->description =
949  "Test creation of JSON for a file";
950  return AST_TEST_NOT_RUN;
951  case TEST_EXECUTE:
952  break;
953  }
954 
955  if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
956  ast_test_status_update(test, "Failed to allocate bucket\n");
957  return AST_TEST_FAIL;
958  }
959 
960  if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
961  ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
962  return AST_TEST_FAIL;
963  }
964 
965  expected = ast_json_pack("{s: s, s: s, s: s, s: s, s: {s :s}}",
966  "modified", "0.000000", "created", "0.000000", "scheme", "test",
967  "id", "test:///tmp/bob", "metadata", "bob", "joe");
968  if (!expected) {
969  ast_test_status_update(test, "Could not produce JSON for expected bucket file value\n");
970  return AST_TEST_FAIL;
971  }
972 
973  json = ast_bucket_file_json(file);
974  if (!json) {
975  ast_test_status_update(test, "Could not produce JSON for a valid file\n");
976  return AST_TEST_FAIL;
977  }
978 
979  if (!ast_json_equal(json, expected)) {
980  ast_test_status_update(test, "Bucket file JSON does not match expected output\n");
981  return AST_TEST_FAIL;
982  }
983 
984  return AST_TEST_PASS;
985 }
986 
987 static int unload_module(void)
988 {
989  AST_TEST_UNREGISTER(bucket_scheme_register);
991  AST_TEST_UNREGISTER(bucket_create);
992  AST_TEST_UNREGISTER(bucket_clone);
993  AST_TEST_UNREGISTER(bucket_delete);
994  AST_TEST_UNREGISTER(bucket_retrieve);
995  AST_TEST_UNREGISTER(bucket_json);
997  AST_TEST_UNREGISTER(bucket_file_create);
998  AST_TEST_UNREGISTER(bucket_file_clone);
999  AST_TEST_UNREGISTER(bucket_file_copy);
1000  AST_TEST_UNREGISTER(bucket_file_retrieve);
1001  AST_TEST_UNREGISTER(bucket_file_update);
1002  AST_TEST_UNREGISTER(bucket_file_delete);
1003  AST_TEST_UNREGISTER(bucket_file_metadata_set);
1004  AST_TEST_UNREGISTER(bucket_file_metadata_unset);
1005  AST_TEST_UNREGISTER(bucket_file_metadata_get);
1006  AST_TEST_UNREGISTER(bucket_file_json);
1007  return 0;
1008 }
1009 
1010 static int load_module(void)
1011 {
1012  if (ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard,
1014  ast_log(LOG_ERROR, "Failed to register Bucket test wizard scheme implementation\n");
1015  return AST_MODULE_LOAD_DECLINE;
1016  }
1017 
1018  AST_TEST_REGISTER(bucket_scheme_register);
1020  AST_TEST_REGISTER(bucket_create);
1021  AST_TEST_REGISTER(bucket_clone);
1022  AST_TEST_REGISTER(bucket_delete);
1023  AST_TEST_REGISTER(bucket_retrieve);
1024  AST_TEST_REGISTER(bucket_is_stale);
1025  AST_TEST_REGISTER(bucket_json);
1027  AST_TEST_REGISTER(bucket_file_create);
1028  AST_TEST_REGISTER(bucket_file_clone);
1029  AST_TEST_REGISTER(bucket_file_copy);
1030  AST_TEST_REGISTER(bucket_file_retrieve);
1031  AST_TEST_REGISTER(bucket_file_update);
1032  AST_TEST_REGISTER(bucket_file_delete);
1033  AST_TEST_REGISTER(bucket_file_is_stale);
1034  AST_TEST_REGISTER(bucket_file_metadata_set);
1035  AST_TEST_REGISTER(bucket_file_metadata_unset);
1036  AST_TEST_REGISTER(bucket_file_metadata_get);
1037  AST_TEST_REGISTER(bucket_file_json);
1038  return AST_MODULE_LOAD_SUCCESS;
1039 }
1040 
struct ast_bucket_metadata * ast_bucket_file_metadata_get(struct ast_bucket_file *file, const char *name)
Retrieve a metadata attribute from a file.
Definition: bucket.c:359
struct ast_bucket * ast_bucket_alloc(const char *uri)
Allocate a new bucket.
Definition: bucket.c:431
static struct ast_sorcery_wizard bucket_file_test_wizard
Definition: test_bucket.c:124
static const char type[]
Definition: chan_ooh323.c:109
int ast_bucket_create(struct ast_bucket *bucket)
Create a new bucket in backend storage.
Definition: bucket.c:488
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
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.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
int ast_bucket_file_metadata_set(struct ast_bucket_file *file, const char *name, const char *value)
Set a metadata attribute on a file to a specific value.
Definition: bucket.c:334
struct ast_bucket * ast_bucket_clone(struct ast_bucket *bucket)
Clone a bucket.
Definition: bucket.c:510
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define OBJ_KEY
Definition: astobj2.h:1155
Bucket structure, contains other buckets and files.
Definition: bucket.h:57
struct ast_bucket_file * ast_bucket_file_retrieve(const char *uri)
Retrieve a bucket file.
Definition: bucket.c:815
Test Framework API.
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
Full structure for sorcery.
Definition: sorcery.c:230
struct ast_bucket_file * ast_bucket_file_copy(struct ast_bucket_file *file, const char *uri)
Copy a bucket file to a new URI.
Definition: bucket.c:791
static int copy(char *infile, char *outfile)
Utility function to copy a file.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
#define NULL
Definition: resample.c:96
static int bucket_test_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_bucket.c:100
struct ast_bucket_file * ast_bucket_file_alloc(const char *uri)
Allocate a new bucket file.
Definition: bucket.c:663
const char * name
Name of the wizard.
Definition: sorcery.h:278
unsigned int is_stale
Whether the object is stale or not.
Definition: test_bucket.c:52
Bucket File API.
static void * bucket_test_wizard_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Definition: test_bucket.c:88
static int bucket_test_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_bucket.c:111
static int bucket_test_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_bucket.c:66
static struct ast_sorcery_wizard bucket_test_wizard
Definition: test_bucket.c:116
unsigned int updated
Whether the object has been updated or not.
Definition: test_bucket.c:48
#define ast_log
Definition: astobj2.c:42
unsigned int created
Whether the object has been created or not.
Definition: test_bucket.c:46
static void * bucket_file_alloc(const char *name)
Allocator for bucket files.
Definition: bucket.c:640
Asterisk JSON abstraction layer.
#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
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
struct ast_bucket_file * ast_bucket_file_clone(struct ast_bucket_file *file)
Clone a bucket file.
Definition: bucket.c:810
static int bucket_test_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
Definition: test_bucket.c:77
int ast_bucket_file_delete(struct ast_bucket_file *file)
Delete a bucket file from backend storage.
Definition: bucket.c:844
struct ast_json * ast_bucket_file_json(const struct ast_bucket_file *file)
Get a JSON representation of a bucket file.
Definition: bucket.c:849
int ast_bucket_file_is_stale(struct ast_bucket_file *file)
Retrieve whether or not the backing datastore views the bucket file as stale.
Definition: bucket.c:824
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
Bucket file structure, contains reference to file and information about it.
Definition: bucket.h:78
static int unload_module(void)
Definition: test_bucket.c:987
struct ast_bucket * ast_bucket_retrieve(const char *uri)
Retrieve information about a bucket.
Definition: bucket.c:515
#define LOG_ERROR
Definition: logger.h:285
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
def info(msg)
#define ast_strlen_zero(a)
Definition: muted.c:73
int ast_bucket_delete(struct ast_bucket *bucket)
Delete a bucket from backend storage.
Definition: bucket.c:539
static struct bucket_test_state bucket_test_wizard_state
Global scope structure for testing bucket wizards.
Definition: test_bucket.c:56
Bucket metadata structure, AO2 key value pair.
Definition: bucket.h:47
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
int ast_bucket_file_temporary_create(struct ast_bucket_file *file)
Common file snapshot creation callback for creating a temporary file.
Definition: bucket.c:899
AST_TEST_DEFINE(bucket_scheme_register)
Definition: test_bucket.c:133
Support for logging to various files, console and syslog Configuration in file logger.conf.
Interface for a sorcery wizard.
Definition: sorcery.h:276
Test state structure for scheme wizards.
Definition: test_bucket.c:44
static struct ast_sorcery * sorcery
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int ast_bucket_file_update(struct ast_bucket_file *file)
Update an existing bucket file in backend storage.
Definition: bucket.c:839
int ast_json_equal(const struct ast_json *lhs, const struct ast_json *rhs)
Compare two JSON objects.
Definition: json.c:347
static void * bucket_alloc(const char *name)
Allocator for buckets.
Definition: bucket.c:402
#define ast_bucket_scheme_register(name, bucket, file, create_cb, destroy_cb)
Register support for a specific scheme.
Definition: bucket.h:137
int ast_bucket_file_metadata_unset(struct ast_bucket_file *file, const char *name)
Unset a specific metadata attribute on a file.
Definition: bucket.c:348
Abstract JSON element (object, array, string, int, ...).
struct ast_json * ast_bucket_json(const struct ast_bucket *bucket)
Get a JSON representation of a bucket.
Definition: bucket.c:544
void ast_bucket_file_temporary_destroy(struct ast_bucket_file *file)
Common file snapshot destruction callback for deleting a temporary file.
Definition: bucket.c:914
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_bucket_is_stale(struct ast_bucket *bucket)
Retrieve whether or not the backing datastore views the bucket as stale.
Definition: bucket.c:524
Asterisk module definitions.
static int load_module(void)
Definition: test_bucket.c:1010
unsigned int deleted
Whether the object has been deleted or not.
Definition: test_bucket.c:50
int ast_bucket_file_create(struct ast_bucket_file *file)
Create a new bucket file in backend storage.
Definition: bucket.c:725
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition: strings.c:206
static void bucket_test_wizard_clear(void)
Definition: test_bucket.c:58