Skip to content

Commit 7d047c6

Browse files
AndrewJackson2020CommanderKeynesAndrew Jackson
authored
Implemented python tests with pytest (#790)
Currently the python tests act as scripts. A lot of output is generated to stdout which makes it very hard to figure out where problems were. Also if you want to run only a single test you basically need to comment out code in order to accomplish this. This PR modifies the python tests to us the pytest python testing framework. This framework allows individual tests to be targeted via the command line, without touching the source code. It also suppressed stdout by default making the test output much easier to read. Also after the tests run it will provide a summary of what failed, what succeded, etc. Co-authored-by: CommanderKeynes <[email protected]> Co-authored-by: Andrew Jackson <[email protected]>
1 parent f73d15f commit 7d047c6

File tree

8 files changed

+125
-124
lines changed

8 files changed

+125
-124
lines changed

.circleci/run_tests.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ cd ../..
107107
# These tests will start and stop the pgcat server so it will need to be restarted after the tests
108108
#
109109
pip3 install -r tests/python/requirements.txt
110-
python3 tests/python/tests.py || exit 1
110+
pytest || exit 1
111111

112112

113113
#

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ lcov.info
1010
dev/.bash_history
1111
dev/cache
1212
!dev/cache/.keepme
13-
.venv
13+
.venv
14+
**/__pycache__

CONTRIBUTING.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Thank you for contributing! Just a few tips here:
77
3. Performance is important, make sure there are no regressions in your branch vs. `main`.
88

99
## How to run the integration tests locally and iterate on them
10-
We have integration tests written in Ruby, Python, Go and Rust.
10+
We have integration tests written in Ruby, Python, Go and Rust.
1111
Below are the steps to run them in a developer-friendly way that allows iterating and quick turnaround.
1212
Hear me out, this should be easy, it will involve opening a shell into a container with all the necessary dependancies available for you and you can modify the test code and immediately rerun your test in the interactive shell.
1313

@@ -21,7 +21,7 @@ Within this test environment you can modify the file in your favorite IDE and re
2121

2222
Once the environment is ready, you can run the tests by running
2323
Ruby: `cd /app/tests/ruby && bundle exec ruby <test_name>.rb --format documentation`
24-
Python: `cd /app && python3 tests/python/tests.py`
24+
Python: `cd /app/ && pytest`
2525
Rust: `cd /app/tests/rust && cargo run`
2626
Go: `cd /app/tests/go && /usr/local/go/bin/go test`
2727

start_test_env.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ docker compose exec --workdir /app/tests/python main pip3 install -r requirement
2323
echo "Interactive test environment ready"
2424
echo "To run integration tests, you can use the following commands:"
2525
echo -e " ${BLUE}Ruby: ${RED}cd /app/tests/ruby && bundle exec ruby tests.rb --format documentation${RESET}"
26-
echo -e " ${BLUE}Python: ${RED}cd /app && python3 tests/python/tests.py${RESET}"
26+
echo -e " ${BLUE}Python: ${RED}cd /app/ && pytest ${RESET}"
2727
echo -e " ${BLUE}Rust: ${RED}cd /app/tests/rust && cargo run ${RESET}"
2828
echo -e " ${BLUE}Go: ${RED}cd /app/tests/go && /usr/local/go/bin/go test${RESET}"
2929
echo "the source code for tests are directly linked to the source code in the container so you can modify the code and run the tests again"
30-
echo "You can rebuild PgCat from within the container by running"
30+
echo "You can rebuild PgCat from within the container by running"
3131
echo -e " ${GREEN}cargo build${RESET}"
3232
echo "and then run the tests again"
3333
echo "==================================="

tests/python/conftest.py

Whitespace-only changes.

tests/python/requirements.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
pytest
12
psycopg2==2.9.3
2-
psutil==5.9.1
3+
psutil==5.9.1
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,29 @@
1-
from typing import Tuple
2-
import psycopg2
3-
import psutil
41
import os
52
import signal
63
import time
74

8-
SHUTDOWN_TIMEOUT = 5
9-
10-
PGCAT_HOST = "127.0.0.1"
11-
PGCAT_PORT = "6432"
12-
13-
14-
def pgcat_start():
15-
pg_cat_send_signal(signal.SIGTERM)
16-
os.system("./target/debug/pgcat .circleci/pgcat.toml &")
17-
time.sleep(2)
18-
19-
20-
def pg_cat_send_signal(signal: signal.Signals):
21-
try:
22-
for proc in psutil.process_iter(["pid", "name"]):
23-
if "pgcat" == proc.name():
24-
os.kill(proc.pid, signal)
25-
except Exception as e:
26-
# The process can be gone when we send this signal
27-
print(e)
28-
29-
if signal == signal.SIGTERM:
30-
# Returns 0 if pgcat process exists
31-
time.sleep(2)
32-
if not os.system('pgrep pgcat'):
33-
raise Exception("pgcat not closed after SIGTERM")
34-
35-
36-
def connect_db(
37-
autocommit: bool = True,
38-
admin: bool = False,
39-
) -> Tuple[psycopg2.extensions.connection, psycopg2.extensions.cursor]:
40-
41-
if admin:
42-
user = "admin_user"
43-
password = "admin_pass"
44-
db = "pgcat"
45-
else:
46-
user = "sharding_user"
47-
password = "sharding_user"
48-
db = "sharded_db"
49-
50-
conn = psycopg2.connect(
51-
f"postgres://{user}:{password}@{PGCAT_HOST}:{PGCAT_PORT}/{db}?application_name=testing_pgcat",
52-
connect_timeout=2,
53-
)
54-
conn.autocommit = autocommit
55-
cur = conn.cursor()
56-
57-
return (conn, cur)
58-
5+
import psycopg2
596

60-
def cleanup_conn(conn: psycopg2.extensions.connection, cur: psycopg2.extensions.cursor):
61-
cur.close()
62-
conn.close()
7+
import utils
638

9+
SHUTDOWN_TIMEOUT = 5
6410

6511
def test_normal_db_access():
66-
pgcat_start()
67-
conn, cur = connect_db(autocommit=False)
12+
utils.pgcat_start()
13+
conn, cur = utils.connect_db(autocommit=False)
6814
cur.execute("SELECT 1")
6915
res = cur.fetchall()
7016
print(res)
71-
cleanup_conn(conn, cur)
17+
utils.cleanup_conn(conn, cur)
7218

7319

7420
def test_admin_db_access():
75-
conn, cur = connect_db(admin=True)
21+
conn, cur = utils.connect_db(admin=True)
7622

7723
cur.execute("SHOW POOLS")
7824
res = cur.fetchall()
7925
print(res)
80-
cleanup_conn(conn, cur)
26+
utils.cleanup_conn(conn, cur)
8127

8228

8329
def test_shutdown_logic():
@@ -86,17 +32,17 @@ def test_shutdown_logic():
8632
# NO ACTIVE QUERIES SIGINT HANDLING
8733

8834
# Start pgcat
89-
pgcat_start()
35+
utils.pgcat_start()
9036

9137
# Create client connection and send query (not in transaction)
92-
conn, cur = connect_db()
38+
conn, cur = utils.connect_db()
9339

9440
cur.execute("BEGIN;")
9541
cur.execute("SELECT 1;")
9642
cur.execute("COMMIT;")
9743

9844
# Send sigint to pgcat
99-
pg_cat_send_signal(signal.SIGINT)
45+
utils.pg_cat_send_signal(signal.SIGINT)
10046
time.sleep(1)
10147

10248
# Check that any new queries fail after sigint since server should close with no active transactions
@@ -108,18 +54,18 @@ def test_shutdown_logic():
10854
# Fail if query execution succeeded
10955
raise Exception("Server not closed after sigint")
11056

111-
cleanup_conn(conn, cur)
112-
pg_cat_send_signal(signal.SIGTERM)
57+
utils.cleanup_conn(conn, cur)
58+
utils.pg_cat_send_signal(signal.SIGTERM)
11359

11460
# - - - - - - - - - - - - - - - - - -
11561
# NO ACTIVE QUERIES ADMIN SHUTDOWN COMMAND
11662

11763
# Start pgcat
118-
pgcat_start()
64+
utils.pgcat_start()
11965

12066
# Create client connection and begin transaction
121-
conn, cur = connect_db()
122-
admin_conn, admin_cur = connect_db(admin=True)
67+
conn, cur = utils.connect_db()
68+
admin_conn, admin_cur = utils.connect_db(admin=True)
12369

12470
cur.execute("BEGIN;")
12571
cur.execute("SELECT 1;")
@@ -138,24 +84,24 @@ def test_shutdown_logic():
13884
# Fail if query execution succeeded
13985
raise Exception("Server not closed after sigint")
14086

141-
cleanup_conn(conn, cur)
142-
cleanup_conn(admin_conn, admin_cur)
143-
pg_cat_send_signal(signal.SIGTERM)
87+
utils.cleanup_conn(conn, cur)
88+
utils.cleanup_conn(admin_conn, admin_cur)
89+
utils.pg_cat_send_signal(signal.SIGTERM)
14490

14591
# - - - - - - - - - - - - - - - - - -
14692
# HANDLE TRANSACTION WITH SIGINT
14793

14894
# Start pgcat
149-
pgcat_start()
95+
utils.pgcat_start()
15096

15197
# Create client connection and begin transaction
152-
conn, cur = connect_db()
98+
conn, cur = utils.connect_db()
15399

154100
cur.execute("BEGIN;")
155101
cur.execute("SELECT 1;")
156102

157103
# Send sigint to pgcat while still in transaction
158-
pg_cat_send_signal(signal.SIGINT)
104+
utils.pg_cat_send_signal(signal.SIGINT)
159105
time.sleep(1)
160106

161107
# Check that any new queries succeed after sigint since server should still allow transaction to complete
@@ -165,18 +111,18 @@ def test_shutdown_logic():
165111
# Fail if query fails since server closed
166112
raise Exception("Server closed while in transaction", e.pgerror)
167113

168-
cleanup_conn(conn, cur)
169-
pg_cat_send_signal(signal.SIGTERM)
114+
utils.cleanup_conn(conn, cur)
115+
utils.pg_cat_send_signal(signal.SIGTERM)
170116

171117
# - - - - - - - - - - - - - - - - - -
172118
# HANDLE TRANSACTION WITH ADMIN SHUTDOWN COMMAND
173119

174120
# Start pgcat
175-
pgcat_start()
121+
utils.pgcat_start()
176122

177123
# Create client connection and begin transaction
178-
conn, cur = connect_db()
179-
admin_conn, admin_cur = connect_db(admin=True)
124+
conn, cur = utils.connect_db()
125+
admin_conn, admin_cur = utils.connect_db(admin=True)
180126

181127
cur.execute("BEGIN;")
182128
cur.execute("SELECT 1;")
@@ -194,30 +140,30 @@ def test_shutdown_logic():
194140
# Fail if query fails since server closed
195141
raise Exception("Server closed while in transaction", e.pgerror)
196142

197-
cleanup_conn(conn, cur)
198-
cleanup_conn(admin_conn, admin_cur)
199-
pg_cat_send_signal(signal.SIGTERM)
143+
utils.cleanup_conn(conn, cur)
144+
utils.cleanup_conn(admin_conn, admin_cur)
145+
utils.pg_cat_send_signal(signal.SIGTERM)
200146

201147
# - - - - - - - - - - - - - - - - - -
202148
# NO NEW NON-ADMIN CONNECTIONS DURING SHUTDOWN
203149
# Start pgcat
204-
pgcat_start()
150+
utils.pgcat_start()
205151

206152
# Create client connection and begin transaction
207-
transaction_conn, transaction_cur = connect_db()
153+
transaction_conn, transaction_cur = utils.connect_db()
208154

209155
transaction_cur.execute("BEGIN;")
210156
transaction_cur.execute("SELECT 1;")
211157

212158
# Send sigint to pgcat while still in transaction
213-
pg_cat_send_signal(signal.SIGINT)
159+
utils.pg_cat_send_signal(signal.SIGINT)
214160
time.sleep(1)
215161

216162
start = time.perf_counter()
217163
try:
218-
conn, cur = connect_db()
164+
conn, cur = utils.connect_db()
219165
cur.execute("SELECT 1;")
220-
cleanup_conn(conn, cur)
166+
utils.cleanup_conn(conn, cur)
221167
except psycopg2.OperationalError as e:
222168
time_taken = time.perf_counter() - start
223169
if time_taken > 0.1:
@@ -227,74 +173,74 @@ def test_shutdown_logic():
227173
else:
228174
raise Exception("Able connect to database during shutdown")
229175

230-
cleanup_conn(transaction_conn, transaction_cur)
231-
pg_cat_send_signal(signal.SIGTERM)
176+
utils.cleanup_conn(transaction_conn, transaction_cur)
177+
utils.pg_cat_send_signal(signal.SIGTERM)
232178

233179
# - - - - - - - - - - - - - - - - - -
234180
# ALLOW NEW ADMIN CONNECTIONS DURING SHUTDOWN
235181
# Start pgcat
236-
pgcat_start()
182+
utils.pgcat_start()
237183

238184
# Create client connection and begin transaction
239-
transaction_conn, transaction_cur = connect_db()
185+
transaction_conn, transaction_cur = utils.connect_db()
240186

241187
transaction_cur.execute("BEGIN;")
242188
transaction_cur.execute("SELECT 1;")
243189

244190
# Send sigint to pgcat while still in transaction
245-
pg_cat_send_signal(signal.SIGINT)
191+
utils.pg_cat_send_signal(signal.SIGINT)
246192
time.sleep(1)
247193

248194
try:
249-
conn, cur = connect_db(admin=True)
195+
conn, cur = utils.connect_db(admin=True)
250196
cur.execute("SHOW DATABASES;")
251-
cleanup_conn(conn, cur)
197+
utils.cleanup_conn(conn, cur)
252198
except psycopg2.OperationalError as e:
253199
raise Exception(e)
254200

255-
cleanup_conn(transaction_conn, transaction_cur)
256-
pg_cat_send_signal(signal.SIGTERM)
201+
utils.cleanup_conn(transaction_conn, transaction_cur)
202+
utils.pg_cat_send_signal(signal.SIGTERM)
257203

258204
# - - - - - - - - - - - - - - - - - -
259205
# ADMIN CONNECTIONS CONTINUING TO WORK AFTER SHUTDOWN
260206
# Start pgcat
261-
pgcat_start()
207+
utils.pgcat_start()
262208

263209
# Create client connection and begin transaction
264-
transaction_conn, transaction_cur = connect_db()
210+
transaction_conn, transaction_cur = utils.connect_db()
265211
transaction_cur.execute("BEGIN;")
266212
transaction_cur.execute("SELECT 1;")
267213

268-
admin_conn, admin_cur = connect_db(admin=True)
214+
admin_conn, admin_cur = utils.connect_db(admin=True)
269215
admin_cur.execute("SHOW DATABASES;")
270216

271217
# Send sigint to pgcat while still in transaction
272-
pg_cat_send_signal(signal.SIGINT)
218+
utils.pg_cat_send_signal(signal.SIGINT)
273219
time.sleep(1)
274220

275221
try:
276222
admin_cur.execute("SHOW DATABASES;")
277223
except psycopg2.OperationalError as e:
278224
raise Exception("Could not execute admin command:", e)
279225

280-
cleanup_conn(transaction_conn, transaction_cur)
281-
cleanup_conn(admin_conn, admin_cur)
282-
pg_cat_send_signal(signal.SIGTERM)
226+
utils.cleanup_conn(transaction_conn, transaction_cur)
227+
utils.cleanup_conn(admin_conn, admin_cur)
228+
utils.pg_cat_send_signal(signal.SIGTERM)
283229

284230
# - - - - - - - - - - - - - - - - - -
285231
# HANDLE SHUTDOWN TIMEOUT WITH SIGINT
286232

287233
# Start pgcat
288-
pgcat_start()
234+
utils.pgcat_start()
289235

290236
# Create client connection and begin transaction, which should prevent server shutdown unless shutdown timeout is reached
291-
conn, cur = connect_db()
237+
conn, cur = utils.connect_db()
292238

293239
cur.execute("BEGIN;")
294240
cur.execute("SELECT 1;")
295241

296242
# Send sigint to pgcat while still in transaction
297-
pg_cat_send_signal(signal.SIGINT)
243+
utils.pg_cat_send_signal(signal.SIGINT)
298244

299245
# pgcat shutdown timeout is set to SHUTDOWN_TIMEOUT seconds, so we sleep for SHUTDOWN_TIMEOUT + 1 seconds
300246
time.sleep(SHUTDOWN_TIMEOUT + 1)
@@ -308,12 +254,5 @@ def test_shutdown_logic():
308254
# Fail if query execution succeeded
309255
raise Exception("Server not closed after sigint and expected timeout")
310256

311-
cleanup_conn(conn, cur)
312-
pg_cat_send_signal(signal.SIGTERM)
313-
314-
# - - - - - - - - - - - - - - - - - -
315-
316-
317-
test_normal_db_access()
318-
test_admin_db_access()
319-
test_shutdown_logic()
257+
utils.cleanup_conn(conn, cur)
258+
utils.pg_cat_send_signal(signal.SIGTERM)

0 commit comments

Comments
 (0)