Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions .github/workflows/functional.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Functional Tests

on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:

jobs:
functional:
runs-on: ubuntu-latest
timeout-minutes: 20

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 (for CLI tests on host)
run: go build -o bin/orchestrator ./go/cmd/orchestrator

- name: Start test infrastructure (MySQL + ProxySQL + Orchestrator)
working-directory: tests/functional
run: |
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
run: bash tests/functional/setup-replication.sh

- name: Start orchestrator in Docker network
working-directory: tests/functional
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 regression tests
run: bash tests/functional/test-regression.sh

- name: Run failover tests
run: bash tests/functional/test-failover.sh

- name: Collect orchestrator logs
if: always()
working-directory: tests/functional
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
path: /tmp/orchestrator-test.log

- name: Collect all docker logs on failure
if: failure()
working-directory: tests/functional
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
path: /tmp/docker-compose-logs.txt

- name: Cleanup
if: always()
working-directory: tests/functional
run: docker compose down -v --remove-orphans 2>/dev/null || true
127 changes: 127 additions & 0 deletions tests/functional/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
version: "3.8"

services:
mysql1:
image: mysql:8.4
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Declared images:"
rg -n '^\s*image:\s*' tests/functional/docker-compose.yml

echo
echo "Floating tags detected (latest or major.minor only):"
rg -nP 'image:\s*\S+:(latest|\d+\.\d+)$' tests/functional/docker-compose.yml || true

Repository: ProxySQL/orchestrator

Length of output: 355


Pin container images to immutable versions (ideally digest-pinned).

Floating tags (mysql:8.4 and proxysql/proxysql:latest) make the functional test suite non-reproducible and vulnerable to upstream image drift. Each pull of the image may yield different contents, causing tests to break without code changes.

Apply to lines 5, 21, 40 (all mysql:8.4), and line 59 (proxysql/proxysql:latest).

🔧 Proposed fix
- image: mysql:8.4
+ image: mysql:8.4.x@sha256:<digest>

