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