tester: add non-regression check for memory leaks

parent 8da731d1
......@@ -331,7 +331,7 @@ static void one_https_get_with_proxy(void){
http_counters_t counters={0};
belle_sip_stack_set_http_proxy_host(stack, test_http_proxy_addr);
belle_sip_stack_set_http_proxy_port(stack, test_http_proxy_port);
if (one_get("https://smtp.linphone.org",&counters,&counters.response_count) == 0) {
BC_ASSERT_EQUAL(counters.response_count, 1, int, "%d");
BC_ASSERT_EQUAL(counters.io_error_count, 0, int, "%d");
......
......@@ -361,8 +361,8 @@ static void simple_call_with_delay(void){
test_t dialog_tests[] = {
{ "Simple call", simple_call },
{ "Simple call with delay", simple_call_with_delay }
TEST_ONE_TAG("Simple call", simple_call, "LeaksMemory"),
TEST_ONE_TAG("Simple call with delay", simple_call_with_delay, "LeaksMemory"),
};
test_suite_t dialog_test_suite = {"Dialog", register_before_all, register_after_all, belle_sip_tester_before_each,
......
......@@ -1029,8 +1029,8 @@ test_t message_tests[] = {
{ "Channel parser malformed start", channel_parser_malformed_start},
{ "Channel parser truncated start", channel_parser_truncated_start},
{ "Channel parser truncated start with garbage",channel_parser_truncated_start_with_garbage},
{ "RFC2543 compatibility", testRFC2543Compat},
{ "RFC2543 compatibility with branch id",testRFC2543CompatWithBranch},
TEST_ONE_TAG("RFC2543 compatibility", testRFC2543Compat, "LeaksMemory"),
TEST_ONE_TAG("RFC2543 compatibility with branch id",testRFC2543CompatWithBranch, "LeaksMemory"),
{ "Uri headers in sip INVITE",testUriHeadersInInvite},
{ "Uris components in request",testUrisComponentsForRequest},
{ "Generic message test",testGenericMessage},
......
......@@ -524,7 +524,7 @@ static void subscribe_base(int with_resource_lists) {
client_callbacks.process_auth_requested=client_process_auth_requested;
server_callbacks.process_request_event=server_process_request_event;
server_callbacks.process_dialog_terminated=server_process_dialog_terminated;
client = create_udp_endpoint(3452,&client_callbacks);
server = create_udp_endpoint(6788,&server_callbacks);
server->expire_in_contact=0;
......@@ -553,7 +553,7 @@ static void subscribe_base(int with_resource_lists) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","resource-lists+xml")));
belle_sip_message_set_body(BELLE_SIP_MESSAGE(req), list, strlen(list));
}
trans=belle_sip_provider_create_client_transaction(client->provider,req);
belle_sip_object_ref(trans);/*to avoid trans from being deleted before refresher can use it*/
belle_sip_client_transaction_send_request(trans);
......@@ -578,31 +578,31 @@ static void subscribe_base(int with_resource_lists) {
end = belle_sip_time_ms();
BC_ASSERT_TRUE(end-begin>=3000*.9);
BC_ASSERT_TRUE(end-begin<5000);
belle_sip_message("simulating dialog error and recovery");
belle_sip_stack_set_send_error(client->stack, 1500);
BC_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.fourHundredEightyOne,1,4000));
belle_sip_stack_set_send_error(client->stack, 0);
wait_for(server->stack,client->stack, &dummy, 1, 1000);
BC_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,4,4000));
BC_ASSERT_EQUAL(client->stat.dialogTerminated, 0, int, "%i");
BC_ASSERT_NOT_EQUAL(client_dialog, belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher))),void*,"%p"); /*make sure dialog has changed*/
/*unsubscribe twice to make sure refresh operation can be safely cascaded*/
belle_sip_refresher_refresh(refresher,0);
belle_sip_refresher_refresh(refresher,0);
belle_sip_refresher_stop(refresher);
BC_ASSERT_TRUE(wait_for(server->stack,client->stack,&server->stat.dialogTerminated,1,4000));
belle_sip_object_unref(refresher);
if (with_resource_lists) {
BC_ASSERT_EQUAL(server->number_of_body_found, (server->auth == none ?1:2), int, "%i");
}
destroy_endpoint(client);
destroy_endpoint(server);
}
......@@ -613,7 +613,7 @@ static void subscribe_test(void) {
static void subscribe_list_test(void) {
subscribe_base(TRUE);
}
static void register_expires_header(void) {
register_test_with_param(0,none);
}
......@@ -846,8 +846,8 @@ test_t refresher_tests[] = {
{ "REGISTER Expires in Contact digest auth", register_expires_in_contact_header_digest_auth },
{ "REGISTER with failure", register_with_failure },
{ "REGISTER with early refresher",register_early_refresher},
{ "SUBSCRIBE", subscribe_test },
{ "SUBSCRIBE of list" , subscribe_list_test },
TEST_ONE_TAG("SUBSCRIBE", subscribe_test, "LeaksMemory"),
TEST_ONE_TAG("SUBSCRIBE of list" , subscribe_list_test, "LeaksMemory"),
{ "PUBLISH", simple_publish },
{ "PUBLISH with early refresher", simple_publish_with_early_refresher },
{ "REGISTER with unrecognizable Contact", register_with_unrecognizable_contact },
......
......@@ -125,7 +125,7 @@ void belle_sip_tester_before_each() {
leaked_objects_count = belle_sip_object_get_object_count();
}
void belle_sip_tester_after_each() {
int belle_sip_tester_after_each() {
int leaked_objects = belle_sip_object_get_object_count() - leaked_objects_count;
if (leaked_objects > 0) {
char* format = belle_sip_strdup_printf("%d object%s leaked in suite [%s] test [%s], please fix that!",
......@@ -137,7 +137,19 @@ void belle_sip_tester_after_each() {
belle_sip_error("%s", format);
all_leaks_buffer = all_leaks_buffer ? belle_sip_strcat_printf(all_leaks_buffer, "\n%s", format) : belle_sip_strdup_printf("\n%s", format);
{
//prevent any future leaks
const char **tags = bc_tester_current_test_tags();
// if the test is NOT marked as leaking memory and it actually is, we should make it fail
if ( tags &&
!((tags[0] && strcmp(tags[0], "LeakingMemory")) || (tags[1] && strcmp(tags[1], "LeakingMemory")))) {
BC_FAIL("This test is leaking memory!");
return 1;
}
}
}
return 0;
}
int belle_sip_tester_set_log_file(const char *filename) {
......
......@@ -50,7 +50,7 @@ void belle_sip_tester_set_root_ca_path(const char *root_ca_path);
void belle_sip_tester_init(void(*ftester_printf)(int level, const char *fmt, va_list args));
void belle_sip_tester_uninit(void);
void belle_sip_tester_before_each(void);
void belle_sip_tester_after_each(void);
int belle_sip_tester_after_each(void);
int belle_sip_tester_set_log_file(const char *filename);
#ifdef __cplusplus
......
......@@ -80,8 +80,9 @@ static unsigned char curses = 0;
char* xml_file = "CUnitAutomated-Results.xml";
int xml_enabled = 0;
char * suite_name;
char * test_name;
char * suite_name = NULL;
char * test_name = NULL;
char * tag_name = NULL;
static long max_vm_kb = 0;
void (*tester_printf_va)(int level, const char *format, va_list args);
......@@ -93,14 +94,38 @@ void bc_tester_printf(int level, const char *format, ...) {
va_end (args);
}
int bc_tester_run_suite(test_suite_t *suite) {
int bc_tester_run_suite(test_suite_t *suite, const char *tag_name) {
int i;
CU_pSuite pSuite = CU_add_suite(suite->name, suite->before_all, suite->after_all);
for (i = 0; i < suite->nb_tests; i++) {
if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) {
return CU_get_error();
CU_pSuite pSuite;
if (tag_name != NULL) {
int j;
int nb_tests_for_tag = 0;
for (i = 0; i < suite->nb_tests; i++) {
for (j = 0; j < (sizeof(suite->tests[i].tags) / sizeof(suite->tests[i].tags[0])); j++) {
if ((suite->tests[i].tags[j] != NULL) && (strcasecmp(tag_name, suite->tests[i].tags[j]) == 0)) {
nb_tests_for_tag++;
}
}
}
if (nb_tests_for_tag > 0) {
pSuite = CU_add_suite(suite->name, suite->before_all, suite->after_all);
for (i = 0; i < suite->nb_tests; i++) {
for (j = 0; j < (sizeof(suite->tests[i].tags) / sizeof(suite->tests[i].tags[0])); j++) {
if ((suite->tests[i].tags[j] != NULL) && (strcasecmp(tag_name, suite->tests[i].tags[j]) == 0)) {
if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) {
return CU_get_error();
}
}
}
}
}
} else {
pSuite = CU_add_suite(suite->name, suite->before_all, suite->after_all);
for (i = 0; i < suite->nb_tests; i++) {
if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) {
return CU_get_error();
}
}
}
......@@ -124,6 +149,19 @@ int bc_tester_suite_index(const char *suite_name) {
return -1;
}
int bc_tester_test_index(test_suite_t *suite, const char *test_name) {
int i;
for (i = 0; i < suite->nb_tests; i++) {
if (strcmp(test_name, suite->tests[i].name) == 0) {
return i;
}
}
return -1;
}
int bc_tester_nb_suites(void) {
return nb_test_suites;
}
......@@ -222,7 +260,11 @@ static void test_complete_message_handler(const CU_pTest pTest, const CU_pSuite
free(result);
if (test_suite[suite_index]->after_each) {
test_suite[suite_index]->after_each();
int err = test_suite[suite_index]->after_each();
//if test passed but not after_each, count it as failure
if (err && !pFailure) {
CU_get_run_summary()->nTestsFailed++;
}
}
//insert empty line
bc_tester_printf(bc_printf_verbosity_info,"");
......@@ -251,7 +293,7 @@ static void test_complete_message_handler(const CU_pTest pTest, const CU_pSuite
}
#endif
int bc_tester_run_tests(const char *suite_name, const char *test_name) {
int bc_tester_run_tests(const char *suite_name, const char *test_name, const char *tag_name) {
int i;
/* initialize the CUnit test registry */
......@@ -259,7 +301,7 @@ int bc_tester_run_tests(const char *suite_name, const char *test_name) {
return CU_get_error();
for (i = 0; i < nb_test_suites; i++) {
bc_tester_run_suite(test_suite[i]);
bc_tester_run_suite(test_suite[i], tag_name);
}
#ifdef HAVE_CU_GET_SUITE
CU_set_suite_start_handler(suite_start_message_handler);
......@@ -284,13 +326,21 @@ int bc_tester_run_tests(const char *suite_name, const char *test_name) {
CU_pSuite suite;
suite=CU_get_suite(suite_name);
if (!suite) {
bc_tester_printf(bc_printf_verbosity_error, "Could not find suite '%s'. Available suites are:", suite_name);
if (tag_name != NULL) {
bc_tester_printf(bc_printf_verbosity_error, "Could not find suite '%s' or this suite has no tests with tag '%s'. Available suites are:", suite_name, tag_name);
} else {
bc_tester_printf(bc_printf_verbosity_error, "Could not find suite '%s'. Available suites are:", suite_name);
}
bc_tester_list_suites();
return -1;
} else if (test_name) {
CU_pTest test=CU_get_test_by_name(test_name, suite);
if (!test) {
bc_tester_printf(bc_printf_verbosity_error, "Could not find test '%s' in suite '%s'. Available tests are:", test_name, suite_name);
if (tag_name != NULL) {
bc_tester_printf(bc_printf_verbosity_error, "Could not find test '%s' in suite '%s' or this test is not tagged '%s'. Available tests are:", test_name, suite_name, tag_name);
} else {
bc_tester_printf(bc_printf_verbosity_error, "Could not find test '%s' in suite '%s'. Available tests are:", test_name, suite_name);
}
// do not use suite_name here, since this method is case sensitive
bc_tester_list_tests(suite->pName);
return -2;
......@@ -446,9 +496,9 @@ void bc_tester_init(void (*ftester_printf)(int level, const char *format, va_lis
bc_tester_writable_dir_prefix = strdup(".");
}
void bc_tester_set_max_vm(long max_vm_kb) {
void bc_tester_set_max_vm(long amax_vm_kb) {
#ifdef __linux
// max_vm_kb = max_vm_kb;
max_vm_kb = amax_vm_kb;
bc_tester_printf(bc_printf_verbosity_info, "Maximum virtual memory space set to %li kilo bytes", max_vm_kb);
#else
bc_tester_printf(bc_printf_verbosity_error, "Maximum virtual memory space setting is only implemented on Linux.");
......@@ -464,9 +514,12 @@ int bc_tester_parse_args(int argc, char **argv, int argid)
} else if (strcmp(argv[i],"--test")==0){
CHECK_ARG("--test", ++i, argc);
test_name=argv[i];
}else if (strcmp(argv[i],"--suite")==0){
} else if (strcmp(argv[i],"--suite")==0){
CHECK_ARG("--suite", ++i, argc);
suite_name=argv[i];
} else if (strcmp(argv[i], "--tag") == 0) {
CHECK_ARG("--tag", ++i, argc);
tag_name = argv[i];
} else if (strcmp(argv[i],"--list-suites")==0){
bc_tester_list_suites();
return 0;
......@@ -518,7 +571,7 @@ int bc_tester_start(const char* prog_name) {
free(xml_tmp_file);
}
ret = bc_tester_run_tests(suite_name, test_name);
ret = bc_tester_run_tests(suite_name, test_name, tag_name);
return ret;
}
......@@ -656,10 +709,23 @@ char* bc_sprintf(const char* format, ...) {
return res;
}
const char * bc_tester_current_suite_name() {
void bc_free(void *ptr) {
free(ptr);
}
const char * bc_tester_current_suite_name(void) {
return bc_current_suite_name;
}
const char * bc_tester_current_test_name() {
const char * bc_tester_current_test_name(void) {
return bc_current_test_name;
}
const char ** bc_tester_current_test_tags(void) {
if (bc_current_suite_name && bc_current_test_name) {
int suite_index = bc_tester_suite_index(bc_current_suite_name);
int test_index = bc_tester_test_index(test_suite[suite_index], bc_current_test_name);
return test_suite[suite_index]->tests[test_index].tags;
}
return NULL;
}
......@@ -27,6 +27,7 @@
#ifdef _WIN32
#ifndef snprintf
#define snprintf _snprintf
#define strcasecmp _stricmp
#endif
#ifndef strdup
#define strdup _strdup
......@@ -46,15 +47,23 @@ typedef int (*pre_post_function_t)(void);
typedef struct {
const char *name;
test_function_t func;
const char *tags[2];
} test_t;
#define TEST_NO_TAG(name, func) \
{ name, func, { NULL, NULL } }
#define TEST_ONE_TAG(name, func, tag) \
{ name, func, { tag, NULL } }
#define TEST_TWO_TAGS(name, func, tag1, tag2) \
{ name, func, { tag1, tag2 } }
typedef struct {
const char *name; /*suite name*/
pre_post_function_t
before_all; /*function invoked before running the suite. If not returning 0, suite is not launched. */
pre_post_function_t after_all; /*function invoked at the end of the suite, even if some tests failed. */
test_function_t before_each; /*function invoked before each test within this suite. */
test_function_t after_each; /*function invoked after each test within this suite, even if it failed. */
pre_post_function_t after_each; /*function invoked after each test within this suite, even if it failed. */
int nb_tests; /* number of tests */
test_t *tests; /* tests within this suite */
} test_suite_t;
......@@ -89,14 +98,16 @@ void bc_tester_list_suites(void);
void bc_tester_list_tests(const char *suite_name);
const char * bc_tester_suite_name(int suite_index);
const char * bc_tester_test_name(const char *suite_name, int test_index);
int bc_tester_run_suite(test_suite_t *suite);
int bc_tester_run_tests(const char *suite_name, const char *test_name);
int bc_tester_run_suite(test_suite_t *suite, const char *tag_name);
int bc_tester_run_tests(const char *suite_name, const char *test_name, const char *tag_name);
int bc_tester_suite_index(const char *suite_name);
const char * bc_tester_current_suite_name(void);
const char * bc_tester_current_test_name(void);
const char ** bc_tester_current_test_tags(void);
char* bc_sprintfva(const char* format, va_list args);
char* bc_sprintf(const char* format, ...);
void bc_free(void *ptr);
/**
* Get full path to the given resource
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment