Fix bucket unit tests
[asterisk/asterisk.git] / tests / test_bucket.c
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 ASTERISK_FILE_VERSION(__FILE__, "")
35
36 #include <sys/stat.h>
37
38 #include "asterisk/test.h"
39 #include "asterisk/module.h"
40 #include "asterisk/bucket.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/json.h"
43 #include "asterisk/file.h"
44
45 /*! \brief Test state structure for scheme wizards */
46 struct bucket_test_state {
47         /*! \brief Whether the object has been created or not */
48         unsigned int created:1;
49         /*! \brief Whether the object has been updated or not */
50         unsigned int updated:1;
51         /*! \brief Whether the object has been deleted or not */
52         unsigned int deleted:1;
53 };
54
55 /*! \brief Global scope structure for testing bucket wizards */
56 static struct bucket_test_state bucket_test_wizard_state;
57
58 static void bucket_test_wizard_clear(void)
59 {
60         bucket_test_wizard_state.created = 0;
61         bucket_test_wizard_state.updated = 0;
62         bucket_test_wizard_state.deleted = 0;
63 }
64
65 static int bucket_test_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
66 {
67         if (bucket_test_wizard_state.created) {
68                 return -1;
69         }
70
71         bucket_test_wizard_state.created = 1;
72
73         return 0;
74 }
75
76 static int bucket_test_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
77 {
78         if (bucket_test_wizard_state.updated) {
79                 return -1;
80         }
81
82         bucket_test_wizard_state.updated = 1;
83
84         return 0;
85 }
86
87 static void *bucket_test_wizard_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type,
88         const char *id)
89 {
90         if (!strcmp(type, "bucket")) {
91                 return ast_bucket_alloc(id);
92         } else if (!strcmp(type, "file")) {
93                 return ast_bucket_file_alloc(id);
94         } else {
95                 return NULL;
96         }
97 }
98
99 static int bucket_test_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
100 {
101         if (bucket_test_wizard_state.deleted) {
102                 return -1;
103         }
104
105         bucket_test_wizard_state.deleted = 1;
106
107         return 0;
108 }
109
110 static struct ast_sorcery_wizard bucket_test_wizard = {
111         .name = "test",
112         .create = bucket_test_wizard_create,
113         .retrieve_id = bucket_test_wizard_retrieve_id,
114         .delete = bucket_test_wizard_delete,
115 };
116
117 static struct ast_sorcery_wizard bucket_file_test_wizard = {
118         .name = "test",
119         .create = bucket_test_wizard_create,
120         .update = bucket_test_wizard_update,
121         .retrieve_id = bucket_test_wizard_retrieve_id,
122         .delete = bucket_test_wizard_delete,
123 };
124
125 AST_TEST_DEFINE(bucket_scheme_register)
126 {
127         switch (cmd) {
128         case TEST_INIT:
129                 info->name = "bucket_scheme_register_unregister";
130                 info->category = "/main/bucket/";
131                 info->summary = "bucket scheme registration/unregistration unit test";
132                 info->description =
133                         "Test registration and unregistration of bucket scheme";
134                 return AST_TEST_NOT_RUN;
135         case TEST_EXECUTE:
136                 break;
137         }
138
139         if (!ast_bucket_scheme_register("", NULL, NULL, NULL, NULL)) {
140                 ast_test_status_update(test, "Successfully registered a Bucket scheme without name or wizards\n");
141                 return AST_TEST_FAIL;
142         }
143
144         if (!ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard, NULL, NULL)) {
145                 ast_test_status_update(test, "Successfully registered a Bucket scheme twice\n");
146                 return AST_TEST_FAIL;
147         }
148
149         return AST_TEST_PASS;
150 }
151
152 AST_TEST_DEFINE(bucket_alloc)
153 {
154         RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
155
156         switch (cmd) {
157         case TEST_INIT:
158                 info->name = "bucket_alloc";
159                 info->category = "/main/bucket/";
160                 info->summary = "bucket allocation unit test";
161                 info->description =
162                         "Test allocation of buckets";
163                 return AST_TEST_NOT_RUN;
164         case TEST_EXECUTE:
165                 break;
166         }
167
168         if ((bucket = ast_bucket_alloc(""))) {
169                 ast_test_status_update(test, "Allocated a bucket with no URI provided\n");
170                 return AST_TEST_FAIL;
171         }
172
173         if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
174                 ast_test_status_update(test, "Failed to allocate bucket\n");
175                 return AST_TEST_FAIL;
176         }
177
178         if (strcmp(ast_sorcery_object_get_id(bucket), "test:///tmp/bob")) {
179                 ast_test_status_update(test, "URI within allocated bucket is '%s' and should be test:///tmp/bob\n",
180                         ast_sorcery_object_get_id(bucket));
181                 return AST_TEST_FAIL;
182         }
183
184         if (strcmp(bucket->scheme, "test")) {
185                 ast_test_status_update(test, "Scheme within allocated bucket is '%s' and should be test\n",
186                         bucket->scheme);
187                 return AST_TEST_FAIL;
188         }
189
190         return AST_TEST_PASS;
191 }
192
193 AST_TEST_DEFINE(bucket_create)
194 {
195         RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
196
197         switch (cmd) {
198         case TEST_INIT:
199                 info->name = "bucket_create";
200                 info->category = "/main/bucket/";
201                 info->summary = "bucket creation unit test";
202                 info->description =
203                         "Test creation of buckets";
204                 return AST_TEST_NOT_RUN;
205         case TEST_EXECUTE:
206                 break;
207         }
208
209         if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
210                 ast_test_status_update(test, "Failed to allocate bucket\n");
211                 return AST_TEST_FAIL;
212         }
213
214         bucket_test_wizard_clear();
215
216         if (ast_bucket_create(bucket)) {
217                 ast_test_status_update(test, "Failed to create bucket with URI '%s'\n",
218                         ast_sorcery_object_get_id(bucket));
219                 return AST_TEST_FAIL;
220         }
221
222         if (!bucket_test_wizard_state.created) {
223                 ast_test_status_update(test, "Bucket creation returned success but scheme implementation never actually created it\n");
224                 return AST_TEST_FAIL;
225         }
226
227         if (!ast_bucket_create(bucket)) {
228                 ast_test_status_update(test, "Successfully created bucket with URI '%s' twice\n",
229                         ast_sorcery_object_get_id(bucket));
230                 return AST_TEST_FAIL;
231         }
232
233         return AST_TEST_PASS;
234 }
235
236 AST_TEST_DEFINE(bucket_delete)
237 {
238         RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
239
240         switch (cmd) {
241         case TEST_INIT:
242                 info->name = "bucket_delete";
243                 info->category = "/main/bucket/";
244                 info->summary = "bucket deletion unit test";
245                 info->description =
246                         "Test deletion of buckets";
247                 return AST_TEST_NOT_RUN;
248         case TEST_EXECUTE:
249                 break;
250         }
251
252         if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
253                 ast_test_status_update(test, "Failed to allocate bucket\n");
254                 return AST_TEST_FAIL;
255         }
256
257         bucket_test_wizard_clear();
258
259         if (ast_bucket_delete(bucket)) {
260                 ast_test_status_update(test, "Failed to delete bucket with URI '%s'\n",
261                         ast_sorcery_object_get_id(bucket));
262                 return AST_TEST_FAIL;
263         }
264
265         if (!bucket_test_wizard_state.deleted) {
266                 ast_test_status_update(test, "Bucket deletion returned success but scheme implementation never actually deleted it\n");
267                 return AST_TEST_FAIL;
268         }
269
270         if (!ast_bucket_delete(bucket)) {
271                 ast_test_status_update(test, "Successfully deleted bucket with URI '%s' twice\n",
272                         ast_sorcery_object_get_id(bucket));
273                 return AST_TEST_FAIL;
274         }
275
276         return AST_TEST_PASS;
277 }
278
279 AST_TEST_DEFINE(bucket_json)
280 {
281         RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
282         RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
283         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
284
285         switch (cmd) {
286         case TEST_INIT:
287                 info->name = "bucket_json";
288                 info->category = "/main/bucket/";
289                 info->summary = "bucket json unit test";
290                 info->description =
291                         "Test creation of JSON for a bucket";
292                 return AST_TEST_NOT_RUN;
293         case TEST_EXECUTE:
294                 break;
295         }
296
297         if (!(bucket = ast_bucket_alloc("test:///tmp/bob"))) {
298                 ast_test_status_update(test, "Failed to allocate bucket\n");
299                 return AST_TEST_FAIL;
300         }
301
302         ast_str_container_add(bucket->buckets, "test:///tmp/bob/joe");
303         ast_str_container_add(bucket->files, "test:///tmp/bob/recording.wav");
304
305         expected = ast_json_pack("{s: s, s: s, s: [s], s: s, s: [s], s: s}",
306                 "modified", "0.000000", "created", "0.000000",
307                 "buckets", "test:///tmp/bob/joe",
308                 "scheme", "test",
309                 "files", "test:///tmp/bob/recording.wav",
310                 "id", "test:///tmp/bob");
311         if (!expected) {
312                 ast_test_status_update(test, "Could not produce JSON for expected bucket value\n");
313                 return AST_TEST_FAIL;
314         }
315
316         json = ast_bucket_json(bucket);
317         if (!json) {
318                 ast_test_status_update(test, "Could not produce JSON for a valid bucket\n");
319                 return AST_TEST_FAIL;
320         }
321
322         if (!ast_json_equal(json, expected)) {
323                 ast_test_status_update(test, "Bucket JSON does not match expected output\n");
324                 return AST_TEST_FAIL;
325         }
326
327         return AST_TEST_PASS;
328 }
329
330 AST_TEST_DEFINE(bucket_retrieve)
331 {
332         RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
333
334         switch (cmd) {
335         case TEST_INIT:
336                 info->name = "bucket_retrieve";
337                 info->category = "/main/bucket/";
338                 info->summary = "bucket retrieval unit test";
339                 info->description =
340                         "Test retrieval of buckets";
341                 return AST_TEST_NOT_RUN;
342         case TEST_EXECUTE:
343                 break;
344         }
345
346         if (!(bucket = ast_bucket_retrieve("test://tmp/bob"))) {
347                 ast_test_status_update(test, "Failed to retrieve known valid bucket\n");
348                 return AST_TEST_FAIL;
349         }
350
351         return AST_TEST_PASS;
352 }
353
354 AST_TEST_DEFINE(bucket_file_alloc)
355 {
356         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
357
358         switch (cmd) {
359         case TEST_INIT:
360                 info->name = "bucket_file_alloc";
361                 info->category = "/main/bucket/";
362                 info->summary = "bucket file allocation unit test";
363                 info->description =
364                         "Test allocation of bucket files";
365                 return AST_TEST_NOT_RUN;
366         case TEST_EXECUTE:
367                 break;
368         }
369
370         if ((file = ast_bucket_file_alloc(""))) {
371                 ast_test_status_update(test, "Allocated a file with no URI provided\n");
372                 return AST_TEST_FAIL;
373         }
374
375         if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
376                 ast_test_status_update(test, "Failed to allocate file\n");
377                 return AST_TEST_FAIL;
378         }
379
380         if (ast_strlen_zero(file->path)) {
381                 ast_test_status_update(test, "Expected temporary path in allocated file");
382                 return AST_TEST_FAIL;
383         }
384
385         if (strcmp(ast_sorcery_object_get_id(file), "test:///tmp/bob")) {
386                 ast_test_status_update(test, "URI within allocated file is '%s' and should be test:///tmp/bob\n",
387                         ast_sorcery_object_get_id(file));
388                 return AST_TEST_FAIL;
389         }
390
391         if (strcmp(file->scheme, "test")) {
392                 ast_test_status_update(test, "Scheme within allocated file is '%s' and should be test\n",
393                         file->scheme);
394                 return AST_TEST_FAIL;
395         }
396
397         return AST_TEST_PASS;
398 }
399
400 AST_TEST_DEFINE(bucket_file_create)
401 {
402         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
403
404         switch (cmd) {
405         case TEST_INIT:
406                 info->name = "bucket_file_create";
407                 info->category = "/main/bucket/";
408                 info->summary = "file creation unit test";
409                 info->description =
410                         "Test creation of files";
411                 return AST_TEST_NOT_RUN;
412         case TEST_EXECUTE:
413                 break;
414         }
415
416         if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
417                 ast_test_status_update(test, "Failed to allocate file\n");
418                 return AST_TEST_FAIL;
419         }
420
421         bucket_test_wizard_clear();
422
423         if (ast_bucket_file_create(file)) {
424                 ast_test_status_update(test, "Failed to create file with URI '%s'\n",
425                         ast_sorcery_object_get_id(file));
426                 return AST_TEST_FAIL;
427         }
428
429         if (!bucket_test_wizard_state.created) {
430                 ast_test_status_update(test, "Bucket file creation returned success but scheme implementation never actually created it\n");
431                 return AST_TEST_FAIL;
432         }
433
434         if (!ast_bucket_file_create(file)) {
435                 ast_test_status_update(test, "Successfully created file with URI '%s' twice\n",
436                         ast_sorcery_object_get_id(file));
437                 return AST_TEST_FAIL;
438         }
439
440         return AST_TEST_PASS;
441 }
442
443 AST_TEST_DEFINE(bucket_file_copy)
444 {
445         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
446         RAII_VAR(struct ast_bucket_file *, copy, NULL, ao2_cleanup);
447         FILE *temporary;
448         struct stat old, new;
449         RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
450
451         switch (cmd) {
452         case TEST_INIT:
453                 info->name = "bucket_file_copy";
454                 info->category = "/main/bucket/";
455                 info->summary = "bucket file copying unit test";
456                 info->description =
457                         "Test copying of bucket files";
458                 return AST_TEST_NOT_RUN;
459         case TEST_EXECUTE:
460                 break;
461         }
462
463         if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
464                 ast_test_status_update(test, "Failed to allocate file\n");
465                 return AST_TEST_FAIL;
466         }
467
468         ast_bucket_file_metadata_set(file, "bob", "joe");
469
470         if (!(temporary = fopen(file->path, "w"))) {
471                 ast_test_status_update(test, "Failed to open temporary file '%s'\n", file->path);
472                 return AST_TEST_FAIL;
473         }
474
475         fprintf(temporary, "bob");
476         fclose(temporary);
477
478         if (!(copy = ast_bucket_file_copy(file, "test:///tmp/bob2"))) {
479                 ast_test_status_update(test, "Failed to copy file '%s' to test:///tmp/bob2\n",
480                         ast_sorcery_object_get_id(file));
481                 return AST_TEST_FAIL;
482         }
483
484         if (stat(file->path, &old)) {
485                 ast_test_status_update(test, "Failed to retrieve information on old file '%s'\n", file->path);
486                 return AST_TEST_FAIL;
487         }
488
489         if (stat(copy->path, &new)) {
490                 ast_test_status_update(test, "Failed to retrieve information on copy file '%s'\n", copy->path);
491                 return AST_TEST_FAIL;
492         }
493
494         if (old.st_size != new.st_size) {
495                 ast_test_status_update(test, "Copying of underlying temporary file failed\n");
496                 return AST_TEST_FAIL;
497         }
498
499         if (ao2_container_count(file->metadata) != ao2_container_count(copy->metadata)) {
500                 ast_test_status_update(test, "Number of metadata entries does not match original\n");
501                 return AST_TEST_FAIL;
502         }
503
504         metadata = ast_bucket_file_metadata_get(copy, "bob");
505         if (!metadata) {
506                 ast_test_status_update(test, "Copy of file does not have expected metadata\n");
507                 return AST_TEST_FAIL;
508         }
509
510         if (strcmp(metadata->value, "joe")) {
511                 ast_test_status_update(test, "Copy of file contains metadata for 'bob' but value is not what it should be\n");
512                 return AST_TEST_FAIL;
513         }
514
515         return AST_TEST_PASS;
516 }
517
518 AST_TEST_DEFINE(bucket_file_retrieve)
519 {
520         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
521
522         switch (cmd) {
523         case TEST_INIT:
524                 info->name = "bucket_file_retrieve";
525                 info->category = "/main/bucket/";
526                 info->summary = "file retrieval unit test";
527                 info->description =
528                         "Test retrieval of files";
529                 return AST_TEST_NOT_RUN;
530         case TEST_EXECUTE:
531                 break;
532         }
533
534         if (!(file = ast_bucket_file_retrieve("test://tmp/bob"))) {
535                 ast_test_status_update(test, "Failed to retrieve known valid file\n");
536                 return AST_TEST_FAIL;
537         }
538
539         return AST_TEST_PASS;
540 }
541
542 AST_TEST_DEFINE(bucket_file_update)
543 {
544         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
545
546         switch (cmd) {
547         case TEST_INIT:
548                 info->name = "bucket_file_update";
549                 info->category = "/main/bucket/";
550                 info->summary = "file updating unit test";
551                 info->description =
552                         "Test updating of files";
553                 return AST_TEST_NOT_RUN;
554         case TEST_EXECUTE:
555                 break;
556         }
557
558         if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
559                 ast_test_status_update(test, "Failed to allocate file\n");
560                 return AST_TEST_FAIL;
561         }
562
563         bucket_test_wizard_clear();
564
565         if (ast_bucket_file_update(file)) {
566                 ast_test_status_update(test, "Failed to update file with URI '%s'\n",
567                         ast_sorcery_object_get_id(file));
568                 return AST_TEST_FAIL;
569         }
570
571         if (!bucket_test_wizard_state.updated) {
572                 ast_test_status_update(test, "Successfully returned file was updated, but it was not\n");
573                 return AST_TEST_FAIL;
574         }
575
576         if (!ast_bucket_file_update(file)) {
577                 ast_test_status_update(test, "Successfully updated file with URI '%s' twice\n",
578                         ast_sorcery_object_get_id(file));
579                 return AST_TEST_FAIL;
580         }
581
582         return AST_TEST_PASS;
583 }
584
585 AST_TEST_DEFINE(bucket_file_delete)
586 {
587         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
588
589         switch (cmd) {
590         case TEST_INIT:
591                 info->name = "bucket_file_delete";
592                 info->category = "/main/bucket/";
593                 info->summary = "file deletion unit test";
594                 info->description =
595                         "Test deletion of files";
596                 return AST_TEST_NOT_RUN;
597         case TEST_EXECUTE:
598                 break;
599         }
600
601         if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
602                 ast_test_status_update(test, "Failed to allocate file\n");
603                 return AST_TEST_FAIL;
604         }
605
606         bucket_test_wizard_clear();
607
608         if (ast_bucket_file_delete(file)) {
609                 ast_test_status_update(test, "Failed to delete file with URI '%s'\n",
610                         ast_sorcery_object_get_id(file));
611                 return AST_TEST_FAIL;
612         }
613
614         if (!bucket_test_wizard_state.deleted) {
615                 ast_test_status_update(test, "Bucket file deletion returned success but scheme implementation never actually deleted it\n");
616                 return AST_TEST_FAIL;
617         }
618
619         if (!ast_bucket_file_delete(file)) {
620                 ast_test_status_update(test, "Successfully deleted file with URI '%s' twice\n",
621                         ast_sorcery_object_get_id(file));
622                 return AST_TEST_FAIL;
623         }
624
625         return AST_TEST_PASS;
626 }
627
628 AST_TEST_DEFINE(bucket_file_metadata_set)
629 {
630         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
631         RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
632
633         switch (cmd) {
634         case TEST_INIT:
635                 info->name = "bucket_file_metadata_set";
636                 info->category = "/main/bucket/";
637                 info->summary = "file metadata setting unit test";
638                 info->description =
639                         "Test setting of metadata on files";
640                 return AST_TEST_NOT_RUN;
641         case TEST_EXECUTE:
642                 break;
643         }
644
645         if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
646                 ast_test_status_update(test, "Failed to allocate file\n");
647                 return AST_TEST_FAIL;
648         }
649
650         if (ao2_container_count(file->metadata) != 0) {
651                 ast_test_status_update(test, "Newly allocated file has metadata count of '%d' when should be 0\n",
652                         ao2_container_count(file->metadata));
653                 return AST_TEST_FAIL;
654         }
655
656         if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
657                 ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
658                 return AST_TEST_FAIL;
659         }
660
661         if (!(metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
662                 ast_test_status_update(test, "Failed to find set metadata 'bob' on newly allocated file\n");
663                 return AST_TEST_FAIL;
664         }
665
666         if (strcmp(metadata->value, "joe")) {
667                 ast_test_status_update(test, "Metadata has value '%s' when should be 'joe'\n",
668                         metadata->value);
669                 return AST_TEST_FAIL;
670         }
671
672         ao2_cleanup(metadata);
673         metadata = NULL;
674
675         if (ast_bucket_file_metadata_set(file, "bob", "fred")) {
676                 ast_test_status_update(test, "Failed to overwrite metadata 'bob' with new value 'fred'\n");
677                 return AST_TEST_FAIL;
678         }
679
680         if (!(metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
681                 ast_test_status_update(test, "Failed to find overwritten metadata 'bob' on newly allocated file\n");
682                 return AST_TEST_FAIL;
683         }
684
685         if (strcmp(metadata->value, "fred")) {
686                 ast_test_status_update(test, "Metadata has value '%s' when should be 'fred'\n",
687                         metadata->value);
688                 return AST_TEST_FAIL;
689         }
690
691         return AST_TEST_PASS;
692 }
693
694 AST_TEST_DEFINE(bucket_file_metadata_unset)
695 {
696         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
697         RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
698
699         switch (cmd) {
700         case TEST_INIT:
701                 info->name = "bucket_file_metadata_unset";
702                 info->category = "/main/bucket/";
703                 info->summary = "file metadata unsetting unit test";
704                 info->description =
705                         "Test unsetting of metadata on files";
706                 return AST_TEST_NOT_RUN;
707         case TEST_EXECUTE:
708                 break;
709         }
710
711         if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
712                 ast_test_status_update(test, "Failed to allocate file\n");
713                 return AST_TEST_FAIL;
714         }
715
716         if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
717                 ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
718                 return AST_TEST_FAIL;
719         }
720
721         if (ast_bucket_file_metadata_unset(file, "bob")) {
722                 ast_test_status_update(test, "Failed to unset metadata 'bob' on newly allocated file\n");
723                 return AST_TEST_FAIL;
724         }
725
726         if ((metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
727                 ast_test_status_update(test, "Metadata 'bob' was unset, but can still be found\n");
728                 return AST_TEST_FAIL;
729         }
730
731         return AST_TEST_PASS;
732 }
733
734 AST_TEST_DEFINE(bucket_file_metadata_get)
735 {
736         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
737         RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
738
739         switch (cmd) {
740         case TEST_INIT:
741                 info->name = "bucket_file_metadata_get";
742                 info->category = "/main/bucket/";
743                 info->summary = "file metadata getting unit test";
744                 info->description =
745                         "Test getting of metadata on files";
746                 return AST_TEST_NOT_RUN;
747         case TEST_EXECUTE:
748                 break;
749         }
750
751         if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
752                 ast_test_status_update(test, "Failed to allocate file\n");
753                 return AST_TEST_FAIL;
754         }
755
756         if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
757                 ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
758                 return AST_TEST_FAIL;
759         }
760
761         if (!(metadata = ast_bucket_file_metadata_get(file, "bob"))) {
762                 ast_test_status_update(test, "Failed to retrieve metadata 'bob' that was just set\n");
763                 return AST_TEST_FAIL;
764         }
765
766         if (strcmp(metadata->value, "joe")) {
767                 ast_test_status_update(test, "Retrieved metadata value is '%s' while it should be 'joe'\n",
768                         metadata->value);
769                 return AST_TEST_FAIL;
770         }
771
772         return AST_TEST_PASS;
773 }
774
775 AST_TEST_DEFINE(bucket_file_json)
776 {
777         RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
778         RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
779         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
780
781         switch (cmd) {
782         case TEST_INIT:
783                 info->name = "bucket_file_json";
784                 info->category = "/main/bucket/";
785                 info->summary = "file json unit test";
786                 info->description =
787                         "Test creation of JSON for a file";
788                 return AST_TEST_NOT_RUN;
789         case TEST_EXECUTE:
790                 break;
791         }
792
793         if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
794                 ast_test_status_update(test, "Failed to allocate bucket\n");
795                 return AST_TEST_FAIL;
796         }
797
798         if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
799                 ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
800                 return AST_TEST_FAIL;
801         }
802
803         expected = ast_json_pack("{s: s, s: s, s: s, s: s, s: {s :s}}",
804                 "modified", "0.000000", "created", "0.000000", "scheme", "test",
805                 "id", "test:///tmp/bob", "metadata", "bob", "joe");
806         if (!expected) {
807                 ast_test_status_update(test, "Could not produce JSON for expected bucket file value\n");
808                 return AST_TEST_FAIL;
809         }
810
811         json = ast_bucket_file_json(file);
812         if (!json) {
813                 ast_test_status_update(test, "Could not produce JSON for a valid file\n");
814                 return AST_TEST_FAIL;
815         }
816
817         if (!ast_json_equal(json, expected)) {
818                 ast_test_status_update(test, "Bucket file JSON does not match expected output\n");
819                 return AST_TEST_FAIL;
820         }
821
822         return AST_TEST_PASS;
823 }
824
825 static int unload_module(void)
826 {
827         AST_TEST_UNREGISTER(bucket_scheme_register);
828         AST_TEST_UNREGISTER(bucket_alloc);
829         AST_TEST_UNREGISTER(bucket_create);
830         AST_TEST_UNREGISTER(bucket_delete);
831         AST_TEST_UNREGISTER(bucket_retrieve);
832         AST_TEST_UNREGISTER(bucket_json);
833         AST_TEST_UNREGISTER(bucket_file_alloc);
834         AST_TEST_UNREGISTER(bucket_file_create);
835         AST_TEST_UNREGISTER(bucket_file_copy);
836         AST_TEST_UNREGISTER(bucket_file_retrieve);
837         AST_TEST_UNREGISTER(bucket_file_update);
838         AST_TEST_UNREGISTER(bucket_file_delete);
839         AST_TEST_UNREGISTER(bucket_file_metadata_set);
840         AST_TEST_UNREGISTER(bucket_file_metadata_unset);
841         AST_TEST_UNREGISTER(bucket_file_metadata_get);
842         AST_TEST_UNREGISTER(bucket_file_json);
843         return 0;
844 }
845
846 static int load_module(void)
847 {
848         if (ast_bucket_scheme_register("test", &bucket_test_wizard, &bucket_file_test_wizard,
849                 ast_bucket_file_temporary_create, ast_bucket_file_temporary_destroy)) {
850                 ast_log(LOG_ERROR, "Failed to register Bucket test wizard scheme implementation\n");
851                 return AST_MODULE_LOAD_FAILURE;
852         }
853
854         AST_TEST_REGISTER(bucket_scheme_register);
855         AST_TEST_REGISTER(bucket_alloc);
856         AST_TEST_REGISTER(bucket_create);
857         AST_TEST_REGISTER(bucket_delete);
858         AST_TEST_REGISTER(bucket_retrieve);
859         AST_TEST_REGISTER(bucket_json);
860         AST_TEST_REGISTER(bucket_file_alloc);
861         AST_TEST_REGISTER(bucket_file_create);
862         AST_TEST_REGISTER(bucket_file_copy);
863         AST_TEST_REGISTER(bucket_file_retrieve);
864         AST_TEST_REGISTER(bucket_file_update);
865         AST_TEST_REGISTER(bucket_file_delete);
866         AST_TEST_REGISTER(bucket_file_metadata_set);
867         AST_TEST_REGISTER(bucket_file_metadata_unset);
868         AST_TEST_REGISTER(bucket_file_metadata_get);
869         AST_TEST_REGISTER(bucket_file_json);
870         return AST_MODULE_LOAD_SUCCESS;
871 }
872
873 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Bucket test module");