- image: proxysql/proxysql:latest
+ image: proxysql/proxysql:<stable-version>@sha256:<digest>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/docker-compose.yml` at line 5, Replace floating image tags
in the docker-compose.yml to pin images to immutable versions: locate the image
entries "mysql:8.4" (appearing at the three occurrences) and
"proxysql/proxysql:latest" and update them to digest-pinned image references
(e.g., mysql@sha256:<digest> and proxysql/proxysql@sha256:<digest>) or a
specific immutable version tag; fetch the appropriate digests from the upstream
registries (Docker Hub or the image provider) and substitute them so the
functional test suite uses fixed, reproducible images.

hostname: mysql1
environment:
MYSQL_ROOT_PASSWORD: testpass
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Hardcoded credentials are used here and throughout the new test files. While this is a test environment, it's a security risk and a bad practice that could be copied elsewhere. Consider using environment variables to manage secrets. You can define them in a .env file (which should be added to .gitignore) and Docker Compose will automatically pick them up. This would centralize credential management and improve security hygiene.

This issue is also present in:

  • tests/functional/docker-compose.yml (lines 13, 24, 32, 43, 51, 71)
  • tests/functional/mysql/init-master.sql
  • tests/functional/mysql/init-replica.sql
  • tests/functional/orchestrator-test.conf.json
  • tests/functional/proxysql/proxysql.cnf
  • tests/functional/run-all.sh
  • tests/functional/test-failover.sh
  • tests/functional/lib.sh

Comment on lines +4 to +8
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functional workflow starts orchestrator as a host process, but these Compose services do not publish MySQL/ProxySQL ports to the runner. A host process also cannot resolve mysql1/proxysql via Docker DNS, so orchestrator won't be able to connect to the topology as configured. Either (a) run orchestrator as a Compose service on orchnet and expose 3099, or (b) publish the needed ports and update the test config/URLs to use host-reachable addresses.

Copilot uses AI. Check for mistakes.
ports:
- "13306:3306"
volumes:
- ./mysql/master.cnf:/etc/mysql/conf.d/repl.cnf
- ./mysql/init-master.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-ptestpass"]
interval: 5s
timeout: 3s
retries: 30
networks:
orchnet:
aliases:
- mysql1

mysql2:
image: mysql:8.4
hostname: mysql2
environment:
MYSQL_ROOT_PASSWORD: testpass
ports:
- "13307:3306"
volumes:
- ./mysql/replica.cnf:/etc/mysql/conf.d/repl.cnf
- ./mysql/init-replica.sql:/docker-entrypoint-initdb.d/init.sql
depends_on:
mysql1:
condition: service_healthy
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-ptestpass"]
interval: 5s
timeout: 3s
retries: 30
networks:
orchnet:
aliases:
- mysql2

mysql3:
image: mysql:8.4
hostname: mysql3
environment:
MYSQL_ROOT_PASSWORD: testpass
ports:
- "13308:3306"
volumes:
- ./mysql/replica2.cnf:/etc/mysql/conf.d/repl.cnf
- ./mysql/init-replica.sql:/docker-entrypoint-initdb.d/init.sql
depends_on:
mysql1:
condition: service_healthy
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-ptestpass"]
interval: 5s
timeout: 3s
retries: 30
networks:
orchnet:
aliases:
- mysql3

proxysql:
image: proxysql/proxysql:latest
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the latest tag for Docker images can lead to non-reproducible builds and may cause tests to fail unexpectedly if a new version is pushed with breaking changes. It's best practice to pin images to a specific version.

    image: proxysql/proxysql:2.6.2

Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using proxysql/proxysql:latest makes the functional tests non-reproducible and can break CI when upstream publishes a new image with behavior/config changes. Pin to a known-good ProxySQL version tag (and ideally document the required major/minor).

Suggested change
image: proxysql/proxysql:latest
image: proxysql/proxysql:2.6.3

Copilot uses AI. Check for mistakes.
hostname: proxysql
ports:
- "16032:6032"
- "16033:6033"
volumes:
- ./proxysql/proxysql.cnf:/etc/proxysql.cnf
depends_on:
mysql1:
condition: service_healthy
mysql2:
condition: service_healthy
mysql3:
condition: service_healthy
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-P6032", "-uradmin", "-pradmin"]
interval: 5s
timeout: 3s
retries: 30
networks:
orchnet:
aliases:
- proxysql

orchestrator:
image: ubuntu:24.04
hostname: orchestrator
volumes:
- ../../bin/orchestrator:/usr/local/bin/orchestrator:ro
- ../../resources:/orchestrator/resources:ro
- ./orchestrator-test.conf.json:/orchestrator/orchestrator.conf.json:ro
command: >
bash -c "
apt-get update -qq && apt-get install -y -qq curl sqlite3 > /dev/null 2>&1 &&
rm -f /tmp/orchestrator-test.sqlite3 &&
cd /orchestrator &&
orchestrator -config orchestrator.conf.json http
"
ports:
- "3099:3099"
depends_on:
proxysql:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:3099/api/clusters"]
interval: 5s
timeout: 3s
retries: 60
start_period: 15s
networks:
orchnet:
aliases:
- orchestrator

networks:
orchnet:
driver: bridge
125 changes: 125 additions & 0 deletions tests/functional/lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/bin/bash
# Shared test helpers for functional tests

PASS_COUNT=0
FAIL_COUNT=0
SKIP_COUNT=0
ORC_URL="http://localhost:3099"

pass() {
echo " ✅ PASS: $1"
((PASS_COUNT++))
}

fail() {
echo " ❌ FAIL: $1"
[ -n "$2" ] && echo " $2"
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With set -u enabled in all test scripts, referencing $2 here will trigger an "unbound variable" error when fail is called with a single argument (which happens throughout the suite). Use a safe expansion like ${2-} (or shift/iterate over args) before testing/printing the optional details parameter.

Suggested change
[ -n "$2" ] && echo " $2"
[ -n "${2-}" ] && echo " ${2-}"

Copilot uses AI. Check for mistakes.
((FAIL_COUNT++))
}

skip() {
echo " ⚠️ SKIP: $1"
((SKIP_COUNT++))
Comment on lines +9 to +22
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
bash -euo pipefail -c 'count=0; ((count++)); echo "unreached"'
bash -euo pipefail -c 'f(){ [ -n "$2" ] && echo "$2"; }; f only-one-arg'

Repository: ProxySQL/orchestrator

Length of output: 106


🏁 Script executed:

#!/bin/bash
# Check lines 1-8 to see if counters are initialized
head -n 30 tests/functional/lib.sh

Repository: ProxySQL/orchestrator

Length of output: 566


🏁 Script executed:

#!/bin/bash
# Test 1: Post-increment at 0 returns old value (0), causing exit status 1 under set -e
bash -euo pipefail -c 'count=0; ((count++)); echo "reached: $count"'
echo "Test 1 exit code: $?"

# Test 2: Post-increment at 1+ returns old value, causing exit status 0 (truthy)
bash -euo pipefail -c 'count=1; ((count++)); echo "reached: $count"'
echo "Test 2 exit code: $?"

# Test 3: Assignment form always succeeds
bash -euo pipefail -c 'count=0; count=$((count+1)); echo "reached: $count"'
echo "Test 3 exit code: $?"

Repository: ProxySQL/orchestrator

Length of output: 146


pass/fail/skip are not safe under the strict mode the suites enable.

The post-increment ((...++)) evaluates to the old value and returns exit status 1 when the counter is 0, causing the script to exit on the first call to any of these functions. Additionally, fail() dereferences $2 without guarding for missing positional parameters, which causes an unbound variable error under set -u when called with a single argument.

Because every suite does set -euo pipefail before sourcing tests/functional/lib.sh, the first PASS, the first SKIP, or any one-argument FAIL exits the script instead of recording the result.

Suggested fix
 pass() {
     echo "  ✅ PASS: $1"
-    ((PASS_COUNT++))
+    PASS_COUNT=$((PASS_COUNT + 1))
 }
 
 fail() {
     echo "  ❌ FAIL: $1"
-    [ -n "$2" ] && echo "         $2"
-    ((FAIL_COUNT++))
+    if [ $# -ge 2 ] && [ -n "$2" ]; then
+        echo "         $2"
+    fi
+    FAIL_COUNT=$((FAIL_COUNT + 1))
 }
 
 skip() {
     echo "  ⚠️  SKIP: $1"
-    ((SKIP_COUNT++))
+    SKIP_COUNT=$((SKIP_COUNT + 1))
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pass() {
echo " ✅ PASS: $1"
((PASS_COUNT++))
}
fail() {
echo " ❌ FAIL: $1"
[ -n "$2" ] && echo " $2"
((FAIL_COUNT++))
}
skip() {
echo " ⚠️ SKIP: $1"
((SKIP_COUNT++))
pass() {
echo " ✅ PASS: $1"
PASS_COUNT=$((PASS_COUNT + 1))
}
fail() {
echo " ❌ FAIL: $1"
if [ $# -ge 2 ] && [ -n "$2" ]; then
echo " $2"
fi
FAIL_COUNT=$((FAIL_COUNT + 1))
}
skip() {
echo " ⚠️ SKIP: $1"
SKIP_COUNT=$((SKIP_COUNT + 1))
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/lib.sh` around lines 9 - 22, The three reporting functions
(pass, fail, skip) are unsafe under set -euo pipefail: change the post-increment
arithmetic ((...++)) to a safe assignment form (e.g.
PASS_COUNT=$((PASS_COUNT+1)), SKIP_COUNT=$((SKIP_COUNT+1)),
FAIL_COUNT=$((FAIL_COUNT+1))) so the increment never produces a failing exit
status, and make fail() guard the optional second parameter by using a parameter
expansion fallback (e.g. "${2:-}") or testing with "${2+set}" before echoing so
referencing $2 cannot trigger an unbound variable error; update the functions
pass, fail, and skip accordingly (ensuring their echo lines remain) to preserve
behavior under strict mode.

}

summary() {
echo ""
echo "=== RESULTS: $PASS_COUNT passed, $FAIL_COUNT failed, $SKIP_COUNT skipped ==="
[ "$FAIL_COUNT" -gt 0 ] && exit 1
exit 0
}

# Test that an HTTP endpoint returns expected status code
test_endpoint() {
local NAME="$1" URL="$2" EXPECT="$3"
local CODE
CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL" 2>&1)
if [ "$CODE" = "$EXPECT" ]; then
pass "$NAME (HTTP $CODE)"
else
fail "$NAME (HTTP $CODE, expected $EXPECT)"
fi
}
Comment on lines +33 to +42
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The use of 2>&1 can lead to incorrect behavior if curl fails to connect. In such cases, the error message from curl is redirected to stdout and gets assigned to the CODE variable, which will then contain more than just the HTTP status code. A more robust approach is to remove the redirection and check curl's exit code separately.

Suggested change
test_endpoint() {
local NAME="$1" URL="$2" EXPECT="$3"
local CODE
CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL" 2>&1)
if [ "$CODE" = "$EXPECT" ]; then
pass "$NAME (HTTP $CODE)"
else
fail "$NAME (HTTP $CODE, expected $EXPECT)"
fi
}
test_endpoint() {
local NAME="$1" URL="$2" EXPECT="$3"
local CODE
CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ $? -ne 0 ]; then
fail "$NAME" "curl command failed for $URL"
return
fi
if [ "$CODE" = "$EXPECT" ]; then
pass "$NAME (HTTP $CODE)"
else
fail "$NAME (HTTP $CODE, expected $EXPECT)"
fi
}


