Skip to content

Commit 9160d2c

Browse files
committed
Add comprehensive PROXYSQL STOP/START dependency testing for issue #5218
Implements shared test framework to verify dependencies between: - PR #5217: PROXYSQL STOP/START crash fixes - PR #4960: MySQL/PostgreSQL module enable/disable functionality Key changes: - Create shared header test_proxysql_stop_query_handling.hpp with centralized test count constant - Refactor original test to use shared header (simpler wrapper) - Extend reg_test_4960_modules_startup-t.cpp: 8 MySQL admin cases get STOP/START testing - Extend reg_test_4960_monitor_modules-t.cpp: all 4 monitor cases get STOP/START testing - Add PROXYSQL_STOP_START_TEST_COUNT constant for maintainability Test coverage now validates STOP/START behavior across 12 different module configurations, addressing the core dependency concerns from issue #5218.
1 parent ee61753 commit 9160d2c

File tree

4 files changed

+279
-150
lines changed

4 files changed

+279
-150
lines changed

test/tap/tests/reg_test_4960_modules_startup-t.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "tap.h"
2626
#include "command_line.h"
2727
#include "utils.h"
28+
#include "test_proxysql_stop_query_handling.hpp"
2829

2930
using std::string;
3031
using std::vector;
@@ -295,6 +296,27 @@ int run_test_case(const TestCase& test_case, const CommandLine& cl) {
295296
}
296297
}
297298

299+
// Run PROXYSQL STOP/START tests if MySQL admin is enabled and all checks passed so far
300+
if (test_case.mysql_admin_expected && result == EXIT_SUCCESS) {
301+
diag(" Running PROXYSQL STOP/START tests for MySQL admin interface...");
302+
303+
// Configure STOP/START test with current test case name for better diagnostics
304+
ProxySQLStopStartTestConfig stop_start_config;
305+
stop_start_config.test_name_prefix = test_case.name + "_mysql_admin";
306+
stop_start_config.verbose_logging = true; // Enable detailed logging for debugging
307+
308+
int stop_start_result = test_proxysql_stop_start_with_connection(
309+
"127.0.0.1", "admin", "admin", test_case.mysql_admin_port, stop_start_config);
310+
311+
if (stop_start_result == -1) {
312+
diag(" ❌ PROXYSQL STOP/START tests failed for test case: %s", test_case.name.c_str());
313+
result = EXIT_FAILURE;
314+
} else {
315+
diag(" ✅ PROXYSQL STOP/START tests passed for test case: %s", test_case.name.c_str());
316+
// Note: The STOP/START tests already perform their own ok() calls internally
317+
}
318+
}
319+
298320
// Force kill any remaining ProxySQL processes to ensure cleanup
299321
diag(" Force killing any remaining ProxySQL processes...");
300322
string kill_cmd = "pkill -f \"proxysql.*" + string { cl.workdir } + "reg_test_4960_node_" + test_case.name + "\" 2>/dev/null || true";
@@ -703,7 +725,18 @@ int main(int argc, char** argv) {
703725
}
704726
};
705727

706-
plan(test_cases.size());
728+
// Count test cases with MySQL admin enabled for STOP/START tests
729+
int mysql_admin_tests = 0;
730+
for (const auto& test_case : test_cases) {
731+
if (test_case.mysql_admin_expected) {
732+
mysql_admin_tests++;
733+
}
734+
}
735+
736+
// Base tests + STOP/START tests (PROXYSQL_STOP_START_TEST_COUNT tests per MySQL admin case)
737+
plan(static_cast<int>(test_cases.size()) + (mysql_admin_tests * PROXYSQL_STOP_START_TEST_COUNT));
738+
diag("Running %d module startup tests + %d STOP/START tests (%d each for %d MySQL admin cases)",
739+
static_cast<int>(test_cases.size()), mysql_admin_tests * PROXYSQL_STOP_START_TEST_COUNT, PROXYSQL_STOP_START_TEST_COUNT, mysql_admin_tests);
707740

708741
// Run all test cases
709742
for (const auto& test_case : test_cases) {

test/tap/tests/reg_test_4960_monitor_modules-t.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "tap.h"
2525
#include "command_line.h"
2626
#include "utils.h"
27+
#include "test_proxysql_stop_query_handling.hpp"
2728

2829
using std::string;
2930
using std::vector;
@@ -206,6 +207,27 @@ int run_monitor_test_case(const MonitorTestCase& test_case, const CommandLine& c
206207
}
207208

208209
mysql_close(mysql);
210+
211+
// Run PROXYSQL STOP/START tests since we have MySQL admin interface and all checks passed
212+
if (result == EXIT_SUCCESS) {
213+
diag(" Running PROXYSQL STOP/START tests for monitor test case...");
214+
215+
// Configure STOP/START test with current test case name for better diagnostics
216+
ProxySQLStopStartTestConfig stop_start_config;
217+
stop_start_config.test_name_prefix = test_case.name + "_monitor";
218+
stop_start_config.verbose_logging = true; // Enable detailed logging for debugging
219+
220+
int stop_start_result = test_proxysql_stop_start_with_connection(
221+
"127.0.0.1", "admin", "admin", test_case.mysql_admin_port, stop_start_config);
222+
223+
if (stop_start_result == -1) {
224+
diag(" ❌ PROXYSQL STOP/START tests failed for monitor test case: %s", test_case.name.c_str());
225+
result = EXIT_FAILURE;
226+
} else {
227+
diag(" ✅ PROXYSQL STOP/START tests passed for monitor test case: %s", test_case.name.c_str());
228+
// Note: The STOP/START tests already perform their own ok() calls internally
229+
}
230+
}
209231
}
210232

