Merge "Revert "app_voicemail: Remove need to subscribe to stasis""
[asterisk/asterisk.git] / tests / test_taskprocessor.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012-2013, Digium, Inc.
5  *
6  * Mark Michelson <mmichelson@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 taskprocessor unit tests
22  *
23  * \author Mark Michelson <mmichelson@digium.com>
24  *
25  */
26
27 /*** MODULEINFO
28         <depend>TEST_FRAMEWORK</depend>
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 #include "asterisk/test.h"
35 #include "asterisk/taskprocessor.h"
36 #include "asterisk/module.h"
37 #include "asterisk/astobj2.h"
38
39 /*!
40  * \brief userdata associated with baseline taskprocessor test
41  */
42 struct task_data {
43         /* Condition used to signal to queuing thread that task was executed */
44         ast_cond_t cond;
45         /* Lock protecting the condition */
46         ast_mutex_t lock;
47         /*! Boolean indicating that the task was run */
48         int task_complete;
49 };
50
51 static void task_data_dtor(void *obj)
52 {
53         struct task_data *task_data = obj;
54
55         ast_mutex_destroy(&task_data->lock);
56         ast_cond_destroy(&task_data->cond);
57 }
58
59 /*! \brief Create a task_data object */
60 static struct task_data *task_data_create(void)
61 {
62         struct task_data *task_data =
63                 ao2_alloc(sizeof(*task_data), task_data_dtor);
64
65         if (!task_data) {
66                 return NULL;
67         }
68
69         ast_cond_init(&task_data->cond, NULL);
70         ast_mutex_init(&task_data->lock);
71         task_data->task_complete = 0;
72
73         return task_data;
74 }
75
76 /*!
77  * \brief Queued task for baseline test.
78  *
79  * The task simply sets a boolean to indicate the
80  * task has been run and then signals a condition
81  * saying it's complete
82  */
83 static int task(void *data)
84 {
85         struct task_data *task_data = data;
86         SCOPED_MUTEX(lock, &task_data->lock);
87         task_data->task_complete = 1;
88         ast_cond_signal(&task_data->cond);
89         return 0;
90 }
91
92 /*!
93  * \brief Wait for a task to execute.
94  */
95 static int task_wait(struct task_data *task_data)
96 {
97         struct timeval start = ast_tvnow();
98         struct timespec end;
99         SCOPED_MUTEX(lock, &task_data->lock);
100
101         end.tv_sec = start.tv_sec + 30;
102         end.tv_nsec = start.tv_usec * 1000;
103
104         while (!task_data->task_complete) {
105                 int res;
106                 res = ast_cond_timedwait(&task_data->cond, &task_data->lock,
107                         &end);
108                 if (res == ETIMEDOUT) {
109                         return -1;
110                 }
111         }
112
113         return 0;
114 }
115
116 /*!
117  * \brief Baseline test for default taskprocessor
118  *
119  * This test ensures that when a task is added to a taskprocessor that
120  * has been allocated with a default listener that the task gets executed
121  * as expected
122  */
123 AST_TEST_DEFINE(default_taskprocessor)
124 {
125         RAII_VAR(struct ast_taskprocessor *, tps, NULL, ast_taskprocessor_unreference);
126         RAII_VAR(struct task_data *, task_data, NULL, ao2_cleanup);
127         int res;
128
129         switch (cmd) {
130         case TEST_INIT:
131                 info->name = "default_taskprocessor";
132                 info->category = "/main/taskprocessor/";
133                 info->summary = "Test of default taskproccesor";
134                 info->description =
135                         "Ensures that a queued task gets executed.";
136                 return AST_TEST_NOT_RUN;
137         case TEST_EXECUTE:
138                 break;
139         }
140
141         tps = ast_taskprocessor_get("test", TPS_REF_DEFAULT);
142
143         if (!tps) {
144                 ast_test_status_update(test, "Unable to create test taskprocessor\n");
145                 return AST_TEST_FAIL;
146         }
147
148         task_data = task_data_create();
149         if (!task_data) {
150                 ast_test_status_update(test, "Unable to create task_data\n");
151                 return AST_TEST_FAIL;
152         }
153
154         if (ast_taskprocessor_push(tps, task, task_data)) {
155                 ast_test_status_update(test, "Failed to queue task\n");
156                 return AST_TEST_FAIL;
157         }
158
159         res = task_wait(task_data);
160         if (res != 0) {
161                 ast_test_status_update(test, "Queued task did not execute!\n");
162                 return AST_TEST_FAIL;
163         }
164
165         return AST_TEST_PASS;
166 }
167
168 #define NUM_TASKS 20000
169
170 /*!
171  * \brief Relevant data associated with taskprocessor load test
172  */
173 static struct load_task_data {
174         /*! Condition used to indicate a task has completed executing */
175         ast_cond_t cond;
176         /*! Lock used to protect the condition */
177         ast_mutex_t lock;
178         /*! Counter of the number of completed tasks */
179         int tasks_completed;
180         /*! Storage for task-specific data */
181         int task_rand[NUM_TASKS];
182 } load_task_results;
183
184 /*!
185  * \brief a queued task to be used in the taskprocessor load test
186  *
187  * The task increments the number of tasks executed and puts the passed-in
188  * data into the next slot in the array of random data.
189  */
190 static int load_task(void *data)
191 {
192         int *randdata = data;
193         SCOPED_MUTEX(lock, &load_task_results.lock);
194         load_task_results.task_rand[load_task_results.tasks_completed++] = *randdata;
195         ast_cond_signal(&load_task_results.cond);
196         return 0;
197 }
198
199 /*!
200  * \brief Load test for taskprocessor with default listener
201  *
202  * This test queues a large number of tasks, each with random data associated.
203  * The test ensures that all of the tasks are run and that the tasks are executed
204  * in the same order that they were queued
205  */
206 AST_TEST_DEFINE(default_taskprocessor_load)
207 {
208         struct ast_taskprocessor *tps;
209         struct timeval start;
210         struct timespec ts;
211         enum ast_test_result_state res = AST_TEST_PASS;
212         int timedwait_res;
213         int i;
214         int rand_data[NUM_TASKS];
215
216         switch (cmd) {
217         case TEST_INIT:
218                 info->name = "default_taskprocessor_load";
219                 info->category = "/main/taskprocessor/";
220                 info->summary = "Load test of default taskproccesor";
221                 info->description =
222                         "Ensure that a large number of queued tasks are executed in the proper order.";
223                 return AST_TEST_NOT_RUN;
224         case TEST_EXECUTE:
225                 break;
226         }
227
228         tps = ast_taskprocessor_get("test", TPS_REF_DEFAULT);
229
230         if (!tps) {
231                 ast_test_status_update(test, "Unable to create test taskprocessor\n");
232                 return AST_TEST_FAIL;
233         }
234
235         start = ast_tvnow();
236
237         ts.tv_sec = start.tv_sec + 60;
238         ts.tv_nsec = start.tv_usec * 1000;
239
240         ast_cond_init(&load_task_results.cond, NULL);
241         ast_mutex_init(&load_task_results.lock);
242         load_task_results.tasks_completed = 0;
243
244         for (i = 0; i < NUM_TASKS; ++i) {
245                 rand_data[i] = ast_random();
246                 if (ast_taskprocessor_push(tps, load_task, &rand_data[i])) {
247                         ast_test_status_update(test, "Failed to queue task\n");
248                         res = AST_TEST_FAIL;
249                         goto test_end;
250                 }
251         }
252
253         ast_mutex_lock(&load_task_results.lock);
254         while (load_task_results.tasks_completed < NUM_TASKS) {
255                 timedwait_res = ast_cond_timedwait(&load_task_results.cond, &load_task_results.lock, &ts);
256                 if (timedwait_res == ETIMEDOUT) {
257                         break;
258                 }
259         }
260         ast_mutex_unlock(&load_task_results.lock);
261
262         if (load_task_results.tasks_completed != NUM_TASKS) {
263                 ast_test_status_update(test, "Unexpected number of tasks executed. Expected %d but got %d\n",
264                                 NUM_TASKS, load_task_results.tasks_completed);
265                 res = AST_TEST_FAIL;
266                 goto test_end;
267         }
268
269         for (i = 0; i < NUM_TASKS; ++i) {
270                 if (rand_data[i] != load_task_results.task_rand[i]) {
271                         ast_test_status_update(test, "Queued tasks did not execute in order\n");
272                         res = AST_TEST_FAIL;
273                         goto test_end;
274                 }
275         }
276
277 test_end:
278         tps = ast_taskprocessor_unreference(tps);
279         ast_mutex_destroy(&load_task_results.lock);
280         ast_cond_destroy(&load_task_results.cond);
281         return res;
282 }
283
284 /*!
285  * \brief Private data for the test taskprocessor listener
286  */
287 struct test_listener_pvt {
288         /* Counter of number of tasks pushed to the queue */
289         int num_pushed;
290         /* Counter of number of times the queue was emptied */
291         int num_emptied;
292         /* Counter of number of times that a pushed task occurred on an empty queue */
293         int num_was_empty;
294         /* Boolean indicating whether the shutdown callback was called */
295         int shutdown;
296 };
297
298 /*!
299  * \brief test taskprocessor listener's alloc callback
300  */
301 static void *test_listener_pvt_alloc(void)
302 {
303         struct test_listener_pvt *pvt;
304
305         pvt = ast_calloc(1, sizeof(*pvt));
306         return pvt;
307 }
308
309 /*!
310  * \brief test taskprocessor listener's start callback
311  */
312 static int test_start(struct ast_taskprocessor_listener *listener)
313 {
314         return 0;
315 }
316
317 /*!
318  * \brief test taskprocessor listener's task_pushed callback
319  *
320  * Adjusts private data's stats as indicated by the parameters.
321  */
322 static void test_task_pushed(struct ast_taskprocessor_listener *listener, int was_empty)
323 {
324         struct test_listener_pvt *pvt = ast_taskprocessor_listener_get_user_data(listener);
325         ++pvt->num_pushed;
326         if (was_empty) {
327                 ++pvt->num_was_empty;
328         }
329 }
330
331 /*!
332  * \brief test taskprocessor listener's emptied callback.
333  */
334 static void test_emptied(struct ast_taskprocessor_listener *listener)
335 {
336         struct test_listener_pvt *pvt = ast_taskprocessor_listener_get_user_data(listener);
337         ++pvt->num_emptied;
338 }
339
340 /*!
341  * \brief test taskprocessor listener's shutdown callback.
342  */
343 static void test_shutdown(struct ast_taskprocessor_listener *listener)
344 {
345         struct test_listener_pvt *pvt = ast_taskprocessor_listener_get_user_data(listener);
346         pvt->shutdown = 1;
347 }
348
349 static const struct ast_taskprocessor_listener_callbacks test_callbacks = {
350         .start = test_start,
351         .task_pushed = test_task_pushed,
352         .emptied = test_emptied,
353         .shutdown = test_shutdown,
354 };
355
356 /*!
357  * \brief Queued task for taskprocessor listener test.
358  *
359  * Does nothing.
360  */
361 static int listener_test_task(void *ignore)
362 {
363         return 0;
364 }
365
366 /*!
367  * \brief helper to ensure that statistics the listener is keeping are what we expect
368  *
369  * \param test The currently-running test
370  * \param pvt The private data for the taskprocessor listener
371  * \param num_pushed The expected current number of tasks pushed to the processor
372  * \param num_emptied The expected current number of times the taskprocessor has become empty
373  * \param num_was_empty The expected current number of times that tasks were pushed to an empty taskprocessor
374  * \retval -1 Stats were not as expected
375  * \retval 0 Stats were as expected
376  */
377 static int check_stats(struct ast_test *test, const struct test_listener_pvt *pvt, int num_pushed, int num_emptied, int num_was_empty)
378 {
379         if (pvt->num_pushed != num_pushed) {
380                 ast_test_status_update(test, "Unexpected number of tasks pushed. Expected %d but got %d\n",
381                                 num_pushed, pvt->num_pushed);
382                 return -1;
383         }
384
385         if (pvt->num_emptied != num_emptied) {
386                 ast_test_status_update(test, "Unexpected number of empties. Expected %d but got %d\n",
387                                 num_emptied, pvt->num_emptied);
388                 return -1;
389         }
390
391         if (pvt->num_was_empty != num_was_empty) {
392                 ast_test_status_update(test, "Unexpected number of empties. Expected %d but got %d\n",
393                                 num_was_empty, pvt->num_emptied);
394                 return -1;
395         }
396
397         return 0;
398 }
399
400 /*!
401  * \brief Test for a taskprocessor with custom listener.
402  *
403  * This test pushes tasks to a taskprocessor with a custom listener, executes the taskss,
404  * and destroys the taskprocessor.
405  *
406  * The test ensures that the listener's callbacks are called when expected and that the data
407  * being passed in is accurate.
408  */
409 AST_TEST_DEFINE(taskprocessor_listener)
410 {
411         struct ast_taskprocessor *tps = NULL;
412         struct ast_taskprocessor_listener *listener = NULL;
413         struct test_listener_pvt *pvt = NULL;
414         enum ast_test_result_state res = AST_TEST_PASS;
415
416         switch (cmd) {
417         case TEST_INIT:
418                 info->name = "taskprocessor_listener";
419                 info->category = "/main/taskprocessor/";
420                 info->summary = "Test of taskproccesor listeners";
421                 info->description =
422                         "Ensures that listener callbacks are called when expected.";
423                 return AST_TEST_NOT_RUN;
424         case TEST_EXECUTE:
425                 break;
426         }
427
428         pvt = test_listener_pvt_alloc();
429         if (!pvt) {
430                 ast_test_status_update(test, "Unable to allocate test taskprocessor listener user data\n");
431                 return AST_TEST_FAIL;
432         }
433
434         listener = ast_taskprocessor_listener_alloc(&test_callbacks, pvt);
435         if (!listener) {
436                 ast_test_status_update(test, "Unable to allocate test taskprocessor listener\n");
437                 res = AST_TEST_FAIL;
438                 goto test_exit;
439         }
440
441         tps = ast_taskprocessor_create_with_listener("test_listener", listener);
442         if (!tps) {
443                 ast_test_status_update(test, "Unable to allocate test taskprocessor\n");
444                 res = AST_TEST_FAIL;
445                 goto test_exit;
446         }
447
448         if (ast_taskprocessor_push(tps, listener_test_task, NULL)) {
449                 ast_test_status_update(test, "Failed to queue task\n");
450                 res = AST_TEST_FAIL;
451                 goto test_exit;
452         }
453
454         if (check_stats(test, pvt, 1, 0, 1) < 0) {
455                 res = AST_TEST_FAIL;
456                 goto test_exit;
457         }
458
459         if (ast_taskprocessor_push(tps, listener_test_task, NULL)) {
460                 ast_test_status_update(test, "Failed to queue task\n");
461                 res = AST_TEST_FAIL;
462                 goto test_exit;
463         }
464
465         if (check_stats(test, pvt, 2, 0, 1) < 0) {
466                 res = AST_TEST_FAIL;
467                 goto test_exit;
468         }
469
470         ast_taskprocessor_execute(tps);
471
472         if (check_stats(test, pvt, 2, 0, 1) < 0) {
473                 res = AST_TEST_FAIL;
474                 goto test_exit;
475         }
476
477         ast_taskprocessor_execute(tps);
478
479         if (check_stats(test, pvt, 2, 1, 1) < 0) {
480                 res = AST_TEST_FAIL;
481                 goto test_exit;
482         }
483
484         tps = ast_taskprocessor_unreference(tps);
485
486         if (!pvt->shutdown) {
487                 res = AST_TEST_FAIL;
488                 goto test_exit;
489         }
490
491 test_exit:
492         ao2_cleanup(listener);
493         /* This is safe even if tps is NULL */
494         ast_taskprocessor_unreference(tps);
495         ast_free(pvt);
496         return res;
497 }
498
499 struct shutdown_data {
500         ast_cond_t in;
501         ast_cond_t out;
502         ast_mutex_t lock;
503         int task_complete;
504         int task_started;
505         int task_stop_waiting;
506 };
507
508 static void shutdown_data_dtor(void *data)
509 {
510         struct shutdown_data *shutdown_data = data;
511         ast_mutex_destroy(&shutdown_data->lock);
512         ast_cond_destroy(&shutdown_data->in);
513         ast_cond_destroy(&shutdown_data->out);
514 }
515
516 static struct shutdown_data *shutdown_data_create(int dont_wait)
517 {
518         RAII_VAR(struct shutdown_data *, shutdown_data, NULL, ao2_cleanup);
519
520         shutdown_data = ao2_alloc(sizeof(*shutdown_data), shutdown_data_dtor);
521         if (!shutdown_data) {
522                 return NULL;
523         }
524
525         ast_mutex_init(&shutdown_data->lock);
526         ast_cond_init(&shutdown_data->in, NULL);
527         ast_cond_init(&shutdown_data->out, NULL);
528         shutdown_data->task_stop_waiting = dont_wait;
529         ao2_ref(shutdown_data, +1);
530         return shutdown_data;
531 }
532
533 static int shutdown_task_exec(void *data)
534 {
535         struct shutdown_data *shutdown_data = data;
536         SCOPED_MUTEX(lock, &shutdown_data->lock);
537         shutdown_data->task_started = 1;
538         ast_cond_signal(&shutdown_data->out);
539         while (!shutdown_data->task_stop_waiting) {
540                 ast_cond_wait(&shutdown_data->in, &shutdown_data->lock);
541         }
542         shutdown_data->task_complete = 1;
543         ast_cond_signal(&shutdown_data->out);
544         return 0;
545 }
546
547 static int shutdown_waitfor_completion(struct shutdown_data *shutdown_data)
548 {
549         struct timeval start = ast_tvnow();
550         struct timespec end = {
551                 .tv_sec = start.tv_sec + 5,
552                 .tv_nsec = start.tv_usec * 1000
553         };
554         SCOPED_MUTEX(lock, &shutdown_data->lock);
555
556         while (!shutdown_data->task_complete) {
557                 if (ast_cond_timedwait(&shutdown_data->out, &shutdown_data->lock, &end) == ETIMEDOUT) {
558                         break;
559                 }
560         }
561
562         return shutdown_data->task_complete;
563 }
564
565 static int shutdown_has_completed(struct shutdown_data *shutdown_data)
566 {
567         SCOPED_MUTEX(lock, &shutdown_data->lock);
568         return shutdown_data->task_complete;
569 }
570
571 static int shutdown_waitfor_start(struct shutdown_data *shutdown_data)
572 {
573         struct timeval start = ast_tvnow();
574         struct timespec end = {
575                 .tv_sec = start.tv_sec + 5,
576                 .tv_nsec = start.tv_usec * 1000
577         };
578         SCOPED_MUTEX(lock, &shutdown_data->lock);
579
580         while (!shutdown_data->task_started) {
581                 if (ast_cond_timedwait(&shutdown_data->out, &shutdown_data->lock, &end) == ETIMEDOUT) {
582                         break;
583                 }
584         }
585
586         return shutdown_data->task_started;
587 }
588
589 static void shutdown_poke(struct shutdown_data *shutdown_data)
590 {
591         SCOPED_MUTEX(lock, &shutdown_data->lock);
592         shutdown_data->task_stop_waiting = 1;
593         ast_cond_signal(&shutdown_data->in);
594 }
595
596 static void *tps_shutdown_thread(void *data)
597 {
598         struct ast_taskprocessor *tps = data;
599         ast_taskprocessor_unreference(tps);
600         return NULL;
601 }
602
603 AST_TEST_DEFINE(taskprocessor_shutdown)
604 {
605         RAII_VAR(struct ast_taskprocessor *, tps, NULL, ast_taskprocessor_unreference);
606         RAII_VAR(struct shutdown_data *, task1, NULL, ao2_cleanup);
607         RAII_VAR(struct shutdown_data *, task2, NULL, ao2_cleanup);
608         int push_res;
609         int wait_res;
610         int pthread_res;
611         pthread_t shutdown_thread;
612
613         switch (cmd) {
614         case TEST_INIT:
615                 info->name = "taskprocessor_shutdown";
616                 info->category = "/main/taskprocessor/";
617                 info->summary = "Test of taskproccesor shutdown sequence";
618                 info->description =
619                         "Ensures that all tasks run to completion after the taskprocessor has been unref'ed.";
620                 return AST_TEST_NOT_RUN;
621         case TEST_EXECUTE:
622                 break;
623         }
624
625         tps = ast_taskprocessor_get("test_shutdown", TPS_REF_DEFAULT);
626         task1 = shutdown_data_create(0); /* task1 waits to be poked */
627         task2 = shutdown_data_create(1); /* task2 waits for nothing */
628
629         if (!tps || !task1 || !task2) {
630                 ast_test_status_update(test, "Allocation error\n");
631                 return AST_TEST_FAIL;
632         }
633
634         push_res = ast_taskprocessor_push(tps, shutdown_task_exec, task1);
635         if (push_res != 0) {
636                 ast_test_status_update(test, "Could not push task1\n");
637                 return AST_TEST_FAIL;
638         }
639
640         push_res = ast_taskprocessor_push(tps, shutdown_task_exec, task2);
641         if (push_res != 0) {
642                 ast_test_status_update(test, "Could not push task2\n");
643                 return AST_TEST_FAIL;
644         }
645
646         wait_res = shutdown_waitfor_start(task1);
647         if (!wait_res) {
648                 ast_test_status_update(test, "Task1 didn't start\n");
649                 return AST_TEST_FAIL;
650         }
651
652         pthread_res = ast_pthread_create(&shutdown_thread, NULL, tps_shutdown_thread, tps);
653         if (pthread_res != 0) {
654                 ast_test_status_update(test, "Failed to create shutdown thread\n");
655                 return AST_TEST_FAIL;
656         }
657         tps = NULL;
658
659         /* Wakeup task1; it should complete */
660         shutdown_poke(task1);
661         wait_res = shutdown_waitfor_completion(task1);
662         if (!wait_res) {
663                 ast_test_status_update(test, "Task1 didn't complete\n");
664                 return AST_TEST_FAIL;
665         }
666
667         /* Wait for shutdown to complete */
668         pthread_join(shutdown_thread, NULL);
669
670         /* Should have also completed task2 */
671         wait_res = shutdown_has_completed(task2);
672         if (!wait_res) {
673                 ast_test_status_update(test, "Task2 didn't finish\n");
674                 return AST_TEST_FAIL;
675         }
676
677         return AST_TEST_PASS;
678 }
679
680 static int local_task_exe(struct ast_taskprocessor_local *local)
681 {
682         int *local_data = local->local_data;
683         struct task_data *task_data = local->data;
684
685         *local_data = 1;
686         task(task_data);
687
688         return 0;
689 }
690
691 AST_TEST_DEFINE(taskprocessor_push_local)
692 {
693         RAII_VAR(struct ast_taskprocessor *, tps, NULL,
694                 ast_taskprocessor_unreference);
695         RAII_VAR(struct task_data *, task_data, NULL, ao2_cleanup);
696         int local_data;
697         int res;
698
699         switch (cmd) {
700         case TEST_INIT:
701                 info->name = __func__;
702                 info->category = "/main/taskprocessor/";
703                 info->summary = "Test of pushing local data";
704                 info->description =
705                         "Ensures that local data is passed along.";
706                 return AST_TEST_NOT_RUN;
707         case TEST_EXECUTE:
708                 break;
709         }
710
711
712         tps = ast_taskprocessor_get("test", TPS_REF_DEFAULT);
713         if (!tps) {
714                 ast_test_status_update(test, "Unable to create test taskprocessor\n");
715                 return AST_TEST_FAIL;
716         }
717
718
719         task_data = task_data_create();
720         if (!task_data) {
721                 ast_test_status_update(test, "Unable to create task_data\n");
722                 return AST_TEST_FAIL;
723         }
724
725         local_data = 0;
726         ast_taskprocessor_set_local(tps, &local_data);
727
728         if (ast_taskprocessor_push_local(tps, local_task_exe, task_data)) {
729                 ast_test_status_update(test, "Failed to queue task\n");
730                 return AST_TEST_FAIL;
731         }
732
733         res = task_wait(task_data);
734         if (res != 0) {
735                 ast_test_status_update(test, "Queued task did not execute!\n");
736                 return AST_TEST_FAIL;
737         }
738
739         if (local_data != 1) {
740                 ast_test_status_update(test,
741                         "Queued task did not set local_data!\n");
742                 return AST_TEST_FAIL;
743         }
744
745         return AST_TEST_PASS;
746 }
747
748 static int unload_module(void)
749 {
750         ast_test_unregister(default_taskprocessor);
751         ast_test_unregister(default_taskprocessor_load);
752         ast_test_unregister(taskprocessor_listener);
753         ast_test_unregister(taskprocessor_shutdown);
754         ast_test_unregister(taskprocessor_push_local);
755         return 0;
756 }
757
758 static int load_module(void)
759 {
760         ast_test_register(default_taskprocessor);
761         ast_test_register(default_taskprocessor_load);
762         ast_test_register(taskprocessor_listener);
763         ast_test_register(taskprocessor_shutdown);
764         ast_test_register(taskprocessor_push_local);
765         return AST_MODULE_LOAD_SUCCESS;
766 }
767
768 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "taskprocessor test module");