Remove ASTERISK_REGISTER_FILE.
[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         struct ast_test *test;
57 };
58
59 #define S2U(x) (long int)(x * 1000 * 1000)
60 #define M2U(x) (long int)(x * 1000)
61
62 static int task_1(void *data)
63 {
64         struct test_data *test = data;
65
66         test->done = 0;
67         test->task_start = ast_tvnow();
68         test->tid = pthread_self();
69         test->is_servant = ast_sip_thread_is_servant();
70         usleep(M2U(test->sleep));
71         test->task_end = ast_tvnow();
72
73         ast_mutex_lock(&test->lock);
74         test->done = 1;
75         ast_mutex_unlock(&test->lock);
76         ast_cond_signal(&test->cond);
77
78         return test->interval;
79 }
80
81
82 static void data_cleanup(void *data)
83 {
84         struct test_data *test_data = data;
85         ast_mutex_destroy(&test_data->lock);
86         ast_cond_destroy(&test_data->cond);
87 }
88
89 #define waitfor(x) \
90 { \
91         ast_mutex_lock(&(x)->lock); \
92         while (!(x)->done) { \
93                 ast_cond_wait(&(x)->cond, &(x)->lock); \
94         } \
95         (x)->done = 0; \
96         ast_mutex_unlock(&(x)->lock); \
97 }
98
99 static int scheduler(struct ast_test *test, int serialized)
100 {
101         RAII_VAR(struct ast_taskprocessor *, tp1, NULL, ast_taskprocessor_unreference);
102         RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup);
103         RAII_VAR(struct test_data *, test_data2, ao2_alloc(sizeof(*test_data2), data_cleanup), ao2_cleanup);
104         RAII_VAR(struct ast_sip_sched_task *, task1, NULL, ao2_cleanup);
105         RAII_VAR(struct ast_sip_sched_task *, task2, NULL, ao2_cleanup);
106         int duration;
107         int delay;
108         struct timeval task1_start;
109
110         ast_test_validate(test, test_data1 != NULL);
111         ast_test_validate(test, test_data2 != NULL);
112
113         test_data1->test = test;
114         test_data1->test_start = ast_tvnow();
115         test_data1->interval = 2000;
116         test_data1->sleep = 1000;
117         ast_mutex_init(&test_data1->lock);
118         ast_cond_init(&test_data1->cond, NULL);
119
120         test_data2->test = test;
121         test_data2->test_start = ast_tvnow();
122         test_data2->interval = 2000;
123         test_data2->sleep = 1000;
124         ast_mutex_init(&test_data2->lock);
125         ast_cond_init(&test_data2->cond, NULL);
126
127         if (serialized) {
128                 ast_test_status_update(test, "This test will take about %3.1f seconds\n",
129                         (test_data1->interval + test_data1->sleep + (MAX(test_data1->interval - test_data2->interval, 0)) + test_data2->sleep) / 1000.0);
130                 tp1 = ast_sip_create_serializer("test-scheduler-serializer");
131                 ast_test_validate(test, (tp1 != NULL));
132         } else {
133                 ast_test_status_update(test, "This test will take about %3.1f seconds\n",
134                         ((MAX(test_data1->interval, test_data2->interval) + MAX(test_data1->sleep, test_data2->sleep)) / 1000.0));
135         }
136
137         task1 = ast_sip_schedule_task(tp1, test_data1->interval, task_1, NULL, test_data1, AST_SIP_SCHED_TASK_FIXED);
138         ast_test_validate(test, task1 != NULL);
139
140         task2 = ast_sip_schedule_task(tp1, test_data2->interval, task_1, NULL, test_data2, AST_SIP_SCHED_TASK_FIXED);
141         ast_test_validate(test, task2 != NULL);
142
143         waitfor(test_data1);
144         ast_sip_sched_task_cancel(task1);
145         ast_test_validate(test, test_data1->is_servant);
146
147         duration = ast_tvdiff_ms(test_data1->task_end, test_data1->test_start);
148         ast_test_validate(test, (duration > ((test_data1->interval + test_data1->sleep) * 0.9))
149                 && (duration < ((test_data1->interval + test_data1->sleep) * 1.1)));
150
151         ast_sip_sched_task_get_times(task1, NULL, &task1_start, NULL);
152         delay = ast_tvdiff_ms(task1_start, test_data1->test_start);
153         ast_test_validate(test, (delay > (test_data1->interval * 0.9)
154                 && (delay < (test_data1->interval * 1.1))));
155
156         waitfor(test_data2);
157         ast_sip_sched_task_cancel(task2);
158         ast_test_validate(test, test_data2->is_servant);
159
160         if (serialized) {
161                 ast_test_validate(test, test_data1->tid == test_data2->tid);
162                 ast_test_validate(test, ast_tvdiff_ms(test_data2->task_start, test_data1->task_end) >= 0);
163         } else {
164                 ast_test_validate(test, test_data1->tid != test_data2->tid);
165         }
166
167         return AST_TEST_PASS;
168 }
169
170 AST_TEST_DEFINE(serialized_scheduler)
171 {
172
173         switch (cmd) {
174         case TEST_INIT:
175                 info->name = __func__;
176                 info->category = CATEGORY;
177                 info->summary = "Test res_pjsip serialized scheduler";
178                 info->description = "Test res_pjsip serialized scheduler";
179                 return AST_TEST_NOT_RUN;
180         case TEST_EXECUTE:
181                 break;
182         }
183
184         return scheduler(test, 1);
185 }
186
187 AST_TEST_DEFINE(unserialized_scheduler)
188 {
189
190         switch (cmd) {
191         case TEST_INIT:
192                 info->name = __func__;
193                 info->category = CATEGORY;
194                 info->summary = "Test res_pjsip unserialized scheduler";
195                 info->description = "Test res_pjsip unserialized scheduler";
196                 return AST_TEST_NOT_RUN;
197         case TEST_EXECUTE:
198                 break;
199         }
200
201         return scheduler(test, 0);
202 }
203
204 static int run_count;
205 static int destruct_count;
206
207 static int dummy_task(void *data)
208 {
209         int *sleep = data;
210
211         usleep(M2U(*sleep));
212         run_count++;
213
214         return 0;
215 }
216
217 static void test_destructor(void *data)
218 {
219         destruct_count++;
220 }
221
222 AST_TEST_DEFINE(scheduler_cleanup)
223 {
224         RAII_VAR(int *, sleep, NULL, ao2_cleanup);
225         RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
226         int interval;
227         int when;
228
229         switch (cmd) {
230         case TEST_INIT:
231                 info->name = __func__;
232                 info->category = CATEGORY;
233                 info->summary = "Test res_pjsip scheduler cleanup";
234                 info->description = "Test res_pjsip scheduler cleanup";
235                 return AST_TEST_NOT_RUN;
236         case TEST_EXECUTE:
237                 break;
238         }
239
240         destruct_count = 0;
241         interval = 1000;
242
243         sleep = ao2_alloc(sizeof(*sleep), test_destructor);
244         ast_test_validate(test, sleep != NULL);
245         *sleep = 500;
246
247         ast_test_status_update(test, "This test will take about %3.1f seconds\n",
248                 ((interval * 1.1) + *sleep) / 1000.0);
249
250         task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep,
251                 AST_SIP_SCHED_TASK_DATA_AO2 | AST_SIP_SCHED_TASK_DATA_FREE);
252         ast_test_validate(test, task != NULL);
253         usleep(M2U(interval * 0.5));
254         when = ast_sip_sched_task_get_next_run(task);
255         ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6)));
256         usleep(M2U(interval * 0.6));
257         ast_test_validate(test, ast_sip_sched_is_task_running(task));
258
259         usleep(M2U(*sleep));
260
261         ast_test_validate(test, (ast_sip_sched_is_task_running(task) == 0));
262         when = ast_sip_sched_task_get_next_run(task);
263         ast_test_validate(test, (when < 0), res, error);
264         ast_test_validate(test, (ao2_ref(task, 0) == 1));
265         ao2_ref(task, -1);
266         task = NULL;
267         ast_test_validate(test, (destruct_count == 1));
268         sleep = NULL;
269
270         return AST_TEST_PASS;
271 }
272
273 AST_TEST_DEFINE(scheduler_cancel)
274 {
275         RAII_VAR(int *, sleep, NULL, ao2_cleanup);
276         RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
277         int interval;
278         int when;
279
280         switch (cmd) {
281         case TEST_INIT:
282                 info->name = __func__;
283                 info->category = CATEGORY;
284                 info->summary = "Test res_pjsip scheduler cancel task";
285                 info->description = "Test res_pjsip scheduler cancel task";
286                 return AST_TEST_NOT_RUN;
287         case TEST_EXECUTE:
288                 break;
289         }
290
291         destruct_count = 0;
292         interval = 1000;
293
294         sleep = ao2_alloc(sizeof(*sleep), test_destructor);
295         ast_test_validate(test, sleep != NULL);
296         *sleep = 500;
297
298         ast_test_status_update(test, "This test will take about %3.1f seconds\n",
299                 (interval + *sleep) / 1000.0);
300
301         task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep, AST_SIP_SCHED_TASK_DATA_NO_CLEANUP);
302         ast_test_validate(test, task != NULL);
303
304         usleep(M2U(interval * 0.5));
305         when = ast_sip_sched_task_get_next_run_by_name("dummy");
306         ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6)));
307         ast_test_validate(test, !ast_sip_sched_is_task_running_by_name("dummy"));
308         ast_test_validate(test, ao2_ref(task, 0) == 2);
309
310         ast_sip_sched_task_cancel_by_name("dummy");
311
312         when = ast_sip_sched_task_get_next_run(task);
313         ast_test_validate(test, when < 0);
314
315         usleep(M2U(interval));
316         ast_test_validate(test, run_count == 0);
317         ast_test_validate(test, destruct_count == 0);
318         ast_test_validate(test, ao2_ref(task, 0) == 1);
319
320         return AST_TEST_PASS;
321 }
322
323 AST_TEST_DEFINE(scheduler_policy)
324 {
325         RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup);
326         RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
327         int when;
328
329         switch (cmd) {
330         case TEST_INIT:
331                 info->name = __func__;
332                 info->category = CATEGORY;
333                 info->summary = "Test res_pjsip scheduler cancel task";
334                 info->description = "Test res_pjsip scheduler cancel task";
335                 return AST_TEST_NOT_RUN;
336         case TEST_EXECUTE:
337                 break;
338         }
339
340         ast_test_validate(test, test_data1 != NULL);
341
342         destruct_count = 0;
343         run_count = 0;
344         test_data1->test = test;
345         test_data1->test_start = ast_tvnow();
346         test_data1->interval = 1000;
347         test_data1->sleep = 500;
348         ast_mutex_init(&test_data1->lock);
349         ast_cond_init(&test_data1->cond, NULL);
350
351         ast_test_status_update(test, "This test will take about %3.1f seconds\n",
352                 ((test_data1->interval * 3) + test_data1->sleep) / 1000.0);
353
354         task = ast_sip_schedule_task(NULL, test_data1->interval, task_1, "test_1", test_data1,
355                 AST_SIP_SCHED_TASK_DATA_NO_CLEANUP | AST_SIP_SCHED_TASK_PERIODIC);
356         ast_test_validate(test, task != NULL);
357
358         waitfor(test_data1);
359         when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
360         ast_test_validate(test, when > test_data1->interval * 0.9 && when < test_data1->interval * 1.1);
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 * 2 * 0.9 && when < test_data1->interval * 2 * 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 * 3 * 0.9 && when < test_data1->interval * 3 * 1.1);
369
370         ast_sip_sched_task_cancel(task);
371         ao2_ref(task, -1);
372         task = NULL;
373
374         return AST_TEST_PASS;
375 }
376
377 static int load_module(void)
378 {
379         CHECK_PJSIP_MODULE_LOADED();
380
381         AST_TEST_REGISTER(serialized_scheduler);
382         AST_TEST_REGISTER(unserialized_scheduler);
383         AST_TEST_REGISTER(scheduler_cleanup);
384         AST_TEST_REGISTER(scheduler_cancel);
385         AST_TEST_REGISTER(scheduler_policy);
386         return AST_MODULE_LOAD_SUCCESS;
387 }
388
389 static int unload_module(void)
390 {
391         AST_TEST_UNREGISTER(scheduler_cancel);
392         AST_TEST_UNREGISTER(scheduler_cleanup);
393         AST_TEST_UNREGISTER(unserialized_scheduler);
394         AST_TEST_UNREGISTER(serialized_scheduler);
395         AST_TEST_UNREGISTER(scheduler_policy);
396         return 0;
397 }
398
399 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "res_pjsip scheduler test module");