211233
// Force cleanup
@@ -307,7 +329,11 @@ int main(int argc, char** argv) {
307329
}
308330
};
309331

310-
plan(test_cases.size());
332+
// All monitor tests use MySQL admin interface, so all get STOP/START tests
333+
// Base tests + STOP/START tests (PROXYSQL_STOP_START_TEST_COUNT tests each)
334+
plan(static_cast<int>(test_cases.size()) + (static_cast<int>(test_cases.size()) * PROXYSQL_STOP_START_TEST_COUNT));
335+
diag("Running %d monitor tests + %d STOP/START tests (%d each for %d test cases)",
336+
static_cast<int>(test_cases.size()), static_cast<int>(test_cases.size()) * PROXYSQL_STOP_START_TEST_COUNT, PROXYSQL_STOP_START_TEST_COUNT, static_cast<int>(test_cases.size()));
311337

312338
// Run all monitor test cases
313339
for (const auto& test_case : test_cases) {

test/tap/tests/test_proxysql_stop_query_handling-t.cpp

Lines changed: 10 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,11 @@
22
* @file test_proxysql_stop_query_handling-t.cpp
33
* @brief This test verifies PROXYSQL STOP query handling fix for issue 5186.
44
* Tests that admin queries are properly handled during STOP state.
5-
* @date 2025-01-18
5+
* This is a wrapper around the shared test functions.
6+
* @date 2025-11-23
67
*/
78

8-
#include <algorithm>
9-
#include <string>
10-
#include <stdio.h>
11-
#include <unistd.h>
12-
#include <vector>
13-
14-
#include "mysql.h"
15-
#include "mysqld_error.h"
16-
17-
#include "tap.h"
18-
#include "command_line.h"
19-
#include "utils.h"
20-
21-
using std::string;
22-
23-
// Helper function to execute query and check if it succeeds
24-
bool execute_query_succeeds(MYSQL* mysql, const string& query) {
25-
if (mysql_query(mysql, query.c_str()) == 0) {
26-
mysql_free_result(mysql_store_result(mysql));
27-
return true;
28-
}
29-
return false;
30-
}
31-
32-
// Helper function to execute query and check if it fails as expected
33-
bool execute_query_fails(MYSQL* mysql, const string& query, const string& expected_error_substring = "") {
34-
int rc = mysql_query(mysql, query.c_str());
35-
if (rc != 0) {
36-
string error = mysql_error(mysql);
37-
if (expected_error_substring.empty() || error.find(expected_error_substring) != string::npos) {
38-
return true; // Failed as expected
39-
}
40-
}
41-
return false; // Should have failed but didn't
42-
}
43-
44-
// Helper function to get row count from a query
45-
int get_row_count(MYSQL* mysql, const string& query) {
46-
if (mysql_query(mysql, query.c_str()) == 0) {
47-
MYSQL_RES* result = mysql_store_result(mysql);
48-
if (result) {
49-
int count = mysql_num_rows(result);
50-
mysql_free_result(result);
51-
return count;
52-
}
53-
}
54-
return -1;
55-
}
9+
#include "test_proxysql_stop_query_handling.hpp"
5610

5711
int main(int argc, char** argv) {
5812
CommandLine cl;
@@ -62,108 +16,16 @@ int main(int argc, char** argv) {
6216
return -1;
6317
}
6418

65-
// We expect 13 test cases:
66-
// 1. Test STOP command succeeds
67-
// 2-5. Test queries that work with null pointer protection during STOP state (4 queries)
68-
// 6. Test LOAD MYSQL USERS TO RUNTIME succeeds (MySQL Auth module is loaded)
69-
// 7. Test LOAD MYSQL QUERY RULES TO RUNTIME fails (Query Processor not started)
70-
// 8-11. Test queries that should succeed during STOP state (4 queries)
71-
// 12. Test START command succeeds
72-
// 13. Test that queries continue to work after START
73-
plan(13);
74-
75-
MYSQL* proxysql_admin = mysql_init(NULL);
76-
if (!proxysql_admin) {
77-
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
78-
return -1;
79-
}
80-
81-
// Connect to local ProxySQL admin interface
82-
if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
83-
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
84-
return -1;
85-
}
19+
// We expect PROXYSQL_STOP_START_TEST_COUNT test cases from the shared test function
20+
plan(PROXYSQL_STOP_START_TEST_COUNT);
8621

87-
// === TEST 1: Execute PROXYSQL STOP ===
88-
bool stop_success = execute_query_succeeds(proxysql_admin, "PROXYSQL STOP");
89-
ok(stop_success, "PROXYSQL STOP command should succeed");
22+
int result = test_proxysql_stop_start_with_connection(cl.host, cl.admin_username,
23+
cl.admin_password, cl.admin_port);
9024

91-
if (!stop_success) {
92-
diag("PROXYSQL STOP failed, cannot continue with remaining tests");
93-
mysql_close(proxysql_admin);
25+
if (result == -1) {
26+
diag("Failed to connect to ProxySQL admin or critical test failure");
9427
return exit_status();
9528
}
9629

97-
// Give some time for STOP to complete
98-
sleep(2);
99-
100-
// === TESTS 2-5: Test queries that work with null pointer protection during STOP state ===
101-
102-
// TEST 2: runtime_mysql_query_rules should work normally with null pointer protection
103-
int row_count = get_row_count(proxysql_admin, "SELECT COUNT(*) FROM runtime_mysql_query_rules");
104-
ok(row_count >= 0, "runtime_mysql_query_rules should return valid count during STOP state, actual: %d", row_count);
105-
106-
// TEST 3: runtime_mysql_query_rules_fast_routing should work normally with null pointer protection
107-
row_count = get_row_count(proxysql_admin, "SELECT COUNT(*) FROM runtime_mysql_query_rules_fast_routing");
108-
ok(row_count >= 0, "runtime_mysql_query_rules_fast_routing should return valid count during STOP state, actual: %d", row_count);
109-
110-
// TEST 4: runtime_mysql_users should work normally with null pointer protection
111-
row_count = get_row_count(proxysql_admin, "SELECT COUNT(*) FROM runtime_mysql_users");
112-
ok(row_count >= 0, "runtime_mysql_users should return valid count during STOP state, actual: %d", row_count);
113-
114-
// TEST 5: stats_mysql_query_digest should work normally with null pointer protection
115-
row_count = get_row_count(proxysql_admin, "SELECT COUNT(*) FROM stats_mysql_query_digest");
116-
ok(row_count >= 0, "stats_mysql_query_digest should return valid count during STOP state, actual: %d", row_count);
117-
118-
// === TEST 6: Test modification queries during STOP state ===
119-
120-
// TEST 6: LOAD MYSQL USERS TO RUNTIME should succeed (MySQL Auth module is loaded)
121-
bool load_users_success = execute_query_succeeds(proxysql_admin, "LOAD MYSQL USERS TO RUNTIME");
122-
ok(load_users_success, "LOAD MYSQL USERS TO RUNTIME should succeed during STOP state");
123-
124-
// TEST 7: LOAD MYSQL QUERY RULES TO RUNTIME should fail (Query Processor not started)
125-
bool load_rules_fails = execute_query_fails(proxysql_admin, "LOAD MYSQL QUERY RULES TO RUNTIME", "Global Query Processor not started");
126-
ok(load_rules_fails, "LOAD MYSQL QUERY RULES TO RUNTIME should fail during STOP state");
127-
128-
// === TESTS 8-11: Test queries that should SUCCEED during STOP state ===
129-
130-
// TEST 8: Basic arithmetic query should work
131-
bool basic_query_success = execute_query_succeeds(proxysql_admin, "SELECT 1+1");
132-
ok(basic_query_success, "Basic arithmetic query (SELECT 1+1) should work during STOP state");
133-
134-
// TEST 9: Version query should work
135-
bool version_success = execute_query_succeeds(proxysql_admin, "SELECT @@version");
136-
ok(version_success, "Version query should work during STOP state");
137-
138-
// TEST 10: SHOW PROMETHEUS METRICS should work (existing functionality)
139-
bool prometheus_success = execute_query_succeeds(proxysql_admin, "SHOW PROMETHEUS METRICS");
140-
ok(prometheus_success, "SHOW PROMETHEUS METRICS should work during STOP state");
141-
142-
// TEST 11: Basic SELECT should work
143-
bool db_select_success = execute_query_succeeds(proxysql_admin, "SELECT DATABASE()");
144-
bool user_select_success = execute_query_succeeds(proxysql_admin, "SELECT USER()");
145-
ok(db_select_success && user_select_success, "Basic SELECT (DATABASE() and USER()) should work during STOP state");
146-
147-
// === TEST 12: Execute PROXYSQL START ===
148-
bool start_success = execute_query_succeeds(proxysql_admin, "PROXYSQL START");
149-
ok(start_success, "PROXYSQL START command should succeed");
150-
151-
if (!start_success) {
152-
diag("PROXYSQL START failed, cannot continue with final test");
153-
mysql_close(proxysql_admin);
154-
return exit_status();
155-
}
156-
157-
// Give some time for START to complete
158-
sleep(3);
159-
160-
// === TEST 13: Test that queries continue to work after START ===
161-
162-
// After START, runtime queries should continue to work normally
163-
row_count = get_row_count(proxysql_admin, "SELECT COUNT(*) FROM runtime_mysql_query_rules");
164-
ok(row_count >= 0, "runtime_mysql_query_rules should continue to work after START, rows: %d", row_count);
165-
166-
mysql_close(proxysql_admin);
167-
16830
return exit_status();
169-
}
31+
}

0 commit comments

Comments
 (0)