Skip to content

Commit 9d13105

Browse files
committed
Added TAP test
1 parent 38befb8 commit 9d13105

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/**
2+
* @file pgsql-proxysql_cmd_test-t.cpp
3+
* @brief Test PAUSE/RESUME/STOP/START command sequences and validate backend connectivity changes.
4+
*/
5+
6+
#include <unistd.h>
7+
#include <string>
8+
#include <sstream>
9+
#include <chrono>
10+
#include <thread>
11+
#include "libpq-fe.h"
12+
#include "command_line.h"
13+
#include "tap.h"
14+
#include "utils.h"
15+
16+
CommandLine cl;
17+
18+
using PGConnPtr = std::unique_ptr<PGconn, decltype(&PQfinish)>;
19+
20+
enum ConnType {
21+
ADMIN,
22+
BACKEND
23+
};
24+
25+
PGConnPtr createNewConnection(ConnType conn_type, const std::string& options = "", bool with_ssl = false) {
26+
27+
const char* host = (conn_type == BACKEND) ? cl.pgsql_host : cl.pgsql_admin_host;
28+
int port = (conn_type == BACKEND) ? cl.pgsql_port : cl.pgsql_admin_port;
29+
const char* username = (conn_type == BACKEND) ? cl.pgsql_root_username : cl.admin_username;
30+
const char* password = (conn_type == BACKEND) ? cl.pgsql_root_password : cl.admin_password;
31+
32+
std::stringstream ss;
33+
34+
ss << "host=" << host << " port=" << port;
35+
ss << " user=" << username << " password=" << password;
36+
ss << (with_ssl ? " sslmode=require" : " sslmode=disable");
37+
38+
if (options.empty() == false) {
39+
ss << " options='" << options << "'";
40+
}
41+
42+
PGconn* conn = PQconnectdb(ss.str().c_str());
43+
if (PQstatus(conn) != CONNECTION_OK) {
44+
fprintf(stderr, "Connection failed to '%s': %s", (conn_type == BACKEND ? "Backend" : "Admin"), PQerrorMessage(conn));
45+
PQfinish(conn);
46+
return PGConnPtr(nullptr, &PQfinish);
47+
}
48+
return PGConnPtr(conn, &PQfinish);
49+
}
50+
51+
bool executeAdminCommand(PGConnPtr& conn, const std::string& command) {
52+
PGresult* res = PQexec(conn.get(), command.c_str());
53+
ConnStatusType status = PQstatus(conn.get());
54+
ExecStatusType result_status = PQresultStatus(res);
55+
56+
bool success = (result_status == PGRES_COMMAND_OK || result_status == PGRES_TUPLES_OK);
57+
58+
if (!success) {
59+
diag("Command failed: %s - %s", command.c_str(), PQerrorMessage(conn.get()));
60+
}
61+
62+
PQclear(res);
63+
return success;
64+
}
65+
66+
bool canConnectToBackend() {
67+
auto conn = createNewConnection(BACKEND);
68+
if (!conn || PQstatus(conn.get()) != CONNECTION_OK) {
69+
return false;
70+
}
71+
72+
// Test if we can execute a simple query
73+
PGresult* res = PQexec(conn.get(), "SELECT 1");
74+
bool query_ok = (PQresultStatus(res) == PGRES_TUPLES_OK);
75+
PQclear(res);
76+
77+
return query_ok;
78+
}
79+
80+
void waitForProxySQLState(int seconds) {
81+
diag("Waiting %d seconds for ProxySQL state change", seconds);
82+
sleep(seconds);
83+
}
84+
85+
void testPauseResumeSequence() {
86+
diag("Testing PROXYSQL PAUSE/RESUME sequence");
87+
88+
auto admin_conn = createNewConnection(ADMIN);
89+
if (!admin_conn) {
90+
ok(false, "Connect to ProxySQL admin");
91+
return;
92+
}
93+
94+
// First PAUSE should succeed
95+
bool result = executeAdminCommand(admin_conn, "PROXYSQL PAUSE");
96+
ok(result, "First PROXYSQL PAUSE command should succeed");
97+
98+
waitForProxySQLState(3);
99+
100+
// Second PAUSE should fail (already paused)
101+
result = executeAdminCommand(admin_conn, "PROXYSQL PAUSE");
102+
ok(!result, "Second PROXYSQL PAUSE should fail (already paused)");
103+
104+
// New connection should be rejected
105+
bool backend_connectable = canConnectToBackend();
106+
ok(!backend_connectable, "New connection should be rejected after PROXYSQL PAUSE");
107+
108+
// First RESUME should succeed
109+
result = executeAdminCommand(admin_conn, "PROXYSQL RESUME");
110+
ok(result, "First PROXYSQL RESUME command should succeed");
111+
112+
waitForProxySQLState(3);
113+
114+
// Second RESUME should fail (already running)
115+
result = executeAdminCommand(admin_conn, "PROXYSQL RESUME");
116+
ok(!result, "Second PROXYSQL RESUME should fail (already running)");
117+
118+
// New connection should succeed
119+
backend_connectable = canConnectToBackend();
120+
ok(backend_connectable, "New connection should succeed after PROXYSQL RESUME");
121+
}
122+
123+
void testStopStartSequence() {
124+
diag("Testing PROXYSQL STOP/START sequence");
125+
126+
auto admin_conn = createNewConnection(ADMIN);
127+
if (!admin_conn) {
128+
ok(false, "Connect to ProxySQL admin");
129+
return;
130+
}
131+
132+
// First STOP should succeed
133+
bool result = executeAdminCommand(admin_conn, "PROXYSQL STOP");
134+
ok(result, "First PROXYSQL STOP command should succeed");
135+
136+
waitForProxySQLState(5); // Give more time for stop
137+
138+
// Try to execute another command - should fail as ProxySQL is stopping/stopped
139+
result = executeAdminCommand(admin_conn, "SELECT 1");
140+
141+
// Note: The connection might be closed during STOP, so we need to handle this
142+
if (PQstatus(admin_conn.get()) != CONNECTION_OK) {
143+
diag("Admin connection closed as expected during PROXYSQL STOP");
144+
// Reconnect for the rest of the test
145+
admin_conn = createNewConnection(ADMIN);
146+
if (!admin_conn) {
147+
ok(false, "Reconnect after PROXYSQL STOP failed");
148+
return;
149+
}
150+
}
151+
152+
// Second STOP should fail (already stopping/stopped)
153+
result = executeAdminCommand(admin_conn, "PROXYSQL STOP");
154+
ok(!result, "Second PROXYSQL STOP should fail (already stopping/stopped)");
155+
156+
// New connection should be rejected
157+
bool backend_connectable = canConnectToBackend();
158+
ok(!backend_connectable, "New connection should be rejected after PROXYSQL STOP");
159+
160+
// First START should succeed
161+
result = executeAdminCommand(admin_conn, "PROXYSQL START");
162+
ok(result, "First PROXYSQL START command should succeed");
163+
164+
waitForProxySQLState(5); // Give more time for start
165+
166+
// Second START should fail (already starting/started)
167+
result = executeAdminCommand(admin_conn, "PROXYSQL START");
168+
ok(!result, "Second PROXYSQL START should fail (already starting/started)");
169+
170+
// New connection should succeed
171+
backend_connectable = canConnectToBackend();
172+
ok(backend_connectable, "New connection should succeed after PROXYSQL START");
173+
}
174+
175+
int main(int argc, char** argv) {
176+
plan(12);
177+
178+
if (cl.getEnv())
179+
return exit_status();
180+
181+
testPauseResumeSequence();
182+
testStopStartSequence();
183+
184+
return exit_status();
185+
}

0 commit comments

Comments
 (0)