-
Notifications
You must be signed in to change notification settings - Fork 6
273 lines (243 loc) · 11.1 KB
/
Copy pathpython-driver-test.yaml
File metadata and controls
273 lines (243 loc) · 11.1 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
name: Python Driver Tests
on:
push:
branches: [ '*' ]
paths-ignore:
- 'README.md'
- 'VERSION.md'
pull_request:
branches: [ '*' ]
paths-ignore:
- 'README.md'
- 'VERSION.md'
jobs:
# Everything that needs no server, on every version claimed to be supported. Kept apart from
# the job below so a lint or typing failure is reported in seconds rather than after a
# half-hour server build.
checks:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.11', '3.12', '3.13', '3.14']
steps:
- uses: actions/checkout@v4
with:
# The version comes from the tags, so a shallow clone would bake in a wrong one.
fetch-depth: 0
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Install
# --all-extras, so the columnar backends are present. Without them the whole of
# columnar.py's suite skips itself, which reads as a pass.
run: uv sync --group dev --all-extras --python ${{ matrix.python-version }}
- name: Format and lint
run: |
uv run ruff format --check src tests tools
uv run ruff check src tests tools
- name: Types
run: uv run mypy
# Three separate things go wrong here, so all three are checked: a generated file edited
# directly, a generated file left behind by an edit to its source, and an awaiting module
# added without being listed for conversion at all.
- name: The generated interface is what its source says
run: uv run python tools/async_to_sync.py --check
# -X dev makes ResourceWarning visible, which is the only way an unclosed socket is found,
# and turns on asyncio's own debug mode. It does not imply -W error, so both are passed.
- name: Tests
run: uv run python -X dev -W error -m pytest -q
- name: Import time
run: uv run python -X importtime -c "import agensgraph" 2>&1 | tail -1
# Atheris ships wheels for cp312 and later on Linux x86_64 and no source distribution, so this
# cannot be part of the matrix above.
fuzz:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Install
run: |
uv sync --group dev --python 3.13
uv pip install atheris
- name: Fuzz what reads the text rendering
run: uv run python tests/fuzz_textfmt.py -atheris_runs=200000 -print_final_stats=1
- name: Keep whatever it found
if: failure()
uses: actions/upload-artifact@v4
with:
name: fuzz-findings
path: |
crash-*
timeout-*
oom-*
# A declared floor is only a claim until something resolves to it.
lowest-versions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: astral-sh/setup-uv@v5
- name: Resolve to the lowest declared versions, and test against those
run: |
uv sync --group dev --resolution lowest-direct
uv run python -m pytest -q
# A package that type-checks in its own tree can still ship without the marker saying so, and a
# source distribution built away from the tags can still carry a wrong version. Neither is found
# except by installing what would actually be published.
package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: astral-sh/setup-uv@v5
- name: Build both distributions
run: uv build
- name: Install the wheel into a clean environment
run: |
uv venv /tmp/from-wheel
VIRTUAL_ENV=/tmp/from-wheel uv pip install dist/*.whl
VIRTUAL_ENV=/tmp/from-wheel uv run python - <<'EOF'
import pathlib
import agensgraph
print("version", agensgraph.__version__)
assert not agensgraph.__version__.startswith("0.0.0"), (
"the version did not come from the tags"
)
marker = pathlib.Path(agensgraph.__file__).parent / "py.typed"
assert marker.exists(), "the typing marker is missing, so nothing downstream is checked"
EOF
- name: Install from the source distribution too
run: |
uv venv /tmp/from-sdist
VIRTUAL_ENV=/tmp/from-sdist uv pip install dist/*.tar.gz
VIRTUAL_ENV=/tmp/from-sdist uv run python -c "import agensgraph; print(agensgraph.__version__)"
# The full suite, against a server built from the engine's own tree.
against-a-server:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Every server the driver says it reads, each on its own PostgreSQL base. Running the same
# suite against all of them is what checks the version gates: a test that needs something
# only the newest has, and does not say so, fails on the older ones instead of passing
# everywhere by accident.
engine: [v2.17, v2.18, main]
name: against-a-server (${{ matrix.engine }})
steps:
- name: Find the engine's latest commit
run: |
hash=$(git ls-remote https://github.com/skaiworldwide-oss/agensgraph.git \
"refs/heads/${{ matrix.engine }}" | awk '{print $1}')
test -n "$hash" || { echo "no branch ${{ matrix.engine }}"; exit 1; }
echo "AG_COMMIT_HASH=$hash" >> $GITHUB_ENV
# Resolved rather than pinned, so the build tracks pgvector's releases the way it already
# tracks the engine's commits. Both go in the cache key: the extension is installed into the
# engine's prefix, so a cached prefix built before either moved is the wrong prefix.
- name: Find pgvector's latest release
run: |
tag=$(git ls-remote --tags --refs --sort=-v:refname \
https://github.com/pgvector/pgvector.git | head -1 | sed 's#.*/##')
test -n "$tag"
echo "PGVECTOR_TAG=$tag" >> $GITHUB_ENV
- name: Cache the build
uses: actions/cache@v4
id: agcache
with:
path: ~/agensgraph_build
key: ${{ runner.os }}-v3-agensgraph-${{ matrix.engine }}-${{ env.AG_COMMIT_HASH }}-pgvector-${{ env.PGVECTOR_TAG }}
- name: System dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential libreadline-dev zlib1g-dev flex bison \
python3-dev libpq-dev git
- name: Build the engine
if: steps.agcache.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch ${{ matrix.engine }} \
https://github.com/skaiworldwide-oss/agensgraph.git ~/agensgraph_source
cd ~/agensgraph_source
./configure --prefix=$HOME/agensgraph_build
make -j$(nproc)
make install
# Built against the engine that was just installed, not against a system PostgreSQL, so the
# extension links to the server it will be loaded into. OPTFLAGS is emptied because pgvector
# compiles with -march=native by default, which builds for whichever runner happened to run
# the build and can then fault on the one that restores the cache.
- name: Build pgvector against it
if: steps.agcache.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch "$PGVECTOR_TAG" \
https://github.com/pgvector/pgvector.git ~/pgvector_source
cd ~/pgvector_source
make -j$(nproc) OPTFLAGS="" PG_CONFIG="$HOME/agensgraph_build/bin/pg_config"
make install OPTFLAGS="" PG_CONFIG="$HOME/agensgraph_build/bin/pg_config"
- name: Start it
run: |
echo "LD_LIBRARY_PATH=$HOME/agensgraph_build/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV
echo "PATH=$HOME/agensgraph_build/bin:$PATH" >> $GITHUB_ENV
mkdir -p "$HOME/agens_data"
$HOME/agensgraph_build/bin/initdb -D "$HOME/agens_data" -A trust
$HOME/agensgraph_build/bin/ag_ctl start -D "$HOME/agens_data" \
-l "$HOME/agens_data/server.log"
for _ in $(seq 30); do
$HOME/agensgraph_build/bin/pg_isready -q && break
sleep 1
done
$HOME/agensgraph_build/bin/createdb agensgraph_test
# The extension is created per database, so this runs on every build and not only on a cache
# miss. Asserted afterwards for the same reason the DSN is: the vector suite asks the server
# whether the type is there and skips itself when it is not, so an extension that failed to
# install would turn that whole half of the file into a silent pass.
- name: Vectors, in the database the suite uses
run: |
$HOME/agensgraph_build/bin/psql -d agensgraph_test -c "CREATE EXTENSION vector"
found=$($HOME/agensgraph_build/bin/psql -d agensgraph_test -tAc \
"SELECT count(*) FROM pg_type WHERE typname IN ('vector', 'sparsevec')")
test "$found" = "2" || { echo "expected the vector and sparsevec types, found $found"; exit 1; }
$HOME/agensgraph_build/bin/psql -d agensgraph_test -tAc \
"SELECT extname || ' ' || extversion FROM pg_extension WHERE extname = 'vector'"
# Every version gate in the suite reads `agversion`, so a build of the wrong branch would
# test the wrong thing without saying so -- a cache key that collided, or a branch that
# moved. A release branch has to report its own number; `main` may report anything.
- name: Which server this is
run: |
reported=$($HOME/agensgraph_build/bin/psql -d agensgraph_test -tAc \
"SELECT current_setting('agversion')")
echo "branch ${{ matrix.engine }} reports agversion $reported"
wanted=${{ matrix.engine }}
if [ "$wanted" != main ] && [ "${reported#"${wanted#v}"}" = "$reported" ]; then
echo "expected an agversion beginning ${wanted#v}"
exit 1
fi
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Install
run: uv sync --group dev --all-extras
# A test needing a server skips itself when this variable is absent, so a job that lost it
# would report a clean pass over the half of the suite that matters. Reaching the server is
# therefore checked before the suite runs -- an unset variable and an unreachable server
# both stop the job here rather than turning into several hundred quiet skips.
- name: The full suite, against the server
env:
AGENSGRAPH_TEST_DSN: host=localhost dbname=agensgraph_test
run: |
uv run python - <<'EOF'
import os
import agensgraph
with agensgraph.connect(os.environ["AGENSGRAPH_TEST_DSN"]) as conn:
print("reached", conn.capabilities.reported, "with", len(agensgraph.__all__), "names")
EOF
uv run python -X dev -W error -m pytest -q
- name: The server's own log, if anything failed
if: failure()
run: tail -100 "$HOME/agens_data/server.log"