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