Skip to content

Commit 67db28b

Browse files
authored
generate coverage + codecov (#504)
* generate coverage + codecov * test arguments * correct token * coverage in integration? * integration coverage fixes * merge down to a single test run instead of test + coverage separately * integration troubleshooting * ensure cov generation uses --release * remove redundant build * explicit checks for coverage changes and manually kill pgdog before coverage run * try stopping between sub-suites * debug output in verify profiles * pour on the debug logging * further debugging * path bug * search anywhere for profiles * whee! * fail to bail when profiles havent changed * add a new test to produce a diff * add bigint binary test for more coverage there (just to check coverage is working) * add codecov config, basic test for arrays
1 parent 5ca5d65 commit 67db28b

File tree

8 files changed

+364
-31
lines changed

8 files changed

+364
-31
lines changed

.github/codecov.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
codecov:
2+
notify:
3+
wait_for_ci: true
4+
after_n_builds: 1
5+
require_ci_to_pass: true
6+
disable_default_path_fixes: false
7+
8+
comment:
9+
layout: "reach,diff,flags,tree"
10+
behavior: default
11+
require_changes: true
12+
show_carryforward_flags: true
13+
14+
coverage:
15+
precision: 2
16+
round: down
17+
range: 60..90
18+
status:
19+
project:
20+
default:
21+
informational: true
22+
target: auto
23+
threshold: 1
24+
base: auto
25+
patch:
26+
default:
27+
informational: true
28+
target: 80
29+
threshold: 5
30+
base: auto
31+
changes: false
32+
33+
flags:
34+
unit:
35+
paths:
36+
- pgdog
37+
carryforward: true
38+
integration:
39+
paths:
40+
- integration
41+
carryforward: false
42+
43+
ignore:
44+
- "**/tests/**"
45+
- "**/examples/**"
46+
- integration/python/venv
47+
48+
slack_app: true

.github/workflows/ci.yml

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ jobs:
4848
with:
4949
toolchain: stable
5050
override: true
51+
components: llvm-tools-preview
5152
- uses: useblacksmith/rust-cache@v3
5253
with:
5354
prefix-key: "v1" # Change this when updating tooling
@@ -68,18 +69,35 @@ jobs:
6869
bash integration/toxi/setup.sh
6970
- name: Install test dependencies
7071
run: cargo install cargo-nextest --version "0.9.78" --locked
71-
- name: Run tests
72-
run: cargo nextest run -E 'package(pgdog)' --no-fail-fast --test-threads=1
72+
- name: Install coverage tooling
73+
run: cargo install cargo-llvm-cov --locked --version "0.6.10"
74+
- name: Run tests with coverage
75+
env:
76+
RUSTFLAGS: "-C link-dead-code"
77+
run: |
78+
cargo llvm-cov clean --workspace
79+
cargo llvm-cov nextest --lcov --output-path lcov.info --no-fail-fast --test-threads=1 --filter-expr "package(pgdog)"
7380
- name: Run documentation tests
7481
run: cargo test --doc
82+
# Requires CODECOV_TOKEN secret for upload
83+
- uses: codecov/codecov-action@v4
84+
env:
85+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
86+
with:
87+
files: lcov.info
88+
flags: unit
89+
fail_ci_if_error: true
7590
integration:
7691
runs-on: blacksmith-4vcpu-ubuntu-2404
92+
env:
93+
LLVM_PROFILE_FILE: ${{ github.workspace }}/target/llvm-cov-target/profiles/pgdog-%p-%m.profraw
7794
steps:
7895
- uses: actions/checkout@v4
7996
- uses: actions-rs/toolchain@v1
8097
with:
8198
toolchain: stable
8299
override: true
100+
components: llvm-tools-preview
83101
- uses: useblacksmith/rust-cache@v3
84102
with:
85103
prefix-key: release-1
@@ -101,29 +119,82 @@ jobs:
101119
bash integration/toxi/setup.sh
102120
sudo curl -SL https://github.com/docker/compose/releases/download/v2.36.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
103121
sudo chmod +x /usr/local/bin/docker-compose
104-
- name: Build PgDog
105-
run: cargo build --release
122+
- name: Install coverage tooling
123+
run: cargo install cargo-llvm-cov --locked --version "0.6.10"
124+
- name: Prepare instrumented PgDog build
125+
env:
126+
RUSTFLAGS: "-C link-dead-code"
127+
run: |
128+
cargo llvm-cov clean --workspace
129+
mkdir -p target/llvm-cov-target/profiles
130+
cargo llvm-cov run --no-report --release --package pgdog --bin pgdog -- --help
131+
rm -f target/llvm-cov-target/profiles/*.profraw
132+
rm -f target/llvm-cov-target/profiles/.last_snapshot
133+
rm -rf target/llvm-cov-target/reports
134+
BIN_PATH=$(find target/llvm-cov-target -type f -path '*/release/pgdog' | head -n 1)
135+
if [ -z "$BIN_PATH" ]; then
136+
echo "Instrumented PgDog binary not found" >&2
137+
exit 1
138+
fi
139+
echo "Using instrumented binary at $BIN_PATH"
140+
echo "PGDOG_BIN=$(realpath "$BIN_PATH")" >> "$GITHUB_ENV"
106141
- name: Load balancer
107142
run: bash integration/load_balancer/run.sh
108143
- name: pgbench
109144
run: bash integration/pgbench/run.sh
145+
- name: Verify coverage (pgbench)
146+
run: bash integration/verify_profiles.sh pgbench
110147
- name: Go
111148
run: bash integration/go/run.sh
149+
- name: Verify coverage (go)
150+
run: bash integration/verify_profiles.sh go
112151
- name: JavaScript
113152
run: bash integration/js/pg_tests/run.sh
153+
- name: Verify coverage (javascript)
154+
run: bash integration/verify_profiles.sh javascript
114155
- name: Toxi
115156
run: bash integration/toxi/run.sh
157+
- name: Verify coverage (toxi)
158+
run: bash integration/verify_profiles.sh toxi
116159
- name: Python
117160
run: bash integration/python/run.sh
161+
- name: Verify coverage (python)
162+
run: bash integration/verify_profiles.sh python
118163
- name: Ruby
119164
run: bash integration/ruby/run.sh
165+
- name: Verify coverage (ruby)
166+
run: bash integration/verify_profiles.sh ruby
120167
- name: Java
121168
run: bash integration/java/run.sh
169+
- name: Verify coverage (java)
170+
run: bash integration/verify_profiles.sh java
122171
- name: More complex stuff
123172
run: bash integration/complex/run.sh
173+
- name: Verify coverage (complex)
174+
run: bash integration/verify_profiles.sh complex
124175
- name: Rust
125176
run: bash integration/rust/run.sh
177+
- name: Verify coverage (rust)
178+
run: bash integration/verify_profiles.sh rust
126179
- name: Dry run
127180
run: bash integration/dry_run/run.sh
181+
- name: Verify coverage (dry_run)
182+
run: bash integration/verify_profiles.sh dry_run
128183
# - name: Plugins
129184
# run: bash integration/plugins/run.sh
185+
- name: Ensure PgDog stopped
186+
run: |
187+
if pgrep -x pgdog > /dev/null; then
188+
killall -TERM pgdog
189+
sleep 5
190+
fi
191+
- name: Generate integration coverage report
192+
run: cargo llvm-cov report --release --package pgdog --lcov --output-path integration.lcov
193+
# Requires CODECOV_TOKEN secret for upload
194+
- uses: codecov/codecov-action@v4
195+
env:
196+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
197+
with:
198+
files: integration.lcov
199+
flags: integration
200+
fail_ci_if_error: true

integration/common.sh

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,77 @@ function wait_for_pgdog() {
1616
function run_pgdog() {
1717
# We expect all test scripts to define $SCRIPT_DIR.
1818
pushd ${COMMON_DIR}/../
19-
# Testing in release is faster
20-
# and a more reliable test of what happens
21-
# in prod.
22-
cargo build --release
2319
local config_path=${1:-"integration"}
24-
target/release/pgdog \
20+
local binary="${PGDOG_BIN:-}"
21+
local pid_file="${COMMON_DIR}/pgdog.pid"
22+
local config_file="${COMMON_DIR}/pgdog.config"
23+
if [ -z "${binary}" ]; then
24+
# Testing in release is faster and mirrors production.
25+
cargo build --release
26+
binary="target/release/pgdog"
27+
fi
28+
if [ -f "${pid_file}" ]; then
29+
local existing_pid=$(cat "${pid_file}")
30+
if [ -n "${existing_pid}" ] && kill -0 "${existing_pid}" 2> /dev/null; then
31+
local existing_config=""
32+
if [ -f "${config_file}" ]; then
33+
existing_config=$(cat "${config_file}")
34+
fi
35+
if [ "${existing_config}" = "${config_path}" ]; then
36+
popd
37+
return
38+
fi
39+
stop_pgdog
40+
fi
41+
fi
42+
echo "Launching PgDog binary '${binary}' with config path '${config_path}'"
43+
"${binary}" \
2544
--config ${config_path}/pgdog.toml \
2645
--users ${config_path}/users.toml \
2746
> ${COMMON_DIR}/log.txt &
47+
echo $! > "${pid_file}"
48+
printf '%s\n' "${config_path}" > "${config_file}"
49+
if [ -z "${PGDOG_STOP_TRAP:-}" ]; then
50+
trap stop_pgdog EXIT
51+
export PGDOG_STOP_TRAP=1
52+
fi
2853
popd
2954
}
3055

3156
function stop_pgdog() {
32-
killall -TERM pgdog 2> /dev/null || true
33-
cat ${COMMON_DIR}/log.txt
34-
rm ${COMMON_DIR}/log.txt
57+
local pid_file="${COMMON_DIR}/pgdog.pid"
58+
local config_file="${COMMON_DIR}/pgdog.config"
59+
if [ -f "${pid_file}" ]; then
60+
local pid=$(cat "${pid_file}")
61+
if [ -n "${pid}" ] && kill -0 "${pid}" 2> /dev/null; then
62+
kill -TERM "${pid}" 2> /dev/null || true
63+
local waited=0
64+
while kill -0 "${pid}" 2> /dev/null && [ ${waited} -lt 30 ]; do
65+
sleep 1
66+
waited=$((waited + 1))
67+
done
68+
if kill -0 "${pid}" 2> /dev/null; then
69+
kill -KILL "${pid}" 2> /dev/null || true
70+
fi
71+
fi
72+
rm -f "${pid_file}"
73+
else
74+
killall -TERM pgdog 2> /dev/null || true
75+
local waited=0
76+
while pgrep -x pgdog > /dev/null && [ ${waited} -lt 30 ]; do
77+
sleep 1
78+
waited=$((waited + 1))
79+
done
80+
fi
81+
sleep 1
82+
if [ -f "${config_file}" ]; then
83+
# Keep the config file so we can restart with the same arguments later.
84+
:
85+
fi
86+
if [ -f ${COMMON_DIR}/log.txt ]; then
87+
cat ${COMMON_DIR}/log.txt
88+
rm ${COMMON_DIR}/log.txt
89+
fi
3590
}
3691

3792
function start_toxi() {

integration/complex/passthrough_auth/run.sh

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@ export PGHOST=127.0.0.1
77

88
killall -TERM pgdog 2> /dev/null || true
99

10-
${SCRIPT_DIR}/../../../target/release/pgdog \
10+
PGDOG_BIN_PATH="${PGDOG_BIN:-${SCRIPT_DIR}/../../../target/release/pgdog}"
11+
12+
"${PGDOG_BIN_PATH}" \
1113
--config ${SCRIPT_DIR}/pgdog-enabled.toml \
1214
--users ${SCRIPT_DIR}/users.toml &
13-
sleep 1
15+
16+
until pg_isready -h 127.0.0.1 -p 6432 -U pgdog -d pgdog; do
17+
sleep 1
18+
done
1419

1520
if ! psql -U pgdog1 pgdog -c 'SELECT 1' > /dev/null; then
1621
echo "AutoDB not working"
@@ -28,10 +33,13 @@ fi
2833

2934
killall -TERM pgdog
3035

31-
${SCRIPT_DIR}/../../../target/release/pgdog \
36+
"${PGDOG_BIN_PATH}" \
3237
--config ${SCRIPT_DIR}/pgdog-disabled.toml \
3338
--users ${SCRIPT_DIR}/users.toml &
34-
sleep 1
39+
40+
until pg_isready -h 127.0.0.1 -p 6432 -U pgdog -d pgdog; do
41+
sleep 1
42+
done
3543

3644
if psql -U pgdog1 pgdog -c 'SELECT 1' 2> /dev/null; then
3745
echo "AutoDB should be disabled"

integration/load_balancer/run.sh

100644100755
Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,29 @@
11
#!/bin/bash
2-
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
32
set -e
3+
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
4+
source ${SCRIPT_DIR}/../common.sh
45

56
pushd ${SCRIPT_DIR}
67

78
export PGUSER=postgres
8-
99
export PGHOST=127.0.0.1
1010
export PGDATABASE=postgres
1111
export PGPASSWORD=postgres
1212

13-
docker-compose up -d
13+
echo "[load_balancer] Using PGDOG_BIN=${PGDOG_BIN}"
14+
echo "[load_balancer] LLVM_PROFILE_FILE=${LLVM_PROFILE_FILE}"
1415

16+
docker-compose up -d
1517

1618
echo "Waiting for Postgres to be ready"
17-
1819
for p in 45000 45001 45002; do
1920
export PGPORT=${p}
2021
while ! pg_isready; do
2122
sleep 1
2223
done
2324
done
2425

25-
26-
pushd ${SCRIPT_DIR}/../../
27-
cargo build --release
28-
popd
29-
30-
sleep 2
31-
32-
cargo run --release -- \
33-
--config ${SCRIPT_DIR}/pgdog.toml \
34-
--users ${SCRIPT_DIR}/users.toml &
26+
run_pgdog ${SCRIPT_DIR}
3527

3628
export PGPORT=6432
3729
while ! pg_isready; do
@@ -43,6 +35,9 @@ go get
4335
go test -v -count 3
4436
popd
4537

46-
killall pgdog
38+
stop_pgdog
39+
40+
PGDOG_NO_RESTART=1 bash ${SCRIPT_DIR}/../verify_profiles.sh load_balancer
4741

4842
docker-compose down
43+
popd

integration/python/test_asyncpg.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,32 @@ async def test_insert_allshard(conns):
138138
no_out_of_sync()
139139

140140

141+
@pytest.mark.asyncio
142+
async def test_bigint_binary(conns):
143+
big_value = 1 << 62
144+
for conn in conns:
145+
await conn.execute("DROP TABLE IF EXISTS binary_bigint")
146+
await conn.execute("CREATE TABLE binary_bigint (id BIGINT)")
147+
await conn.execute("INSERT INTO binary_bigint (id) VALUES($1)", big_value)
148+
row = await conn.fetchrow("SELECT id FROM binary_bigint")
149+
assert row["id"] == big_value
150+
await conn.execute("DROP TABLE binary_bigint")
151+
no_out_of_sync()
152+
153+
154+
@pytest.mark.asyncio
155+
async def test_int_array_binary(conns):
156+
values = [1, 2, 3]
157+
for conn in conns:
158+
await conn.execute("DROP TABLE IF EXISTS binary_array")
159+
await conn.execute("CREATE TABLE binary_array (vals INT[])")
160+
await conn.execute("INSERT INTO binary_array (vals) VALUES($1)", values)
161+
row = await conn.fetchrow("SELECT vals FROM binary_array")
162+
assert row["vals"] == values
163+
await conn.execute("DROP TABLE binary_array")
164+
no_out_of_sync()
165+
166+
141167
@pytest.mark.asyncio
142168
async def test_direct_shard(conns):
143169
conn = conns[1]

0 commit comments

Comments
 (0)