Skip to content

ibrarahmad is running the unit tests. #191

ibrarahmad is running the unit tests.

ibrarahmad is running the unit tests. #191

Workflow file for this run

name: Docker tests
run-name: ${{ github.actor }} is running the unit tests.
on:
push:
branches:
- main
pull_request:
jobs:
run-scripts:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
pgver: [16, 17, 18, 19]
include:
# Spock PG 19 support is merged but not yet released; build Spock
# from this branch for PG 19 and drop the override once a Spock
# release includes it
- pgver: 19
spock_ref: main
runs-on: ${{ matrix.os }}
# Without this a hung tester burns the 6 hour job ceiling on every matrix
# entry, and the run is cancelled rather than failed, which skips the
# diagnostic steps below. Leave room for image build and container startup
# ahead of the 25 minute test wait, so the wait's own deadline is what fires
# and the diagnostics actually run.
timeout-minutes: 60
steps:
- name: Checkout lolor
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ github.ref }}
- name: Add permissions
run: |
sudo chmod -R a+w ${GITHUB_WORKSPACE}
- name: Set up Docker
uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2
- name: Set up docker-compose
uses: docker/setup-compose-action@2fe291b7677a45ee1269ec56a42604c143505e7e # v1
# Resolve the exact source tags on the runner and pass them in as build
# args: the docker layer cache then reuses the compiled PostgreSQL and
# Spock until a new release is tagged.
- name: Resolve PostgreSQL and Spock release tags
id: tags
run: |
PG_TAGS=$(git ls-remote --tags https://github.com/postgres/postgres.git "REL_${{ matrix.pgver }}_*" \
| awk -F/ '{print $NF}' | grep -v '\^{}')
PG_TAG=$(echo "$PG_TAGS" | grep -E "^REL_${{ matrix.pgver }}_[0-9]+$" | sort -t_ -k3,3n | tail -n 1)
# A pre-GA major has no stable minor tag yet: latest RC, else BETA
[ -n "$PG_TAG" ] || PG_TAG=$(echo "$PG_TAGS" | grep -E "^REL_${{ matrix.pgver }}_RC[0-9]+$" | sort -V | tail -n 1)
[ -n "$PG_TAG" ] || PG_TAG=$(echo "$PG_TAGS" | grep -E "^REL_${{ matrix.pgver }}_BETA[0-9]+$" | sort -V | tail -n 1)
if [ -n "${{ matrix.spock_ref }}" ]; then
# Pin the moving branch to its current SHA so the docker layer
# cache is invalidated by every Spock merge
SPOCK_TAG=$(git ls-remote https://github.com/pgEdge/spock.git "refs/heads/${{ matrix.spock_ref }}" | cut -f1)
else
SPOCK_TAG=$(git ls-remote --tags https://github.com/pgEdge/spock.git \
| awk -F/ '{print $NF}' \
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
| sort -V | tail -n 1)
fi
if [ -z "$PG_TAG" ] || [ -z "$SPOCK_TAG" ]; then
echo "::error::Failed to resolve tags (PG_TAG='$PG_TAG', SPOCK_TAG='$SPOCK_TAG')"
exit 1
fi
echo "Using PostgreSQL $PG_TAG and Spock $SPOCK_TAG"
echo "pg_tag=$PG_TAG" >> $GITHUB_OUTPUT
echo "spock_tag=$SPOCK_TAG" >> $GITHUB_OUTPUT
- name: Build node image
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
with:
context: docker
file: docker/Dockerfile.el9
tags: lolor
load: true
build-args: |
PGVER=${{ matrix.pgver }}
PG_TAG=${{ steps.tags.outputs.pg_tag }}
SPOCK_TAG=${{ steps.tags.outputs.spock_tag }}
cache-from: type=gha,scope=pg${{ matrix.pgver }}
cache-to: type=gha,mode=max,scope=pg${{ matrix.pgver }}
- name: Build tester image
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
with:
context: docker
file: docker/Dockerfile.tester
tags: lolor-tester
load: true
cache-from: type=gha,scope=tester
cache-to: type=gha,scope=tester
- name: Run docker images
run: |
cd docker
echo PG_VER=${{ matrix.pgver }} >> pgedge.env
docker compose up -d
env:
PG_VER: ${{ matrix.pgver }}
- name: Dump container logs on failure
if: failure()
run: |
cd docker
docker compose logs --no-color || true
for c in n1 n2 n3 tester; do
echo "===== $c ====="
docker logs "$c" 2>&1 || true
done
- name: Wait for tests to complete
id: test_step
continue-on-error: true
run: |
# Cap the wait so a test blocked on a lock or on sub_wait_for_sync()
# fails the step while the cluster is still up to be inspected.
deadline=$(( SECONDS + 25 * 60 ))
while [ "$(docker inspect -f '{{.State.Running}}' tester)" == "true" ]; do
if [ "$SECONDS" -ge "$deadline" ]; then
echo "::error::Tests did not finish within 25 minutes; dumping cluster state"
# These run precisely because the cluster is wedged, so bound each
# one: "|| true" catches a bad exit status but not a hang, and a
# blocked query here would burn the job timeout and skip the
# failure-log step below.
PGV=${{ matrix.pgver }}
echo "===== tester output so far ====="
tail -n 200 tests/out.txt || true
for n in n1 n2 n3; do
echo "===== $n: sessions and what they are waiting on ====="
timeout --kill-after=5s 20s docker exec "$n" bash -c "source /home/pgedge/pgedge/pg${PGV}/pg${PGV}.env && psql -U admin -d demo -x -c \"
SELECT pid, state, wait_event_type, wait_event, now() - xact_start AS xact_age,
left(query, 400) AS query
FROM pg_stat_activity
WHERE datname = 'demo' AND pid <> pg_backend_pid()
ORDER BY xact_start\"" || true
echo "===== $n: ungranted locks ====="
timeout --kill-after=5s 20s docker exec "$n" bash -c "source /home/pgedge/pgedge/pg${PGV}/pg${PGV}.env && psql -U admin -d demo -c \"
SELECT l.pid, l.locktype, l.mode, l.granted,
coalesce(c.relname, l.classid::text) AS object
FROM pg_locks l LEFT JOIN pg_class c ON c.oid = l.relation
WHERE NOT l.granted OR l.mode LIKE 'Share%' OR l.mode LIKE '%Exclusive%'
ORDER BY l.granted, l.pid\"" || true
echo "===== $n: subscription status ====="
timeout --kill-after=5s 20s docker exec "$n" bash -c "source /home/pgedge/pgedge/pg${PGV}/pg${PGV}.env && psql -U admin -d demo -c 'SELECT * FROM spock.sub_show_status()'" || true
done
exit 1
fi
echo "Waiting for tests to complete..."
sleep 1
done
docker logs n1
docker logs n2
docker logs n3
# grep exits 2 when the file is missing, which "|| exit 0" would turn
# into a pass: a tester that died before writing anything would look
# green. Check for output first, then for failures in it.
if [ ! -s tests/out.txt ]; then
echo "::error::tests/out.txt is missing or empty; the tester produced no output"
exit 1
fi
if grep -Eq "FAIL|ERROR" tests/out.txt; then
exit 1
fi
- name: Dump container logs when the tests failed
if: steps.test_step.outcome == 'failure'
run: |
cd docker
for c in n1 n2 n3 tester; do
echo "===== $c ====="
docker logs "$c" > /tmp/$c.log 2>&1 || true
echo "--- first 120 lines (setup) ---"; head -n 120 /tmp/$c.log || true
echo "--- last 120 lines ---"; tail -n 120 /tmp/$c.log || true
done
- name: Upload Log File as Artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: latest-log-${{ matrix.pgver }}
path: tests/out.txt
if: always()
- name: Fail the Job if tests failed
if: steps.test_step.outcome == 'failure'
run: exit 1