pytest-neon 0.2.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-0.2.0/.env.example +4 -0
- pytest_neon-0.2.0/.github/workflows/tests.yml +76 -0
- pytest_neon-0.2.0/.gitignore +39 -0
- pytest_neon-0.2.0/.neon +3 -0
- pytest_neon-0.2.0/CLAUDE.md +45 -0
- pytest_neon-0.2.0/LICENSE +21 -0
- pytest_neon-0.2.0/PKG-INFO +314 -0
- pytest_neon-0.2.0/README.md +272 -0
- pytest_neon-0.2.0/pyproject.toml +70 -0
- pytest_neon-0.2.0/src/pytest_neon/__init__.py +20 -0
- pytest_neon-0.2.0/src/pytest_neon/plugin.py +477 -0
- pytest_neon-0.2.0/src/pytest_neon/py.typed +0 -0
- pytest_neon-0.2.0/tests/conftest.py +64 -0
- pytest_neon-0.2.0/tests/test_branch_lifecycle.py +246 -0
- pytest_neon-0.2.0/tests/test_cli_options.py +18 -0
- pytest_neon-0.2.0/tests/test_env_var.py +206 -0
- pytest_neon-0.2.0/tests/test_fixture_errors.py +30 -0
- pytest_neon-0.2.0/tests/test_integration.py +133 -0
- pytest_neon-0.2.0/tests/test_skip_behavior.py +47 -0
- pytest_neon-0.2.0/uv.lock +1432 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
pip install -e ".[dev,psycopg]"
|
|
29
|
+
|
|
30
|
+
- name: Run unit tests
|
|
31
|
+
run: pytest tests/ --ignore=tests/test_integration.py -v
|
|
32
|
+
|
|
33
|
+
integration:
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
# Only run integration tests on main branch pushes to avoid using API quota on PRs
|
|
36
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
37
|
+
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
|
|
41
|
+
- name: Set up Python
|
|
42
|
+
uses: actions/setup-python@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: "3.14"
|
|
45
|
+
|
|
46
|
+
- name: Install dependencies
|
|
47
|
+
run: |
|
|
48
|
+
python -m pip install --upgrade pip
|
|
49
|
+
pip install -e ".[dev,psycopg]"
|
|
50
|
+
|
|
51
|
+
- name: Run integration tests
|
|
52
|
+
env:
|
|
53
|
+
NEON_API_KEY: ${{ secrets.NEON_API_KEY }}
|
|
54
|
+
NEON_PROJECT_ID: ${{ secrets.NEON_PROJECT_ID }}
|
|
55
|
+
run: pytest tests/test_integration.py -v
|
|
56
|
+
|
|
57
|
+
lint:
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
|
|
62
|
+
- name: Set up Python
|
|
63
|
+
uses: actions/setup-python@v5
|
|
64
|
+
with:
|
|
65
|
+
python-version: "3.14"
|
|
66
|
+
|
|
67
|
+
- name: Install dependencies
|
|
68
|
+
run: |
|
|
69
|
+
python -m pip install --upgrade pip
|
|
70
|
+
pip install -e ".[dev]"
|
|
71
|
+
|
|
72
|
+
- name: Run ruff check
|
|
73
|
+
run: ruff check .
|
|
74
|
+
|
|
75
|
+
- name: Run ruff format check
|
|
76
|
+
run: ruff format --check .
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.idea/
|
|
19
|
+
.vscode/
|
|
20
|
+
*.swp
|
|
21
|
+
*.swo
|
|
22
|
+
|
|
23
|
+
# Testing
|
|
24
|
+
.pytest_cache/
|
|
25
|
+
.coverage
|
|
26
|
+
htmlcov/
|
|
27
|
+
.tox/
|
|
28
|
+
.nox/
|
|
29
|
+
|
|
30
|
+
# mypy
|
|
31
|
+
.mypy_cache/
|
|
32
|
+
|
|
33
|
+
# Environment
|
|
34
|
+
.env
|
|
35
|
+
.env.local
|
|
36
|
+
|
|
37
|
+
# OS
|
|
38
|
+
.DS_Store
|
|
39
|
+
Thumbs.db
|
pytest_neon-0.2.0/.neon
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Claude Code Instructions for pytest-neon
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
This is a pytest plugin that provides isolated Neon database branches for integration testing. Each test module gets its own branch, with automatic cleanup.
|
|
6
|
+
|
|
7
|
+
## Key Architecture
|
|
8
|
+
|
|
9
|
+
- **Entry point**: `src/pytest_neon/plugin.py` - Contains all fixtures and pytest hooks
|
|
10
|
+
- **Core fixture**: `neon_branch` - Creates branch, sets `DATABASE_URL`, yields `NeonBranch` dataclass
|
|
11
|
+
- **Convenience fixtures**: `neon_connection`, `neon_connection_psycopg`, `neon_engine` - Optional, require extras
|
|
12
|
+
|
|
13
|
+
## Dependencies
|
|
14
|
+
|
|
15
|
+
- Core: `pytest`, `neon-api` only
|
|
16
|
+
- Optional extras: `psycopg2`, `psycopg`, `sqlalchemy` - for convenience fixtures
|
|
17
|
+
|
|
18
|
+
## Important Patterns
|
|
19
|
+
|
|
20
|
+
### Fixture Scopes
|
|
21
|
+
- `neon_branch`: `scope="module"` - one branch per test file
|
|
22
|
+
- Connection fixtures: `scope="function"` (default) - fresh connection per test
|
|
23
|
+
|
|
24
|
+
### Environment Variable Handling
|
|
25
|
+
The `_temporary_env` context manager sets `DATABASE_URL` during test execution and restores the original value after. This is critical for not polluting other tests.
|
|
26
|
+
|
|
27
|
+
### Error Messages
|
|
28
|
+
Convenience fixtures use `pytest.fail()` with detailed, formatted error messages when dependencies are missing. Keep this pattern - users need clear guidance on how to fix import errors.
|
|
29
|
+
|
|
30
|
+
## Commit Messages
|
|
31
|
+
- Do NOT add Claude attribution or Co-Authored-By lines
|
|
32
|
+
- Keep commits clean and descriptive
|
|
33
|
+
|
|
34
|
+
## Testing
|
|
35
|
+
|
|
36
|
+
Tests in `tests/` use `pytester` for testing pytest plugins. The plugin itself can be tested without a real Neon connection by mocking `NeonAPI`.
|
|
37
|
+
|
|
38
|
+
## Publishing
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python -m build
|
|
42
|
+
python -m twine upload dist/*
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Package name on PyPI: `pytest-neon`
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Zain Rizvi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pytest-neon
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Pytest plugin for Neon database branch isolation in tests
|
|
5
|
+
Project-URL: Homepage, https://github.com/zain/pytest-neon
|
|
6
|
+
Project-URL: Repository, https://github.com/zain/pytest-neon
|
|
7
|
+
Project-URL: Issues, https://github.com/zain/pytest-neon/issues
|
|
8
|
+
Author: Zain Rizvi
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: branching,database,neon,postgres,pytest,testing
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Framework :: Pytest
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Database
|
|
25
|
+
Classifier: Topic :: Software Development :: Testing
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Requires-Dist: neon-api>=0.1.0
|
|
28
|
+
Requires-Dist: pytest>=7.0
|
|
29
|
+
Requires-Dist: requests>=2.20
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-mock>=3.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
35
|
+
Provides-Extra: psycopg
|
|
36
|
+
Requires-Dist: psycopg[binary]>=3.1; extra == 'psycopg'
|
|
37
|
+
Provides-Extra: psycopg2
|
|
38
|
+
Requires-Dist: psycopg2-binary>=2.9; extra == 'psycopg2'
|
|
39
|
+
Provides-Extra: sqlalchemy
|
|
40
|
+
Requires-Dist: sqlalchemy>=2.0; extra == 'sqlalchemy'
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
# pytest-neon
|
|
44
|
+
|
|
45
|
+
Pytest plugin for [Neon](https://neon.tech) database branch isolation in tests.
|
|
46
|
+
|
|
47
|
+
Each test gets its own isolated database state via Neon's instant branching and reset features. Branches are automatically cleaned up after tests complete.
|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- **Isolated test environments**: Each test runs against a clean database state
|
|
52
|
+
- **Fast resets**: ~0.5s per test to reset the branch (not create a new one)
|
|
53
|
+
- **Automatic cleanup**: Branches are deleted after tests, with auto-expiry fallback
|
|
54
|
+
- **Zero infrastructure**: No Docker, no local Postgres, no manual setup
|
|
55
|
+
- **Real database testing**: Test against actual Postgres with your production schema
|
|
56
|
+
- **Automatic `DATABASE_URL`**: Connection string is set in environment automatically
|
|
57
|
+
- **Driver agnostic**: Bring your own driver, or use the optional convenience fixtures
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
Core package (bring your own database driver):
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install pytest-neon
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
With optional convenience fixtures:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# For psycopg v3 (recommended)
|
|
71
|
+
pip install pytest-neon[psycopg]
|
|
72
|
+
|
|
73
|
+
# For psycopg2 (legacy)
|
|
74
|
+
pip install pytest-neon[psycopg2]
|
|
75
|
+
|
|
76
|
+
# For SQLAlchemy
|
|
77
|
+
pip install pytest-neon[sqlalchemy]
|
|
78
|
+
|
|
79
|
+
# Multiple extras
|
|
80
|
+
pip install pytest-neon[psycopg,sqlalchemy]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Quick Start
|
|
84
|
+
|
|
85
|
+
1. Set environment variables:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
export NEON_API_KEY="your-api-key"
|
|
89
|
+
export NEON_PROJECT_ID="your-project-id"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
2. Write tests:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
def test_user_creation(neon_branch):
|
|
96
|
+
# DATABASE_URL is automatically set to the test branch
|
|
97
|
+
import psycopg # Your own install
|
|
98
|
+
|
|
99
|
+
with psycopg.connect() as conn: # Uses DATABASE_URL by default
|
|
100
|
+
with conn.cursor() as cur:
|
|
101
|
+
cur.execute("INSERT INTO users (email) VALUES ('test@example.com')")
|
|
102
|
+
conn.commit()
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
3. Run tests:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pytest
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Fixtures
|
|
112
|
+
|
|
113
|
+
### `neon_branch` (default, recommended)
|
|
114
|
+
|
|
115
|
+
The primary fixture for database testing. Creates one branch per test module, then resets it to the parent branch's state after each test. This provides test isolation with ~0.5s overhead per test.
|
|
116
|
+
|
|
117
|
+
Returns a `NeonBranch` dataclass with:
|
|
118
|
+
|
|
119
|
+
- `branch_id`: The Neon branch ID
|
|
120
|
+
- `project_id`: The Neon project ID
|
|
121
|
+
- `connection_string`: Full PostgreSQL connection URI
|
|
122
|
+
- `host`: The database host
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
import os
|
|
126
|
+
|
|
127
|
+
def test_branch_info(neon_branch):
|
|
128
|
+
# DATABASE_URL is set automatically
|
|
129
|
+
assert os.environ["DATABASE_URL"] == neon_branch.connection_string
|
|
130
|
+
|
|
131
|
+
# Use with any driver
|
|
132
|
+
import psycopg
|
|
133
|
+
conn = psycopg.connect(neon_branch.connection_string)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Performance**: ~1.5s initial setup per module + ~0.5s reset per test. For a module with 10 tests, expect ~6.5s total overhead.
|
|
137
|
+
|
|
138
|
+
### `neon_branch_shared` (fastest, no isolation)
|
|
139
|
+
|
|
140
|
+
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.
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
def test_read_only_query(neon_branch_shared):
|
|
144
|
+
# Fast: no reset between tests
|
|
145
|
+
# Warning: data from other tests in this module may be visible
|
|
146
|
+
conn = psycopg.connect(neon_branch_shared.connection_string)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Use this when**:
|
|
150
|
+
- Tests are read-only
|
|
151
|
+
- Tests don't interfere with each other
|
|
152
|
+
- You manually clean up test data
|
|
153
|
+
- Maximum speed is more important than isolation
|
|
154
|
+
|
|
155
|
+
**Performance**: ~1.5s initial setup per module, no per-test overhead.
|
|
156
|
+
|
|
157
|
+
### `neon_connection_psycopg` (psycopg v3)
|
|
158
|
+
|
|
159
|
+
Convenience fixture providing a [psycopg v3](https://www.psycopg.org/psycopg3/) connection with automatic rollback and cleanup.
|
|
160
|
+
|
|
161
|
+
**Requires:** `pip install pytest-neon[psycopg]`
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
def test_insert(neon_connection_psycopg):
|
|
165
|
+
with neon_connection_psycopg.cursor() as cur:
|
|
166
|
+
cur.execute("INSERT INTO users (name) VALUES (%s)", ("test",))
|
|
167
|
+
neon_connection_psycopg.commit()
|
|
168
|
+
|
|
169
|
+
with neon_connection_psycopg.cursor() as cur:
|
|
170
|
+
cur.execute("SELECT name FROM users")
|
|
171
|
+
assert cur.fetchone()[0] == "test"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### `neon_connection` (psycopg2)
|
|
175
|
+
|
|
176
|
+
Convenience fixture providing a [psycopg2](https://www.psycopg.org/docs/) connection with automatic rollback and cleanup.
|
|
177
|
+
|
|
178
|
+
**Requires:** `pip install pytest-neon[psycopg2]`
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
def test_insert(neon_connection):
|
|
182
|
+
cur = neon_connection.cursor()
|
|
183
|
+
cur.execute("INSERT INTO users (name) VALUES (%s)", ("test",))
|
|
184
|
+
neon_connection.commit()
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### `neon_engine` (SQLAlchemy)
|
|
188
|
+
|
|
189
|
+
Convenience fixture providing a [SQLAlchemy](https://www.sqlalchemy.org/) engine with automatic disposal.
|
|
190
|
+
|
|
191
|
+
**Requires:** `pip install pytest-neon[sqlalchemy]`
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
from sqlalchemy import text
|
|
195
|
+
|
|
196
|
+
def test_query(neon_engine):
|
|
197
|
+
with neon_engine.connect() as conn:
|
|
198
|
+
result = conn.execute(text("SELECT 1"))
|
|
199
|
+
assert result.scalar() == 1
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Configuration
|
|
203
|
+
|
|
204
|
+
### Environment Variables
|
|
205
|
+
|
|
206
|
+
| Variable | Description | Required |
|
|
207
|
+
|----------|-------------|----------|
|
|
208
|
+
| `NEON_API_KEY` | Your Neon API key | Yes |
|
|
209
|
+
| `NEON_PROJECT_ID` | Your Neon project ID | Yes |
|
|
210
|
+
| `NEON_PARENT_BRANCH_ID` | Parent branch to create test branches from | No |
|
|
211
|
+
| `NEON_DATABASE` | Database name (default: `neondb`) | No |
|
|
212
|
+
| `NEON_ROLE` | Database role (default: `neondb_owner`) | No |
|
|
213
|
+
|
|
214
|
+
### Command Line Options
|
|
215
|
+
|
|
216
|
+
| Option | Description | Default |
|
|
217
|
+
|--------|-------------|---------|
|
|
218
|
+
| `--neon-api-key` | Neon API key | `NEON_API_KEY` env |
|
|
219
|
+
| `--neon-project-id` | Neon project ID | `NEON_PROJECT_ID` env |
|
|
220
|
+
| `--neon-parent-branch` | Parent branch ID | Project default |
|
|
221
|
+
| `--neon-database` | Database name | `neondb` |
|
|
222
|
+
| `--neon-role` | Database role | `neondb_owner` |
|
|
223
|
+
| `--neon-keep-branches` | Don't delete branches after tests | `false` |
|
|
224
|
+
| `--neon-branch-expiry` | Branch auto-expiry in seconds | `600` (10 min) |
|
|
225
|
+
| `--neon-env-var` | Environment variable for connection string | `DATABASE_URL` |
|
|
226
|
+
|
|
227
|
+
Examples:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Keep branches for debugging
|
|
231
|
+
pytest --neon-keep-branches
|
|
232
|
+
|
|
233
|
+
# Disable auto-expiry
|
|
234
|
+
pytest --neon-branch-expiry=0
|
|
235
|
+
|
|
236
|
+
# Use a different env var
|
|
237
|
+
pytest --neon-env-var=TEST_DATABASE_URL
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## CI/CD Integration
|
|
241
|
+
|
|
242
|
+
### GitHub Actions
|
|
243
|
+
|
|
244
|
+
```yaml
|
|
245
|
+
name: Tests
|
|
246
|
+
|
|
247
|
+
on: [push, pull_request]
|
|
248
|
+
|
|
249
|
+
jobs:
|
|
250
|
+
test:
|
|
251
|
+
runs-on: ubuntu-latest
|
|
252
|
+
steps:
|
|
253
|
+
- uses: actions/checkout@v4
|
|
254
|
+
- uses: actions/setup-python@v5
|
|
255
|
+
with:
|
|
256
|
+
python-version: '3.12'
|
|
257
|
+
|
|
258
|
+
- name: Install dependencies
|
|
259
|
+
run: pip install -e .[psycopg,dev]
|
|
260
|
+
|
|
261
|
+
- name: Run tests
|
|
262
|
+
env:
|
|
263
|
+
NEON_API_KEY: ${{ secrets.NEON_API_KEY }}
|
|
264
|
+
NEON_PROJECT_ID: ${{ secrets.NEON_PROJECT_ID }}
|
|
265
|
+
run: pytest
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## How It Works
|
|
269
|
+
|
|
270
|
+
1. Before each test module, the plugin creates a new Neon branch from your parent branch
|
|
271
|
+
2. `DATABASE_URL` is set to point to the new branch
|
|
272
|
+
3. Tests run against this isolated branch with full access to your schema and data
|
|
273
|
+
4. After each test, the branch is reset to its parent state (~0.5s)
|
|
274
|
+
5. After all tests in the module complete, the branch is deleted
|
|
275
|
+
6. As a safety net, branches auto-expire after 10 minutes even if cleanup fails
|
|
276
|
+
|
|
277
|
+
Branches use copy-on-write storage, so you only pay for data that differs from the parent branch.
|
|
278
|
+
|
|
279
|
+
## Troubleshooting
|
|
280
|
+
|
|
281
|
+
### "psycopg not installed" or "psycopg2 not installed"
|
|
282
|
+
|
|
283
|
+
The convenience fixtures require their respective drivers. Install the appropriate extra:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# For neon_connection_psycopg fixture
|
|
287
|
+
pip install pytest-neon[psycopg]
|
|
288
|
+
|
|
289
|
+
# For neon_connection fixture
|
|
290
|
+
pip install pytest-neon[psycopg2]
|
|
291
|
+
|
|
292
|
+
# For neon_engine fixture
|
|
293
|
+
pip install pytest-neon[sqlalchemy]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Or use the core `neon_branch` fixture with your own driver:
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
def test_example(neon_branch):
|
|
300
|
+
import my_preferred_driver
|
|
301
|
+
conn = my_preferred_driver.connect(neon_branch.connection_string)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### "Neon API key not configured"
|
|
305
|
+
|
|
306
|
+
Set the `NEON_API_KEY` environment variable or use the `--neon-api-key` CLI option.
|
|
307
|
+
|
|
308
|
+
### "Neon project ID not configured"
|
|
309
|
+
|
|
310
|
+
Set the `NEON_PROJECT_ID` environment variable or use the `--neon-project-id` CLI option.
|
|
311
|
+
|
|
312
|
+
## License
|
|
313
|
+
|
|
314
|
+
MIT
|