pytest-neon 1.0.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/CLAUDE.md +7 -2
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/PKG-INFO +84 -29
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/README.md +83 -28
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/pyproject.toml +1 -1
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/src/pytest_neon/__init__.py +1 -1
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/src/pytest_neon/plugin.py +160 -21
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/tests/test_integration.py +35 -14
- pytest_neon-2.1.0/tests/test_readwrite_readonly_fixtures.py +258 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/tests/test_reset_behavior.py +113 -0
- pytest_neon-2.1.0/tests/test_xdist_worker_support.py +189 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/uv.lock +10 -1
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/.env.example +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/.github/workflows/release.yml +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/.github/workflows/tests.yml +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/.gitignore +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/.neon +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/LICENSE +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/src/pytest_neon/py.typed +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/tests/conftest.py +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/tests/test_branch_lifecycle.py +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/tests/test_cli_options.py +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/tests/test_env_var.py +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/tests/test_fixture_errors.py +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/tests/test_migrations.py +0 -0
- {pytest_neon-1.0.0 → pytest_neon-2.1.0}/tests/test_skip_behavior.py +0 -0
|
@@ -13,7 +13,10 @@ This is a pytest plugin that provides isolated Neon database branches for integr
|
|
|
13
13
|
- **Entry point**: `src/pytest_neon/plugin.py` - Contains all fixtures and pytest hooks
|
|
14
14
|
- **Migration fixture**: `_neon_migration_branch` - Session-scoped, parent for all test branches
|
|
15
15
|
- **User migration hook**: `neon_apply_migrations` - Session-scoped no-op, users override to run migrations
|
|
16
|
-
- **Core
|
|
16
|
+
- **Core fixtures**:
|
|
17
|
+
- `neon_branch_readwrite` - Function-scoped, resets after each test (recommended for write tests)
|
|
18
|
+
- `neon_branch_readonly` - Function-scoped, NO reset (recommended for read-only tests, faster)
|
|
19
|
+
- `neon_branch` - Deprecated alias for `neon_branch_readwrite`
|
|
17
20
|
- **Shared fixture**: `neon_branch_shared` - Module-scoped, no reset between tests
|
|
18
21
|
- **Convenience fixtures**: `neon_connection`, `neon_connection_psycopg`, `neon_engine` - Optional, require extras
|
|
19
22
|
|
|
@@ -28,7 +31,9 @@ This is a pytest plugin that provides isolated Neon database branches for integr
|
|
|
28
31
|
- `_neon_migration_branch`: `scope="session"` - internal, parent for all test branches, migrations run here
|
|
29
32
|
- `neon_apply_migrations`: `scope="session"` - user overrides to run migrations
|
|
30
33
|
- `_neon_branch_for_reset`: `scope="session"` - internal, creates one branch per session from migration branch
|
|
31
|
-
- `
|
|
34
|
+
- `neon_branch_readwrite`: `scope="function"` - resets branch after each test (for write tests)
|
|
35
|
+
- `neon_branch_readonly`: `scope="function"` - NO reset (for read-only tests, faster)
|
|
36
|
+
- `neon_branch`: `scope="function"` - deprecated alias for `neon_branch_readwrite`
|
|
32
37
|
- `neon_branch_shared`: `scope="module"` - one branch per test file, no reset
|
|
33
38
|
- Connection fixtures: `scope="function"` (default) - fresh connection per test
|
|
34
39
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-neon
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Pytest plugin for Neon database branch isolation in tests
|
|
5
5
|
Project-URL: Homepage, https://github.com/ZainRizvi/pytest-neon
|
|
6
6
|
Project-URL: Repository, https://github.com/ZainRizvi/pytest-neon
|
|
@@ -97,7 +97,7 @@ export NEON_PROJECT_ID="your-project-id"
|
|
|
97
97
|
2. Write tests:
|
|
98
98
|
|
|
99
99
|
```python
|
|
100
|
-
def test_user_creation(
|
|
100
|
+
def test_user_creation(neon_branch_readwrite):
|
|
101
101
|
# DATABASE_URL is automatically set to the test branch
|
|
102
102
|
import psycopg # Your own install
|
|
103
103
|
|
|
@@ -105,6 +105,7 @@ def test_user_creation(neon_branch):
|
|
|
105
105
|
with conn.cursor() as cur:
|
|
106
106
|
cur.execute("INSERT INTO users (email) VALUES ('test@example.com')")
|
|
107
107
|
conn.commit()
|
|
108
|
+
# Branch automatically resets after test - next test sees clean state
|
|
108
109
|
```
|
|
109
110
|
|
|
110
111
|
3. Run tests:
|
|
@@ -115,33 +116,75 @@ pytest
|
|
|
115
116
|
|
|
116
117
|
## Fixtures
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
**Which fixture should I use?**
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
- **Use `neon_branch_readonly`** if your test only reads data (SELECT queries). This is the fastest option with no per-test overhead.
|
|
122
|
+
- **Use `neon_branch_readwrite`** if your test modifies data (INSERT, UPDATE, DELETE). This resets the branch after each test for isolation.
|
|
121
123
|
|
|
122
|
-
|
|
124
|
+
### `neon_branch_readonly` (recommended, fastest)
|
|
123
125
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
**Use this fixture by default** if your tests don't need to write data. It provides the best performance by skipping the branch reset step (~0.5s saved per test), which also reduces API calls and avoids rate limiting issues.
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
def test_query_users(neon_branch_readonly):
|
|
130
|
+
# DATABASE_URL is set automatically
|
|
131
|
+
import psycopg
|
|
132
|
+
with psycopg.connect(neon_branch_readonly.connection_string) as conn:
|
|
133
|
+
result = conn.execute("SELECT * FROM users").fetchall()
|
|
134
|
+
assert len(result) >= 0
|
|
135
|
+
# No reset after this test - fast!
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Use this when**:
|
|
139
|
+
- Tests only perform SELECT queries
|
|
140
|
+
- Tests don't modify database state
|
|
141
|
+
- You want maximum performance
|
|
142
|
+
|
|
143
|
+
**Warning**: If you accidentally write data using this fixture, subsequent tests will see those modifications. The fixture does not enforce read-only access at the database level.
|
|
144
|
+
|
|
145
|
+
**Performance**: ~1.5s initial setup per session, **no per-test overhead**. For 10 read-only tests, expect only ~1.5s total overhead (vs ~6.5s with readwrite).
|
|
146
|
+
|
|
147
|
+
### `neon_branch_readwrite` (for write tests)
|
|
148
|
+
|
|
149
|
+
Use this fixture when your tests need to INSERT, UPDATE, or DELETE data. Creates one branch per test session, then resets it to the parent branch's state after each test. This provides test isolation with ~0.5s overhead per test.
|
|
129
150
|
|
|
130
151
|
```python
|
|
131
152
|
import os
|
|
132
153
|
|
|
133
|
-
def
|
|
154
|
+
def test_insert_user(neon_branch_readwrite):
|
|
134
155
|
# DATABASE_URL is set automatically
|
|
135
|
-
assert os.environ["DATABASE_URL"] ==
|
|
156
|
+
assert os.environ["DATABASE_URL"] == neon_branch_readwrite.connection_string
|
|
136
157
|
|
|
137
158
|
# Use with any driver
|
|
138
159
|
import psycopg
|
|
139
|
-
|
|
160
|
+
with psycopg.connect(neon_branch_readwrite.connection_string) as conn:
|
|
161
|
+
conn.execute("INSERT INTO users (name) VALUES ('test')")
|
|
162
|
+
conn.commit()
|
|
163
|
+
# Branch resets after this test - changes won't affect other tests
|
|
140
164
|
```
|
|
141
165
|
|
|
142
|
-
**Performance**: ~1.5s initial setup per session + ~0.5s reset per test. For 10 tests, expect ~6.5s total overhead.
|
|
166
|
+
**Performance**: ~1.5s initial setup per session + ~0.5s reset per test. For 10 write tests, expect ~6.5s total overhead.
|
|
143
167
|
|
|
144
|
-
### `
|
|
168
|
+
### `NeonBranch` dataclass
|
|
169
|
+
|
|
170
|
+
Both fixtures return a `NeonBranch` dataclass with:
|
|
171
|
+
|
|
172
|
+
- `branch_id`: The Neon branch ID
|
|
173
|
+
- `project_id`: The Neon project ID
|
|
174
|
+
- `connection_string`: Full PostgreSQL connection URI
|
|
175
|
+
- `host`: The database host
|
|
176
|
+
- `parent_id`: The parent branch ID (used for resets)
|
|
177
|
+
|
|
178
|
+
### `neon_branch` (deprecated)
|
|
179
|
+
|
|
180
|
+
> **Deprecated**: Use `neon_branch_readwrite` or `neon_branch_readonly` instead.
|
|
181
|
+
|
|
182
|
+
This fixture is an alias for `neon_branch_readwrite` and will emit a deprecation warning. Migrate to the explicit fixture names for clarity:
|
|
183
|
+
|
|
184
|
+
- `neon_branch_readwrite`: For tests that modify data (INSERT/UPDATE/DELETE)
|
|
185
|
+
- `neon_branch_readonly`: For tests that only read data (SELECT)
|
|
186
|
+
|
|
187
|
+
### `neon_branch_shared` (module-scoped, no isolation)
|
|
145
188
|
|
|
146
189
|
Creates one branch per test module and shares it across all tests without resetting. This is the fastest option but tests can see each other's data modifications.
|
|
147
190
|
|
|
@@ -207,19 +250,21 @@ def test_query(neon_engine):
|
|
|
207
250
|
|
|
208
251
|
### Using Your Own SQLAlchemy Engine
|
|
209
252
|
|
|
210
|
-
If you have a module-level SQLAlchemy engine (common pattern)
|
|
253
|
+
If you have a module-level SQLAlchemy engine (common pattern) and use `neon_branch_readwrite`, you **must** use `pool_pre_ping=True`:
|
|
211
254
|
|
|
212
255
|
```python
|
|
213
256
|
# database.py
|
|
214
257
|
from sqlalchemy import create_engine
|
|
215
258
|
from config import DATABASE_URL
|
|
216
259
|
|
|
217
|
-
# pool_pre_ping=True is REQUIRED
|
|
260
|
+
# pool_pre_ping=True is REQUIRED when using neon_branch_readwrite
|
|
218
261
|
# It verifies connections are alive before using them
|
|
219
262
|
engine = create_engine(DATABASE_URL, pool_pre_ping=True)
|
|
220
263
|
```
|
|
221
264
|
|
|
222
|
-
**Why?** After each test,
|
|
265
|
+
**Why?** After each test, `neon_branch_readwrite` resets the branch which terminates server-side connections. Without `pool_pre_ping`, SQLAlchemy may try to reuse a dead pooled connection, causing `SSL connection has been closed unexpectedly` errors.
|
|
266
|
+
|
|
267
|
+
**Note**: If you only use `neon_branch_readonly`, `pool_pre_ping` is not required since no resets occur.
|
|
223
268
|
|
|
224
269
|
This is also a best practice for any cloud database (Neon, RDS, etc.) where connections can be terminated externally.
|
|
225
270
|
|
|
@@ -435,7 +480,7 @@ Branches use copy-on-write storage, so you only pay for data that differs from t
|
|
|
435
480
|
|
|
436
481
|
### What Reset Does
|
|
437
482
|
|
|
438
|
-
The `
|
|
483
|
+
The `neon_branch_readwrite` fixture uses Neon's branch restore API to reset database state after each test:
|
|
439
484
|
|
|
440
485
|
- **Data changes are reverted**: All INSERT, UPDATE, DELETE operations are undone
|
|
441
486
|
- **Schema changes are reverted**: CREATE TABLE, ALTER TABLE, DROP TABLE, etc. are undone
|
|
@@ -444,16 +489,26 @@ The `neon_branch` fixture uses Neon's branch restore API to reset database state
|
|
|
444
489
|
|
|
445
490
|
This is similar to database transactions but at the branch level.
|
|
446
491
|
|
|
447
|
-
##
|
|
492
|
+
## Parallel Test Execution (pytest-xdist)
|
|
493
|
+
|
|
494
|
+
This plugin supports parallel test execution with [pytest-xdist](https://pytest-xdist.readthedocs.io/). Each xdist worker automatically gets its own isolated branch.
|
|
448
495
|
|
|
449
|
-
|
|
496
|
+
```bash
|
|
497
|
+
# Run tests in parallel with 4 workers
|
|
498
|
+
pip install pytest-xdist
|
|
499
|
+
pytest -n 4
|
|
500
|
+
```
|
|
450
501
|
|
|
451
|
-
|
|
502
|
+
**How it works:**
|
|
503
|
+
- Each xdist worker (gw0, gw1, gw2, etc.) creates its own branch
|
|
504
|
+
- Branches are named with the worker ID suffix (e.g., `-test-gw0`, `-test-gw1`)
|
|
505
|
+
- Workers run tests in parallel without database state interference
|
|
506
|
+
- All branches are cleaned up after the test session
|
|
452
507
|
|
|
453
|
-
|
|
454
|
-
-
|
|
455
|
-
-
|
|
456
|
-
-
|
|
508
|
+
**Cost implications:**
|
|
509
|
+
- Running with `-n 4` creates 4 branches (one per worker) plus the migration branch
|
|
510
|
+
- Choose your parallelism level based on your Neon plan's branch limits
|
|
511
|
+
- Each worker's branch is reset after each test using the fast reset operation (~0.5s)
|
|
457
512
|
|
|
458
513
|
## Troubleshooting
|
|
459
514
|
|
|
@@ -472,12 +527,12 @@ pip install pytest-neon[psycopg2]
|
|
|
472
527
|
pip install pytest-neon[sqlalchemy]
|
|
473
528
|
```
|
|
474
529
|
|
|
475
|
-
Or use the core
|
|
530
|
+
Or use the core fixtures with your own driver:
|
|
476
531
|
|
|
477
532
|
```python
|
|
478
|
-
def test_example(
|
|
533
|
+
def test_example(neon_branch_readwrite):
|
|
479
534
|
import my_preferred_driver
|
|
480
|
-
conn = my_preferred_driver.connect(
|
|
535
|
+
conn = my_preferred_driver.connect(neon_branch_readwrite.connection_string)
|
|
481
536
|
```
|
|
482
537
|
|
|
483
538
|
### "Neon API key not configured"
|
|
@@ -52,7 +52,7 @@ export NEON_PROJECT_ID="your-project-id"
|
|
|
52
52
|
2. Write tests:
|
|
53
53
|
|
|
54
54
|
```python
|
|
55
|
-
def test_user_creation(
|
|
55
|
+
def test_user_creation(neon_branch_readwrite):
|
|
56
56
|
# DATABASE_URL is automatically set to the test branch
|
|
57
57
|
import psycopg # Your own install
|
|
58
58
|
|
|
@@ -60,6 +60,7 @@ def test_user_creation(neon_branch):
|
|
|
60
60
|
with conn.cursor() as cur:
|
|
61
61
|
cur.execute("INSERT INTO users (email) VALUES ('test@example.com')")
|
|
62
62
|
conn.commit()
|
|
63
|
+
# Branch automatically resets after test - next test sees clean state
|
|
63
64
|
```
|
|
64
65
|
|
|
65
66
|
3. Run tests:
|
|
@@ -70,33 +71,75 @@ pytest
|
|
|
70
71
|
|
|
71
72
|
## Fixtures
|
|
72
73
|
|
|
73
|
-
|
|
74
|
+
**Which fixture should I use?**
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
- **Use `neon_branch_readonly`** if your test only reads data (SELECT queries). This is the fastest option with no per-test overhead.
|
|
77
|
+
- **Use `neon_branch_readwrite`** if your test modifies data (INSERT, UPDATE, DELETE). This resets the branch after each test for isolation.
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
### `neon_branch_readonly` (recommended, fastest)
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
**Use this fixture by default** if your tests don't need to write data. It provides the best performance by skipping the branch reset step (~0.5s saved per test), which also reduces API calls and avoids rate limiting issues.
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
def test_query_users(neon_branch_readonly):
|
|
85
|
+
# DATABASE_URL is set automatically
|
|
86
|
+
import psycopg
|
|
87
|
+
with psycopg.connect(neon_branch_readonly.connection_string) as conn:
|
|
88
|
+
result = conn.execute("SELECT * FROM users").fetchall()
|
|
89
|
+
assert len(result) >= 0
|
|
90
|
+
# No reset after this test - fast!
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Use this when**:
|
|
94
|
+
- Tests only perform SELECT queries
|
|
95
|
+
- Tests don't modify database state
|
|
96
|
+
- You want maximum performance
|
|
97
|
+
|
|
98
|
+
**Warning**: If you accidentally write data using this fixture, subsequent tests will see those modifications. The fixture does not enforce read-only access at the database level.
|
|
99
|
+
|
|
100
|
+
**Performance**: ~1.5s initial setup per session, **no per-test overhead**. For 10 read-only tests, expect only ~1.5s total overhead (vs ~6.5s with readwrite).
|
|
101
|
+
|
|
102
|
+
### `neon_branch_readwrite` (for write tests)
|
|
103
|
+
|
|
104
|
+
Use this fixture when your tests need to INSERT, UPDATE, or DELETE data. Creates one branch per test session, then resets it to the parent branch's state after each test. This provides test isolation with ~0.5s overhead per test.
|
|
84
105
|
|
|
85
106
|
```python
|
|
86
107
|
import os
|
|
87
108
|
|
|
88
|
-
def
|
|
109
|
+
def test_insert_user(neon_branch_readwrite):
|
|
89
110
|
# DATABASE_URL is set automatically
|
|
90
|
-
assert os.environ["DATABASE_URL"] ==
|
|
111
|
+
assert os.environ["DATABASE_URL"] == neon_branch_readwrite.connection_string
|
|
91
112
|
|
|
92
113
|
# Use with any driver
|
|
93
114
|
import psycopg
|
|
94
|
-
|
|
115
|
+
with psycopg.connect(neon_branch_readwrite.connection_string) as conn:
|
|
116
|
+
conn.execute("INSERT INTO users (name) VALUES ('test')")
|
|
117
|
+
conn.commit()
|
|
118
|
+
# Branch resets after this test - changes won't affect other tests
|
|
95
119
|
```
|
|
96
120
|
|
|
97
|
-
**Performance**: ~1.5s initial setup per session + ~0.5s reset per test. For 10 tests, expect ~6.5s total overhead.
|
|
121
|
+
**Performance**: ~1.5s initial setup per session + ~0.5s reset per test. For 10 write tests, expect ~6.5s total overhead.
|
|
98
122
|
|
|
99
|
-
### `
|
|
123
|
+
### `NeonBranch` dataclass
|
|
124
|
+
|
|
125
|
+
Both fixtures return a `NeonBranch` dataclass with:
|
|
126
|
+
|
|
127
|
+
- `branch_id`: The Neon branch ID
|
|
128
|
+
- `project_id`: The Neon project ID
|
|
129
|
+
- `connection_string`: Full PostgreSQL connection URI
|
|
130
|
+
- `host`: The database host
|
|
131
|
+
- `parent_id`: The parent branch ID (used for resets)
|
|
132
|
+
|
|
133
|
+
### `neon_branch` (deprecated)
|
|
134
|
+
|
|
135
|
+
> **Deprecated**: Use `neon_branch_readwrite` or `neon_branch_readonly` instead.
|
|
136
|
+
|
|
137
|
+
This fixture is an alias for `neon_branch_readwrite` and will emit a deprecation warning. Migrate to the explicit fixture names for clarity:
|
|
138
|
+
|
|
139
|
+
- `neon_branch_readwrite`: For tests that modify data (INSERT/UPDATE/DELETE)
|
|
140
|
+
- `neon_branch_readonly`: For tests that only read data (SELECT)
|
|
141
|
+
|
|
142
|
+
### `neon_branch_shared` (module-scoped, no isolation)
|
|
100
143
|
|
|
101
144
|
Creates one branch per test module and shares it across all tests without resetting. This is the fastest option but tests can see each other's data modifications.
|
|
102
145
|
|
|
@@ -162,19 +205,21 @@ def test_query(neon_engine):
|
|
|
162
205
|
|
|
163
206
|
### Using Your Own SQLAlchemy Engine
|
|
164
207
|
|
|
165
|
-
If you have a module-level SQLAlchemy engine (common pattern)
|
|
208
|
+
If you have a module-level SQLAlchemy engine (common pattern) and use `neon_branch_readwrite`, you **must** use `pool_pre_ping=True`:
|
|
166
209
|
|
|
167
210
|
```python
|
|
168
211
|
# database.py
|
|
169
212
|
from sqlalchemy import create_engine
|
|
170
213
|
from config import DATABASE_URL
|
|
171
214
|
|
|
172
|
-
# pool_pre_ping=True is REQUIRED
|
|
215
|
+
# pool_pre_ping=True is REQUIRED when using neon_branch_readwrite
|
|
173
216
|
# It verifies connections are alive before using them
|
|
174
217
|
engine = create_engine(DATABASE_URL, pool_pre_ping=True)
|
|
175
218
|
```
|
|
176
219
|
|
|
177
|
-
**Why?** After each test,
|
|
220
|
+
**Why?** After each test, `neon_branch_readwrite` resets the branch which terminates server-side connections. Without `pool_pre_ping`, SQLAlchemy may try to reuse a dead pooled connection, causing `SSL connection has been closed unexpectedly` errors.
|
|
221
|
+
|
|
222
|
+
**Note**: If you only use `neon_branch_readonly`, `pool_pre_ping` is not required since no resets occur.
|
|
178
223
|
|
|
179
224
|
This is also a best practice for any cloud database (Neon, RDS, etc.) where connections can be terminated externally.
|
|
180
225
|
|
|
@@ -390,7 +435,7 @@ Branches use copy-on-write storage, so you only pay for data that differs from t
|
|
|
390
435
|
|
|
391
436
|
### What Reset Does
|
|
392
437
|
|
|
393
|
-
The `
|
|
438
|
+
The `neon_branch_readwrite` fixture uses Neon's branch restore API to reset database state after each test:
|
|
394
439
|
|
|
395
440
|
- **Data changes are reverted**: All INSERT, UPDATE, DELETE operations are undone
|
|
396
441
|
- **Schema changes are reverted**: CREATE TABLE, ALTER TABLE, DROP TABLE, etc. are undone
|
|
@@ -399,16 +444,26 @@ The `neon_branch` fixture uses Neon's branch restore API to reset database state
|
|
|
399
444
|
|
|
400
445
|
This is similar to database transactions but at the branch level.
|
|
401
446
|
|
|
402
|
-
##
|
|
447
|
+
## Parallel Test Execution (pytest-xdist)
|
|
448
|
+
|
|
449
|
+
This plugin supports parallel test execution with [pytest-xdist](https://pytest-xdist.readthedocs.io/). Each xdist worker automatically gets its own isolated branch.
|
|
403
450
|
|
|
404
|
-
|
|
451
|
+
```bash
|
|
452
|
+
# Run tests in parallel with 4 workers
|
|
453
|
+
pip install pytest-xdist
|
|
454
|
+
pytest -n 4
|
|
455
|
+
```
|
|
405
456
|
|
|
406
|
-
|
|
457
|
+
**How it works:**
|
|
458
|
+
- Each xdist worker (gw0, gw1, gw2, etc.) creates its own branch
|
|
459
|
+
- Branches are named with the worker ID suffix (e.g., `-test-gw0`, `-test-gw1`)
|
|
460
|
+
- Workers run tests in parallel without database state interference
|
|
461
|
+
- All branches are cleaned up after the test session
|
|
407
462
|
|
|
408
|
-
|
|
409
|
-
-
|
|
410
|
-
-
|
|
411
|
-
-
|
|
463
|
+
**Cost implications:**
|
|
464
|
+
- Running with `-n 4` creates 4 branches (one per worker) plus the migration branch
|
|
465
|
+
- Choose your parallelism level based on your Neon plan's branch limits
|
|
466
|
+
- Each worker's branch is reset after each test using the fast reset operation (~0.5s)
|
|
412
467
|
|
|
413
468
|
## Troubleshooting
|
|
414
469
|
|
|
@@ -427,12 +482,12 @@ pip install pytest-neon[psycopg2]
|
|
|
427
482
|
pip install pytest-neon[sqlalchemy]
|
|
428
483
|
```
|
|
429
484
|
|
|
430
|
-
Or use the core
|
|
485
|
+
Or use the core fixtures with your own driver:
|
|
431
486
|
|
|
432
487
|
```python
|
|
433
|
-
def test_example(
|
|
488
|
+
def test_example(neon_branch_readwrite):
|
|
434
489
|
import my_preferred_driver
|
|
435
|
-
conn = my_preferred_driver.connect(
|
|
490
|
+
conn = my_preferred_driver.connect(neon_branch_readwrite.connection_string)
|
|
436
491
|
```
|
|
437
492
|
|
|
438
493
|
### "Neon API key not configured"
|