asterisk/tests/test_res_pjsip_scheduler.c
George Joseph 3b4f5d1345 test_res_pjsip_scheduler: Add 'depends' on pjproject in MODULEINFO
Since the file was missing the depends on pjproject, it wasn't
picking up the pjproject related include path.  If there was no
system installed pjproject and pjproject-bundled was used, a compile
would fail because pjsip.h wasn't found.

ASTERISK-26139 #close

Change-Id: I2ee64a999051452bc198c4e2c168c70769cd3757
2016-06-22 10:55:58 -05:00

402 lines
11 KiB
C

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2016, Fairview 5 Engineering, LLC
*
* George Joseph <george.joseph@fairview5.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*!
* \file
* \brief res_pjsip scheduler tests
*
* \author George Joseph <george.joseph@fairview5.com>
*
*/
/*** MODULEINFO
<depend>TEST_FRAMEWORK</depend>
<depend>pjproject</depend>
<depend>res_pjsip</depend>
<support_level>core</support_level>
***/
#include "asterisk.h"
ASTERISK_REGISTER_FILE()
#include <pjsip.h>
#include "asterisk/test.h"
#include "asterisk/module.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/utils.h"
#define CATEGORY "/res/res_pjsip/scheduler/"
struct test_data {
ast_mutex_t lock;
ast_cond_t cond;
pthread_t tid;
struct timeval test_start;
struct timeval task_start;
struct timeval task_end;
int is_servant;
int interval;
int sleep;
int done;
struct ast_test *test;
};
#define S2U(x) (long int)(x * 1000 * 1000)
#define M2U(x) (long int)(x * 1000)
static int task_1(void *data)
{
struct test_data *test = data;
test->done = 0;
test->task_start = ast_tvnow();
test->tid = pthread_self();
test->is_servant = ast_sip_thread_is_servant();
usleep(M2U(test->sleep));
test->task_end = ast_tvnow();
ast_mutex_lock(&test->lock);
test->done = 1;
ast_mutex_unlock(&test->lock);
ast_cond_signal(&test->cond);
return test->interval;
}
static void data_cleanup(void *data)
{
struct test_data *test_data = data;
ast_mutex_destroy(&test_data->lock);
ast_cond_destroy(&test_data->cond);
}
#define waitfor(x) \
{ \
ast_mutex_lock(&(x)->lock); \
while (!(x)->done) { \
ast_cond_wait(&(x)->cond, &(x)->lock); \
} \
(x)->done = 0; \
ast_mutex_unlock(&(x)->lock); \
}
static int scheduler(struct ast_test *test, int serialized)
{
RAII_VAR(struct ast_taskprocessor *, tp1, NULL, ast_taskprocessor_unreference);
RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup);
RAII_VAR(struct test_data *, test_data2, ao2_alloc(sizeof(*test_data2), data_cleanup), ao2_cleanup);
RAII_VAR(struct ast_sip_sched_task *, task1, NULL, ao2_cleanup);
RAII_VAR(struct ast_sip_sched_task *, task2, NULL, ao2_cleanup);
int duration;
int delay;
struct timeval task1_start;
ast_test_validate(test, test_data1 != NULL);
ast_test_validate(test, test_data2 != NULL);
test_data1->test = test;
test_data1->test_start = ast_tvnow();
test_data1->interval = 2000;
test_data1->sleep = 1000;
ast_mutex_init(&test_data1->lock);
ast_cond_init(&test_data1->cond, NULL);
test_data2->test = test;
test_data2->test_start = ast_tvnow();
test_data2->interval = 2000;
test_data2->sleep = 1000;
ast_mutex_init(&test_data2->lock);
ast_cond_init(&test_data2->cond, NULL);
if (serialized) {
ast_test_status_update(test, "This test will take about %3.1f seconds\n",
(test_data1->interval + test_data1->sleep + (MAX(test_data1->interval - test_data2->interval, 0)) + test_data2->sleep) / 1000.0);
tp1 = ast_sip_create_serializer("test-scheduler-serializer");
ast_test_validate(test, (tp1 != NULL));
} else {
ast_test_status_update(test, "This test will take about %3.1f seconds\n",
((MAX(test_data1->interval, test_data2->interval) + MAX(test_data1->sleep, test_data2->sleep)) / 1000.0));
}
task1 = ast_sip_schedule_task(tp1, test_data1->interval, task_1, NULL, test_data1, AST_SIP_SCHED_TASK_FIXED);
ast_test_validate(test, task1 != NULL);
task2 = ast_sip_schedule_task(tp1, test_data2->interval, task_1, NULL, test_data2, AST_SIP_SCHED_TASK_FIXED);
ast_test_validate(test, task2 != NULL);
waitfor(test_data1);
ast_sip_sched_task_cancel(task1);
ast_test_validate(test, test_data1->is_servant);
duration = ast_tvdiff_ms(test_data1->task_end, test_data1->test_start);
ast_test_validate(test, (duration > ((test_data1->interval + test_data1->sleep) * 0.9))
&& (duration < ((test_data1->interval + test_data1->sleep) * 1.1)));
ast_sip_sched_task_get_times(task1, NULL, &task1_start, NULL);
delay = ast_tvdiff_ms(task1_start, test_data1->test_start);
ast_test_validate(test, (delay > (test_data1->interval * 0.9)
&& (delay < (test_data1->interval * 1.1))));
waitfor(test_data2);
ast_sip_sched_task_cancel(task2);
ast_test_validate(test, test_data2->is_servant);
if (serialized) {
ast_test_validate(test, test_data1->tid == test_data2->tid);
ast_test_validate(test, ast_tvdiff_ms(test_data2->task_start, test_data1->task_end) >= 0);
} else {
ast_test_validate(test, test_data1->tid != test_data2->tid);
}
return AST_TEST_PASS;
}
AST_TEST_DEFINE(serialized_scheduler)
{
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = CATEGORY;
info->summary = "Test res_pjsip serialized scheduler";
info->description = "Test res_pjsip serialized scheduler";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
return scheduler(test, 1);
}
AST_TEST_DEFINE(unserialized_scheduler)
{
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = CATEGORY;
info->summary = "Test res_pjsip unserialized scheduler";
info->description = "Test res_pjsip unserialized scheduler";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
return scheduler(test, 0);
}
static int run_count;
static int destruct_count;
static int dummy_task(void *data)
{
int *sleep = data;
usleep(M2U(*sleep));
run_count++;
return 0;
}
static void test_destructor(void *data)
{
destruct_count++;
}
AST_TEST_DEFINE(scheduler_cleanup)
{
RAII_VAR(int *, sleep, NULL, ao2_cleanup);
RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
int interval;
int when;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = CATEGORY;
info->summary = "Test res_pjsip scheduler cleanup";
info->description = "Test res_pjsip scheduler cleanup";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
destruct_count = 0;
interval = 1000;
sleep = ao2_alloc(sizeof(*sleep), test_destructor);
ast_test_validate(test, sleep != NULL);
*sleep = 500;
ast_test_status_update(test, "This test will take about %3.1f seconds\n",
((interval * 1.1) + *sleep) / 1000.0);
task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep,
AST_SIP_SCHED_TASK_DATA_AO2 | AST_SIP_SCHED_TASK_DATA_FREE);
ast_test_validate(test, task != NULL);
usleep(M2U(interval * 0.5));
when = ast_sip_sched_task_get_next_run(task);
ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6)));
usleep(M2U(interval * 0.6));
ast_test_validate(test, ast_sip_sched_is_task_running(task));
usleep(M2U(*sleep));
ast_test_validate(test, (ast_sip_sched_is_task_running(task) == 0));
when = ast_sip_sched_task_get_next_run(task);
ast_test_validate(test, (when < 0), res, error);
ast_test_validate(test, (ao2_ref(task, 0) == 1));
ao2_ref(task, -1);
task = NULL;
ast_test_validate(test, (destruct_count == 1));
sleep = NULL;
return AST_TEST_PASS;
}
AST_TEST_DEFINE(scheduler_cancel)
{
RAII_VAR(int *, sleep, NULL, ao2_cleanup);
RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
int interval;
int when;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = CATEGORY;
info->summary = "Test res_pjsip scheduler cancel task";
info->description = "Test res_pjsip scheduler cancel task";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
destruct_count = 0;
interval = 1000;
sleep = ao2_alloc(sizeof(*sleep), test_destructor);
ast_test_validate(test, sleep != NULL);
*sleep = 500;
ast_test_status_update(test, "This test will take about %3.1f seconds\n",
(interval + *sleep) / 1000.0);
task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep, AST_SIP_SCHED_TASK_DATA_NO_CLEANUP);
ast_test_validate(test, task != NULL);
usleep(M2U(interval * 0.5));
when = ast_sip_sched_task_get_next_run_by_name("dummy");
ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6)));
ast_test_validate(test, !ast_sip_sched_is_task_running_by_name("dummy"));
ast_test_validate(test, ao2_ref(task, 0) == 2);
ast_sip_sched_task_cancel_by_name("dummy");
when = ast_sip_sched_task_get_next_run(task);
ast_test_validate(test, when < 0);
usleep(M2U(interval));
ast_test_validate(test, run_count == 0);
ast_test_validate(test, destruct_count == 0);
ast_test_validate(test, ao2_ref(task, 0) == 1);
return AST_TEST_PASS;
}
AST_TEST_DEFINE(scheduler_policy)
{
RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup);
RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
int when;
switch (cmd) {
case TEST_INIT:
info->name = __func__;
info->category = CATEGORY;
info->summary = "Test res_pjsip scheduler cancel task";
info->description = "Test res_pjsip scheduler cancel task";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
ast_test_validate(test, test_data1 != NULL);
destruct_count = 0;
run_count = 0;
test_data1->test = test;
test_data1->test_start = ast_tvnow();
test_data1->interval = 1000;
test_data1->sleep = 500;
ast_mutex_init(&test_data1->lock);
ast_cond_init(&test_data1->cond, NULL);
ast_test_status_update(test, "This test will take about %3.1f seconds\n",
((test_data1->interval * 3) + test_data1->sleep) / 1000.0);
task = ast_sip_schedule_task(NULL, test_data1->interval, task_1, "test_1", test_data1,
AST_SIP_SCHED_TASK_DATA_NO_CLEANUP | AST_SIP_SCHED_TASK_PERIODIC);
ast_test_validate(test, task != NULL);
waitfor(test_data1);
when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
ast_test_validate(test, when > test_data1->interval * 0.9 && when < test_data1->interval * 1.1);
waitfor(test_data1);
when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
ast_test_validate(test, when > test_data1->interval * 2 * 0.9 && when < test_data1->interval * 2 * 1.1);
waitfor(test_data1);
when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
ast_test_validate(test, when > test_data1->interval * 3 * 0.9 && when < test_data1->interval * 3 * 1.1);
ast_sip_sched_task_cancel(task);
ao2_ref(task, -1);
task = NULL;
return AST_TEST_PASS;
}
static int load_module(void)
{
CHECK_PJSIP_MODULE_LOADED();
AST_TEST_REGISTER(serialized_scheduler);
AST_TEST_REGISTER(unserialized_scheduler);
AST_TEST_REGISTER(scheduler_cleanup);
AST_TEST_REGISTER(scheduler_cancel);
AST_TEST_REGISTER(scheduler_policy);
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
{
AST_TEST_UNREGISTER(scheduler_cancel);
AST_TEST_UNREGISTER(scheduler_cleanup);
AST_TEST_UNREGISTER(unserialized_scheduler);
AST_TEST_UNREGISTER(serialized_scheduler);
AST_TEST_UNREGISTER(scheduler_policy);
return 0;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "res_pjsip scheduler test module");