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