-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_basic.py
More file actions
325 lines (259 loc) · 10.6 KB
/
Copy pathtest_basic.py
File metadata and controls
325 lines (259 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
"""
Basic tests for pgsql-test framework.
These tests verify the core functionality of the testing framework itself.
"""
import pytest
from pgsql_test import get_connections, seed
from pgsql_test.admin import DbAdmin
from pgsql_test.manager import generate_test_db_name
class TestGetConnections:
"""Tests for the get_connections() function."""
def test_creates_isolated_database(self, pg_config):
"""Test that get_connections creates a new isolated database."""
conn = get_connections(pg_config)
try:
# Verify we got a connection
assert conn.pg is not None
assert conn.db is not None
assert conn.admin is not None
assert conn.manager is not None
# Verify the database name is unique (contains UUID)
db_name = conn.pg.config.get("database", "")
assert db_name.startswith("pgsql_test_")
assert len(db_name) > len("pgsql_test_")
finally:
conn.teardown()
def test_database_is_functional(self, pg_config):
"""Test that the created database can execute queries."""
conn = get_connections(pg_config)
try:
result = conn.db.query("SELECT 1 as value")
assert len(result.rows) == 1
assert result.rows[0]["value"] == 1
finally:
conn.teardown()
def test_teardown_drops_database(self, pg_config):
"""Test that teardown drops the test database."""
conn = get_connections(pg_config)
db_name = conn.pg.config.get("database")
# Verify database exists
admin = DbAdmin(pg_config)
assert admin.database_exists(db_name)
admin.close()
# Teardown
conn.teardown()
# Verify database is dropped
admin = DbAdmin(pg_config)
assert not admin.database_exists(db_name)
admin.close()
class TestPgTestClient:
"""Tests for the PgTestClient class."""
def test_query_returns_results(self, db_connection):
"""Test that query() returns proper results."""
result = db_connection.db.query("SELECT 1 as num, 'hello' as greeting")
assert len(result.rows) == 1
assert result.rows[0]["num"] == 1
assert result.rows[0]["greeting"] == "hello"
def test_query_with_params(self, db_connection):
"""Test that query() handles parameters correctly."""
result = db_connection.db.query(
"SELECT %s as value, %s as name",
(42, "test"),
)
assert result.rows[0]["value"] == 42
assert result.rows[0]["name"] == "test"
def test_one_returns_single_row(self, db_connection):
"""Test that one() returns exactly one row."""
row = db_connection.db.one("SELECT 1 as value")
assert row["value"] == 1
def test_one_raises_on_no_rows(self, db_connection):
"""Test that one() raises when no rows returned."""
db_connection.db.query("CREATE TEMP TABLE empty_table (id INT)")
with pytest.raises(ValueError, match="no rows"):
db_connection.db.one("SELECT * FROM empty_table")
def test_one_or_none_returns_none(self, db_connection):
"""Test that one_or_none() returns None when no rows."""
db_connection.db.query("CREATE TEMP TABLE empty_table (id INT)")
result = db_connection.db.one_or_none("SELECT * FROM empty_table")
assert result is None
def test_many_returns_multiple_rows(self, db_connection):
"""Test that many() returns multiple rows."""
rows = db_connection.db.many(
"SELECT generate_series(1, 3) as num"
)
assert len(rows) == 3
assert [r["num"] for r in rows] == [1, 2, 3]
def test_execute_returns_row_count(self, db_connection):
"""Test that execute() returns affected row count."""
db_connection.db.query("CREATE TEMP TABLE test_exec (id INT)")
count = db_connection.db.execute(
"INSERT INTO test_exec VALUES (1), (2), (3)"
)
assert count == 3
def test_transaction_rollback(self, db_connection):
"""Test that before_each/after_each provides transaction isolation."""
db = db_connection.db
# Create a table
db.query("CREATE TABLE rollback_test (id INT)")
db.connection.commit()
# Start test isolation
db.before_each()
# Insert data
db.execute("INSERT INTO rollback_test VALUES (1), (2)")
result = db.query("SELECT COUNT(*) as count FROM rollback_test")
assert result.rows[0]["count"] == 2
# Rollback
db.after_each()
# Verify data is gone
result = db.query("SELECT COUNT(*) as count FROM rollback_test")
assert result.rows[0]["count"] == 0
def test_set_context(self, db_connection):
"""Test that set_context() sets session variables."""
db = db_connection.db
db.begin()
db.set_context({"app.user_id": "123"})
result = db.one("SELECT current_setting('app.user_id') as user_id")
assert result["user_id"] == "123"
db.rollback()
class TestSqlFileSeeding:
"""Tests for SQL file seeding."""
def test_sqlfile_loads_schema(self, pg_config, sql_dir):
"""Test that sqlfile adapter loads SQL files."""
schema_file = sql_dir / "schema.sql"
conn = get_connections(
pg_config,
seed_adapters=[seed.sqlfile([schema_file])],
)
try:
# Verify tables were created
result = conn.db.query(
"""
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name IN ('users', 'posts')
ORDER BY table_name
"""
)
tables = [r["table_name"] for r in result.rows]
assert "posts" in tables
assert "users" in tables
# Verify data was inserted
users = conn.db.many("SELECT * FROM users ORDER BY id")
assert len(users) == 2
assert users[0]["name"] == "Alice"
assert users[1]["name"] == "Bob"
posts = conn.db.many("SELECT * FROM posts ORDER BY id")
assert len(posts) == 3
finally:
conn.teardown()
def test_sqlfile_raises_on_missing_file(self, pg_config):
"""Test that sqlfile raises when file doesn't exist."""
conn = get_connections(pg_config)
try:
with pytest.raises(FileNotFoundError):
seed.sqlfile(["/nonexistent/file.sql"]).seed({
"config": conn.pg.config,
"admin": conn.admin,
"pg": conn.pg,
})
finally:
conn.teardown()
class TestFnSeeding:
"""Tests for function-based seeding."""
def test_fn_adapter_executes_function(self, pg_config):
"""Test that fn adapter executes the provided function."""
def my_seed(ctx):
ctx["pg"].query("CREATE TABLE fn_test (value TEXT)")
ctx["pg"].execute("INSERT INTO fn_test VALUES ('seeded')")
conn = get_connections(
pg_config,
seed_adapters=[seed.fn(my_seed)],
)
try:
result = conn.db.one("SELECT value FROM fn_test")
assert result["value"] == "seeded"
finally:
conn.teardown()
class TestComposeSeeding:
"""Tests for composed seeding."""
def test_compose_runs_adapters_in_order(self, pg_config):
"""Test that compose runs adapters in order."""
execution_order = []
def first_seed(ctx):
execution_order.append("first")
ctx["pg"].query("CREATE TABLE compose_test (step INT)")
def second_seed(ctx):
execution_order.append("second")
ctx["pg"].execute("INSERT INTO compose_test VALUES (1)")
def third_seed(ctx):
execution_order.append("third")
ctx["pg"].execute("INSERT INTO compose_test VALUES (2)")
conn = get_connections(
pg_config,
seed_adapters=[
seed.compose([
seed.fn(first_seed),
seed.fn(second_seed),
seed.fn(third_seed),
])
],
)
try:
assert execution_order == ["first", "second", "third"]
result = conn.db.many("SELECT step FROM compose_test ORDER BY step")
assert [r["step"] for r in result] == [1, 2]
finally:
conn.teardown()
class TestDbAdmin:
"""Tests for DbAdmin class."""
def test_create_and_drop_database(self, pg_config):
"""Test creating and dropping a database."""
admin = DbAdmin(pg_config)
test_db = f"pgsql_admin_test_{generate_test_db_name('')}"
try:
# Create
admin.create(test_db)
assert admin.database_exists(test_db)
# Drop
admin.drop(test_db)
assert not admin.database_exists(test_db)
finally:
# Cleanup in case of failure
if admin.database_exists(test_db):
admin.drop(test_db)
admin.close()
def test_install_extensions(self, pg_config):
"""Test installing extensions."""
admin = DbAdmin(pg_config)
test_db = generate_test_db_name()
try:
admin.create(test_db)
admin.install_extensions(["uuid-ossp"], test_db)
# Verify extension is installed by connecting to the DB
from pgsql_test.client import PgTestClient
client_config = {**pg_config, "database": test_db}
client = PgTestClient(client_config)
client.connect()
result = client.one(
"SELECT 1 FROM pg_extension WHERE extname = 'uuid-ossp'"
)
assert result is not None
client.close()
finally:
admin.drop(test_db)
admin.close()
class TestGenerateTestDbName:
"""Tests for the generate_test_db_name function."""
def test_generates_unique_names(self):
"""Test that generated names are unique."""
names = [generate_test_db_name() for _ in range(100)]
assert len(set(names)) == 100 # All unique
def test_uses_prefix(self):
"""Test that generated names use the provided prefix."""
name = generate_test_db_name("my_prefix_")
assert name.startswith("my_prefix_")
def test_default_prefix(self):
"""Test the default prefix."""
name = generate_test_db_name()
assert name.startswith("pgsql_test_")