Skip to content

fix: respect CoMasterRecoveryMustPromoteOtherCoMaster=false when co-m… #165

fix: respect CoMasterRecoveryMustPromoteOtherCoMaster=false when co-m…

fix: respect CoMasterRecoveryMustPromoteOtherCoMaster=false when co-m… #165

Workflow file for this run

name: Functional Tests
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25.7'
cache: true
- name: Build orchestrator
run: go build -o bin/orchestrator ./go/cmd/orchestrator
- name: Upload orchestrator binary
uses: actions/upload-artifact@v4
with:
name: orchestrator-binary
path: bin/orchestrator
retention-days: 1
functional-mysql:
runs-on: ubuntu-latest
timeout-minutes: 30
needs: build
strategy:
fail-fast: false
matrix:
mysql_version: ['5.7', '8.0', '8.4', '9.6', '9.7']
steps:
- uses: actions/checkout@v4
- name: Download orchestrator binary
uses: actions/download-artifact@v4
with:
name: orchestrator-binary
path: bin
- name: Make binary executable
run: chmod +x bin/orchestrator
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build orchestrator runtime image
uses: docker/build-push-action@v6
with:
context: tests/functional
file: tests/functional/orchestrator-runtime.Dockerfile
tags: orchestrator-runtime:latest
load: true
cache-from: type=gha,scope=orchestrator-runtime
cache-to: type=gha,mode=max,scope=orchestrator-runtime
- name: Start test infrastructure (MySQL + ProxySQL)
working-directory: tests/functional
env:
MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
run: |
echo "Using MySQL image: $MYSQL_IMAGE"
docker compose up -d mysql1 mysql2 mysql3 proxysql
echo "Waiting for MySQL and ProxySQL to be healthy..."
timeout 120 bash -c '
while true; do
HEALTHY=$(docker compose ps --format json 2>/dev/null | python3 -c "
import json, sys
healthy = 0
for line in sys.stdin:
svc = json.loads(line)
if \"healthy\" in svc.get(\"Status\",\"\").lower():
healthy += 1
print(healthy)
" 2>/dev/null || echo "0")
if [ "$HEALTHY" -ge 4 ]; then
echo "All 4 services healthy"
exit 0
fi
sleep 2
done
' || { echo "Timeout"; docker compose ps; docker compose logs --tail=30; exit 1; }
- name: Setup replication
env:
MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
run: bash tests/functional/setup-replication.sh
- name: Start orchestrator in Docker network
working-directory: tests/functional
env:
MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
run: |
docker compose up -d orchestrator
echo "Waiting for orchestrator to be ready..."
timeout 120 bash -c '
while true; do
if curl -sf http://localhost:3099/api/clusters > /dev/null 2>&1; then
echo "Orchestrator ready"
exit 0
fi
sleep 2
done
' || { echo "Orchestrator not ready"; docker compose logs orchestrator --tail=50; exit 1; }
- name: Run smoke tests
run: bash tests/functional/test-smoke.sh
- name: Run topology discovery validation
run: bash tests/functional/test-topology-discovery.sh
- name: Run problem detection tests
run: bash tests/functional/test-problem-detection.sh
- name: Run topology operations tests
run: bash tests/functional/test-topology-operations.sh
- name: Run regression tests
run: bash tests/functional/test-regression.sh
- name: Run failover tests
run: bash tests/functional/test-failover.sh
- name: Run advanced failover tests
run: bash tests/functional/test-failover-advanced.sh
- name: Run named channels tests
run: bash tests/functional/test-named-channels.sh
# Last: mutates topology (stops mysql1). Keep after other suites.
- name: Run relay drain / SQL-stopped failover tests
env:
MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
run: bash tests/functional/test-mariadb-relay-drain.sh
- name: Collect orchestrator logs
if: always()
working-directory: tests/functional
env:
MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
run: |
docker compose logs orchestrator > /tmp/orchestrator-test.log 2>&1 || true
- name: Upload orchestrator logs
if: always()
uses: actions/upload-artifact@v4
with:
name: orchestrator-test-logs-mysql-${{ matrix.mysql_version }}
path: /tmp/orchestrator-test.log
- name: Collect all docker logs on failure
if: failure()
working-directory: tests/functional
env:
MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
run: docker compose logs > /tmp/docker-compose-logs.txt 2>&1 || true
- name: Upload docker logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: docker-compose-logs-mysql-${{ matrix.mysql_version }}
path: /tmp/docker-compose-logs.txt
- name: Cleanup
if: always()
working-directory: tests/functional
env:
MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
run: docker compose down -v --remove-orphans 2>/dev/null || true
functional-mariadb:
runs-on: ubuntu-latest
timeout-minutes: 30
needs: build
strategy:
fail-fast: false
matrix:
mariadb_version: ['10.6', '10.11']
steps:
- uses: actions/checkout@v4
- name: Download orchestrator binary
uses: actions/download-artifact@v4
with:
name: orchestrator-binary
path: bin
- name: Make binary executable
run: chmod +x bin/orchestrator
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build orchestrator runtime image
uses: docker/build-push-action@v6
with:
context: tests/functional
file: tests/functional/orchestrator-runtime.Dockerfile
tags: orchestrator-runtime:latest
load: true
cache-from: type=gha,scope=orchestrator-runtime
cache-to: type=gha,mode=max,scope=orchestrator-runtime
- name: Start test infrastructure (MariaDB + ProxySQL)
working-directory: tests/functional
env:
MYSQL_IMAGE: mariadb:${{ matrix.mariadb_version }}
run: |
echo "Using MariaDB image: $MYSQL_IMAGE"
docker compose -f docker-compose.yml -f docker-compose.mariadb.yml up -d mysql1 mysql2 mysql3 proxysql
echo "Waiting for MariaDB and ProxySQL to be healthy..."
timeout 120 bash -c '
while true; do
HEALTHY=$(docker compose -f docker-compose.yml -f docker-compose.mariadb.yml ps --format json 2>/dev/null | python3 -c "
import json, sys
healthy = 0
for line in sys.stdin:
svc = json.loads(line)
if \"healthy\" in svc.get(\"Status\",\"\").lower():
healthy += 1
print(healthy)
" 2>/dev/null || echo "0")
if [ "$HEALTHY" -ge 4 ]; then
echo "All 4 services healthy"
exit 0
fi
sleep 2
done
' || { echo "Timeout"; docker compose -f docker-compose.yml -f docker-compose.mariadb.yml ps; docker compose -f docker-compose.yml -f docker-compose.mariadb.yml logs --tail=30; exit 1; }
- name: Setup replication
env:
MYSQL_IMAGE: mariadb:${{ matrix.mariadb_version }}
COMPOSE: docker compose -f tests/functional/docker-compose.yml -f tests/functional/docker-compose.mariadb.yml
run: bash tests/functional/setup-replication.sh
- name: Start orchestrator in Docker network
working-directory: tests/functional
env:
MYSQL_IMAGE: mariadb:${{ matrix.mariadb_version }}
run: |
docker compose -f docker-compose.yml -f docker-compose.mariadb.yml up -d orchestrator
echo "Waiting for orchestrator to be ready..."
timeout 120 bash -c '
while true; do
if curl -sf http://localhost:3099/api/clusters > /dev/null 2>&1; then
echo "Orchestrator ready"
exit 0
fi
sleep 2
done
' || { echo "Orchestrator not ready"; docker compose -f docker-compose.yml -f docker-compose.mariadb.yml logs orchestrator --tail=50; exit 1; }
- name: Run smoke tests
env:
MYSQL_IMAGE: mariadb:${{ matrix.mariadb_version }}
COMPOSE: docker compose -f tests/functional/docker-compose.yml -f tests/functional/docker-compose.mariadb.yml
run: bash tests/functional/test-smoke.sh
- name: Run relay drain / SQL-stopped failover tests
env:
MYSQL_IMAGE: mariadb:${{ matrix.mariadb_version }}
COMPOSE: docker compose -f tests/functional/docker-compose.yml -f tests/functional/docker-compose.mariadb.yml
run: bash tests/functional/test-mariadb-relay-drain.sh
- name: Collect orchestrator logs
if: always()
working-directory: tests/functional
env:
MYSQL_IMAGE: mariadb:${{ matrix.mariadb_version }}
run: |
docker compose -f docker-compose.yml -f docker-compose.mariadb.yml logs orchestrator > /tmp/orchestrator-mariadb-test.log 2>&1 || true
- name: Upload orchestrator logs
if: always()
uses: actions/upload-artifact@v4
with:
name: orchestrator-test-logs-mariadb-${{ matrix.mariadb_version }}
path: /tmp/orchestrator-mariadb-test.log
- name: Cleanup
if: always()
working-directory: tests/functional
env:
MYSQL_IMAGE: mariadb:${{ matrix.mariadb_version }}
run: docker compose -f docker-compose.yml -f docker-compose.mariadb.yml down -v --remove-orphans 2>/dev/null || true
functional-postgresql:
runs-on: ubuntu-latest
timeout-minutes: 30
needs: build
strategy:
fail-fast: false
matrix:
pg_version: ['15', '16', '17']
steps:
- uses: actions/checkout@v4
- name: Download orchestrator binary
uses: actions/download-artifact@v4
with:
name: orchestrator-binary
path: bin
- name: Make binary executable
run: chmod +x bin/orchestrator
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build orchestrator runtime image
uses: docker/build-push-action@v6
with:
context: tests/functional
file: tests/functional/orchestrator-runtime.Dockerfile
tags: orchestrator-runtime:latest
load: true
cache-from: type=gha,scope=orchestrator-runtime
cache-to: type=gha,mode=max,scope=orchestrator-runtime
- name: Start PostgreSQL containers
working-directory: tests/functional
env:
PG_IMAGE: postgres:${{ matrix.pg_version }}
run: |
echo "Using PostgreSQL image: $PG_IMAGE"
docker compose up -d pgprimary
echo "Waiting for pgprimary to be healthy..."
timeout 120 bash -c '
while true; do
STATUS=$(docker compose ps pgprimary --format json 2>/dev/null | python3 -c "
import json, sys
for line in sys.stdin:
svc = json.loads(line)
if \"healthy\" in svc.get(\"Status\",\"\").lower():
print(\"healthy\")
sys.exit(0)
print(\"waiting\")
" 2>/dev/null || echo "waiting")
if [ "$STATUS" = "healthy" ]; then
echo "pgprimary healthy"
exit 0
fi
sleep 2
done
' || { echo "Timeout waiting for pgprimary"; docker compose logs pgprimary --tail=30; exit 1; }
docker compose up -d pgstandby1
echo "Waiting for pgstandby1 to be healthy..."
timeout 120 bash -c '
while true; do
STATUS=$(docker compose ps pgstandby1 --format json 2>/dev/null | python3 -c "
import json, sys
for line in sys.stdin:
svc = json.loads(line)
if \"healthy\" in svc.get(\"Status\",\"\").lower():
print(\"healthy\")
sys.exit(0)
print(\"waiting\")
" 2>/dev/null || echo "waiting")
if [ "$STATUS" = "healthy" ]; then
echo "pgstandby1 healthy"
exit 0
fi
sleep 2
done
' || { echo "Timeout waiting for pgstandby1"; docker compose logs pgstandby1 --tail=30; exit 1; }
- name: Start PostgreSQL orchestrator
working-directory: tests/functional
env:
PG_IMAGE: postgres:${{ matrix.pg_version }}
run: |
docker compose up -d orchestrator-pg
echo "Waiting for PostgreSQL orchestrator to be ready..."
timeout 120 bash -c '
while true; do
if curl -sf http://localhost:3098/api/clusters > /dev/null 2>&1; then
echo "PostgreSQL orchestrator ready"
exit 0
fi
sleep 2
done
' || { echo "PostgreSQL orchestrator not ready"; docker compose logs orchestrator-pg --tail=50; exit 1; }
- name: Run PostgreSQL tests
run: bash tests/functional/test-postgresql.sh
- name: Collect orchestrator logs
if: always()
working-directory: tests/functional
env:
PG_IMAGE: postgres:${{ matrix.pg_version }}
run: |
docker compose logs orchestrator-pg > /tmp/orchestrator-pg-test.log 2>&1 || true
- name: Upload orchestrator logs
if: always()
uses: actions/upload-artifact@v4
with:
name: orchestrator-test-logs-pg-${{ matrix.pg_version }}
path: /tmp/orchestrator-pg-test.log
- name: Collect all docker logs on failure
if: failure()
working-directory: tests/functional
env:
PG_IMAGE: postgres:${{ matrix.pg_version }}
run: docker compose logs > /tmp/docker-compose-logs.txt 2>&1 || true
- name: Upload docker logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: docker-compose-logs-pg-${{ matrix.pg_version }}
path: /tmp/docker-compose-logs.txt
- name: Cleanup
if: always()
working-directory: tests/functional
env:
PG_IMAGE: postgres:${{ matrix.pg_version }}
run: docker compose down -v --remove-orphans 2>/dev/null || true
functional-raft:
runs-on: ubuntu-latest
timeout-minutes: 30
needs: build
steps:
- uses: actions/checkout@v4
- name: Download orchestrator binary
uses: actions/download-artifact@v4
with:
name: orchestrator-binary
path: bin
- name: Make binary executable
run: chmod +x bin/orchestrator
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build orchestrator runtime image
uses: docker/build-push-action@v6
with:
context: tests/functional
file: tests/functional/orchestrator-runtime.Dockerfile
tags: orchestrator-runtime:latest
load: true
cache-from: type=gha,scope=orchestrator-runtime
cache-to: type=gha,mode=max,scope=orchestrator-runtime
- name: Start MySQL infrastructure
working-directory: tests/functional
run: |
docker compose up -d mysql1 mysql2 mysql3
echo "Waiting for MySQL to be healthy..."
timeout 120 bash -c '
while true; do
HEALTHY=$(docker compose ps --format json 2>/dev/null | python3 -c "
import json, sys
healthy = 0
for line in sys.stdin:
svc = json.loads(line)
if \"healthy\" in svc.get(\"Status\",\"\").lower():
healthy += 1
print(healthy)
" 2>/dev/null || echo "0")
if [ "$HEALTHY" -ge 3 ]; then
echo "All 3 MySQL services healthy"
exit 0
fi
sleep 2
done
' || { echo "Timeout"; docker compose ps; docker compose logs --tail=30; exit 1; }
- name: Setup replication
run: bash tests/functional/setup-replication.sh
- name: Run Raft consensus tests
run: bash tests/functional/test-raft.sh
- name: Collect Raft orchestrator logs
if: always()
working-directory: tests/functional
run: |
docker compose logs orchestrator-raft1 > /tmp/orchestrator-raft1.log 2>&1 || true
docker compose logs orchestrator-raft2 > /tmp/orchestrator-raft2.log 2>&1 || true
docker compose logs orchestrator-raft3 > /tmp/orchestrator-raft3.log 2>&1 || true
- name: Upload Raft orchestrator logs
if: always()
uses: actions/upload-artifact@v4
with:
name: orchestrator-raft-logs
path: |
/tmp/orchestrator-raft1.log
/tmp/orchestrator-raft2.log
/tmp/orchestrator-raft3.log
- name: Collect all docker logs on failure
if: failure()
working-directory: tests/functional
run: docker compose logs > /tmp/docker-compose-raft-logs.txt 2>&1 || true
- name: Upload docker logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: docker-compose-raft-logs
path: /tmp/docker-compose-raft-logs.txt
- name: Cleanup
if: always()
working-directory: tests/functional
run: docker compose down -v --remove-orphans 2>/dev/null || true