# Test that response body contains a string
test_body_contains() {
local NAME="$1" URL="$2" EXPECT="$3"
local BODY
BODY=$(curl -s "$URL" 2>&1)
if echo "$BODY" | grep -q "$EXPECT"; then
pass "$NAME"
else
fail "$NAME" "Response does not contain '$EXPECT'"
fi
}
Comment on lines +45 to +54
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This function is not fully robust. If curl fails with a network error, the error message is captured in BODY, and the test might fail with a generic message. It's better to explicitly check curl's exit code. Additionally, using grep -F is safer for matching fixed strings, as it prevents misinterpretation of special characters as regex.

Suggested change
test_body_contains() {
local NAME="$1" URL="$2" EXPECT="$3"
local BODY
BODY=$(curl -s "$URL" 2>&1)
if echo "$BODY" | grep -q "$EXPECT"; then
pass "$NAME"
else
fail "$NAME" "Response does not contain '$EXPECT'"
fi
}
test_body_contains() {
local NAME="$1" URL="$2" EXPECT="$3"
local BODY
BODY=$(curl -s "$URL")
if [ $? -ne 0 ]; then
fail "$NAME" "curl command failed for $URL"
return
fi
if echo "$BODY" | grep -qF -- "$EXPECT"; then
pass "$NAME"
else
fail "$NAME" "Response does not contain '$EXPECT'"
fi
}


