Merge "Revert "app_voicemail: Remove need to subscribe to stasis""
[asterisk/asterisk.git] / tests / test_res_pjsip_scheduler.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2016, Fairview 5 Engineering, LLC
5  *
6  * George Joseph <george.joseph@fairview5.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 res_pjsip scheduler tests
22  *
23  * \author George Joseph <george.joseph@fairview5.com>
24  *
25  */
26
27 /*** MODULEINFO
28         <depend>TEST_FRAMEWORK</depend>
29         <depend>pjproject</depend>
30         <depend>res_pjsip</depend>
31         <support_level>core</support_level>
32  ***/
33
34 #include "asterisk.h"
35
36 #include <pjsip.h>
37 #include "asterisk/test.h"
38 #include "asterisk/module.h"
39 #include "asterisk/taskprocessor.h"
40 #include "asterisk/res_pjsip.h"
41 #include "asterisk/utils.h"
42
43 #define CATEGORY "/res/res_pjsip/scheduler/"
44
45 struct test_data {
46         ast_mutex_t lock;
47         ast_cond_t cond;
48         pthread_t tid;
49         struct timeval test_start;
50         struct timeval task_start;
51         struct timeval task_end;
52         int is_servant;
53         int interval;
54         int sleep;
55         int done;
56         int no_clear_done;
57         struct ast_test *test;
58 };
59
60 #define S2U(x) (long int)(x * 1000 * 1000)
61 #define M2U(x) (long int)(x * 1000)
62
63 static int task_1(void *data)
64 {
65         struct test_data *test = data;
66
67         if (!test->no_clear_done) {
68                 test->done = 0;
69         }
70         test->task_start = ast_tvnow();
71         test->tid = pthread_self();
72         test->is_servant = ast_sip_thread_is_servant();
73         usleep(M2U(test->sleep));
74         test->task_end = ast_tvnow();
75
76         ast_mutex_lock(&test->lock);
77         test->done++;
78         ast_mutex_unlock(&test->lock);
79         ast_cond_signal(&test->cond);
80
81         return test->interval;
82 }
83
84
85 static void data_cleanup(void *data)
86 {
87         struct test_data *test_data = data;
88         ast_mutex_destroy(&test_data->lock);
89         ast_cond_destroy(&test_data->cond);
90 }
91
92 #define waitfor(x) \
93 { \
94         ast_mutex_lock(&(x)->lock); \
95         while (!(x)->done) { \
96                 ast_cond_wait(&(x)->cond, &(x)->lock); \
97         } \
98         (x)->done = 0; \
99         ast_mutex_unlock(&(x)->lock); \
100 }
101
102 static int scheduler(struct ast_test *test, int serialized)
103 {
104         RAII_VAR(struct ast_taskprocessor *, tp1, NULL, ast_taskprocessor_unreference);
105         RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup);
106         RAII_VAR(struct test_data *, test_data2, ao2_alloc(sizeof(*test_data2), data_cleanup), ao2_cleanup);
107         RAII_VAR(struct ast_sip_sched_task *, task1, NULL, ao2_cleanup);
108         RAII_VAR(struct ast_sip_sched_task *, task2, NULL, ao2_cleanup);
109         int duration;
110         int delay;
111         struct timeval task1_start;
112
113         ast_test_validate(test, test_data1 != NULL);
114         ast_test_validate(test, test_data2 != NULL);
115
116         test_data1->test = test;
117         test_data1->test_start = ast_tvnow();
118         test_data1->interval = 2000;
119         test_data1->sleep = 1000;
120         ast_mutex_init(&test_data1->lock);
121         ast_cond_init(&test_data1->cond, NULL);
122
123         test_data2->test = test;
124         test_data2->test_start = ast_tvnow();
125         test_data2->interval = 2000;
126         test_data2->sleep = 1000;
127         ast_mutex_init(&test_data2->lock);
128         ast_cond_init(&test_data2->cond, NULL);
129
130         if (serialized) {
131                 ast_test_status_update(test, "This test will take about %3.1f seconds\n",
132                         (test_data1->interval + test_data1->sleep + (MAX(test_data1->interval - test_data2->interval, 0)) + test_data2->sleep) / 1000.0);
133                 tp1 = ast_sip_create_serializer("test-scheduler-serializer");
134                 ast_test_validate(test, (tp1 != NULL));
135         } else {
136                 ast_test_status_update(test, "This test will take about %3.1f seconds\n",
137                         ((MAX(test_data1->interval, test_data2->interval) + MAX(test_data1->sleep, test_data2->sleep)) / 1000.0));
138         }
139
140         task1 = ast_sip_schedule_task(tp1, test_data1->interval, task_1, NULL, test_data1, AST_SIP_SCHED_TASK_FIXED);
141         ast_test_validate(test, task1 != NULL);
142
143         task2 = ast_sip_schedule_task(tp1, test_data2->interval, task_1, NULL, test_data2, AST_SIP_SCHED_TASK_FIXED);
144         ast_test_validate(test, task2 != NULL);
145
146         waitfor(test_data1);
147         ast_sip_sched_task_cancel(task1);
148         ast_test_validate(test, test_data1->is_servant);
149
150         duration = ast_tvdiff_ms(test_data1->task_end, test_data1->test_start);
151         ast_test_validate(test, (duration > ((test_data1->interval + test_data1->sleep) * 0.9))
152                 && (duration < ((test_data1->interval + test_data1->sleep) * 1.1)));
153
154         ast_sip_sched_task_get_times(task1, NULL, &task1_start, NULL);
155         delay = ast_tvdiff_ms(task1_start, test_data1->test_start);
156         ast_test_validate(test, (delay > (test_data1->interval * 0.9)
157                 && (delay < (test_data1->interval * 1.1))));
158
159         waitfor(test_data2);
160         ast_sip_sched_task_cancel(task2);
161         ast_test_validate(test, test_data2->is_servant);
162
163         if (serialized) {
164                 ast_test_validate(test, test_data1->tid == test_data2->tid);
165                 ast_test_validate(test, ast_tvdiff_ms(test_data2->task_start, test_data1->task_end) >= 0);
166         } else {
167                 ast_test_validate(test, test_data1->tid != test_data2->tid);
168         }
169
170         return AST_TEST_PASS;
171 }
172
173 AST_TEST_DEFINE(serialized_scheduler)
174 {
175
176         switch (cmd) {
177         case TEST_INIT:
178                 info->name = __func__;
179                 info->category = CATEGORY;
180                 info->summary = "Test res_pjsip serialized scheduler";
181                 info->description = "Test res_pjsip serialized scheduler";
182                 return AST_TEST_NOT_RUN;
183         case TEST_EXECUTE:
184                 break;
185         }
186
187         return scheduler(test, 1);
188 }
189
190 AST_TEST_DEFINE(unserialized_scheduler)
191 {
192
193         switch (cmd) {
194         case TEST_INIT:
195                 info->name = __func__;
196                 info->category = CATEGORY;
197                 info->summary = "Test res_pjsip unserialized scheduler";
198                 info->description = "Test res_pjsip unserialized scheduler";
199                 return AST_TEST_NOT_RUN;
200         case TEST_EXECUTE:
201                 break;
202         }
203
204         return scheduler(test, 0);
205 }
206
207 static int run_count;
208 static int destruct_count;
209
210 static int dummy_task(void *data)
211 {
212         int *sleep = data;
213
214         usleep(M2U(*sleep));
215         run_count++;
216
217         return 0;
218 }
219
220 static void test_destructor(void *data)
221 {
222         destruct_count++;
223 }
224
225 AST_TEST_DEFINE(scheduler_cleanup)
226 {
227         RAII_VAR(int *, sleep, NULL, ao2_cleanup);
228         RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
229         int interval;
230         int when;
231
232         switch (cmd) {
233         case TEST_INIT:
234                 info->name = __func__;
235                 info->category = CATEGORY;
236                 info->summary = "Test res_pjsip scheduler cleanup";
237                 info->description = "Test res_pjsip scheduler cleanup";
238                 return AST_TEST_NOT_RUN;
239         case TEST_EXECUTE:
240                 break;
241         }
242
243         destruct_count = 0;
244         interval = 1000;
245
246         sleep = ao2_alloc(sizeof(*sleep), test_destructor);
247         ast_test_validate(test, sleep != NULL);
248         *sleep = 500;
249
250         ast_test_status_update(test, "This test will take about %3.1f seconds\n",
251                 ((interval * 1.1) + *sleep) / 1000.0);
252
253         task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep,
254                 AST_SIP_SCHED_TASK_DATA_AO2 | AST_SIP_SCHED_TASK_DATA_FREE);
255         ast_test_validate(test, task != NULL);
256         usleep(M2U(interval * 0.5));
257         when = ast_sip_sched_task_get_next_run(task);
258         ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6)));
259         usleep(M2U(interval * 0.6));
260         ast_test_validate(test, ast_sip_sched_is_task_running(task));
261
262         usleep(M2U(*sleep));
263
264         ast_test_validate(test, (ast_sip_sched_is_task_running(task) == 0));
265         when = ast_sip_sched_task_get_next_run(task);
266         ast_test_validate(test, (when < 0), res, error);
267         ast_test_validate(test, (ao2_ref(task, 0) == 1));
268         ao2_ref(task, -1);
269         task = NULL;
270         ast_test_validate(test, (destruct_count == 1));
271         sleep = NULL;
272
273         return AST_TEST_PASS;
274 }
275
276 AST_TEST_DEFINE(scheduler_cancel)
277 {
278         RAII_VAR(int *, sleep, NULL, ao2_cleanup);
279         RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
280         int interval;
281         int when;
282
283         switch (cmd) {
284         case TEST_INIT:
285                 info->name = __func__;
286                 info->category = CATEGORY;
287                 info->summary = "Test res_pjsip scheduler cancel task";
288                 info->description = "Test res_pjsip scheduler cancel task";
289                 return AST_TEST_NOT_RUN;
290         case TEST_EXECUTE:
291                 break;
292         }
293
294         destruct_count = 0;
295         interval = 1000;
296
297         sleep = ao2_alloc(sizeof(*sleep), test_destructor);
298         ast_test_validate(test, sleep != NULL);
299         *sleep = 500;
300
301         ast_test_status_update(test, "This test will take about %3.1f seconds\n",
302                 (interval + *sleep) / 1000.0);
303
304         task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep, AST_SIP_SCHED_TASK_DATA_NO_CLEANUP);
305         ast_test_validate(test, task != NULL);
306
307         usleep(M2U(interval * 0.5));
308         when = ast_sip_sched_task_get_next_run_by_name("dummy");
309         ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6)));
310         ast_test_validate(test, !ast_sip_sched_is_task_running_by_name("dummy"));
311         ast_test_validate(test, ao2_ref(task, 0) == 2);
312
313         ast_sip_sched_task_cancel_by_name("dummy");
314
315         when = ast_sip_sched_task_get_next_run(task);
316         ast_test_validate(test, when < 0);
317
318         usleep(M2U(interval));
319         ast_test_validate(test, run_count == 0);
320         ast_test_validate(test, destruct_count == 0);
321         ast_test_validate(test, ao2_ref(task, 0) == 1);
322
323         return AST_TEST_PASS;
324 }
325
326 AST_TEST_DEFINE(scheduler_policy)
327 {
328         RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup);
329         RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
330         int when;
331
332         switch (cmd) {
333         case TEST_INIT:
334                 info->name = __func__;
335                 info->category = CATEGORY;
336                 info->summary = "Test res_pjsip scheduler cancel task";
337                 info->description = "Test res_pjsip scheduler cancel task";
338                 return AST_TEST_NOT_RUN;
339         case TEST_EXECUTE:
340                 break;
341         }
342
343         ast_test_validate(test, test_data1 != NULL);
344
345         destruct_count = 0;
346         run_count = 0;
347         test_data1->test = test;
348         test_data1->test_start = ast_tvnow();
349         test_data1->interval = 1000;
350         test_data1->sleep = 500;
351         test_data1->no_clear_done = 1;
352         ast_mutex_init(&test_data1->lock);
353         ast_cond_init(&test_data1->cond, NULL);
354
355         ast_test_status_update(test, "This test will take about %3.1f seconds\n",
356                 ((test_data1->interval * 4) + test_data1->sleep) / 1000.0);
357
358         task = ast_sip_schedule_task(NULL, test_data1->interval, task_1, "test_1", test_data1,
359                 AST_SIP_SCHED_TASK_DATA_NO_CLEANUP | AST_SIP_SCHED_TASK_PERIODIC);
360         ast_test_validate(test, task != NULL);
361
362         waitfor(test_data1);
363         when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
364         ast_test_validate(test, when > test_data1->interval * 0.9 && when < test_data1->interval * 1.1);
365
366         waitfor(test_data1);
367         when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
368         ast_test_validate(test, when > test_data1->interval * 2 * 0.9 && when < test_data1->interval * 2 * 1.1);
369
370         waitfor(test_data1);
371         when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
372         ast_test_validate(test, when > test_data1->interval * 3 * 0.9 && when < test_data1->interval * 3 * 1.1);
373
374         ast_sip_sched_task_cancel(task);
375
376         /* Wait a full interval in case a 4th call to test_1 happened before the cancel */
377         usleep(M2U(test_data1->interval));
378
379         ast_mutex_lock(&test_data1->lock);
380         if (test_data1->done) {
381                 int done = test_data1->done;
382
383                 test_data1->done = 0;
384                 ast_mutex_unlock(&test_data1->lock);
385
386                 ast_test_validate(test, done == 1);
387
388                 /* Wait two full intervals to be certain no further calls to test_1. */
389                 usleep(M2U(test_data1->interval * 2));
390
391                 ast_mutex_lock(&test_data1->lock);
392                 if (test_data1->done != 0) {
393                         ast_mutex_unlock(&test_data1->lock);
394                         /* The cancelation failed so we need to prevent cleanup of
395                          * test_data1 to prevent a crash from write-after-free. */
396                         test_data1 = NULL;
397                         ast_test_status_update(test, "Failed to cancel task");
398                         return AST_TEST_FAIL;
399                 }
400         }
401         ast_mutex_unlock(&test_data1->lock);
402
403         return AST_TEST_PASS;
404 }
405
406 static int load_module(void)
407 {
408         AST_TEST_REGISTER(serialized_scheduler);
409         AST_TEST_REGISTER(unserialized_scheduler);
410         AST_TEST_REGISTER(scheduler_cleanup);
411         AST_TEST_REGISTER(scheduler_cancel);
412         AST_TEST_REGISTER(scheduler_policy);
413         return AST_MODULE_LOAD_SUCCESS;
414 }
415
416 static int unload_module(void)
417 {
418         AST_TEST_UNREGISTER(scheduler_cancel);
419         AST_TEST_UNREGISTER(scheduler_cleanup);
420         AST_TEST_UNREGISTER(unserialized_scheduler);
421         AST_TEST_UNREGISTER(serialized_scheduler);
422         AST_TEST_UNREGISTER(scheduler_policy);
423         return 0;
424 }
425
426 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "res_pjsip scheduler test module",
427         .support_level = AST_MODULE_SUPPORT_CORE,
428         .load = load_module,
429         .unload = unload_module,
430         .requires = "res_pjsip",
431 );