fix: respect CoMasterRecoveryMustPromoteOtherCoMaster=false when co-m… #165
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |