diff --git a/test/tap/tests/test_tsdb_api-t.cpp b/test/tap/tests/test_tsdb_api-t.cpp index 4501d0c88..cb5697831 100644 --- a/test/tap/tests/test_tsdb_api-t.cpp +++ b/test/tap/tests/test_tsdb_api-t.cpp @@ -95,65 +95,140 @@ int main() { curl_global_init(CURL_GLOBAL_ALL); plan(10); + diag("TSDB API Test Configuration:"); + diag(" ProxySQL host: %s", cl.host); + diag(" Admin port: %d", cl.admin_port); + diag(" Admin username: %s", cl.admin_username); + MYSQL* admin = mysql_init(NULL); if (!mysql_real_connect(admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { diag("Connection failed: %s", mysql_error(admin)); return EXIT_FAILURE; } + diag("Connected to ProxySQL admin interface"); // 1. Enable TSDB and REST API diag("Enabling TSDB, Web, and REST API..."); - mysql_query(admin, "SET tsdb-enabled='1'"); drain_results(admin); - mysql_query(admin, "SET tsdb-sample_interval='1'"); drain_results(admin); - mysql_query(admin, "SET admin-restapi_enabled='1'"); drain_results(admin); - mysql_query(admin, "SET admin-web_enabled='1'"); drain_results(admin); - mysql_query(admin, "LOAD TSDB VARIABLES TO RUNTIME"); drain_results(admin); - mysql_query(admin, "LOAD ADMIN VARIABLES TO RUNTIME"); drain_results(admin); + int rc; + rc = mysql_query(admin, "SET tsdb-enabled='1'"); + if (rc) { + diag("SET tsdb-enabled failed: %s", mysql_error(admin)); + return EXIT_FAILURE; + } + drain_results(admin); + + rc = mysql_query(admin, "SET tsdb-sample_interval='1'"); + if (rc) { + diag("SET tsdb-sample_interval failed: %s", mysql_error(admin)); + return EXIT_FAILURE; + } + drain_results(admin); + + rc = mysql_query(admin, "SET admin-restapi_enabled='1'"); + if (rc) { + diag("SET admin-restapi_enabled failed: %s", mysql_error(admin)); + return EXIT_FAILURE; + } + drain_results(admin); + + rc = mysql_query(admin, "SET admin-web_enabled='1'"); + if (rc) { + diag("SET admin-web_enabled failed: %s", mysql_error(admin)); + return EXIT_FAILURE; + } + drain_results(admin); + + rc = mysql_query(admin, "LOAD TSDB VARIABLES TO RUNTIME"); + if (rc) { + diag("LOAD TSDB VARIABLES failed: %s", mysql_error(admin)); + return EXIT_FAILURE; + } + drain_results(admin); + + rc = mysql_query(admin, "LOAD ADMIN VARIABLES TO RUNTIME"); + if (rc) { + diag("LOAD ADMIN VARIABLES failed: %s", mysql_error(admin)); + return EXIT_FAILURE; + } + drain_results(admin); + + // Verify the settings were applied + MYSQL_RES* res; + rc = mysql_query(admin, "SELECT variable_name, variable_value FROM runtime_global_variables WHERE variable_name IN ('admin-restapi_enabled', 'admin-web_enabled', 'tsdb-enabled')"); + if (rc == 0) { + res = mysql_store_result(admin); + if (res) { + diag("Runtime variable status:"); + MYSQL_ROW row; + while ((row = mysql_fetch_row(res))) { + diag(" %s = %s", row[0], row[1]); + } + mysql_free_result(res); + } + } drain_results(admin); // 2. Wait for background loops to collect data and HTTP server to start diag("Waiting for initialization and data collection (7s)..."); sleep(7); - string base_url = "https://127.0.0.1:6080"; - string rest_url = "http://127.0.0.1:6070"; + // Use admin interface host for HTTP endpoints + string base_url = string("https://") + cl.admin_host + ":6080"; + string rest_url = string("http://") + cl.admin_host + ":6070"; + diag("Web dashboard URL: %s", base_url.c_str()); + diag("REST API URL: %s", rest_url.c_str()); + string response; - long rc; + long http_rc; // 3. Test /tsdb Dashboard (HTML) diag("Testing GET /tsdb"); - // Retry once if server returned nothing - for (int i=0; i<3; i++) { - rc = http_get((base_url + "/tsdb").c_str(), response); - if (rc != 0) break; - diag("Retry %d for /tsdb...", i+1); + response.clear(); + // Retry multiple times if server returned nothing + for (int i=0; i<5; i++) { + http_rc = http_get((base_url + "/tsdb").c_str(), response); + if (http_rc != 0) break; + diag("Retry %d for /tsdb (got response code 0, connection likely failed)...", i+1); sleep(2); } - - ok(rc == 200, "Dashboard /tsdb returns 200 (got %ld)", rc); + + ok(http_rc == 200, "Dashboard /tsdb returns 200 (got %ld)", http_rc); + if (http_rc != 200) { + diag("Dashboard response code: %ld", http_rc); + diag("This may indicate web interface is not enabled or not accessible at %s", base_url.c_str()); + } ok(response.find("ProxySQL TSDB Dashboard") != string::npos, "Dashboard contains title"); ok(response.find("tsdbChart") != string::npos, "Dashboard contains canvas element"); // 4. Test /api/tsdb/status diag("Testing GET /api/tsdb/status"); - rc = http_get((rest_url + "/api/tsdb/status").c_str(), response, "admin:admin"); - ok(rc == 200, "API /api/tsdb/status returns 200"); + response.clear(); + string auth_creds = string(cl.admin_username) + ":" + string(cl.admin_password); + diag("Using authentication with username: %s", cl.admin_username); + http_rc = http_get((rest_url + "/api/tsdb/status").c_str(), response, auth_creds.c_str()); + ok(http_rc == 200, "API /api/tsdb/status returns 200 (got %ld)", http_rc); + if (http_rc != 200) { + diag("REST API may not be enabled or not accessible at %s", rest_url.c_str()); + } ok(response.find("total_datapoints") != string::npos, "Status contains total_datapoints"); - diag("Status response: %s", response.c_str()); + diag("Status response (first 200 chars): %s", response.substr(0, 200).c_str()); // 5. Test /api/tsdb/metrics diag("Testing GET /api/tsdb/metrics"); - rc = http_get((rest_url + "/api/tsdb/metrics").c_str(), response, "admin:admin"); - ok(rc == 200, "API /api/tsdb/metrics returns 200"); - ok(response.length() > 2, "Metrics list is not empty"); + response.clear(); + http_rc = http_get((rest_url + "/api/tsdb/metrics").c_str(), response, auth_creds.c_str()); + ok(http_rc == 200, "API /api/tsdb/metrics returns 200 (got %ld)", http_rc); + ok(response.length() > 2, "Metrics list is not empty (length: %zu)", response.length()); + diag("Metrics response (first 200 chars): %s", response.substr(0, 200).c_str()); // 6. Test /api/tsdb/query diag("Testing GET /api/tsdb/query for proxysql_uptime_seconds_total"); - rc = http_get((rest_url + "/api/tsdb/query?metric=proxysql_uptime_seconds_total").c_str(), response, "admin:admin"); - ok(rc == 200, "API /api/tsdb/query returns 200"); + response.clear(); + http_rc = http_get((rest_url + "/api/tsdb/query?metric=proxysql_uptime_seconds_total").c_str(), response, auth_creds.c_str()); + ok(http_rc == 200, "API /api/tsdb/query returns 200 (got %ld)", http_rc); ok(response.find("\"metric\":\"proxysql_uptime_seconds_total\"") != string::npos, "Query result contains metric name"); ok(response.find("\"value\":") != string::npos, "Query result contains data values"); - diag("Query response (first 100 chars): %s", response.substr(0, 100).c_str()); + diag("Query response (first 200 chars): %s", response.substr(0, 200).c_str()); mysql_close(admin); return exit_status(); diff --git a/test/tap/tests/test_tsdb_variables-t.cpp b/test/tap/tests/test_tsdb_variables-t.cpp index 1ceab9ff2..9845ddaf2 100644 --- a/test/tap/tests/test_tsdb_variables-t.cpp +++ b/test/tap/tests/test_tsdb_variables-t.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "mysql.h" @@ -193,15 +194,76 @@ int main() { ok(dp_ok && atoi(count.c_str()) > 0, "SHOW TSDB STATUS reports datapoints > 0 (found %s)", count.c_str()); // 12. Test Downsampling command + // NOTE: Downsampling only processes COMPLETED hours (data with timestamps before current_hour). + // Since we only have a few seconds of data, we need to insert test data with timestamps + // from at least 1 hour ago for the downsample to produce results. diag("Testing TSDB downsampling via command..."); + + // Get current timestamp and calculate timestamp from 2 hours ago + time_t now = time(NULL); + time_t two_hours_ago = ((now - 7200) / 3600) * 3600; // Start of the hour, 2 hours ago + diag("Current time: %ld, Two hours ago (hour boundary): %ld", now, two_hours_ago); + + // Insert test data with timestamps from 2 hours ago (completed hour) + diag("Inserting test metrics data with timestamps from completed hour..."); + char insert_query[512]; + snprintf(insert_query, sizeof(insert_query), + "INSERT OR REPLACE INTO stats_history.tsdb_metrics (timestamp, metric_name, labels, value) " + "VALUES (%ld, 'test_downsample_metric', '{\"test\":\"true\"}', 42.0)", + two_hours_ago); + rc = mysql_query(admin, insert_query); + if (rc != 0) { + diag("Failed to insert test data: %s", mysql_error(admin)); + } + drain_results(admin); + diag("Inserted test metric at timestamp %ld", two_hours_ago); + + // Also insert a few more data points in the same hour for realistic test + for (int i = 1; i <= 3; i++) { + snprintf(insert_query, sizeof(insert_query), + "INSERT OR REPLACE INTO stats_history.tsdb_metrics (timestamp, metric_name, labels, value) " + "VALUES (%ld, 'test_downsample_metric', '{\"test\":\"true\"}', %f)", + two_hours_ago + i * 60, 42.0 + i); // Add data points every minute + mysql_query(admin, insert_query); + drain_results(admin); + } + diag("Inserted 4 total test data points in the completed hour"); + + // Check metrics count before downsampling + string before_count; + fetch_single_string(admin, "SELECT COUNT(*) FROM stats_history.tsdb_metrics WHERE metric_name='test_downsample_metric'", before_count); + diag("Test metrics in tsdb_metrics before downsample: %s", before_count.c_str()); + + // Run the downsample command rc = mysql_query(admin, "PROXYSQL TSDB DOWNSAMPLE"); ok(rc == 0, "PROXYSQL TSDB DOWNSAMPLE command is supported"); drain_results(admin); - + + // Check hourly table after downsampling diag("Verifying downsampled data..."); string ds_count; bool ds_ok = fetch_single_string(admin, "SELECT COUNT(*) FROM stats_history.tsdb_metrics_hour", ds_count); - ok(ds_ok && atoi(ds_count.c_str()) > 0, "Downsample produced rows in tsdb_metrics_hour (count: %s)", ds_count.c_str()); + diag("Rows in tsdb_metrics_hour after downsample: %s", ds_count.c_str()); + + // Also check for our specific test metric + string test_metric_count; + bool test_metric_ok = fetch_single_string(admin, + "SELECT COUNT(*) FROM stats_history.tsdb_metrics_hour WHERE metric_name='test_downsample_metric'", + test_metric_count); + diag("Test metric rows in tsdb_metrics_hour: %s", test_metric_count.c_str()); + + ok( + ds_ok && test_metric_ok && atoi(test_metric_count.c_str()) > 0, + "Downsample produced rows for test_downsample_metric (metric rows: %s, total rows: %s)", + test_metric_count.c_str(), ds_count.c_str() + ); + + // Cleanup: remove test data + diag("Cleaning up test data..."); + mysql_query(admin, "DELETE FROM stats_history.tsdb_metrics WHERE metric_name='test_downsample_metric'"); + drain_results(admin); + mysql_query(admin, "DELETE FROM stats_history.tsdb_metrics_hour WHERE metric_name='test_downsample_metric'"); + drain_results(admin); mysql_close(admin); return exit_status();