# Wait for orchestrator to be ready
wait_for_orchestrator() {
echo "Waiting for orchestrator to be ready..."
for i in $(seq 1 30); do
if curl -s -o /dev/null "$ORC_URL/api/clusters" 2>/dev/null; then
echo "Orchestrator ready after ${i}s"
return 0
fi
Comment on lines +57 to +63
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Does curlreturn a zero exit status for HTTP 404/500 responses unless-f/--fail is used?

💡 Result:

Yes, curl returns a zero exit status for HTTP 404 and 500 responses unless the -f or --fail option is used. By default, curl considers the transfer successful as long as the HTTP response is received, regardless of the status code (4xx or 5xx). The --fail option makes curl return a non-zero exit code (typically 22) for HTTP responses with status codes >= 400.

Citations:


Fix readiness check to require HTTP success response.

curl -s -o /dev/null exits with code 0 for HTTP 404/500 responses, allowing wait_for_orchestrator() to incorrectly report success when the endpoint is failing. Use curl -fsS to make curl fail on HTTP error status codes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/lib.sh` around lines 57 - 63, The readiness check in
wait_for_orchestrator currently treats any HTTP response (including 4xx/5xx) as
success because curl is invoked with -s -o /dev/null; change the curl invocation
in wait_for_orchestrator (the call hitting "$ORC_URL/api/clusters") to use flags
that cause non-2xx responses to exit nonzero (e.g., replace -s -o /dev/null with
-fsS -o /dev/null or equivalent) so the loop only reports "Orchestrator ready"
on actual HTTP success.

sleep 1
done
echo "Orchestrator not ready after 30s"
return 1
}

# Seed discovery and wait for all instances
# Sets CLUSTER_NAME as a global variable
CLUSTER_NAME=""
discover_topology() {
local MASTER_HOST="$1"
echo "Seeding discovery with $MASTER_HOST..."
curl -s "$ORC_URL/api/discover/$MASTER_HOST/3306" > /dev/null

# Also seed replicas directly
curl -s "$ORC_URL/api/discover/mysql2/3306" > /dev/null 2>&1
curl -s "$ORC_URL/api/discover/mysql3/3306" > /dev/null 2>&1

echo "Waiting for topology discovery..."
for i in $(seq 1 60); do
# Get the cluster name dynamically
CLUSTER_NAME=$(curl -s "$ORC_URL/api/clusters" 2>/dev/null | python3 -c "import json,sys; c=json.load(sys.stdin); print(c[0] if c else '')" 2>/dev/null || echo "")
if [ -n "$CLUSTER_NAME" ]; then
local COUNT
COUNT=$(curl -s "$ORC_URL/api/cluster/$CLUSTER_NAME" 2>/dev/null | python3 -c "import json,sys; print(len(json.load(sys.stdin)))" 2>/dev/null || echo "0")
if [ "$COUNT" -ge 3 ] 2>/dev/null; then
echo "Full topology discovered (${COUNT} instances, cluster=$CLUSTER_NAME) after ${i}s"
return 0
fi
fi
# Re-seed replicas periodically
if [ "$((i % 10))" = "0" ]; then
curl -s "$ORC_URL/api/discover/mysql2/3306" > /dev/null 2>&1
curl -s "$ORC_URL/api/discover/mysql3/3306" > /dev/null 2>&1
fi
sleep 1
done
echo "WARNING: Cluster=$CLUSTER_NAME, instances=${COUNT:-0} after 60s"
return 1
}

# Get ProxySQL servers for a hostgroup
proxysql_servers() {
local HG="$1"
docker compose -f tests/functional/docker-compose.yml exec -T proxysql \
mysql -h127.0.0.1 -P6032 -uradmin -pradmin -Nse \
"SELECT hostname, port, status FROM runtime_mysql_servers WHERE hostgroup_id=$HG" 2>/dev/null
}

# Get MySQL read_only status
mysql_read_only() {
local CONTAINER="$1"
docker compose -f tests/functional/docker-compose.yml exec -T "$CONTAINER" \
mysql -uroot -ptestpass -Nse "SELECT @@read_only" 2>/dev/null
}

# Get MySQL replication source
mysql_source_host() {
local CONTAINER="$1"
docker compose -f tests/functional/docker-compose.yml exec -T "$CONTAINER" \
mysql -uroot -ptestpass -Nse "SHOW REPLICA STATUS\G" 2>/dev/null | grep "Source_Host" | awk '{print $2}'
}
9 changes: 9 additions & 0 deletions tests/functional/mysql/init-master.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Orchestrator user with full privileges
CREATE USER IF NOT EXISTS 'orchestrator'@'%' IDENTIFIED BY 'orch_pass';
GRANT ALL PRIVILEGES ON *.* TO 'orchestrator'@'%' WITH GRANT OPTION;

-- Replication user
CREATE USER IF NOT EXISTS 'repl'@'%' IDENTIFIED BY 'repl_pass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';

FLUSH PRIVILEGES;
8 changes: 8 additions & 0 deletions tests/functional/mysql/init-replica.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Orchestrator user
CREATE USER IF NOT EXISTS 'orchestrator'@'%' IDENTIFIED BY 'orch_pass';
GRANT ALL PRIVILEGES ON *.* TO 'orchestrator'@'%' WITH GRANT OPTION;
-- Replication user (needed if this replica gets promoted)
CREATE USER IF NOT EXISTS 'repl'@'%' IDENTIFIED BY 'repl_pass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
-- NOTE: Replication is configured by setup-replication.sh after all containers are up
9 changes: 9 additions & 0 deletions tests/functional/mysql/master.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[mysqld]
server-id=1
log-bin=mysql-bin
binlog-format=ROW
gtid-mode=ON
enforce-gtid-consistency=ON
log-replica-updates=ON
binlog-row-image=MINIMAL
report-host=mysql1
Loading
Loading