From 629d2e34508838069db83e1082ce9e7f2c7b8ff8 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Fri, 21 Oct 2011 16:26:18 +0200 Subject: multi tests: OOM handling fixes Additionally, improved error checking and logging. --- tests/libtest/test.h | 337 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 332 insertions(+), 5 deletions(-) (limited to 'tests/libtest/test.h') diff --git a/tests/libtest/test.h b/tests/libtest/test.h index 046b5504e..81c435d1f 100644 --- a/tests/libtest/test.h +++ b/tests/libtest/test.h @@ -50,9 +50,6 @@ # include "select.h" #endif -#define TEST_ERR_MAJOR_BAD 100 -#define TEST_ERR_RUNS_FOREVER 99 - #define test_setopt(A,B,C) \ if((res = curl_easy_setopt((A),(B),(C))) != CURLE_OK) goto test_cleanup @@ -66,8 +63,10 @@ extern char *libtest_arg3; /* set by first.c to the argv[3] or NULL */ extern int test_argc; extern char **test_argv; -extern int select_test(int num_fds, fd_set *rd, fd_set *wr, fd_set *exc, - struct timeval *tv); +extern struct timeval tv_test_start; /* for test timing */ + +extern int select_wrapper(int nfds, fd_set *rd, fd_set *wr, fd_set *exc, + struct timeval *tv); extern int test(char *URL); /* the actual test function provided by each individual libXXX.c file */ @@ -75,3 +74,331 @@ extern int test(char *URL); /* the actual test function provided by each #ifdef UNITTESTS extern int unitfail; #endif + +/* +** TEST_ERR_* values must be greater than CURL_LAST CURLcode in order +** to avoid confusion with any CURLcode or CURLMcode. These TEST_ERR_* +** codes are returned to signal test specific situations and should +** not get mixed with CURLcode or CURLMcode values. +** +** For portability reasons TEST_ERR_* values should be less than 127. +*/ + +#define TEST_ERR_MAJOR_BAD 126 +#define TEST_ERR_RUNS_FOREVER 125 +#define TEST_ERR_EASY_INIT 124 +#define TEST_ERR_MULTI_INIT 123 +#define TEST_ERR_NUM_HANDLES 122 +#define TEST_ERR_SELECT 121 +#define TEST_ERR_SUCCESS 120 +#define TEST_ERR_FAILURE 119 +#define TEST_ERR_USAGE 118 +#define TEST_ERR_FOPEN 117 +#define TEST_ERR_FSTAT 116 + +/* +** Macros for test source code readability/maintainability. +** +** All of the following macros require that an int data type 'res' variable +** exists in scope where macro is used, and that it has been initialized to +** zero before the macro is used. +** +** exe_* and chk_* macros are helper macros not intended to be used from +** outside of this header file. Arguments 'Y' and 'Z' of these represent +** source code file and line number, while Arguments 'A', 'B', etc, are +** the arguments used to actually call a libcurl function. +** +** All easy_* and multi_* macros call a libcurl function and evaluate if +** the function has succeeded or failed. When the function succeeds 'res' +** variable is not set nor cleared and program continues normal flow. On +** the other hand if function fails 'res' variable is set and a jump to +** label 'test_cleanup' is performed. +** +** Every easy_* and multi_* macros have a res_easy_* and res_multi_* macro +** counterpart that operates in tha same way with the exception that no +** jump takes place in case of failure. res_easy_* and res_multi_* macros +** should be immediately followed by checking if 'res' variable has been +** set. +** +** 'res' variable when set will hold a CURLcode, CURLMcode, or any of the +** TEST_ERR_* values defined above. It is advisable to return this value +** as test result. +*/ + +/* ---------------------------------------------------------------- */ + +#define exe_easy_init(A,Y,Z) do { \ + if(((A) = curl_easy_init()) == NULL) { \ + fprintf(stderr, "%s:%d curl_easy_init() failed\n", (Y), (Z)); \ + res = TEST_ERR_EASY_INIT; \ + } \ +} WHILE_FALSE + +#define res_easy_init(A) \ + exe_easy_init((A),(__FILE__),(__LINE__)) + +#define chk_easy_init(A,Y,Z) do { \ + exe_easy_init((A),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define easy_init(A) \ + chk_easy_init((A),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_init(A,Y,Z) do { \ + if(((A) = curl_multi_init()) == NULL) { \ + fprintf(stderr, "%s:%d curl_multi_init() failed\n", (Y), (Z)); \ + res = TEST_ERR_MULTI_INIT; \ + } \ +} WHILE_FALSE + +#define res_multi_init(A) \ + exe_multi_init((A),(__FILE__),(__LINE__)) + +#define chk_multi_init(A,Y,Z) do { \ + exe_multi_init((A),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_init(A) \ + chk_multi_init((A),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_easy_setopt(A,B,C,Y,Z) do { \ + CURLcode ec; \ + if((ec = curl_easy_setopt((A),(B),(C))) != CURLE_OK) { \ + fprintf(stderr, "%s:%d curl_easy_setopt() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_easy_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_easy_setopt(A,B,C) \ + exe_easy_setopt((A),(B),(C),(__FILE__),(__LINE__)) + +#define chk_easy_setopt(A,B,C,Y,Z) do { \ + exe_easy_setopt((A),(B),(C),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define easy_setopt(A,B,C) \ + chk_easy_setopt((A),(B),(C),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_setopt(A,B,C,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_setopt((A),(B),(C))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_setopt() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_multi_setopt(A,B,C) \ + exe_multi_setopt((A),(B),(C),(__FILE__),(__LINE__)) + +#define chk_multi_setopt(A,B,C,Y,Z) do { \ + exe_multi_setopt((A),(B),(C),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_setopt(A,B,C) \ + chk_multi_setopt((A),(B),(C),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_add_handle(A,B,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_add_handle((A),(B))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_add_handle() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_multi_add_handle(A,B) \ + exe_multi_add_handle((A),(B),(__FILE__),(__LINE__)) + +#define chk_multi_add_handle(A,B,Y,Z) do { \ + exe_multi_add_handle((A),(B),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_add_handle(A,B) \ + chk_multi_add_handle((A),(B),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_perform(A,B,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_perform((A),(B))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_perform() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ + else if(*((B)) < 0) { \ + fprintf(stderr, "%s:%d curl_multi_perform() succeeded, " \ + "but returned invalid running_handles value (%d)\n", \ + (Y), (Z), (int)*((B))); \ + res = TEST_ERR_NUM_HANDLES; \ + } \ +} WHILE_FALSE + +#define res_multi_perform(A,B) \ + exe_multi_perform((A),(B),(__FILE__),(__LINE__)) + +#define chk_multi_perform(A,B,Y,Z) do { \ + exe_multi_perform((A),(B),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_perform(A,B) \ + chk_multi_perform((A),(B),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_fdset(A,B,C,D,E,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_fdset((A),(B),(C),(D),(E))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_fdset() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ + else if(*((E)) < -1) { \ + fprintf(stderr, "%s:%d curl_multi_fdset() succeeded, " \ + "but returned invalid max_fd value (%d)\n", \ + (Y), (Z), (int)*((E))); \ + res = TEST_ERR_NUM_HANDLES; \ + } \ +} WHILE_FALSE + +#define res_multi_fdset(A,B,C,D,E) \ + exe_multi_fdset((A),(B),(C),(D),(E),(__FILE__),(__LINE__)) + +#define chk_multi_fdset(A,B,C,D,E,Y,Z) do { \ + exe_multi_fdset((A),(B),(C),(D),(E),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_fdset(A,B,C,D,E) \ + chk_multi_fdset((A),(B),(C),(D),(E),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_timeout(A,B,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_timeout((A),(B))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_timeout() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_multi_timeout(A,B) \ + exe_multi_timeout((A),(B),(__FILE__),(__LINE__)) + +#define chk_multi_timeout(A,B,Y,Z) do { \ + exe_multi_timeout((A),(B),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_timeout(A,B) \ + chk_multi_timeout((A),(B),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_select_test(A,B,C,D,E,Y,Z) do { \ + int ec; \ + if(select_wrapper((A),(B),(C),(D),(E)) == -1 ) { \ + ec = SOCKERRNO; \ + fprintf(stderr, "%s:%d select() failed, with " \ + "errno %d (%s)\n", \ + (Y), (Z), ec, strerror(ec)); \ + res = TEST_ERR_SELECT; \ + } \ +} WHILE_FALSE + +#define res_select_test(A,B,C,D,E) \ + exe_select_test((A),(B),(C),(D),(E),(__FILE__),(__LINE__)) + +#define chk_select_test(A,B,C,D,E,Y,Z) do { \ + exe_select_test((A),(B),(C),(D),(E),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define select_test(A,B,C,D,E) \ + chk_select_test((A),(B),(C),(D),(E),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define start_test_timing() do { \ + tv_test_start = tutil_tvnow(); \ +} WHILE_FALSE + +#define exe_test_timedout(Y,Z) do { \ + if(tutil_tvdiff(tutil_tvnow(), tv_test_start) > TEST_HANG_TIMEOUT) { \ + fprintf(stderr, "%s:%d ABORTING TEST, since it seems " \ + "that it would have run forever.\n", (Y), (Z)); \ + res = TEST_ERR_RUNS_FOREVER; \ + } \ +} WHILE_FALSE + +#define res_test_timedout() \ + exe_test_timedout((__FILE__),(__LINE__)) + +#define chk_test_timedout(Y,Z) do { \ + exe_test_timedout(Y,Z); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define abort_on_test_timeout() \ + chk_test_timedout((__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_global_init(A,Y,Z) do { \ + CURLcode ec; \ + if((ec = curl_global_init((A))) != CURLE_OK) { \ + fprintf(stderr, "%s:%d curl_global_init() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_easy_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_global_init(A) \ + exe_global_init((A),(__FILE__),(__LINE__)) + +#define chk_global_init(A,Y,Z) do { \ + exe_global_init((A),(Y),(Z)); \ + if(res) \ + return res; \ +} WHILE_FALSE + +/* global_init() is different than other macros. In case of + failure it 'return's instead of going to 'test_cleanup'. */ + +#define global_init(A) \ + chk_global_init((A),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ -- cgit v1.2.3