diff --git a/test/tap/tests/reg_test_3223-restapi_return_codes-t.cpp b/test/tap/tests/reg_test_3223-restapi_return_codes-t.cpp index f152d7930..3ed243af4 100644 --- a/test/tap/tests/reg_test_3223-restapi_return_codes-t.cpp +++ b/test/tap/tests/reg_test_3223-restapi_return_codes-t.cpp @@ -17,6 +17,7 @@ #include #include +#include "proxysql_utils.h" #include "tap.h" #include "command_line.h" #include "utils.h" @@ -38,22 +39,25 @@ size_t my_dummy_write(char*, size_t size, size_t nmemb, void*) { * * @param endpoint The endpoint to be exercised by the POST. * @param post_params The post parameters to be supplied to the script. + * @param curl_out_err A uint64_t reference returning the result code of the + * query in case it has been performed. In case the query couldn't be + * performed, this value is never initialized. * @param curl_out_err A string reference to collect the error as a string reported * by 'libcurl' in case of failure. * * @return The response code of the query in case of the query. */ -long perform_simple_post(const string& endpoint, const string& post_params, string& curl_out_err) { +CURLcode perform_simple_post( + const string& endpoint, const string& post_params, uint64_t& curl_res_code, + string& curl_out_err +) { CURL *curl; CURLcode res; - long response_code; curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if(curl) { - diag("endpoint: %s", endpoint.c_str()); - curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_params.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &my_dummy_write); @@ -63,13 +67,13 @@ long perform_simple_post(const string& endpoint, const string& post_params, stri if(res != CURLE_OK) { curl_out_err = std::string { curl_easy_strerror(res) }; } else { - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &curl_res_code); } curl_easy_cleanup(curl); } - return response_code; + return res; } const std::string base_address { "http://localhost:6070/sync/" }; @@ -92,6 +96,49 @@ std::vector> invalid_requests { std::make_tuple( "valid_output_script", "", 400 ) }; +/** + * @brief Waits until the provided endpoint is ready to be used or the + * timeout period expired. For this checks the return code of + * 'perform_simple_post' which only fails in case the 'CURL' request couldn't + * be performed, which is interpreted as endpoint not being yet ready. + * + * @param endpoint The endpoint to be queried. + * @param post_params The required params to be supplied for the 'POST' endpoint + * call. + * @param timeout The max time to wait before declaring a timeout, and + * returning '-1'. + * @param delay The delay specified in 'ms' to be waited between retries. + * + * @return '0' in case the endpoint became available before the timeout, or + * '-1' in case the timeout expired. + */ +int wait_until_enpoint_ready( + std::string endpoint, std::string post_params, uint32_t timeout, uint32_t delay=100 +) { + double waited = 0; + int res = -1; + + while (waited < timeout) { + std::string curl_str_err {}; + uint64_t curl_res_code = 0; + int curl_err = perform_simple_post(endpoint, post_params, curl_res_code, curl_str_err); + + if (curl_err != CURLE_OK) { + diag( + "'curl_err_code': %d, 'curl_err': '%s', waiting for '%d'ms...", + curl_err, curl_str_err.c_str(), delay + ); + waited += static_cast(delay) / 1000; + usleep(delay * 1000); + } else { + res = 0; + break; + } + } + + return res; +} + int main(int argc, char** argv) { CommandLine cl; @@ -125,23 +172,33 @@ int main(int argc, char** argv) { MYSQL_QUERY(proxysql_admin, "DELETE FROM restapi_routes"); // Configure restapi_routes to be used + std::string test_script_base_path { + std::string { cl.workdir } + "reg_test_3223_scripts" + }; - // Congigure routes for valid scripts - MYSQL_QUERY( - proxysql_admin, + std::vector t_valid_scripts_inserts { "INSERT INTO restapi_routes (active, timeout_ms, method, uri, script, comment) " - "VALUES (1,5000,'POST','large_output_script','../test/tap/tests/reg_test_3223_scripts/large_output_script.py','comm')" - ); - MYSQL_QUERY( - proxysql_admin, + "VALUES (1,5000,'POST','large_output_script','%s/large_output_script.py','comm')", "INSERT INTO restapi_routes (active, timeout_ms, method, uri, script, comment) " - "VALUES (1,5000,'POST','partial_output_flush_script','../test/tap/tests/reg_test_3223_scripts/partial_output_flush_script.py','comm')" - ); - MYSQL_QUERY( - proxysql_admin, + "VALUES (1,5000,'POST','partial_output_flush_script','%s/partial_output_flush_script.py','comm')", "INSERT INTO restapi_routes (active, timeout_ms, method, uri, script, comment) " - "VALUES (1,1000,'POST','valid_output_script','../test/tap/tests/reg_test_3223_scripts/valid_output_script.py','comm')" - ); + "VALUES (1,1000,'POST','valid_output_script','%s/valid_output_script.py','comm')" + }; + std::vector valid_scripts_inserts {}; + + for (const auto& t_valid_script_insert : t_valid_scripts_inserts) { + std::string valid_script_insert {}; + string_format(t_valid_script_insert, valid_script_insert, test_script_base_path.c_str()); + valid_scripts_inserts.push_back(valid_script_insert); + } + + // Configure routes for valid scripts + for (const auto& valid_script_insert : valid_scripts_inserts) { + MYSQL_QUERY( + proxysql_admin, + valid_script_insert.c_str() + ); + } // NOTE: Disable due to requiring python2 annotation in file // MYSQL_QUERY( @@ -150,37 +207,67 @@ int main(int argc, char** argv) { // "VALUES (1,1000,'POST','metrics','../scripts/metrics.py','comm')" // ); - // Congigure routes for invalid scripts - MYSQL_QUERY( - proxysql_admin, + std::vector t_invalid_scripts_inserts { "INSERT INTO restapi_routes (active, timeout_ms, method, uri, script, comment) " - "VALUES (1,1000,'POST','invalid_output_script','../test/tap/tests/reg_test_3223_scripts/invalid_output_script.py','comm')" - ); - MYSQL_QUERY( - proxysql_admin, + "VALUES (1,1000,'POST','invalid_output_script','%s/invalid_output_script.py','comm')", "INSERT INTO restapi_routes (active, timeout_ms, method, uri, script, comment) " - "VALUES (1,1000,'POST','timeout_script','../test/tap/tests/reg_test_3223_scripts/timeout_script.py','comm')" - ); - MYSQL_QUERY( - proxysql_admin, + "VALUES (1,1000,'POST','timeout_script','%s/timeout_script.py','comm')", "INSERT INTO restapi_routes (active, timeout_ms, method, uri, script, comment) " - "VALUES (1,1000,'POST','invalid_script','../test/tap/tests/reg_test_3223_scripts/invalid_script.py','comm')" - ); + "VALUES (1,1000,'POST','invalid_script','%s/invalid_script.py','comm')" + }; + std::vector invalid_scripts_inserts {}; + + for (const auto& t_invalid_script_insert : t_invalid_scripts_inserts) { + std::string invalid_script_insert {}; + string_format(t_invalid_script_insert, invalid_script_insert, test_script_base_path.c_str()); + invalid_scripts_inserts.push_back(invalid_script_insert); + } + + // Configure routes for invalid scripts + for (const auto& invalid_script_insert : invalid_scripts_inserts) { + MYSQL_QUERY( + proxysql_admin, + invalid_script_insert.c_str() + ); + } MYSQL_QUERY(proxysql_admin, "LOAD restapi TO RUNTIME"); + // Sensible wait until the new configured enpoints are ready. + // Use the first enpoint for the check + const auto& first_request_tuple { valid_endpoints.front() }; + const std::string full_endpoint { + base_address + std::get<0>(first_request_tuple) + "/" + }; + int endpoint_timeout = wait_until_enpoint_ready( + full_endpoint, std::get<1>(first_request_tuple), 10, 500 + ); + + if (endpoint_timeout) { + diag( + "Timeout while trying to reach first valid enpoint." + " Test failed, skipping endpoint testing..." + ); + goto skip_endpoints_testing; + } + for (const auto& valid_request_tuple : valid_endpoints) { const std::string full_endpoint { base_address + std::get<0>(valid_request_tuple) + "/"}; std::string post_out_err { "" }; + uint64_t curl_res_code = 0; // perform the POST operation - int post_err = perform_simple_post(full_endpoint, std::get<1>(valid_request_tuple), post_out_err); + CURLcode post_err = perform_simple_post( + full_endpoint, std::get<1>(valid_request_tuple), curl_res_code, post_out_err + ); ok( - post_err == 200, - "Performing a POST over endpoint '%s' should result into a 200 response: (errcode: '%d', curlerr: '%s' )", + post_err == CURLE_OK && curl_res_code == 200, + "Performing a POST over endpoint '%s' should result into a 200 response:" + " (curl_err: '%d', response_errcode: '%ld', curlerr: '%s')", full_endpoint.c_str(), post_err, + curl_res_code, post_out_err.c_str() ); } @@ -188,18 +275,24 @@ int main(int argc, char** argv) { for (const auto& invalid_request_tuple : invalid_requests) { const std::string full_endpoint { base_address + std::get<0>(invalid_request_tuple) + "/" }; std::string post_out_err { "" }; + uint64_t curl_res_code = 0; // perform the POST operation - int post_err = perform_simple_post(full_endpoint, std::get<1>(invalid_request_tuple), post_out_err); + CURLcode post_err = perform_simple_post( + full_endpoint, std::get<1>(invalid_request_tuple), curl_res_code, post_out_err); ok( - post_err == std::get<2>(invalid_request_tuple), - "Performing a POST over endpoint '%s' shouldn't result into a 200 response: (errcode: '%d', curlerr: '%s' )", + post_err == CURLE_OK && curl_res_code == std::get<2>(invalid_request_tuple), + "Performing a POST over endpoint '%s' shouldn't result into a 200 response:" + " (curl_err: '%d', response_errcode: '%ld', curlerr: '%s')", full_endpoint.c_str(), post_err, + curl_res_code, post_out_err.c_str() ); } +skip_endpoints_testing: + return exit_status(); }