git migration: Refactor the ASTERISK_FILE_VERSION macro
[asterisk/asterisk.git] / tests / test_voicemail_api.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Matt Jordan
5  *
6  * Matt Jordan <mjordan@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 Skeleton Test
22  *
23  * \author\verbatim Matt Jordan <mjordan@digium.com> \endverbatim
24  *
25  * Tests for the publicly exposed Voicemail API
26  * \ingroup tests
27  */
28
29 /*** MODULEINFO
30         <depend>TEST_FRAMEWORK</depend>
31         <support_level>core</support_level>
32  ***/
33
34 #include "asterisk.h"
35
36 ASTERISK_REGISTER_FILE()
37
38 #include <sys/stat.h>
39
40 #include "asterisk/utils.h"
41 #include "asterisk/module.h"
42 #include "asterisk/test.h"
43 #include "asterisk/paths.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/app.h"
46 #include "asterisk/format_cache.h"
47
48 /*!
49  * \internal
50  * \brief Permissions to set on the voicemail directories we create
51  *
52  * \note taken from app_voicemail
53  */
54 #define VOICEMAIL_DIR_MODE 0777
55
56 /*!
57  * \internal
58  * \brief Permissions to set on the voicemail files we create
59  *
60  * \note taken from app_voicemail
61  */
62 #define VOICEMAIL_FILE_MODE 0666
63
64 /*!
65  * \internal
66  * \brief The number of mock snapshot objects we use for tests
67  */
68 #define TOTAL_SNAPSHOTS 4
69
70 /*!
71  * \internal
72  * \brief Create and populate the mock message objects and create the
73  * envelope files on the file system
74  */
75 #define VM_API_TEST_SETUP do { \
76         if (!ast_vm_is_registered()) { \
77                 ast_test_status_update(test, "No voicemail provider registered.\n"); \
78                 return AST_TEST_FAIL; \
79         } else if (test_vm_api_test_setup()) { \
80                 VM_API_TEST_CLEANUP; \
81                 ast_test_status_update(test, "Failed to set up necessary mock objects for voicemail API test\n"); \
82                 return AST_TEST_FAIL; \
83         } else { \
84                 int i = 0; \
85                 for (; i < TOTAL_SNAPSHOTS; i++) { \
86                         ast_test_status_update(test, "Created message in %s/%s with ID %s\n", \
87                                 test_snapshots[i]->exten, test_snapshots[i]->folder_name, test_snapshots[i]->msg_id); \
88                 } \
89 } } while (0)
90
91 /*!
92  * \internal
93  * \brief Safely cleanup after a test run.
94  *
95  * \note This should be called both when a test fails and when it passes
96  */
97 #define VM_API_TEST_CLEANUP test_vm_api_test_teardown()
98
99 /*!
100  * \internal
101  * \brief Safely cleanup a snapshot and a test run.
102  *
103  * \note It assumes that the mailbox snapshot object is test_mbox_snapshot
104  */
105 #define VM_API_SNAPSHOT_TEST_CLEANUP \
106                 if (test_mbox_snapshot) { \
107                         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \
108                 } \
109                 VM_API_TEST_CLEANUP; \
110
111 /*!
112  * \internal
113  * \brief Verify the expected result from two string values obtained
114  * from a mailbox snapshot.
115  *
116  * \note It assumes the mailbox snapshot object is test_mbox_snapshot
117  */
118 #define VM_API_STRING_FIELD_VERIFY(expected, actual) do { \
119         if (strcmp((expected), (actual))) { \
120                 ast_test_status_update(test, "Test failed for parameter %s: Expected [%s], Actual [%s]\n", #actual, expected, actual); \
121                 VM_API_SNAPSHOT_TEST_CLEANUP; \
122                 return AST_TEST_FAIL; \
123         } } while (0)
124
125 /*!
126  * \internal
127  * \brief Verify the expected result from two integer values.
128  *
129  * \note It assumes the mailbox snapshot object is test_mbox_snapshot
130  */
131 #define VM_API_INT_VERIFY(expected, actual) do { \
132         if ((expected) != (actual)) { \
133                 ast_test_status_update(test, "Test failed for parameter %s: Expected [%d], Actual [%d]\n", #actual, (int)expected, (int)actual); \
134                 VM_API_SNAPSHOT_TEST_CLEANUP; \
135                 return AST_TEST_FAIL; \
136         } } while (0)
137
138 /*!
139  * \internal
140  * \brief Verify that a mailbox snapshot contains the expected message
141  * snapshot, in the correct position, with the expected values.
142  *
143  * \note It assumes the mailbox snapshot object is test_mbox_snapshot
144  */
145 #define VM_API_SNAPSHOT_MSG_VERIFY(expected, actual, expected_folder, expected_index) do { \
146         struct ast_vm_msg_snapshot *msg; \
147         int found = 0; \
148         int counter = 0; \
149         AST_LIST_TRAVERSE(&((actual)->snapshots[get_folder_by_name(expected_folder)]), msg, msg) { \
150                 if (!(strcmp(msg->msg_id, (expected)->msg_id))) { \
151                         ast_test_status_update(test, "Found message %s in snapshot\n", msg->msg_id); \
152                         found = 1; \
153                         if ((expected_index) != counter) { \
154                                 ast_test_status_update(test, "Expected message %s at index %d; Actual [%d]\n", \
155                                         (expected)->msg_id, (expected_index), counter); \
156                                 VM_API_SNAPSHOT_TEST_CLEANUP; \
157                                 return AST_TEST_FAIL; \
158                         } \
159                         VM_API_STRING_FIELD_VERIFY((expected)->callerid, msg->callerid); \
160                         VM_API_STRING_FIELD_VERIFY((expected)->callerchan, msg->callerchan); \
161                         VM_API_STRING_FIELD_VERIFY((expected)->exten, msg->exten); \
162                         VM_API_STRING_FIELD_VERIFY((expected)->origdate, msg->origdate); \
163                         VM_API_STRING_FIELD_VERIFY((expected)->origtime, msg->origtime); \
164                         VM_API_STRING_FIELD_VERIFY((expected)->duration, msg->duration); \
165                         VM_API_STRING_FIELD_VERIFY((expected)->folder_name, msg->folder_name); \
166                         VM_API_STRING_FIELD_VERIFY((expected)->flag, msg->flag); \
167                         VM_API_INT_VERIFY((expected)->msg_number, msg->msg_number); \
168                         break; \
169                 } \
170                 ++counter; \
171         } \
172         if (!found) { \
173                 ast_test_status_update(test, "Test failed for message snapshot %s: not found in mailbox snapshot\n", (expected)->msg_id); \
174                 VM_API_SNAPSHOT_TEST_CLEANUP; \
175                 return AST_TEST_FAIL; \
176 } } while (0)
177
178
179 /*!
180  * \internal
181  * \brief Create a message snapshot, failing the test if the snapshot could not be created.
182  *
183  * \note This requires having a snapshot named test_mbox_snapshot.
184  */
185 #define VM_API_SNAPSHOT_CREATE(mailbox, context, folder, desc, sort, old_and_inbox) do { \
186         if (!(test_mbox_snapshot = ast_vm_mailbox_snapshot_create( \
187                 (mailbox), (context), (folder), (desc), (sort), (old_and_inbox)))) { \
188                 ast_test_status_update(test, "Failed to create voicemail mailbox snapshot\n"); \
189                 VM_API_TEST_CLEANUP; \
190                 return AST_TEST_FAIL; \
191         } } while (0)
192
193 /*!
194  * \internal
195  * \brief Create a message snapshot, failing the test if the snapshot could be created.
196  *
197  * \note This is used to test off nominal conditions.
198  * \note This requires having a snapshot named test_mbox_snapshot.
199  */
200 #define VM_API_SNAPSHOT_OFF_NOMINAL_TEST(mailbox, context, folder, desc, sort, old_and_inbox) do { \
201         if ((test_mbox_snapshot = ast_vm_mailbox_snapshot_create( \
202                 (mailbox), (context), (folder), (desc), (sort), (old_and_inbox)))) { \
203                 ast_test_status_update(test, "Created mailbox snapshot when none was expected\n"); \
204                 test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \
205                 VM_API_TEST_CLEANUP; \
206                 return AST_TEST_FAIL; \
207         } } while (0)
208
209 /*!
210  * \internal
211  * \brief Move a voicemail message, failing the test if the message could not be moved
212  */
213 #define VM_API_MOVE_MESSAGE(mailbox, context, number_of_messages, source, message_numbers_in, dest) do { \
214         if (ast_vm_msg_move((mailbox), (context), (number_of_messages), (source), (message_numbers_in), (dest))) { \
215                 ast_test_status_update(test, "Failed to move message %s@%s from %s to %s\n", \
216                         (mailbox) ? (mailbox): "(NULL)", (context) ? (context) : "(NULL)", (source) ? (source) : "(NULL)", (dest) ? (dest) : "(NULL)"); \
217                 VM_API_TEST_CLEANUP; \
218                 return AST_TEST_FAIL; \
219         } } while (0)
220
221 /*!
222  * \internal
223  * \brief Attempt to move a voicemail message, failing the test if the message could be moved
224  */
225 #define VM_API_MOVE_MESSAGE_OFF_NOMINAL(mailbox, context, number_of_messages, source, message_numbers_in, dest) do { \
226         if (!ast_vm_msg_move((mailbox), (context), (number_of_messages), (source), (message_numbers_in), (dest))) { \
227                 ast_test_status_update(test, "Succeeded to move message %s@%s from %s to %s when we really shouldn't\n", \
228                         (mailbox) ? (mailbox): "(NULL)", (context) ? (context) : "(NULL)", (source) ? (source) : "(NULL)", (dest) ? (dest) : "(NULL)"); \
229                 VM_API_TEST_CLEANUP; \
230                 return AST_TEST_FAIL; \
231         } } while (0)
232
233 /*!
234  * \internal
235  * \brief Remove a message, failing the test if the method failed or if the message is still present.
236  */
237 #define VM_API_REMOVE_MESSAGE(mailbox, context, number_of_messages, folder, message_numbers_in) do { \
238         if (ast_vm_msg_remove((mailbox), (context), (number_of_messages), (folder), (message_numbers_in))) { \
239                 ast_test_status_update(test, "Failed to remove message from mailbox %s@%s, folder %s", \
240                         (mailbox) ? (mailbox): "(NULL)", (context) ? (context) : "(NULL)", (folder) ? (folder) : "(NULL)"); \
241                 VM_API_TEST_CLEANUP; \
242                 return AST_TEST_FAIL; \
243         } \
244         VM_API_SNAPSHOT_CREATE((mailbox), (context), (folder), 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); \
245         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 0); \
246         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \
247 } while (0)
248
249 /*!
250  * \internal
251  * \brief Remove a message, failing the test if the method succeeds
252  */
253 #define VM_API_REMOVE_MESSAGE_OFF_NOMINAL(mailbox, context, number_of_messages, folder, message_numbers_in) do { \
254         if (!ast_vm_msg_remove((mailbox), (context), (number_of_messages), (folder), (message_numbers_in))) { \
255                 ast_test_status_update(test, "Succeeded in removing message from mailbox %s@%s, folder %s, when expected result was failure\n", \
256                                 (mailbox) ? (mailbox): "(NULL)", (context) ? (context) : "(NULL)", (folder) ? (folder) : "(NULL)"); \
257                 VM_API_TEST_CLEANUP; \
258                 return AST_TEST_FAIL; \
259         } } while (0)
260
261 /*!
262  * \internal
263  * \brief Forward a message, failing the test if the message could not be forwarded
264  */
265 # define VM_API_FORWARD_MESSAGE(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, number_of_messages, message_numbers_in, delete_old) do { \
266         if (ast_vm_msg_forward((from_mailbox), (from_context), (from_folder), (to_mailbox), (to_context), (to_folder), (number_of_messages), (message_numbers_in), (delete_old))) { \
267                 ast_test_status_update(test, "Failed to forward message from %s@%s [%s] to %s@%s [%s]\n", \
268                         (from_mailbox) ? (from_mailbox) : "(NULL)", (from_context) ? (from_context) : "(NULL)", (from_folder) ? (from_folder) : "(NULL)", \
269                         (to_mailbox) ? (to_mailbox) : "(NULL)", (to_context) ? (to_context) : "(NULL)", (to_folder) ? (to_folder) : "(NULL)"); \
270                         VM_API_TEST_CLEANUP; \
271                         return AST_TEST_FAIL; \
272         } } while (0)
273
274 /*!
275  * \internal
276  * \brief Forward a message, failing the test if the message was successfully forwarded
277  */
278 #define VM_API_FORWARD_MESSAGE_OFF_NOMINAL(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, number_of_messages, message_numbers_in, delete_old) do { \
279         if (!ast_vm_msg_forward((from_mailbox), (from_context), (from_folder), (to_mailbox), (to_context), (to_folder), (number_of_messages), (message_numbers_in), (delete_old))) { \
280                 ast_test_status_update(test, "Succeeded in forwarding message from %s@%s [%s] to %s@%s [%s] when expected result was fail\n", \
281                         (from_mailbox) ? (from_mailbox) : "(NULL)", (from_context) ? (from_context) : "(NULL)", (from_folder) ? (from_folder) : "(NULL)", \
282                         (to_mailbox) ? (to_mailbox) : "(NULL)", (to_context) ? (to_context) : "(NULL)", (to_folder) ? (to_folder) : "(NULL)"); \
283                         VM_API_TEST_CLEANUP; \
284                         return AST_TEST_FAIL; \
285         } } while (0)
286
287 /*!
288  * \internal                                                                                                              .
289  * \brief Playback a message on a channel or callback function                                                            .
290  *                                                                                                                        .
291  * \note The channel name must be test_channel.
292  * \note Fail the test if the message could not be played.
293  */
294 #define VM_API_PLAYBACK_MESSAGE(channel, mailbox, context, folder, message, callback_fn) do { \
295         if (ast_vm_msg_play((channel), (mailbox), (context), (folder), (message), (callback_fn))) { \
296                 ast_test_status_update(test, "Failed nominal playback message test\n"); \
297                 ast_hangup(test_channel); \
298                 VM_API_TEST_CLEANUP; \
299                 return AST_TEST_FAIL; \
300         } } while (0)
301
302 /*!
303  * \internal
304  * \brief Playback a message on a channel or callback function.
305  *
306  * \note The channel name must be test_channel.
307  * \note Fail the test if the message is successfully played
308  */
309 #define VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(channel, mailbox, context, folder, message, callback_fn) do { \
310         if (!ast_vm_msg_play((channel), (mailbox), (context), (folder), (message), (callback_fn))) { \
311                 ast_test_status_update(test, "Succeeded in playing back of message when expected result was to fail\n"); \
312                 ast_hangup(test_channel); \
313                 VM_API_TEST_CLEANUP; \
314                 return AST_TEST_FAIL; \
315         } } while (0)
316
317
318 /*!
319  * \internal
320  * \brief Possible names of folders.
321  *
322  * \note Taken from app_voicemail
323  */
324 static const char * const mailbox_folders[] = {
325         "INBOX",
326         "Old",
327         "Work",
328         "Family",
329         "Friends",
330         "Cust1",
331         "Cust2",
332         "Cust3",
333         "Cust4",
334         "Cust5",
335         "Deleted",
336         "Urgent",
337 };
338
339 /*!
340  * \internal
341  * \brief Message snapshots representing the messages that are used by the various tests
342  */
343 static struct ast_vm_msg_snapshot *test_snapshots[TOTAL_SNAPSHOTS];
344
345 /*!
346  * \internal
347  * \brief Tracks whether or not we entered into the message playback callback function
348  */
349 static int global_entered_playback_callback = 0;
350
351 /*!
352  * \internal
353  * \brief Get a folder index by its name
354  */
355 static int get_folder_by_name(const char *folder)
356 {
357         size_t i;
358
359         for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
360                 if (strcasecmp(folder, mailbox_folders[i]) == 0) {
361                         return i;
362                 }
363         }
364
365         return -1;
366 }
367
368 /*!
369  * \internal
370  * \brief Get a mock snapshot object
371  *
372  * \param context The mailbox context
373  * \param exten The mailbox extension
374  * \param callerid The caller ID of the person leaving the message
375  *
376  * \returns an ast_vm_msg_snapshot object on success
377  * \returns NULL on error
378  */
379 static struct ast_vm_msg_snapshot *test_vm_api_create_mock_snapshot(const char *context, const char *exten, const char *callerid)
380 {
381         char msg_id_hash[AST_MAX_CONTEXT + AST_MAX_EXTENSION + sizeof(callerid) + 1];
382         char msg_id_buf[256];
383         struct ast_vm_msg_snapshot *snapshot;
384
385         snprintf(msg_id_hash, sizeof(msg_id_hash), "%s%s%s", exten, context, callerid);
386         snprintf(msg_id_buf, sizeof(msg_id_buf), "%ld-%d", (long)time(NULL), ast_str_hash(msg_id_hash));
387
388         if ((snapshot = ast_calloc(1, sizeof(*snapshot)))) {
389                 if (ast_string_field_init(snapshot, 128)) {
390                         ast_free(snapshot);
391                         return NULL;
392                 }
393                 ast_string_field_set(snapshot, msg_id, msg_id_buf);
394                 ast_string_field_set(snapshot, exten, exten);
395                 ast_string_field_set(snapshot, callerid, callerid);
396         }
397         return snapshot;
398 }
399
400 /*!
401  * \internal
402  * \brief Destroy a mock snapshot object
403  */
404 static void test_vm_api_destroy_mock_snapshot(struct ast_vm_msg_snapshot *snapshot)
405 {
406         if (snapshot) {
407                 ast_string_field_free_memory(snapshot);
408                 ast_free(snapshot);
409         }
410 }
411
412 /*!
413  * \internal
414  * \brief Make a voicemail mailbox folder based on the values provided in a message snapshot
415  *
416  * \param snapshot The snapshot containing the information to create the folder from
417  *
418  * \returns 0 on success
419  * \returns 1 on failure
420  */
421 static int test_vm_api_create_voicemail_folder(const char *folder_path)
422 {
423         mode_t mode = VOICEMAIL_DIR_MODE;
424         int res;
425
426         if ((res = ast_mkdir(folder_path, mode))) {
427                 ast_log(AST_LOG_ERROR, "ast_mkdir '%s' failed: %s\n", folder_path, strerror(res));
428                 return 1;
429         }
430         return 0;
431 }
432
433 /*!
434  * \internal
435  * \brief Create the voicemail files specified by a snapshot
436  *
437  * \param context The context of the mailbox
438  * \param mailbox The actual mailbox
439  * \param snapshot The message snapshot object containing the relevant envelope data
440  *
441  * \note This will symbolic link the sound file 'beep.gsm' to act as the 'sound' portion of the voicemail.
442  * Certain actions in app_voicemail will fail if an actual sound file does not exist
443  *
444  * \returns 0 on success
445  * \returns 1 on any failure
446  */
447 static int test_vm_api_create_voicemail_files(const char *context, const char *mailbox, struct ast_vm_msg_snapshot *snapshot)
448 {
449         FILE *msg_file;
450         char folder_path[PATH_MAX];
451         char msg_path[PATH_MAX];
452         char snd_path[PATH_MAX];
453         char beep_path[PATH_MAX];
454
455         /* Note that we create both the text and a dummy sound file here.  Without
456          * the sound file, a number of the voicemail operations 'silently' fail, as it
457          * does not believe that an actual voicemail exists
458          */
459         snprintf(folder_path, sizeof(folder_path), "%s/voicemail/%s/%s/%s",
460                 ast_config_AST_SPOOL_DIR, context, mailbox, snapshot->folder_name);
461         snprintf(msg_path, sizeof(msg_path), "%s/msg%04u.txt",
462                 folder_path, snapshot->msg_number);
463         snprintf(snd_path, sizeof(snd_path), "%s/msg%04u.gsm",
464                 folder_path, snapshot->msg_number);
465         snprintf(beep_path, sizeof(beep_path), "%s/sounds/en/beep.gsm", ast_config_AST_VAR_DIR);
466
467         if (test_vm_api_create_voicemail_folder(folder_path)) {
468                 return 1;
469         }
470
471         if (ast_lock_path(folder_path) == AST_LOCK_FAILURE) {
472                 ast_log(AST_LOG_ERROR, "Unable to lock directory %s\n", folder_path);
473                 return 1;
474         }
475
476         if (symlink(beep_path, snd_path)) {
477                 ast_unlock_path(folder_path);
478                 ast_log(AST_LOG_ERROR, "Failed to create a symbolic link from %s to %s: %s\n",
479                         beep_path, snd_path, strerror(errno));
480                 return 1;
481         }
482
483         if (!(msg_file = fopen(msg_path, "w"))) {
484                 /* Attempt to remove the sound file */
485                 unlink(snd_path);
486                 ast_unlock_path(folder_path);
487                 ast_log(AST_LOG_ERROR, "Failed to open %s for writing\n", msg_path);
488                 return 1;
489         }
490
491         fprintf(msg_file, ";\n; Message Information file\n;\n"
492                 "[message]\n"
493                 "origmailbox=%s\n"
494                 "context=%s\n"
495                 "macrocontext=%s\n"
496                 "exten=%s\n"
497                 "rdnis=%s\n"
498                 "priority=%d\n"
499                 "callerchan=%s\n"
500                 "callerid=%s\n"
501                 "origdate=%s\n"
502                 "origtime=%s\n"
503                 "category=%s\n"
504                 "msg_id=%s\n"
505                 "flag=%s\n"
506                 "duration=%s\n",
507                 mailbox,
508                 context,
509                 "",
510                 snapshot->exten,
511                 "unknown",
512                 1,
513                 snapshot->callerchan,
514                 snapshot->callerid,
515                 snapshot->origdate,
516                 snapshot->origtime,
517                 "",
518                 snapshot->msg_id,
519                 snapshot->flag,
520                 snapshot->duration);
521         fclose(msg_file);
522
523         if (chmod(msg_path, VOICEMAIL_FILE_MODE) < 0) {
524                 ast_unlock_path(folder_path);
525                 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", msg_path, strerror(errno));
526                 return 1;
527         }
528         ast_unlock_path(folder_path);
529
530         return 0;
531 }
532
533 /*!
534  * \internal
535  * \brief Destroy the voicemail on the file system associated with a snapshot
536  *
537  * \param snapshot The snapshot describing the voicemail
538  */
539 static void test_vm_api_remove_voicemail(struct ast_vm_msg_snapshot *snapshot)
540 {
541         char msg_path[PATH_MAX];
542         char snd_path[PATH_MAX];
543         char folder_path[PATH_MAX];
544
545         if (!snapshot) {
546                 return;
547         }
548
549         snprintf(folder_path, sizeof(folder_path), "%s/voicemail/%s/%s/%s",
550                 ast_config_AST_SPOOL_DIR, "default", snapshot->exten, snapshot->folder_name);
551
552         snprintf(msg_path, sizeof(msg_path), "%s/msg%04u.txt",
553                         folder_path, snapshot->msg_number);
554         snprintf(snd_path, sizeof(snd_path), "%s/msg%04u.gsm",
555                         folder_path, snapshot->msg_number);
556         unlink(msg_path);
557         unlink(snd_path);
558
559         return;
560 }
561
562 /*!
563  * \internal
564  * \brief Destroy the voicemails associated with a mailbox snapshot
565  *
566  * \param mailbox The actual mailbox name
567  * \param mailbox_snapshot The mailbox snapshot containing the voicemails to destroy
568  *
569  * \note It is necessary to specify not just the snapshot, but the mailbox itself.  The
570  * message snapshots contained in the snapshot may have originated from a different mailbox
571  * then the one we're destroying, which means that we can't determine the files to delete
572  * without knowing the actual mailbox they exist in.
573  */
574 static void test_vm_api_destroy_mailbox_voicemails(const char *mailbox, struct ast_vm_mailbox_snapshot *mailbox_snapshot)
575 {
576         struct ast_vm_msg_snapshot *msg;
577         int i;
578
579         for (i = 0; i < 12; ++i) {
580                 AST_LIST_TRAVERSE(&mailbox_snapshot->snapshots[i], msg, msg) {
581                         ast_string_field_set(msg, exten, mailbox);
582                         test_vm_api_remove_voicemail(msg);
583                 }
584         }
585 }
586
587 /*!
588  * \internal
589  * \brief Use snapshots to remove all messages in the mailboxes
590  */
591 static void test_vm_api_remove_all_messages(void)
592 {
593         struct ast_vm_mailbox_snapshot *mailbox_snapshot;
594
595         /* Take a snapshot of each mailbox and remove the contents.  Note that we need to use
596          * snapshots of the mailboxes in addition to our tracked test snapshots, as there's a good chance
597          * we've created copies of the snapshots */
598         if ((mailbox_snapshot = ast_vm_mailbox_snapshot_create("test_vm_api_1234", "default", NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0))) {
599                 test_vm_api_destroy_mailbox_voicemails("test_vm_api_1234", mailbox_snapshot);
600                 mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
601         } else {
602                 ast_log(AST_LOG_WARNING, "Failed to create mailbox snapshot - could not remove test messages for test_vm_api_1234\n");
603         }
604         if ((mailbox_snapshot = ast_vm_mailbox_snapshot_create("test_vm_api_2345", "default", NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0))) {
605                 test_vm_api_destroy_mailbox_voicemails("test_vm_api_2345", mailbox_snapshot);
606                 mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
607         } else {
608                 ast_log(AST_LOG_WARNING, "Failed to create mailbox snapshot - could not remove test messages for test_vm_api_2345\n");
609         }
610 }
611
612 /*!
613  * \internal
614  * \brief Set up the necessary voicemails for a unit test run
615  *
616  * \details
617  * This creates 4 voicemails, stores them on the file system, and creates snapshot objects
618  * representing them for expected/actual value comparisons in the array test_snapshots.
619  *
620  * test_snapshots[0] => in test_vm_1234@default, folder INBOX, message 0
621  * test_snapshots[1] => in test_vm_1234@default, folder Old, message 0
622  * test_snapshots[2] => in test_vm_2345@default, folder INBOX, message 0
623  * test_snapshots[3] => in test_vm_2345@default, folder Old, message 1
624  *
625  * \returns 0 on success
626  * \returns 1 on failure
627  */
628 static int test_vm_api_test_setup(void)
629 {
630         int i, res = 0;
631         struct ast_vm_msg_snapshot *msg_one = NULL;
632         struct ast_vm_msg_snapshot *msg_two = NULL;
633         struct ast_vm_msg_snapshot *msg_three = NULL;
634         struct ast_vm_msg_snapshot *msg_four = NULL;
635
636         /* Make the four sample voicemails */
637         if (   !((msg_one = test_vm_api_create_mock_snapshot("default", "test_vm_api_1234", "\"Phil\" <2000>")))
638                 || !((msg_two = test_vm_api_create_mock_snapshot("default", "test_vm_api_1234", "\"Noel\" <8000>")))
639                 || !((msg_three = test_vm_api_create_mock_snapshot("default", "test_vm_api_2345", "\"Phil\" <2000>")))
640                 || !((msg_four = test_vm_api_create_mock_snapshot("default", "test_vm_api_2345", "\"Bill\" <3000>")))) {
641                 ast_log(AST_LOG_ERROR, "Failed to create mock snapshots for test\n");
642                 test_vm_api_destroy_mock_snapshot(msg_one);
643                 test_vm_api_destroy_mock_snapshot(msg_two);
644                 test_vm_api_destroy_mock_snapshot(msg_three);
645                 test_vm_api_destroy_mock_snapshot(msg_four);
646                 return 1;
647         }
648
649         /* Create the voicemail users */
650         if (ast_vm_test_create_user("default", "test_vm_api_1234")
651                 || ast_vm_test_create_user("default", "test_vm_api_2345")) {
652                 ast_log(AST_LOG_ERROR, "Failed to create test voicemail users\n");
653                 test_vm_api_destroy_mock_snapshot(msg_one);
654                 test_vm_api_destroy_mock_snapshot(msg_two);
655                 test_vm_api_destroy_mock_snapshot(msg_three);
656                 test_vm_api_destroy_mock_snapshot(msg_four);
657                 /* Note that the cleanup macro will ensure that any test user that
658                  * was successfully created is removed
659                  */
660                 return 1;
661         }
662
663         /* Now that the users exist from the perspective of the voicemail
664          * application, attempt to remove any existing voicemails
665          */
666         test_vm_api_remove_all_messages();
667
668         /* Set the basic properties on each */
669         ast_string_field_set(msg_one, callerchan, "SIP/2000-00000000");
670         ast_string_field_set(msg_one, origdate, "Mon Mar 19 04:14:21 PM UTC 2012");
671         ast_string_field_set(msg_one, origtime, "1332173661");
672         ast_string_field_set(msg_one, duration, "8");
673         ast_string_field_set(msg_one, folder_name, "Old");
674         msg_one->msg_number = 0;
675         test_snapshots[0] = msg_one;
676
677         ast_string_field_set(msg_two, callerchan, "SIP/8000-00000001");
678         ast_string_field_set(msg_two, origdate, "Mon Mar 19 06:16:13 PM UTC 2012");
679         ast_string_field_set(msg_two, origtime, "1332180973");
680         ast_string_field_set(msg_two, duration, "24");
681         ast_string_field_set(msg_two, folder_name, "INBOX");
682         msg_two->msg_number = 0;
683         test_snapshots[1] = msg_two;
684
685         ast_string_field_set(msg_three, callerchan, "IAX/2000-000000a3");
686         ast_string_field_set(msg_three, origdate, "Thu Mar 22 23:13:03 PM UTC 2012");
687         ast_string_field_set(msg_three, origtime, "1332181251");
688         ast_string_field_set(msg_three, duration, "25");
689         ast_string_field_set(msg_three, folder_name, "INBOX");
690         msg_three->msg_number = 0;
691         test_snapshots[2] = msg_three;
692
693         ast_string_field_set(msg_four, callerchan, "DAHDI/3000-00000010");
694         ast_string_field_set(msg_four, origdate, "Fri Mar 23 03:01:03 AM UTC 2012");
695         ast_string_field_set(msg_four, origtime, "1332181362");
696         ast_string_field_set(msg_four, duration, "13");
697         ast_string_field_set(msg_four, folder_name, "INBOX");
698         msg_three->msg_number = 1;
699         test_snapshots[3] = msg_four;
700
701         /* Store the messages */
702         for (i = 0; i < TOTAL_SNAPSHOTS; ++i) {
703                 if (test_vm_api_create_voicemail_files("default", test_snapshots[i]->exten, test_snapshots[i])) {
704                         /* On a failure, the test_vm_api_test_teardown method will remove and
705                          * unlink any created files. Since we failed to create the file, clean
706                          * up the object here instead */
707                         ast_log(AST_LOG_ERROR, "Failed to store voicemail %s/%s\n",
708                                 "default", test_snapshots[i]->exten);
709                         test_vm_api_destroy_mock_snapshot(test_snapshots[i]);
710                         test_snapshots[i] = NULL;
711                         res = 1;
712                 }
713         }
714
715         return res;
716 }
717
718 static void test_vm_api_test_teardown(void)
719 {
720         int i;
721
722         /* Remove our test message snapshots */
723         for (i = 0; i < TOTAL_SNAPSHOTS; ++i) {
724                 test_vm_api_remove_voicemail(test_snapshots[i]);
725                 test_vm_api_destroy_mock_snapshot(test_snapshots[i]);
726                 test_snapshots[i] = NULL;
727         }
728
729         test_vm_api_remove_all_messages();
730
731         /* Remove the test users */
732         ast_vm_test_destroy_user("default", "test_vm_api_1234");
733         ast_vm_test_destroy_user("default", "test_vm_api_2345");
734 }
735
736 /*!
737  * \internal
738  * \brief Update the test snapshots with a new mailbox snapshot
739  *
740  * \param mailbox_snapshot The new mailbox shapshot to update the test snapshots with
741  */
742 static void test_vm_api_update_test_snapshots(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
743 {
744         int i, j;
745         struct ast_vm_msg_snapshot *msg;
746
747         for (i = 0; i < TOTAL_SNAPSHOTS; ++i) {
748                 for (j = 0; j < 12; ++j) {
749                         AST_LIST_TRAVERSE(&mailbox_snapshot->snapshots[j], msg, msg) {
750                                 if (!strcmp(msg->msg_id, test_snapshots[i]->msg_id)) {
751                                         ast_string_field_set(test_snapshots[i], callerid, msg->callerid);
752                                         ast_string_field_set(test_snapshots[i], callerchan, msg->callerchan);
753                                         ast_string_field_set(test_snapshots[i], exten, msg->exten);
754                                         ast_string_field_set(test_snapshots[i], origdate, msg->origdate);
755                                         ast_string_field_set(test_snapshots[i], origtime, msg->origtime);
756                                         ast_string_field_set(test_snapshots[i], duration, msg->duration);
757                                         ast_string_field_set(test_snapshots[i], folder_name, msg->folder_name);
758                                         ast_string_field_set(test_snapshots[i], flag, msg->flag);
759                                         test_snapshots[i]->msg_number = msg->msg_number;
760                                 }
761                         }
762                 }
763         }
764 }
765
766 /*!
767  * \internal
768  * \brief A callback function for message playback
769  *
770  * \param chan The channel the file would be played back on
771  * \param file The file to play back
772  * \param duration The duration of the file
773  *
774  * \note This sets global_entered_playback_callback to 1 if the parameters
775  * passed to the callback are minimally valid
776  */
777 static void message_playback_callback_fn(struct ast_channel *chan, const char *file, int duration)
778 {
779         if ((chan) && !ast_strlen_zero(file) && duration > 0) {
780                 global_entered_playback_callback = 1;
781         } else {
782                 ast_log(AST_LOG_WARNING, "Entered into message playback callback function with invalid parameters\n");
783         }
784 }
785
786 /*!
787  * \internal
788  * \brief Dummy channel write function for mock_channel_tech
789  */
790 static int test_vm_api_mock_channel_write(struct ast_channel *chan, struct ast_frame *frame)
791 {
792         return 0;
793 }
794
795 /*!
796  * \internal
797  * \brief Dummy channel read function for mock_channel_tech
798  */
799 static struct ast_frame *test_vm_api_mock_channel_read(struct ast_channel *chan)
800 {
801         return &ast_null_frame;
802 }
803
804 /*!
805  * \internal
806  * \brief A dummy channel technology
807  */
808 static const struct ast_channel_tech mock_channel_tech = {
809                 .write = test_vm_api_mock_channel_write,
810                 .read = test_vm_api_mock_channel_read,
811 };
812
813 /*!
814  * \internal
815  * \brief Create a dummy channel suitable for 'playing back' gsm sound files on
816  *
817  * \returns a channel on success
818  * \returns NULL on failure
819  */
820 static struct ast_channel *test_vm_api_create_mock_channel(void)
821 {
822         struct ast_channel *mock_channel;
823         struct ast_format_cap *native_formats;
824
825         if (!(mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel"))) {
826                 return NULL;
827         }
828
829         ast_channel_set_writeformat(mock_channel, ast_format_gsm);
830         native_formats = ast_channel_nativeformats(mock_channel);
831         ast_format_cap_append(native_formats, ast_channel_writeformat(mock_channel), 0);
832         ast_channel_set_rawwriteformat(mock_channel, ast_format_gsm);
833         ast_channel_set_readformat(mock_channel, ast_format_gsm);
834         ast_channel_set_rawreadformat(mock_channel, ast_format_gsm);
835         ast_channel_tech_set(mock_channel, &mock_channel_tech);
836
837         ast_channel_unlock(mock_channel);
838
839         return mock_channel;
840 }
841
842 AST_TEST_DEFINE(voicemail_api_nominal_snapshot)
843 {
844         struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
845
846         switch (cmd) {
847         case TEST_INIT:
848                 info->name = "nominal_snapshot";
849                 info->category = "/main/voicemail_api/";
850                 info->summary = "Nominal mailbox snapshot tests";
851                 info->description =
852                         "Test retrieving mailbox snapshots";
853                 return AST_TEST_NOT_RUN;
854         case TEST_EXECUTE:
855                 break;
856         }
857
858         VM_API_TEST_SETUP;
859
860         ast_test_status_update(test, "Test retrieving message 1 from INBOX of test_vm_1234\n");
861         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
862         VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num);
863         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
864         ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
865
866         ast_test_status_update(test, "Test retrieving message 0 from Old of test_vm_1234\n");
867         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
868         VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num);
869         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "Old", 0);
870         ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
871
872         ast_test_status_update(test, "Test retrieving message 0, 1 from Old and INBOX of test_vm_1234 ordered by time\n");
873         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 1);
874         VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
875         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "INBOX", 0);
876         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 1);
877         ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
878
879         ast_test_status_update(test, "Test retrieving message 1, 0 from Old and INBOX of test_vm_1234 ordered by time desc\n");
880         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 1, AST_VM_SNAPSHOT_SORT_BY_TIME, 1);
881         VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
882         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
883         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "INBOX", 1);
884         ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
885
886         ast_test_status_update(test, "Test retrieving message 0, 1 from Old and INBOX of test_vm_1234 ordered by id\n");
887         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_ID, 1);
888         VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
889         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
890         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "INBOX", 1);
891         ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
892
893         ast_test_status_update(test, "Test retrieving message 1, 0 from Old and INBOX of test_vm_1234 ordered by id desc\n");
894         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 1, AST_VM_SNAPSHOT_SORT_BY_ID, 1);
895         VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
896         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "INBOX", 0);
897         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 1);
898         ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
899
900         ast_test_status_update(test, "Test retrieving message 0, 1 from all folders of test_vm_1234 ordered by id\n");
901         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0);
902         VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
903         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "Old", 0);
904         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
905         ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
906
907         ast_test_status_update(test, "Test retrieving message 0, 1 from all folders of test_vm_1234 ordered by time\n");
908         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", NULL, 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
909         VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
910         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "Old", 0);
911         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
912         ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
913
914         ast_test_status_update(test, "Test retrieving message 0, 1 from all folders of test_vm_1234, default context ordered by time\n");
915         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", NULL, NULL, 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
916         VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
917         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "Old", 0);
918         VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
919         ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
920
921         VM_API_TEST_CLEANUP;
922
923         return AST_TEST_PASS;
924 }
925
926 AST_TEST_DEFINE(voicemail_api_off_nominal_snapshot)
927 {
928         struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
929
930         switch (cmd) {
931         case TEST_INIT:
932                 info->name = "off_nominal_snapshot";
933                 info->category = "/main/voicemail_api/";
934                 info->summary = "Off nominal mailbox snapshot tests";
935                 info->description =
936                         "Test off nominal requests for mailbox snapshots.  This includes"
937                         " testing the following:\n"
938                         " * Access to non-exisstent mailbox\n"
939                         " * Access to NULL mailbox\n"
940                         " * Access to non-existent context\n"
941                         " * Access to non-existent folder\n"
942                         " * Access to NULL folder\n"
943                         " * Invalid sort identifier\n";
944                 return AST_TEST_NOT_RUN;
945         case TEST_EXECUTE:
946                 break;
947         }
948
949         VM_API_TEST_SETUP;
950
951         ast_test_status_update(test, "Test access to non-existent mailbox test_vm_api_3456\n");
952         VM_API_SNAPSHOT_OFF_NOMINAL_TEST("test_vm_api_3456", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
953
954         ast_test_status_update(test, "Test access to null mailbox\n");
955         VM_API_SNAPSHOT_OFF_NOMINAL_TEST(NULL, "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
956
957         ast_test_status_update(test, "Test access non-existent context test_vm_api_defunct\n");
958         VM_API_SNAPSHOT_OFF_NOMINAL_TEST("test_vm_api_1234", "test_vm_api_defunct", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
959
960         ast_test_status_update(test, "Test non-existent folder test_vm_api_platypus\n");
961         VM_API_SNAPSHOT_OFF_NOMINAL_TEST("test_vm_api_1234", "default", "test_vm_api_platypus", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
962
963         VM_API_TEST_CLEANUP;
964
965         return AST_TEST_PASS;
966 }
967
968 AST_TEST_DEFINE(voicemail_api_nominal_move)
969 {
970         struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
971         const char *inbox_msg_id;
972         const char *old_msg_id;
973         const char *multi_msg_ids[2];
974
975         switch (cmd) {
976         case TEST_INIT:
977                 info->name = "nominal_move";
978                 info->category = "/main/voicemail_api/";
979                 info->summary = "Nominal move voicemail tests";
980                 info->description =
981                         "Test nominal requests to move a voicemail to a different"
982                         " folder.  This includes moving messages given a context,"
983                         " given a NULL context, and moving multiple messages";
984                 return AST_TEST_NOT_RUN;
985         case TEST_EXECUTE:
986                 break;
987         }
988
989         VM_API_TEST_SETUP;
990         old_msg_id = test_snapshots[0]->msg_id;
991         inbox_msg_id = test_snapshots[1]->msg_id;
992
993         multi_msg_ids[0] = test_snapshots[2]->msg_id;
994         multi_msg_ids[1] = test_snapshots[3]->msg_id;
995
996         ast_test_status_update(test, "Test move of test_vm_api_1234 message from INBOX to Family\n");
997         VM_API_MOVE_MESSAGE("test_vm_api_1234", "default", 1, "INBOX", &inbox_msg_id, "Family");
998
999         ast_test_status_update(test, "Test move of test_vm_api_1234 message from Old to Family\n");
1000         VM_API_MOVE_MESSAGE("test_vm_api_1234", NULL, 1, "Old", &old_msg_id, "Family");
1001
1002         /* Take a snapshot and update the test snapshots for verification */
1003         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Family", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1004         test_vm_api_update_test_snapshots(test_mbox_snapshot);
1005         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1006
1007         VM_API_STRING_FIELD_VERIFY(test_snapshots[0]->folder_name, "Family");
1008         VM_API_STRING_FIELD_VERIFY(test_snapshots[1]->folder_name, "Family");
1009         VM_API_INT_VERIFY(test_snapshots[1]->msg_number, 0);
1010         VM_API_INT_VERIFY(test_snapshots[0]->msg_number, 1);
1011
1012         /* Move both of the 2345 messages to Family */
1013         ast_test_status_update(test, "Test move of test_vm_api_2345 messages from Inbox to Family\n");
1014         VM_API_MOVE_MESSAGE("test_vm_api_2345", "default", 2, "INBOX", multi_msg_ids, "Family");
1015
1016         /* Take a snapshot and update the test snapshots for verification */
1017         VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "Family", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1018         test_vm_api_update_test_snapshots(test_mbox_snapshot);
1019         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1020
1021         VM_API_STRING_FIELD_VERIFY(test_snapshots[2]->folder_name, "Family");
1022         VM_API_STRING_FIELD_VERIFY(test_snapshots[3]->folder_name, "Family");
1023
1024         ast_test_status_update(test, "Test move of test_vm_api_2345 message from Family to INBOX\n");
1025         VM_API_MOVE_MESSAGE("test_vm_api_2345", "default", 2, "Family", multi_msg_ids, "INBOX");
1026
1027         VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1028         test_vm_api_update_test_snapshots(test_mbox_snapshot);
1029         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1030
1031         VM_API_STRING_FIELD_VERIFY(test_snapshots[2]->folder_name, "INBOX");
1032         VM_API_STRING_FIELD_VERIFY(test_snapshots[3]->folder_name, "INBOX");
1033
1034         VM_API_TEST_CLEANUP;
1035
1036         return AST_TEST_PASS;
1037 }
1038
1039 AST_TEST_DEFINE(voicemail_api_off_nominal_move)
1040 {
1041         const char *inbox_msg_id;
1042         const char *multi_msg_ids[4];
1043
1044         switch (cmd) {
1045         case TEST_INIT:
1046                 info->name = "off_nominal_move";
1047                 info->category = "/main/voicemail_api/";
1048                 info->summary = "Off nominal mailbox message move tests";
1049                 info->description =
1050                         "Test nominal requests to move a voicemail to a different"
1051                         " folder.  This includes testing the following:\n"
1052                         " * Moving to a non-existent mailbox\n"
1053                         " * Moving to a NULL mailbox\n"
1054                         " * Moving to a non-existent context\n"
1055                         " * Moving to/from non-existent folder\n"
1056                         " * Moving to/from NULL folder\n"
1057                         " * Invalid message identifier(s)\n";
1058                 return AST_TEST_NOT_RUN;
1059         case TEST_EXECUTE:
1060                 break;
1061         }
1062
1063         VM_API_TEST_SETUP;
1064
1065         inbox_msg_id = test_snapshots[1]->msg_id;
1066
1067         multi_msg_ids[0] = test_snapshots[0]->msg_id;
1068         multi_msg_ids[1] = test_snapshots[1]->msg_id;
1069         multi_msg_ids[2] = test_snapshots[2]->msg_id;
1070         multi_msg_ids[3] = test_snapshots[3]->msg_id;
1071
1072         ast_test_status_update(test, "Test move attempt for invalid mailbox test_vm_3456\n");
1073         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_3456", "default", 1, "INBOX", &inbox_msg_id, "Family");
1074
1075         VM_API_MOVE_MESSAGE_OFF_NOMINAL(NULL, "default", 1, "INBOX", &inbox_msg_id, "Family");
1076
1077         ast_test_status_update(test, "Test move attempt for invalid context test_vm_api_defunct\n");
1078         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "test_vm_api_defunct", 1, "INBOX", &inbox_msg_id, "Family");
1079
1080         ast_test_status_update(test, "Test move attempt to invalid folder\n");
1081         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", &inbox_msg_id, "SPAMALOT");
1082
1083         ast_test_status_update(test, "Test move attempt from invalid folder\n");
1084         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "MEATINACAN", &inbox_msg_id, "Family");
1085
1086         ast_test_status_update(test, "Test move attempt to NULL folder\n");
1087         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", &inbox_msg_id, NULL);
1088
1089         ast_test_status_update(test, "Test move attempt from NULL folder\n");
1090         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, NULL, &inbox_msg_id, "Family");
1091
1092         ast_test_status_update(test, "Test move attempt with non-existent message number\n");
1093         inbox_msg_id = "6";
1094         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", &inbox_msg_id, "Family");
1095
1096         ast_test_status_update(test, "Test move attempt with invalid message number\n");
1097         inbox_msg_id = "";
1098         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", &inbox_msg_id, "Family");
1099
1100         ast_test_status_update(test, "Test move attempt with 0 number of messages\n");
1101         inbox_msg_id = test_snapshots[1]->msg_id;
1102         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 0, "INBOX", &inbox_msg_id, "Family");
1103
1104         ast_test_status_update(test, "Test move attempt with invalid number of messages\n");
1105         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", -30, "INBOX", &inbox_msg_id, "Family");
1106
1107         ast_test_status_update(test, "Test move attempt with non-existent multiple messages, where some messages exist\n");
1108         VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 4, "INBOX", multi_msg_ids, "Family");
1109
1110         VM_API_TEST_CLEANUP;
1111
1112         return AST_TEST_PASS;
1113 }
1114
1115 AST_TEST_DEFINE(voicemail_api_nominal_remove)
1116 {
1117         struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
1118         const char *inbox_msg_id;
1119         const char *old_msg_id;
1120         const char *multi_msg_ids[2];
1121
1122         switch (cmd) {
1123         case TEST_INIT:
1124                 info->name = "nominal_remove";
1125                 info->category = "/main/voicemail_api/";
1126                 info->summary = "Nominal mailbox remove message tests";
1127                 info->description =
1128                         "Tests removing messages from voicemail folders.  Includes"
1129                         " both removing messages one at a time, and in a set";
1130                 return AST_TEST_NOT_RUN;
1131         case TEST_EXECUTE:
1132                 break;
1133         }
1134
1135         VM_API_TEST_SETUP;
1136
1137         old_msg_id = test_snapshots[0]->msg_id;
1138         inbox_msg_id = test_snapshots[1]->msg_id;
1139
1140         multi_msg_ids[0] = test_snapshots[2]->msg_id;
1141         multi_msg_ids[1] = test_snapshots[3]->msg_id;
1142
1143         ast_test_status_update(test, "Test removing a single message from INBOX\n");
1144         VM_API_REMOVE_MESSAGE("test_vm_api_1234", "default", 1, "INBOX", &inbox_msg_id);
1145
1146         ast_test_status_update(test, "Test removing a single message from Old\n");
1147         VM_API_REMOVE_MESSAGE("test_vm_api_1234", "default", 1, "Old", &old_msg_id);
1148
1149         ast_test_status_update(test, "Test removing multiple messages from INBOX\n");
1150         VM_API_REMOVE_MESSAGE("test_vm_api_2345", "default", 2, "INBOX", multi_msg_ids);
1151
1152         VM_API_TEST_CLEANUP;
1153
1154         return AST_TEST_PASS;
1155 }
1156
1157 AST_TEST_DEFINE(voicemail_api_off_nominal_remove)
1158 {
1159         const char *inbox_msg_id;
1160         const char *multi_msg_ids[2];
1161         const char *empty_msg_ids[] = { };
1162
1163         switch (cmd) {
1164         case TEST_INIT:
1165                 info->name = "off_nominal_remove";
1166                 info->category = "/main/voicemail_api/";
1167                 info->summary = "Off nominal mailbox message removal tests";
1168                 info->description =
1169                         "Test off nominal requests for removing messages from "
1170                         "a mailbox.  This includes:\n"
1171                         " * Removing messages with an invalid mailbox\n"
1172                         " * Removing messages from a NULL mailbox\n"
1173                         " * Removing messages from an invalid context\n"
1174                         " * Removing messages from an invalid folder\n"
1175                         " * Removing messages from a NULL folder\n"
1176                         " * Removing messages with bad identifiers\n";
1177                 return AST_TEST_NOT_RUN;
1178         case TEST_EXECUTE:
1179                 break;
1180         }
1181
1182         VM_API_TEST_SETUP;
1183
1184         inbox_msg_id = test_snapshots[1]->msg_id;
1185         multi_msg_ids[0] = test_snapshots[2]->msg_id;
1186         multi_msg_ids[1] = test_snapshots[3]->msg_id;
1187
1188         ast_test_status_update(test, "Test removing a single message with an invalid mailbox\n");
1189         VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_3456", "default", 1, "INBOX", &inbox_msg_id);
1190
1191         ast_test_status_update(test, "Test removing a single message with a NULL mailbox\n");
1192         VM_API_REMOVE_MESSAGE_OFF_NOMINAL(NULL, "default", 1, "INBOX", &inbox_msg_id);
1193
1194         ast_test_status_update(test, "Test removing a single message with an invalid context\n");
1195         VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "defunct", 1, "INBOX", &inbox_msg_id);
1196
1197         ast_test_status_update(test, "Test removing a single message with an invalid folder\n");
1198         VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "SPAMINACAN", &inbox_msg_id);
1199
1200         ast_test_status_update(test, "Test removing a single message with a NULL folder\n");
1201         VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, NULL, &inbox_msg_id);
1202
1203         ast_test_status_update(test, "Test removing a single message with an invalid message number\n");
1204         inbox_msg_id = "POOPOO";
1205         VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", &inbox_msg_id);
1206
1207         ast_test_status_update(test, "Test removing multiple messages with a single invalid message number\n");
1208         multi_msg_ids[1] = "POOPOO";
1209         VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_2345", "default", 2, "INBOX", multi_msg_ids);
1210
1211         ast_test_status_update(test, "Test removing no messages with no message numbers\n");
1212         VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 0, "INBOX", empty_msg_ids);
1213
1214         ast_test_status_update(test, "Test removing multiple messages with an invalid size specifier\n");
1215         VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_2345", "default", -30, "INBOX", multi_msg_ids);
1216
1217         VM_API_TEST_CLEANUP;
1218
1219         return AST_TEST_PASS;
1220 }
1221
1222 AST_TEST_DEFINE(voicemail_api_nominal_forward)
1223 {
1224         struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
1225         const char *inbox_msg_id;
1226         const char *multi_msg_ids[2];
1227
1228         switch (cmd) {
1229         case TEST_INIT:
1230                 info->name = "nominal_forward";
1231                 info->category = "/main/voicemail_api/";
1232                 info->summary = "Nominal message forward tests";
1233                 info->description =
1234                         "Tests the nominal cases of forwarding messages"
1235                         " between mailboxes";
1236                 return AST_TEST_NOT_RUN;
1237         case TEST_EXECUTE:
1238                 break;
1239         }
1240
1241         VM_API_TEST_SETUP;
1242
1243         inbox_msg_id = test_snapshots[1]->msg_id;
1244
1245         multi_msg_ids[0] = test_snapshots[2]->msg_id;
1246         multi_msg_ids[1] = test_snapshots[3]->msg_id;
1247
1248         ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX\n");
1249         VM_API_FORWARD_MESSAGE("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, &inbox_msg_id, 0);
1250
1251         /* Make sure we didn't delete the message */
1252         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1253         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1);
1254         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1255
1256         /* We should now have a total of 3 messages in test_vm_api_2345 INBOX */
1257         VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1258         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 3);
1259         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1260
1261         ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX with default context to test_vm_api_2345 INBOX\n");
1262         VM_API_FORWARD_MESSAGE("test_vm_api_1234", NULL, "INBOX", "test_vm_api_2345", "default", "INBOX", 1, &inbox_msg_id, 0);
1263
1264         /* Make sure we didn't delete the message */
1265         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1266         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1);
1267         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1268
1269         /* We should now have a total of 4 messages in test_vm_api_2345 INBOX */
1270         VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1271         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 4);
1272         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1273
1274         ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX with default context\n");
1275         VM_API_FORWARD_MESSAGE("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", NULL, "INBOX", 1, &inbox_msg_id, 0);
1276
1277         /* Make sure we didn't delete the message */
1278         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1279         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1);
1280         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1281
1282         /* We should now have a total of 5 messages in test_vm_api_2345 INBOX */
1283         VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1284         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 5);
1285         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1286
1287         ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX, deleting original\n");
1288         VM_API_FORWARD_MESSAGE("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", NULL, "INBOX", 1, &inbox_msg_id, 1);
1289
1290         /* Make sure we deleted the message */
1291         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1292         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 0);
1293         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1294
1295         /* We should now have a total of 6 messages in test_vm_api_2345 INBOX */
1296         VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1297         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 6);
1298         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1299
1300         ast_test_status_update(test, "Test forwarding 2 messages from test_vm_api_2345 INBOX to test_vm_api_1234 INBOX");
1301         VM_API_FORWARD_MESSAGE("test_vm_api_2345", "default", "INBOX", "test_vm_api_1234", "default", "INBOX", 2, multi_msg_ids, 0);
1302
1303         /* Make sure we didn't delete the messages */
1304         VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1305         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 6);
1306         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1307
1308         /* We should now have a total of 2 messages in test_vm_api_1234 INBOX */
1309         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1310         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
1311         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1312
1313         ast_test_status_update(test, "Test forwarding 2 messages from test_vm_api_2345 INBOX to test_vm_api_1234 Family, deleting original\n");
1314         VM_API_FORWARD_MESSAGE("test_vm_api_2345", "default", "INBOX", "test_vm_api_1234", "default", "Family", 2, multi_msg_ids, 1);
1315         /* Make sure we deleted the messages */
1316         VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1317         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 4);
1318         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1319
1320         /* We should now have a total of 2 messages in test_vm_api_1234 Family */
1321         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Family", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1322         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
1323         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1324
1325         VM_API_TEST_CLEANUP;
1326
1327         return AST_TEST_PASS;
1328 }
1329
1330 AST_TEST_DEFINE(voicemail_api_off_nominal_forward)
1331 {
1332         const char *inbox_msg_id;
1333         const char *multi_msg_ids[4];
1334
1335         const char *empty_msg_ids[] = { };
1336
1337         switch (cmd) {
1338         case TEST_INIT:
1339                 info->name = "off_nominal_forward";
1340                 info->category = "/main/voicemail_api/";
1341                 info->summary = "Off nominal message forwarding tests";
1342                 info->description =
1343                         "Test off nominal forwarding of messages.  This includes:\n"
1344                         " * Invalid/NULL from mailbox\n"
1345                         " * Invalid from context\n"
1346                         " * Invalid/NULL from folder\n"
1347                         " * Invalid/NULL to mailbox\n"
1348                         " * Invalid to context\n"
1349                         " * Invalid/NULL to folder\n"
1350                         " * Invalid message numbers\n"
1351                         " * Invalid number of messages\n";
1352                 return AST_TEST_NOT_RUN;
1353         case TEST_EXECUTE:
1354                 break;
1355         }
1356
1357         VM_API_TEST_SETUP;
1358
1359         inbox_msg_id = test_snapshots[1]->msg_id;
1360
1361         multi_msg_ids[0] = test_snapshots[0]->msg_id;
1362         multi_msg_ids[1] = test_snapshots[1]->msg_id;
1363         multi_msg_ids[2] = test_snapshots[2]->msg_id;
1364         multi_msg_ids[3] = test_snapshots[3]->msg_id;
1365
1366         ast_test_status_update(test, "Test forwarding from an invalid mailbox\n");
1367         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_3456", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, &inbox_msg_id, 0);
1368
1369         ast_test_status_update(test, "Test forwarding from a NULL mailbox\n");
1370         VM_API_FORWARD_MESSAGE_OFF_NOMINAL(NULL, "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, &inbox_msg_id, 0);
1371
1372         ast_test_status_update(test, "Test forwarding from an invalid context\n");
1373         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "defunct", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, &inbox_msg_id, 0);
1374
1375         ast_test_status_update(test, "Test forwarding from an invalid folder\n");
1376         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "POTTEDMEAT", "test_vm_api_2345", "default", "INBOX", 1, &inbox_msg_id, 0);
1377
1378         ast_test_status_update(test, "Test forwarding from a NULL folder\n");
1379         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", NULL, "test_vm_api_2345", "default", "INBOX", 1, &inbox_msg_id, 0);
1380
1381         ast_test_status_update(test, "Test forwarding to an invalid mailbox\n");
1382         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_3456", "default", "INBOX", 1, &inbox_msg_id, 0);
1383
1384         ast_test_status_update(test, "Test forwarding to a NULL mailbox\n");
1385         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", NULL, "default", "INBOX", 1, &inbox_msg_id, 0);
1386
1387         ast_test_status_update(test, "Test forwarding to an invalid context\n");
1388         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "defunct", "INBOX", 1, &inbox_msg_id, 0);
1389
1390         ast_test_status_update(test, "Test forwarding to an invalid folder\n");
1391
1392         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "POTTEDMEAT", 1, &inbox_msg_id, 0);
1393
1394         ast_test_status_update(test, "Test forwarding to a NULL folder\n");
1395         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", NULL, 1, &inbox_msg_id, 0);
1396
1397         ast_test_status_update(test, "Test forwarding when no messages are select\n");
1398         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 0, empty_msg_ids, 0);
1399
1400         ast_test_status_update(test, "Test forwarding a message that doesn't exist\n");
1401         inbox_msg_id = "POOPOO";
1402         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, &inbox_msg_id, 0);
1403
1404         ast_test_status_update(test, "Test forwarding multiple messages, where some messages don't exist\n");
1405         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_2345", "default", "INBOX", "test_vm_api_1234", "default", "INBOX", 4, multi_msg_ids, 0);
1406
1407         ast_test_status_update(test, "Test forwarding a message with an invalid size specifier\n");
1408         VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", -30, &inbox_msg_id, 0);
1409
1410         VM_API_TEST_CLEANUP;
1411
1412         return AST_TEST_PASS;
1413 }
1414
1415 AST_TEST_DEFINE(voicemail_api_nominal_msg_playback)
1416 {
1417         struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
1418         struct ast_channel *test_channel;
1419         const char *message_id_1234;
1420         const char *message_id_2345[2];
1421
1422         switch (cmd) {
1423         case TEST_INIT:
1424                 info->name = "nominal_msg_playback";
1425                 info->category = "/main/voicemail_api/";
1426                 info->summary = "Nominal message playback";
1427                 info->description =
1428                         "Tests playing back a message on a provided"
1429                         " channel or callback function\n";
1430                 return AST_TEST_NOT_RUN;
1431         case TEST_EXECUTE:
1432                 break;
1433         }
1434
1435         VM_API_TEST_SETUP;
1436
1437         message_id_1234 = test_snapshots[1]->msg_id;
1438         message_id_2345[0] = test_snapshots[2]->msg_id;
1439         message_id_2345[1] = test_snapshots[3]->msg_id;
1440
1441         if (!(test_channel = test_vm_api_create_mock_channel())) {
1442                 ast_log(AST_LOG_ERROR, "Failed to create mock channel for testing\n");
1443                 VM_API_TEST_CLEANUP;
1444                 return AST_TEST_FAIL;
1445         }
1446
1447         ast_test_status_update(test, "Playing back message from test_vm_api_1234 to mock channel\n");
1448         VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_1234", "default", "INBOX", message_id_1234, NULL);
1449
1450         ast_test_status_update(test, "Playing back message from test_vm_api_2345 to callback function\n");
1451         VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_2345", "default", "INBOX", message_id_2345[0], &message_playback_callback_fn);
1452         VM_API_INT_VERIFY(global_entered_playback_callback, 1);
1453         global_entered_playback_callback = 0;
1454
1455         ast_test_status_update(test, "Playing back message from test_vm_api_2345 to callback function with default context\n");
1456         VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_2345", NULL, "INBOX", message_id_2345[1], &message_playback_callback_fn);
1457         VM_API_INT_VERIFY(global_entered_playback_callback, 1);
1458         global_entered_playback_callback = 0;
1459
1460         VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1461         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
1462         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1463
1464         VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
1465         VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
1466         test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
1467
1468         ast_hangup(test_channel);
1469         VM_API_TEST_CLEANUP;
1470
1471         return AST_TEST_PASS;
1472 }
1473
1474 AST_TEST_DEFINE(voicemail_api_off_nominal_msg_playback)
1475 {
1476         struct ast_channel *test_channel;
1477         const char *msg_id;
1478         const char *invalid_msg_id = "POOPOO";
1479
1480         switch (cmd) {
1481         case TEST_INIT:
1482                 info->name = "off_nominal_msg_playback";
1483                 info->category = "/main/voicemail_api/";
1484                 info->summary = "Off nominal message playback";
1485                 info->description =
1486                         "Tests off nominal conditions in playing back a "
1487                         "message.  This includes:\n"
1488                         " * Invalid/NULL mailbox\n"
1489                         " * Invalid context\n"
1490                         " * Invalid/NULL folder\n"
1491                         " * Invalid message identifiers\n";
1492                 return AST_TEST_NOT_RUN;
1493         case TEST_EXECUTE:
1494                 break;
1495         }
1496
1497         VM_API_TEST_SETUP;
1498         msg_id = test_snapshots[0]->msg_id;
1499
1500         if (!(test_channel = test_vm_api_create_mock_channel())) {
1501                 ast_log(AST_LOG_ERROR, "Failed to create mock channel for testing\n");
1502                 VM_API_TEST_CLEANUP;
1503                 return AST_TEST_FAIL;
1504         }
1505
1506         ast_test_status_update(test, "Playing back message from invalid mailbox\n");
1507         VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_3456", "default", "INBOX", msg_id, NULL);
1508
1509         ast_test_status_update(test, "Playing back message from NULL mailbox\n");
1510         VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, NULL, "default", "INBOX", msg_id, NULL);
1511
1512         ast_test_status_update(test, "Playing back message from invalid context\n");
1513         VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "defunct", "INBOX", msg_id, NULL);
1514
1515         ast_test_status_update(test, "Playing back message from invalid folder\n");
1516         VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "default", "BACON", msg_id, NULL);
1517
1518         ast_test_status_update(test, "Playing back message from NULL folder\n");
1519         VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "default",  NULL, msg_id, NULL);
1520
1521         ast_test_status_update(test, "Playing back message with invalid message specifier\n");
1522         VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "default", "INBOX", invalid_msg_id, NULL);
1523
1524         ast_test_status_update(test, "Playing back message with NULL message specifier\n");
1525         VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "default", "INBOX", NULL, NULL);
1526         ast_hangup(test_channel);
1527         VM_API_TEST_CLEANUP;
1528
1529         return AST_TEST_PASS;
1530 }
1531
1532 static int unload_module(void)
1533 {
1534         /* Snapshot tests */
1535         AST_TEST_UNREGISTER(voicemail_api_nominal_snapshot);
1536         AST_TEST_UNREGISTER(voicemail_api_off_nominal_snapshot);
1537
1538         /* Move Tests */
1539         AST_TEST_UNREGISTER(voicemail_api_nominal_move);
1540         AST_TEST_UNREGISTER(voicemail_api_off_nominal_move);
1541
1542         /* Remove Tests */
1543         AST_TEST_UNREGISTER(voicemail_api_nominal_remove);
1544         AST_TEST_UNREGISTER(voicemail_api_off_nominal_remove);
1545
1546         /* Forward Tests */
1547         AST_TEST_UNREGISTER(voicemail_api_nominal_forward);
1548         AST_TEST_UNREGISTER(voicemail_api_off_nominal_forward);
1549
1550         /* Message Playback Tests */
1551         AST_TEST_UNREGISTER(voicemail_api_nominal_msg_playback);
1552         AST_TEST_UNREGISTER(voicemail_api_off_nominal_msg_playback);
1553         return 0;
1554 }
1555
1556 static int load_module(void)
1557 {
1558         /* Snapshot tests */
1559         AST_TEST_REGISTER(voicemail_api_nominal_snapshot);
1560         AST_TEST_REGISTER(voicemail_api_off_nominal_snapshot);
1561
1562         /* Move Tests */
1563         AST_TEST_REGISTER(voicemail_api_nominal_move);
1564         AST_TEST_REGISTER(voicemail_api_off_nominal_move);
1565
1566         /* Remove Tests */
1567         AST_TEST_REGISTER(voicemail_api_nominal_remove);
1568         AST_TEST_REGISTER(voicemail_api_off_nominal_remove);
1569
1570         /* Forward Tests */
1571         AST_TEST_REGISTER(voicemail_api_nominal_forward);
1572         AST_TEST_REGISTER(voicemail_api_off_nominal_forward);
1573
1574         /* Message Playback Tests */
1575         AST_TEST_REGISTER(voicemail_api_nominal_msg_playback);
1576         AST_TEST_REGISTER(voicemail_api_off_nominal_msg_playback);
1577
1578         return AST_MODULE_LOAD_SUCCESS;
1579 }
1580
1581 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Core Voicemail API Tests");