mirror of https://github.com/sysown/proxysql
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
9.2 KiB
271 lines
9.2 KiB
#include <map>
|
|
#include <string>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <unistd.h>
|
|
|
|
#include "mysql.h"
|
|
|
|
#include "tap.h"
|
|
#include "command_line.h"
|
|
#include "utils.h"
|
|
|
|
using std::map;
|
|
using std::string;
|
|
|
|
static void drain_results(MYSQL* mysql) {
|
|
MYSQL_RES* res;
|
|
while (1) {
|
|
res = mysql_store_result(mysql);
|
|
if (res) mysql_free_result(res);
|
|
if (mysql_next_result(mysql) != 0) break;
|
|
}
|
|
}
|
|
|
|
static bool fetch_single_string(MYSQL* mysql, const string& query, string& out) {
|
|
if (mysql_query(mysql, query.c_str())) {
|
|
diag("Query failed: %s (Error: %s)", query.c_str(), mysql_error(mysql));
|
|
return false;
|
|
}
|
|
MYSQL_RES* res = mysql_store_result(mysql);
|
|
if (!res) {
|
|
diag("No result set for query: %s", query.c_str());
|
|
drain_results(mysql);
|
|
return false;
|
|
}
|
|
MYSQL_ROW row = mysql_fetch_row(res);
|
|
if (!row || !row[0]) {
|
|
mysql_free_result(res);
|
|
drain_results(mysql);
|
|
return false;
|
|
}
|
|
out = row[0];
|
|
mysql_free_result(res);
|
|
drain_results(mysql);
|
|
return true;
|
|
}
|
|
|
|
int main() {
|
|
CommandLine cl;
|
|
if (cl.getEnv()) {
|
|
diag("Failed to get the required environmental variables.");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
plan(19);
|
|
|
|
MYSQL* admin = mysql_init(NULL);
|
|
if (!admin) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
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));
|
|
mysql_close(admin);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
int rc;
|
|
drain_results(admin);
|
|
|
|
// 1. Test SET and validation
|
|
diag("Running command: SET tsdb-enabled='1'");
|
|
rc = mysql_query(admin, "SET tsdb-enabled='1'");
|
|
ok(rc == 0, "SET tsdb-enabled works");
|
|
drain_results(admin);
|
|
|
|
diag("Running command: SET tsdb-sample_interval='1'");
|
|
rc = mysql_query(admin, "SET tsdb-sample_interval='1'");
|
|
ok(rc == 0, "SET tsdb-sample_interval works");
|
|
drain_results(admin);
|
|
|
|
diag("Running command: SET tsdb-monitor_enabled='1'");
|
|
rc = mysql_query(admin, "SET tsdb-monitor_enabled='1'");
|
|
ok(rc == 0, "SET tsdb-monitor_enabled works");
|
|
drain_results(admin);
|
|
|
|
diag("Running command: SET tsdb-monitor_interval='1'");
|
|
rc = mysql_query(admin, "SET tsdb-monitor_interval='1'");
|
|
ok(rc == 0, "SET tsdb-monitor_interval works");
|
|
drain_results(admin);
|
|
|
|
// 2. Test LOAD TSDB VARIABLES
|
|
diag("Running command: LOAD TSDB VARIABLES TO RUNTIME");
|
|
rc = mysql_query(admin, "LOAD TSDB VARIABLES TO RUNTIME");
|
|
ok(rc == 0, "`LOAD TSDB VARIABLES TO RUNTIME` is supported");
|
|
drain_results(admin);
|
|
|
|
// 3. Test SHOW TSDB VARIABLES
|
|
diag("Running command: SHOW TSDB VARIABLES");
|
|
rc = mysql_query(admin, "SHOW TSDB VARIABLES");
|
|
ok(rc == 0, "SHOW TSDB VARIABLES is supported");
|
|
MYSQL_RES* res = mysql_store_result(admin);
|
|
if (res) {
|
|
int rows = mysql_num_rows(res);
|
|
ok(rows == 5, "SHOW TSDB VARIABLES returns 5 rows (found %d)", rows);
|
|
mysql_free_result(res);
|
|
} else {
|
|
ok(0, "SHOW TSDB VARIABLES returned no result set");
|
|
}
|
|
drain_results(admin);
|
|
|
|
// 4. Test Runtime values (Virtual table refresh)
|
|
diag("Verifying runtime_global_variables for tsdb- prefix");
|
|
string count;
|
|
bool count_ok = fetch_single_string(
|
|
admin,
|
|
"SELECT COUNT(*) FROM runtime_global_variables WHERE variable_name LIKE 'tsdb-%'",
|
|
count
|
|
);
|
|
ok(count_ok && count == "5", "Five tsdb-* runtime variables are present (found %s)", count.c_str());
|
|
|
|
// 5. Test SAVE TSDB VARIABLES
|
|
diag("Running command: SAVE TSDB VARIABLES TO DISK");
|
|
rc = mysql_query(admin, "SAVE TSDB VARIABLES TO DISK");
|
|
ok(rc == 0, "`SAVE TSDB VARIABLES TO DISK` is supported");
|
|
drain_results(admin);
|
|
|
|
diag("Verifying global_variables on disk");
|
|
string disk_enabled;
|
|
bool disk_ok = fetch_single_string(
|
|
admin,
|
|
"SELECT variable_value FROM disk.global_variables WHERE variable_name='tsdb-enabled'",
|
|
disk_enabled
|
|
);
|
|
ok(disk_ok && disk_enabled == "1", "TSDB variable is persisted to disk (value: %s)", disk_enabled.c_str());
|
|
|
|
// 6. Test SHOW TSDB STATUS (triggers refresh)
|
|
diag("Running command: SHOW TSDB STATUS");
|
|
rc = mysql_query(admin, "SHOW TSDB STATUS");
|
|
ok(rc == 0, "SHOW TSDB STATUS is supported");
|
|
res = mysql_store_result(admin);
|
|
if (res) {
|
|
int rows = mysql_num_rows(res);
|
|
ok(rows >= 5, "SHOW TSDB STATUS returns at least 5 rows (found %d)", rows);
|
|
mysql_free_result(res);
|
|
} else {
|
|
ok(0, "SHOW TSDB STATUS returned no result set");
|
|
}
|
|
drain_results(admin);
|
|
|
|
// 7. Verify table schemas
|
|
diag("Verifying tsdb_metrics table in stats_history");
|
|
string table_name;
|
|
bool table_exists = fetch_single_string(
|
|
admin,
|
|
"SELECT name FROM stats_history.sqlite_master WHERE type='table' AND name='tsdb_metrics'",
|
|
table_name
|
|
);
|
|
ok(
|
|
table_exists,
|
|
"tsdb_metrics table exists in stats_history"
|
|
);
|
|
|
|
// 8. Wait for background loops to collect some data
|
|
diag("Waiting for TSDB background loops (sampler and monitor) to collect data...");
|
|
sleep(4);
|
|
|
|
// 9. Verify data collection in tsdb_metrics
|
|
diag("Checking if metrics were collected in stats_history.tsdb_metrics");
|
|
string metric_count;
|
|
bool metrics_collected = fetch_single_string(
|
|
admin,
|
|
"SELECT COUNT(*) FROM stats_history.tsdb_metrics",
|
|
metric_count
|
|
);
|
|
ok(metrics_collected && atoi(metric_count.c_str()) > 0, "Metrics are being collected in tsdb_metrics (count: %s)", metric_count.c_str());
|
|
|
|
// 10. Verify data collection in tsdb_backend_health
|
|
diag("Checking if tsdb_backend_health is accessible in stats_history");
|
|
string health_count;
|
|
bool health_accessible = fetch_single_string(
|
|
admin,
|
|
"SELECT COUNT(*) FROM stats_history.tsdb_backend_health",
|
|
health_count
|
|
);
|
|
ok(health_accessible, "tsdb_backend_health table is accessible");
|
|
|
|
// 11. Test SHOW TSDB STATUS again to see updated values
|
|
diag("Checking updated stats in SHOW TSDB STATUS");
|
|
rc = mysql_query(admin, "SHOW TSDB STATUS");
|
|
ok(rc == 0, "Second SHOW TSDB STATUS call successful");
|
|
drain_results(admin);
|
|
|
|
bool dp_ok = fetch_single_string(admin, "SELECT Variable_Value FROM stats_tsdb WHERE Variable_Name='Total_Datapoints'", count);
|
|
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);
|
|
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();
|
|
}
|