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