Skip to content

CI: MySQL version matrix (5.7-9.6) and named channels tests#85

Merged
renecannao merged 4 commits intomasterfrom
issue80-81-mysql-matrix-channels
Apr 9, 2026
Merged

CI: MySQL version matrix (5.7-9.6) and named channels tests#85
renecannao merged 4 commits intomasterfrom
issue80-81-mysql-matrix-channels

Conversation

@renecannao
Copy link
Copy Markdown

@renecannao renecannao commented Apr 9, 2026

Summary

Changes

  • Parameterized docker-compose.yml with MYSQL_IMAGE env var
  • Made MySQL configs backward-compatible (log-slave-updates works on all versions)
  • Made setup-replication.sh version-aware (5.7 vs 8.0+ SQL syntax)
  • Added version helper functions to lib.sh (mysql_version, mysql_is_57, mysql_change_source_sql, etc.)
  • Made test-failover.sh restore section version-aware
  • Created test-named-channels.sh for multi-source replication channel testing
  • Split CI workflow into build, functional-mysql (7-version matrix), and functional-postgresql jobs

Closes #80, closes #81

Test plan

  • CI passes on all 7 MySQL versions
  • Named channels test passes on MySQL 8.0+
  • Named channels test gracefully skips on MySQL 5.7
  • PostgreSQL tests unaffected

Summary by CodeRabbit

  • Tests

    • Multi-version MySQL functional testing (matrix) and a new named-channel replication test
    • Added PostgreSQL-specific functional job
    • Tests use bounded HTTP timeouts and version-aware replication handling; replica logging behavior adjusted
  • Documentation

    • Added “Named replication channels” under Failure detection & recovery
  • Chores

    • CI split into build, MySQL and PostgreSQL jobs; improved artifact/log collection and configurable MySQL image via env var

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

Warning

Rate limit exceeded

@renecannao has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 47 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 4 minutes and 47 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dfd98224-fe74-4e3a-8e2c-dee0c22ef604

📥 Commits

Reviewing files that changed from the base of the PR and between fa42679 and 75fe695.

📒 Files selected for processing (2)
  • tests/functional/lib.sh
  • tests/functional/test-named-channels.sh
📝 Walkthrough

Walkthrough

Split the functional CI into a build job plus separate MySQL and PostgreSQL test jobs (MySQL uses a version matrix), parameterized Docker Compose, added MySQL-version-aware replication helpers, introduced a named-channels functional test, tightened curl timeouts, and adjusted MySQL replica binlog config keys.

Changes

Cohort / File(s) Summary
CI workflow
.github/workflows/functional.yml
Replace single functional job with build, functional-mysql (MySQL version matrix) and functional-postgresql; artifactize bin/orchestrator; per-job timeouts, matrix-specific log uploads, conditional docker log collection, and guaranteed cleanup.
Compose parameterization
tests/functional/docker-compose.yml
Make MySQL service images configurable via MYSQL_IMAGE (${MYSQL_IMAGE:-mysql:8.4}) to support CI matrix runs.
Test library & HTTP timeouts
tests/functional/lib.sh, tests/functional/test-postgresql.sh, tests/functional/test-smoke.sh, tests/functional/test-failover.sh
Add curl --max-time timeouts on HTTP calls; introduce MYSQL_MAJOR_VERSION, mysql_version, mysql_is_57, and version-aware SQL helper functions; make mysql_source_host version-aware.
Replication setup script
tests/functional/setup-replication.sh
Detect MySQL version and switch between 5.7 (CHANGE MASTER/START SLAVE/SHOW SLAVE STATUS) and non-5.7 (CHANGE REPLICATION SOURCE/START REPLICA/SHOW REPLICA STATUS) command sequences.
Named-channels test
tests/functional/test-named-channels.sh
New functional test (skips on MySQL 5.7) to configure a named replication channel, verify replication via performance_schema, trigger rediscovery, assert /api/v2/channels and /api/instance-channels/..., and clean up.
Failover & restore adjustments
tests/functional/test-failover.sh
Replace hardcoded replication SQL with version-aware helper outputs for restore steps; add HTTP timeouts.
MySQL configurations
tests/functional/mysql/master.cnf, tests/functional/mysql/replica.cnf, tests/functional/mysql/replica2.cnf
Change replication binlog option key from log-replica-updates=ON to log-slave-updates=ON.
Docs / TOC
docs/README.md, docs/toc.md
Add "Named replication channels" entry to documentation and table of contents.

Sequence Diagram(s)

sequenceDiagram
    participant GH as "GitHub Actions"
    participant Build as "Build Job (compile)"
    participant Artifact as "Artifact Storage"
    participant Test as "Test Job (MySQL matrix)"
    participant Docker as "Docker Compose"
    participant Orch as "orchestrator (binary)"
    participant MySQL as "MySQL instances"

    GH->>Build: trigger build
    Build->>Artifact: upload bin/orchestrator
    GH->>Test: start matrix job (per MYSQL_IMAGE)
    Test->>Artifact: download bin/orchestrator
    Test->>Docker: start services (uses MYSQL_IMAGE)
    Docker->>MySQL: boot mysql1/mysql2/mysql3
    Test->>Orch: start orchestrator (downloaded binary)
    Orch->>MySQL: discover/query replication state
    Test->>MySQL: run setup, named-channel SQL (version-aware)
    Orch->>Test: expose API (/api/v2/channels, /api/instance-channels/...)
    Test->>GH: upload logs/artifacts and exit status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through versions, sniffed the logs and found,

Channels named and tests that span each ground,
CI split the work, artifacts on their way,
Replicas danced in versioned play,
A rabbit thumps—green checks all around!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two main changes: adding a MySQL version matrix (5.7-9.6) and new named channels tests, matching the PR's primary objectives.
Linked Issues check ✅ Passed All coding requirements from #80 (version matrix, parameterization, version-aware scripts) and #81 (named-channels test, channel APIs, channel-aware failover) are implemented and integrated into CI.
Out of Scope Changes check ✅ Passed All changes are directly scoped to #80 and #81: CI workflow refactoring, version-aware SQL handling, Docker parameterization, timeout additions, and the new named-channels test.
Docstring Coverage ✅ Passed Docstring coverage is 84.62% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue80-81-mysql-matrix-channels

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request significantly enhances the functional testing suite by introducing MySQL version awareness. Key changes include parameterizing MySQL image versions in docker-compose.yml, adding helper functions in lib.sh to abstract version-specific replication commands (e.g., CHANGE MASTER TO vs. CHANGE REPLICATION SOURCE TO), and updating existing replication setup and failover scripts (setup-replication.sh, test-failover.sh) to utilize these new helpers. A new test script (test-named-channels.sh) is also added to verify multi-source replication channel discovery, specifically for MySQL 8.0+. Feedback suggests refactoring setup-replication.sh to avoid duplicating version detection logic already present in lib.sh, improving the mysql_source_host function for better code reusability, and removing unreachable code in test-named-channels.sh.

Comment on lines +9 to +22
# Detect MySQL version
MYSQL_FULL_VERSION=$($COMPOSE exec -T mysql1 mysql -uroot -ptestpass -Nse "SELECT VERSION()" 2>/dev/null | tr -d '[:space:]')
MYSQL_MAJOR=$(echo "$MYSQL_FULL_VERSION" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
echo "Detected MySQL version: $MYSQL_FULL_VERSION (major: $MYSQL_MAJOR)"

if [ "$MYSQL_MAJOR" = "5.7" ]; then
CHANGE_SOURCE_CMD="CHANGE MASTER TO MASTER_HOST='mysql1', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='repl_pass', MASTER_AUTO_POSITION=1"
START_REPLICA_CMD="START SLAVE"
SHOW_REPLICA_CMD="SHOW SLAVE STATUS\G"
else
CHANGE_SOURCE_CMD="CHANGE REPLICATION SOURCE TO SOURCE_HOST='mysql1', SOURCE_PORT=3306, SOURCE_USER='repl', SOURCE_PASSWORD='repl_pass', SOURCE_AUTO_POSITION=1, GET_SOURCE_PUBLIC_KEY=1"
START_REPLICA_CMD="START REPLICA"
SHOW_REPLICA_CMD="SHOW REPLICA STATUS\G"
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

This script duplicates the logic for detecting the MySQL version and constructing version-specific SQL commands, which is already implemented in the new helper functions in tests/functional/lib.sh.

To improve maintainability and avoid code duplication, you should source lib.sh at the top of the script (e.g., after cd ...) and then replace this block with calls to the helper functions.

For example:

# At the top of the script
source tests/functional/lib.sh

# ...

# Replace the version detection block with this:
CHANGE_SOURCE_CMD=$(mysql_change_source_sql mysql1 3306 repl repl_pass)
START_REPLICA_CMD=$(mysql_start_replica_sql)
if mysql_is_57; then
    SHOW_REPLICA_CMD="SHOW SLAVE STATUS\G"
else
    SHOW_REPLICA_CMD="SHOW REPLICA STATUS\G"
fi

Comment on lines 178 to 187
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}'
if mysql_is_57; then
docker compose -f tests/functional/docker-compose.yml exec -T "$CONTAINER" \
mysql -uroot -ptestpass -Nse "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Master_Host" | awk '{print $2}'
else
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}'
fi
}
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 mysql_source_host function contains duplicated code for handling MySQL 5.7 and newer versions. You can refactor this to be more DRY by using variables for the version-specific commands and fields.

Suggested change
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}'
if mysql_is_57; then
docker compose -f tests/functional/docker-compose.yml exec -T "$CONTAINER" \
mysql -uroot -ptestpass -Nse "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Master_Host" | awk '{print $2}'
else
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}'
fi
}
mysql_source_host() {
local CONTAINER="$1"
local show_cmd grep_field
if mysql_is_57; then
show_cmd="SHOW SLAVE STATUS\G"
grep_field="Master_Host"
else
show_cmd="SHOW REPLICA STATUS\G"
grep_field="Source_Host"
fi
docker compose -f tests/functional/docker-compose.yml exec -T "$CONTAINER" \
mysql -uroot -ptestpass -Nse "$show_cmd" 2>/dev/null | grep "$grep_field" | awk '{print $2}'
}

Comment on lines +109 to +113
if mysql_is_57; then
RESET_CHANNEL_SQL="STOP SLAVE FOR CHANNEL 'extra'; RESET SLAVE ALL FOR CHANNEL 'extra';"
else
RESET_CHANNEL_SQL="STOP REPLICA FOR CHANNEL 'extra'; RESET REPLICA ALL FOR CHANNEL 'extra';"
fi
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 if/else block for setting RESET_CHANNEL_SQL is unreachable because the script exits at the beginning if the MySQL version is 5.7. You can remove this conditional and just keep the else part.

Suggested change
if mysql_is_57; then
RESET_CHANNEL_SQL="STOP SLAVE FOR CHANNEL 'extra'; RESET SLAVE ALL FOR CHANNEL 'extra';"
else
RESET_CHANNEL_SQL="STOP REPLICA FOR CHANNEL 'extra'; RESET REPLICA ALL FOR CHANNEL 'extra';"
fi
RESET_CHANNEL_SQL="STOP REPLICA FOR CHANNEL 'extra'; RESET REPLICA ALL FOR CHANNEL 'extra';"

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
tests/functional/setup-replication.sh (1)

9-22: Version detection logic is duplicated from lib.sh.

This script duplicates the MySQL version detection and command generation logic that exists in tests/functional/lib.sh (see mysql_version(), mysql_change_source_sql(), mysql_start_replica_sql()). Consider sourcing lib.sh to reuse those helpers and reduce maintenance burden.

That said, keeping this script self-contained may be intentional if it runs in contexts where lib.sh isn't available.

♻️ Optional refactor to reuse lib.sh helpers
 #!/bin/bash
 # Set up replication after all MySQL containers are running
 set -euo pipefail
+cd "$(dirname "$0")/../.."
+source tests/functional/lib.sh
 
 COMPOSE="docker compose -f tests/functional/docker-compose.yml"
 
 echo "Setting up replication..."
 
-# Detect MySQL version
-MYSQL_FULL_VERSION=$($COMPOSE exec -T mysql1 mysql -uroot -ptestpass -Nse "SELECT VERSION()" 2>/dev/null | tr -d '[:space:]')
-MYSQL_MAJOR=$(echo "$MYSQL_FULL_VERSION" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
-echo "Detected MySQL version: $MYSQL_FULL_VERSION (major: $MYSQL_MAJOR)"
-
-if [ "$MYSQL_MAJOR" = "5.7" ]; then
-    CHANGE_SOURCE_CMD="CHANGE MASTER TO MASTER_HOST='mysql1', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='repl_pass', MASTER_AUTO_POSITION=1"
-    START_REPLICA_CMD="START SLAVE"
-    SHOW_REPLICA_CMD="SHOW SLAVE STATUS\G"
-else
-    CHANGE_SOURCE_CMD="CHANGE REPLICATION SOURCE TO SOURCE_HOST='mysql1', SOURCE_PORT=3306, SOURCE_USER='repl', SOURCE_PASSWORD='repl_pass', SOURCE_AUTO_POSITION=1, GET_SOURCE_PUBLIC_KEY=1"
-    START_REPLICA_CMD="START REPLICA"
-    SHOW_REPLICA_CMD="SHOW REPLICA STATUS\G"
-fi
+VERSION=$(mysql_version)
+echo "Detected MySQL version: $VERSION"
+
+CHANGE_SOURCE_CMD=$(mysql_change_source_sql mysql1 3306 repl repl_pass | sed 's/;$//')
+START_REPLICA_CMD=$(mysql_start_replica_sql | sed 's/;$//')
+SHOW_REPLICA_CMD=$(if mysql_is_57; then echo "SHOW SLAVE STATUS\G"; else echo "SHOW REPLICA STATUS\G"; fi)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/setup-replication.sh` around lines 9 - 22, The MySQL version
detection and command construction in this script duplicates logic from
tests/functional/lib.sh (see mysql_version(), mysql_change_source_sql(),
mysql_start_replica_sql()); update the script to source lib.sh at the top and
replace the local variables/commands (MYSQL_FULL_VERSION, MYSQL_MAJOR,
CHANGE_SOURCE_CMD, START_REPLICA_CMD, SHOW_REPLICA_CMD) with calls to the shared
helpers (mysql_version() to set version, mysql_change_source_sql(),
mysql_start_replica_sql(), and the equivalent for show status) so the script
reuses the centralized implementations and avoids duplication.
tests/functional/test-named-channels.sh (2)

4-4: Add error handling for cd failure.

Per Shellcheck SC2164, if cd fails the script would continue from an unexpected directory.

♻️ Proposed fix
-cd "$(dirname "$0")/../.."
+cd "$(dirname "$0")/../.." || exit 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/test-named-channels.sh` at line 4, The cd command in
test-named-channels.sh can fail and the script would continue in the wrong
directory; update the line with cd "$(dirname "$0")/../.." to handle failure by
checking its return and aborting on error (e.g., append an OR-fail clause to
print an explanatory error and exit nonzero) so the script stops if the
directory change fails.

33-39: Consider using channel-specific START REPLICA FOR CHANNEL.

mysql_start_replica_sql() returns a generic START REPLICA; which starts all channels. While this works (since the default channel should already be running), using a channel-specific start would be more precise:

# More explicit: start only the 'extra' channel
if mysql_is_57; then
    START_SQL="START SLAVE FOR CHANNEL 'extra';"
else
    START_SQL="START REPLICA FOR CHANNEL 'extra';"
fi

This is a minor readability/precision suggestion; the current code is functionally correct.

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

In `@tests/functional/test-named-channels.sh` around lines 33 - 39, The current
test uses a generic START_SQL from mysql_start_replica_sql() which runs START
REPLICA for all channels; change the test to start only the named channel
created by mysql_change_source_channel_sql (the 'extra' channel) by constructing
START_SQL to use a channel-specific command: use "START SLAVE FOR CHANNEL
'extra';" when mysql_is_57 is true and "START REPLICA FOR CHANNEL 'extra';"
otherwise, then pass that START_SQL into the heredoc where CHANGE_SQL and
START_SQL are executed so only the 'extra' channel is started.
tests/functional/lib.sh (1)

105-118: Consider adding error handling for failed version detection.

If the Docker exec or MySQL query fails silently (due to 2>/dev/null), MYSQL_MAJOR_VERSION remains empty and all subsequent mysql_is_57 checks default to 8.0+ syntax. This could cause hard-to-diagnose failures when running against MySQL 5.7 with connectivity issues.

🔧 Optional: Add validation for detected version
 mysql_version() {
     if [ -n "$MYSQL_MAJOR_VERSION" ]; then
         echo "$MYSQL_MAJOR_VERSION"
         return
     fi
     local FULL
     FULL=$(docker compose -f tests/functional/docker-compose.yml exec -T mysql1 \
         mysql -uroot -ptestpass -Nse "SELECT VERSION()" 2>/dev/null | tr -d '[:space:]')
     MYSQL_MAJOR_VERSION=$(echo "$FULL" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
+    if [ -z "$MYSQL_MAJOR_VERSION" ]; then
+        echo "ERROR: Failed to detect MySQL version" >&2
+        return 1
+    fi
     echo "$MYSQL_MAJOR_VERSION"
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/lib.sh` around lines 105 - 118, The mysql_version function
currently silences failures and can return an empty MYSQL_MAJOR_VERSION, causing
downstream checks like mysql_is_57 to mis-detect version; update mysql_version
to detect errors from the docker compose exec/mysql command (check the command
exit status and whether FULL is non-empty), capture stderr instead of discarding
it, and when the query fails set MYSQL_MAJOR_VERSION to an explicit
empty/invalid sentinel and print a clear error message (or exit non-zero) via
>&2 so callers know detection failed; reference the MYSQL_MAJOR_VERSION variable
and the mysql_version function when making these changes so callers can handle a
failure case instead of assuming 8.0+.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/functional/test-named-channels.sh`:
- Around line 12-15: The script checks VERSION and calls skip and summary when
MySQL 5.7 is detected but does not stop execution, so the test continues; modify
the conditional block that tests VERSION (uses the VERSION variable and calls
skip and summary) to exit immediately after summary (e.g., call exit with a
success code) so the test harness stops further execution when skipping named
channels tests on MySQL 5.7.

---

Nitpick comments:
In `@tests/functional/lib.sh`:
- Around line 105-118: The mysql_version function currently silences failures
and can return an empty MYSQL_MAJOR_VERSION, causing downstream checks like
mysql_is_57 to mis-detect version; update mysql_version to detect errors from
the docker compose exec/mysql command (check the command exit status and whether
FULL is non-empty), capture stderr instead of discarding it, and when the query
fails set MYSQL_MAJOR_VERSION to an explicit empty/invalid sentinel and print a
clear error message (or exit non-zero) via >&2 so callers know detection failed;
reference the MYSQL_MAJOR_VERSION variable and the mysql_version function when
making these changes so callers can handle a failure case instead of assuming
8.0+.

In `@tests/functional/setup-replication.sh`:
- Around line 9-22: The MySQL version detection and command construction in this
script duplicates logic from tests/functional/lib.sh (see mysql_version(),
mysql_change_source_sql(), mysql_start_replica_sql()); update the script to
source lib.sh at the top and replace the local variables/commands
(MYSQL_FULL_VERSION, MYSQL_MAJOR, CHANGE_SOURCE_CMD, START_REPLICA_CMD,
SHOW_REPLICA_CMD) with calls to the shared helpers (mysql_version() to set
version, mysql_change_source_sql(), mysql_start_replica_sql(), and the
equivalent for show status) so the script reuses the centralized implementations
and avoids duplication.

In `@tests/functional/test-named-channels.sh`:
- Line 4: The cd command in test-named-channels.sh can fail and the script would
continue in the wrong directory; update the line with cd "$(dirname "$0")/../.."
to handle failure by checking its return and aborting on error (e.g., append an
OR-fail clause to print an explanatory error and exit nonzero) so the script
stops if the directory change fails.
- Around line 33-39: The current test uses a generic START_SQL from
mysql_start_replica_sql() which runs START REPLICA for all channels; change the
test to start only the named channel created by mysql_change_source_channel_sql
(the 'extra' channel) by constructing START_SQL to use a channel-specific
command: use "START SLAVE FOR CHANNEL 'extra';" when mysql_is_57 is true and
"START REPLICA FOR CHANNEL 'extra';" otherwise, then pass that START_SQL into
the heredoc where CHANGE_SQL and START_SQL are executed so only the 'extra'
channel is started.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c9b218fd-dd8f-4e89-9023-2e1e849ca877

📥 Commits

Reviewing files that changed from the base of the PR and between bfe313e and 865880c.

📒 Files selected for processing (9)
  • .github/workflows/functional.yml
  • tests/functional/docker-compose.yml
  • tests/functional/lib.sh
  • tests/functional/mysql/master.cnf
  • tests/functional/mysql/replica.cnf
  • tests/functional/mysql/replica2.cnf
  • tests/functional/setup-replication.sh
  • tests/functional/test-failover.sh
  • tests/functional/test-named-channels.sh

Comment on lines +12 to +15
if [ "$VERSION" = "5.7" ]; then
skip "Named channels tests require MySQL 8.0+ (detected $VERSION)"
summary
fi
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

Missing exit after skipping on MySQL 5.7 — test will continue executing.

When MySQL 5.7 is detected, the script calls skip and summary but doesn't exit. Control flow continues to line 17 and beyond, causing the test to run against MySQL 5.7 anyway (and likely fail).

🐛 Proposed fix
 if [ "$VERSION" = "5.7" ]; then
     skip "Named channels tests require MySQL 8.0+ (detected $VERSION)"
     summary
+    exit 0
 fi
📝 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
if [ "$VERSION" = "5.7" ]; then
skip "Named channels tests require MySQL 8.0+ (detected $VERSION)"
summary
fi
if [ "$VERSION" = "5.7" ]; then
skip "Named channels tests require MySQL 8.0+ (detected $VERSION)"
summary
exit 0
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/test-named-channels.sh` around lines 12 - 15, The script
checks VERSION and calls skip and summary when MySQL 5.7 is detected but does
not stop execution, so the test continues; modify the conditional block that
tests VERSION (uses the VERSION variable and calls skip and summary) to exit
immediately after summary (e.g., call exit with a success code) so the test
harness stops further execution when skipping named channels tests on MySQL 5.7.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
tests/functional/test-named-channels.sh (1)

12-15: ⚠️ Potential issue | 🔴 Critical

Stop execution after the MySQL 5.7 skip path.

On Line [15], control falls through after skip/summary, so the test continues and runs 8.0+ SQL later. Add an explicit successful exit.

🐛 Proposed fix
 if [ "$VERSION" = "5.7" ]; then
     skip "Named channels tests require MySQL 8.0+ (detected $VERSION)"
     summary
+    exit 0
 fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/test-named-channels.sh` around lines 12 - 15, The test
script's skip branch for MySQL 5.7 uses skip and summary but falls through to
run subsequent 8.0+ SQL; update the conditional that checks VERSION (the block
containing skip "Named channels tests require MySQL 8.0+ (detected $VERSION)"
and summary) to terminate early by adding an explicit successful exit (e.g.,
exit 0) immediately after summary so control does not continue to run 8.0+ tests
when VERSION is 5.7.
🧹 Nitpick comments (1)
tests/functional/test-named-channels.sh (1)

42-43: Prefer polling with timeout over fixed sleeps to reduce CI flakiness.

Lines [42], [53], and [69] use fixed delays. In matrix CI, readiness/discovery times vary and this can cause intermittent failures.

♻️ Refactor sketch
-# Verify the extra channel is running
-sleep 3
-CHANNEL_STATUS=$($COMPOSE exec -T mysql3 mysql -uroot -ptestpass -Nse \
-    "SELECT SERVICE_STATE FROM performance_schema.replication_connection_status WHERE CHANNEL_NAME='extra'" 2>/dev/null | tr -d '[:space:]')
+# Verify the extra channel is running (poll up to 15s)
+CHANNEL_STATUS=""
+for _ in $(seq 1 15); do
+    CHANNEL_STATUS=$($COMPOSE exec -T mysql3 mysql -uroot -ptestpass -Nse \
+        "SELECT SERVICE_STATE FROM performance_schema.replication_connection_status WHERE CHANNEL_NAME='extra'" 2>/dev/null | tr -d '[:space:]')
+    [ "$CHANNEL_STATUS" = "ON" ] && break
+    sleep 1
+done

Also applies to: 53-54, 68-70

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

In `@tests/functional/test-named-channels.sh` around lines 42 - 43, Replace fixed
sleep calls with a timed polling loop that checks readiness and fails after a
timeout: create a helper (e.g., wait_for_mysql_or_timeout) that repeatedly runs
the same command used to set CHANNEL_STATUS ($COMPOSE exec -T mysql3 mysql
-uroot -ptestpass -Nse ...) or another lightweight readiness query, sleeping a
short interval (e.g., 1s) between attempts and aborting after a configurable
timeout; then call that helper in place of the three plain sleep invocations so
tests wait until the mysql container is actually ready instead of waiting a
fixed amount of time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/functional/test-named-channels.sh`:
- Line 4: The unguarded cd "$(dirname "$0")/../.." can fail and leave the script
in the wrong directory; update the invocation that sets the working dir (the cd
call) to check its exit status and abort on failure (e.g., guard the cd with an
inline failure handler that logs an error and exits) so subsequent operations
like sourcing tests/functional/lib.sh run from the intended location; locate the
cd invocation in tests/functional/test-named-channels.sh and replace it with a
guarded variant that exits non‑zero and prints a clear error if the cd fails.

---

Duplicate comments:
In `@tests/functional/test-named-channels.sh`:
- Around line 12-15: The test script's skip branch for MySQL 5.7 uses skip and
summary but falls through to run subsequent 8.0+ SQL; update the conditional
that checks VERSION (the block containing skip "Named channels tests require
MySQL 8.0+ (detected $VERSION)" and summary) to terminate early by adding an
explicit successful exit (e.g., exit 0) immediately after summary so control
does not continue to run 8.0+ tests when VERSION is 5.7.

---

Nitpick comments:
In `@tests/functional/test-named-channels.sh`:
- Around line 42-43: Replace fixed sleep calls with a timed polling loop that
checks readiness and fails after a timeout: create a helper (e.g.,
wait_for_mysql_or_timeout) that repeatedly runs the same command used to set
CHANNEL_STATUS ($COMPOSE exec -T mysql3 mysql -uroot -ptestpass -Nse ...) or
another lightweight readiness query, sleeping a short interval (e.g., 1s)
between attempts and aborting after a configurable timeout; then call that
helper in place of the three plain sleep invocations so tests wait until the
mysql container is actually ready instead of waiting a fixed amount of time.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ec8b71d0-9198-4190-b897-eb546eee5b41

📥 Commits

Reviewing files that changed from the base of the PR and between 865880c and da2ad94.

📒 Files selected for processing (3)
  • docs/README.md
  • docs/toc.md
  • tests/functional/test-named-channels.sh
✅ Files skipped from review due to trivial changes (2)
  • docs/toc.md
  • docs/README.md

#!/bin/bash
# Named channels functional tests — verify multi-source replication channel discovery
set -uo pipefail # no -e: we handle failures ourselves
cd "$(dirname "$0")/../.."
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "test-named-channels.sh" -type f

Repository: ProxySQL/orchestrator

Length of output: 106


🏁 Script executed:

head -20 "tests/functional/test-named-channels.sh"

Repository: ProxySQL/orchestrator

Length of output: 702


🏁 Script executed:

cd tests/functional && head -20 lib.sh

Repository: ProxySQL/orchestrator

Length of output: 353


Guard cd failure to prevent silent breakage of relative paths.

The cd command on line 4 is unguarded. If it fails, the script continues executing in the original directory, causing the source tests/functional/lib.sh on line 5 to fail or source the wrong file. Although the script uses set -uo pipefail (intentionally without -e), the file demonstrates explicit error handling elsewhere (e.g., wait_for_orchestrator || { ... exit 1; }), establishing a pattern of guarding critical operations.

🛠️ Proposed fix
-cd "$(dirname "$0")/../.."
+cd "$(dirname "$0")/../.." || exit 1
 source tests/functional/lib.sh
📝 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
cd "$(dirname "$0")/../.."
cd "$(dirname "$0")/../.." || exit 1
source tests/functional/lib.sh
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 4-4: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.

(SC2164)

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

In `@tests/functional/test-named-channels.sh` at line 4, The unguarded cd
"$(dirname "$0")/../.." can fail and leave the script in the wrong directory;
update the invocation that sets the working dir (the cd call) to check its exit
status and abort on failure (e.g., guard the cd with an inline failure handler
that logs an error and exits) so subsequent operations like sourcing
tests/functional/lib.sh run from the intended location; locate the cd invocation
in tests/functional/test-named-channels.sh and replace it with a guarded variant
that exits non‑zero and prints a clear error if the cd fails.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/functional.yml (1)

107-117: ⚠️ Potential issue | 🟠 Major

Propagate MYSQL_IMAGE into the MySQL test steps.

The compose file is parameterized by MYSQL_IMAGE (lines 5, 26, 50 of docker-compose.yml reference ${MYSQL_IMAGE:-mysql:8.4}), and the test scripts invoke docker compose directly via lib.sh. The four test steps (lines 107–117) do not export MYSQL_IMAGE, so compose will use the default fallback value regardless of the matrix entry, breaking version-specific testing.

Proposed fix
     - name: Run smoke tests
+      env:
+        MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
       run: bash tests/functional/test-smoke.sh

     - name: Run regression tests
+      env:
+        MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
       run: bash tests/functional/test-regression.sh

     - name: Run failover tests
+      env:
+        MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
       run: bash tests/functional/test-failover.sh

     - name: Run named channels tests
+      env:
+        MYSQL_IMAGE: mysql:${{ matrix.mysql_version }}
       run: bash tests/functional/test-named-channels.sh
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/functional.yml around lines 107 - 117, The four workflow
steps named "Run smoke tests", "Run regression tests", "Run failover tests", and
"Run named channels tests" do not pass the MYSQL_IMAGE matrix value into the
shell that runs tests, so docker compose falls back to the default image; update
each of those steps to propagate the matrix value by setting the MYSQL_IMAGE
environment variable for the step (e.g., add an env: MYSQL_IMAGE: ${{
matrix.MYSQL_IMAGE }} for each step) or export MYSQL_IMAGE=${{
matrix.MYSQL_IMAGE }} in the run command before invoking the test scripts
(lib.sh -> docker compose) so the compose file picks up the intended image.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/functional/lib.sh`:
- Around line 177-186: The helper mysql_source_host() currently assumes
single-source replication and can return concatenated hosts for multi-channel
replicas; update it to be channel-aware by adding an optional channel parameter
(e.g., channel="$2") and parse the output of SHOW SLAVE/REPLICA STATUS\G to map
Channel (or use absence of Channel for MySQL 5.7) to its corresponding
Master_Host/Source_Host; if a channel is provided, return only that channel's
host, and if no channel is provided but multiple channels are present, fail fast
with a clear error and non-zero exit code so callers don't receive concatenated
values (ensure changes touch mysql_source_host and its usage contract).

In `@tests/functional/test-named-channels.sh`:
- Around line 105-124: The test currently jumps from API assertions to cleanup
and never triggers a failover/recovery to verify named-channel durability;
insert a failover/recovery phase before the cleanup block that triggers a master
failover (using the same docker/compose pattern as other tests, e.g. via
$COMPOSE exec -T mysqlX or orchestrator command), wait for replication to
re-establish, then query performance_schema.replication_connection_status to
assert the "extra" channel still exists and is in a running state (reuse the
CHANNEL_AFTER lookup pattern and the pass/fail helpers to assert COUNT(*) > 0
and appropriate STATUS), only then proceed to the RESET_CHANNEL_SQL cleanup and
summary.
- Around line 26-39: The bootstrap mysql commands can fail silently because
stderr is discarded and the script doesn’t check exit status; update the block
that runs the seed and channel-setup to fail fast by removing the 2>/dev/null
redirection (or capture stdout/stderr) and check the exit code after the COMPOSE
exec calls, failing the test if non-zero; specifically, when you run the seed
write and the channel-change/start using CHANGE_SQL, START_SQL and the helper
functions mysql_change_source_channel_sql and mysql_start_replica_sql on
mysql2/mysql3, ensure you either enable errexit (set -e) for the script or
append a post-command check like "|| { echo 'mysql command failed: <context>';
exit 1; }" so any rejected write or channel change aborts immediately.

---

Outside diff comments:
In @.github/workflows/functional.yml:
- Around line 107-117: The four workflow steps named "Run smoke tests", "Run
regression tests", "Run failover tests", and "Run named channels tests" do not
pass the MYSQL_IMAGE matrix value into the shell that runs tests, so docker
compose falls back to the default image; update each of those steps to propagate
the matrix value by setting the MYSQL_IMAGE environment variable for the step
(e.g., add an env: MYSQL_IMAGE: ${{ matrix.MYSQL_IMAGE }} for each step) or
export MYSQL_IMAGE=${{ matrix.MYSQL_IMAGE }} in the run command before invoking
the test scripts (lib.sh -> docker compose) so the compose file picks up the
intended image.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0d21aa68-89b4-413c-84fa-228ebc2d3afd

📥 Commits

Reviewing files that changed from the base of the PR and between da2ad94 and e81056f.

📒 Files selected for processing (13)
  • .github/workflows/functional.yml
  • docs/README.md
  • docs/toc.md
  • tests/functional/docker-compose.yml
  • tests/functional/lib.sh
  • tests/functional/mysql/master.cnf
  • tests/functional/mysql/replica.cnf
  • tests/functional/mysql/replica2.cnf
  • tests/functional/setup-replication.sh
  • tests/functional/test-failover.sh
  • tests/functional/test-named-channels.sh
  • tests/functional/test-postgresql.sh
  • tests/functional/test-smoke.sh
✅ Files skipped from review due to trivial changes (6)
  • docs/README.md
  • docs/toc.md
  • tests/functional/mysql/replica2.cnf
  • tests/functional/docker-compose.yml
  • tests/functional/mysql/replica.cnf
  • tests/functional/setup-replication.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/functional/mysql/master.cnf
  • tests/functional/test-failover.sh

Comment on lines 177 to +186
# 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}'
if mysql_is_57; then
docker compose -f tests/functional/docker-compose.yml exec -T "$CONTAINER" \
mysql -uroot -ptestpass -Nse "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Master_Host" | awk '{print $2}'
else
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}'
fi
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

mysql_source_host() still assumes single-source replication.

On a multi-channel replica, SHOW SLAVE/REPLICA STATUS\G returns one block per channel. This helper will therefore emit every Master_Host/Source_Host it finds, so callers get a concatenated value as soon as mysql3 has both its default channel and extra. Please make this helper channel-aware, or fail fast when multiple channels are present.

🐛 Proposed fix
 mysql_source_host() {
-    local CONTAINER="$1"
+    local CONTAINER="$1" CHANNEL="${2:-}"
     if mysql_is_57; then
+        local STATUS_SQL="SHOW SLAVE STATUS\\G"
+        [ -n "$CHANNEL" ] && STATUS_SQL="SHOW SLAVE STATUS FOR CHANNEL '${CHANNEL}'\\G"
         docker compose -f tests/functional/docker-compose.yml exec -T "$CONTAINER" \
-            mysql -uroot -ptestpass -Nse "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Master_Host" | awk '{print $2}'
+            mysql -uroot -ptestpass -Nse "$STATUS_SQL" 2>/dev/null |
+            awk -F': ' '$1 == "Master_Host" { print $2; exit }'
     else
+        local STATUS_SQL="SHOW REPLICA STATUS\\G"
+        [ -n "$CHANNEL" ] && STATUS_SQL="SHOW REPLICA STATUS FOR CHANNEL '${CHANNEL}'\\G"
         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}'
+            mysql -uroot -ptestpass -Nse "$STATUS_SQL" 2>/dev/null |
+            awk -F': ' '$1 == "Source_Host" { print $2; exit }'
     fi
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/lib.sh` around lines 177 - 186, The helper
mysql_source_host() currently assumes single-source replication and can return
concatenated hosts for multi-channel replicas; update it to be channel-aware by
adding an optional channel parameter (e.g., channel="$2") and parse the output
of SHOW SLAVE/REPLICA STATUS\G to map Channel (or use absence of Channel for
MySQL 5.7) to its corresponding Master_Host/Source_Host; if a channel is
provided, return only that channel's host, and if no channel is provided but
multiple channels are present, fail fast with a clear error and non-zero exit
code so callers don't receive concatenated values (ensure changes touch
mysql_source_host and its usage contract).

Comment on lines +26 to +39
$COMPOSE exec -T mysql2 mysql -uroot -ptestpass -e "
CREATE DATABASE IF NOT EXISTS extra_db;
CREATE TABLE IF NOT EXISTS extra_db.test (id INT PRIMARY KEY AUTO_INCREMENT, val VARCHAR(100));
INSERT INTO extra_db.test (val) VALUES ('channel-test');
" 2>/dev/null

# Add a named channel 'extra' on mysql3 replicating from mysql2
CHANGE_SQL=$(mysql_change_source_channel_sql mysql2 3306 repl repl_pass extra)
START_SQL=$(mysql_start_replica_sql)

$COMPOSE exec -T mysql3 mysql -uroot -ptestpass -e "
$CHANGE_SQL
$START_SQL
" 2>/dev/null
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

Fail fast if the channel setup SQL fails.

With -e intentionally disabled, both of these bootstrap commands can fail silently and the test will keep going with a half-configured topology. That makes the later failures hard to interpret, especially if mysql2 rejects the seed write or mysql3 rejects the channel change.

🐛 Proposed fix
-$COMPOSE exec -T mysql2 mysql -uroot -ptestpass -e "
+if ! $COMPOSE exec -T mysql2 mysql -uroot -ptestpass -e "
     CREATE DATABASE IF NOT EXISTS extra_db;
     CREATE TABLE IF NOT EXISTS extra_db.test (id INT PRIMARY KEY AUTO_INCREMENT, val VARCHAR(100));
     INSERT INTO extra_db.test (val) VALUES ('channel-test');
-" 2>/dev/null
+"; then
+    fail "Seed extra_db on mysql2"
+    summary
+fi
@@
-$COMPOSE exec -T mysql3 mysql -uroot -ptestpass -e "
+if ! $COMPOSE exec -T mysql3 mysql -uroot -ptestpass -e "
     $CHANGE_SQL
     $START_SQL
-" 2>/dev/null
+"; then
+    fail "Configure named channel 'extra' on mysql3"
+    summary
+fi
📝 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
$COMPOSE exec -T mysql2 mysql -uroot -ptestpass -e "
CREATE DATABASE IF NOT EXISTS extra_db;
CREATE TABLE IF NOT EXISTS extra_db.test (id INT PRIMARY KEY AUTO_INCREMENT, val VARCHAR(100));
INSERT INTO extra_db.test (val) VALUES ('channel-test');
" 2>/dev/null
# Add a named channel 'extra' on mysql3 replicating from mysql2
CHANGE_SQL=$(mysql_change_source_channel_sql mysql2 3306 repl repl_pass extra)
START_SQL=$(mysql_start_replica_sql)
$COMPOSE exec -T mysql3 mysql -uroot -ptestpass -e "
$CHANGE_SQL
$START_SQL
" 2>/dev/null
if ! $COMPOSE exec -T mysql2 mysql -uroot -ptestpass -e "
CREATE DATABASE IF NOT EXISTS extra_db;
CREATE TABLE IF NOT EXISTS extra_db.test (id INT PRIMARY KEY AUTO_INCREMENT, val VARCHAR(100));
INSERT INTO extra_db.test (val) VALUES ('channel-test');
"; then
fail "Seed extra_db on mysql2"
summary
fi
# Add a named channel 'extra' on mysql3 replicating from mysql2
CHANGE_SQL=$(mysql_change_source_channel_sql mysql2 3306 repl repl_pass extra)
START_SQL=$(mysql_start_replica_sql)
if ! $COMPOSE exec -T mysql3 mysql -uroot -ptestpass -e "
$CHANGE_SQL
$START_SQL
"; then
fail "Configure named channel 'extra' on mysql3"
summary
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/test-named-channels.sh` around lines 26 - 39, The bootstrap
mysql commands can fail silently because stderr is discarded and the script
doesn’t check exit status; update the block that runs the seed and channel-setup
to fail fast by removing the 2>/dev/null redirection (or capture stdout/stderr)
and check the exit code after the COMPOSE exec calls, failing the test if
non-zero; specifically, when you run the seed write and the channel-change/start
using CHANGE_SQL, START_SQL and the helper functions
mysql_change_source_channel_sql and mysql_start_replica_sql on mysql2/mysql3,
ensure you either enable errexit (set -e) for the script or append a
post-command check like "|| { echo 'mysql command failed: <context>'; exit 1; }"
so any rejected write or channel change aborts immediately.

Comment on lines +105 to +124
# ----------------------------------------------------------------
echo ""
echo "--- Cleanup: Remove extra channel from mysql3 ---"

# Script already exits on MySQL 5.7, so only 8.0+ syntax needed here
RESET_CHANNEL_SQL="STOP REPLICA FOR CHANNEL 'extra'; RESET REPLICA ALL FOR CHANNEL 'extra';"

$COMPOSE exec -T mysql3 mysql -uroot -ptestpass -e "$RESET_CHANNEL_SQL" 2>/dev/null

# Verify channel removed
CHANNEL_AFTER=$($COMPOSE exec -T mysql3 mysql -uroot -ptestpass -Nse \
"SELECT COUNT(*) FROM performance_schema.replication_connection_status WHERE CHANNEL_NAME='extra'" 2>/dev/null | tr -d '[:space:]')

if [ "$CHANNEL_AFTER" = "0" ]; then
pass "Named channel 'extra' cleaned up successfully"
else
fail "Named channel 'extra' still present after cleanup"
fi

summary
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

This test never exercises the failover path.

After the API assertions, the script goes straight to cleanup, so CI still does not cover the #81 acceptance case that a recovery preserves the other replication channel(s). Please add a failover/recovery phase before cleanup and assert that extra is still present and running afterwards.

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

In `@tests/functional/test-named-channels.sh` around lines 105 - 124, The test
currently jumps from API assertions to cleanup and never triggers a
failover/recovery to verify named-channel durability; insert a failover/recovery
phase before the cleanup block that triggers a master failover (using the same
docker/compose pattern as other tests, e.g. via $COMPOSE exec -T mysqlX or
orchestrator command), wait for replication to re-establish, then query
performance_schema.replication_connection_status to assert the "extra" channel
still exists and is in a running state (reuse the CHANNEL_AFTER lookup pattern
and the pass/fail helpers to assert COUNT(*) > 0 and appropriate STATUS), only
then proceed to the RESET_CHANNEL_SQL cleanup and summary.

MySQL version matrix (Issue #80):
- Parameterize docker-compose.yml with MYSQL_IMAGE env var (default mysql:8.4)
- Use log-slave-updates in cnf files (compatible with all MySQL versions 5.7-9.x)
- Make setup-replication.sh version-aware (CHANGE MASTER vs CHANGE REPLICATION SOURCE)
- Add version helper functions to lib.sh (mysql_version, mysql_is_57,
  mysql_change_source_sql, mysql_start/stop/reset_replica_sql, etc.)
- Update test-failover.sh restore section to use version-aware helpers
- Split CI workflow into build + functional-mysql (7-version matrix) +
  functional-postgresql jobs with unique artifact names per matrix entry

Named channels functional tests (Issue #81):
- Create test-named-channels.sh testing multi-source replication discovery
- Sets up mysql3 with a named channel 'extra' replicating from mysql2
- Tests channel API endpoints (/api/v2/channels, /api/instance-channels)
- Verifies data replication through named channel
- Gracefully skips on MySQL 5.7 (requires 8.0+)
- Cleans up channel after tests
- Add named-channels.md to docs/toc.md and README.md to fix doc
  validation check
- Remove unreachable MySQL 5.7 branch in channel cleanup code
  (script already exits on 5.7)
All curl calls in test scripts and lib.sh lacked --max-time, causing
tests to hang indefinitely if any API endpoint was slow to respond.
Added --max-time 10 to every curl call across all test scripts.
@renecannao renecannao force-pushed the issue80-81-mysql-matrix-channels branch from e81056f to fa42679 Compare April 9, 2026 07:33
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
tests/functional/test-named-channels.sh (2)

26-39: ⚠️ Potential issue | 🟠 Major

Channel setup commands can fail silently.

Both the mysql2 seed and mysql3 channel configuration suppress stderr and don't check exit status. If either fails, the test continues with a broken topology, making later failures hard to diagnose.

🐛 Proposed fix
-$COMPOSE exec -T mysql2 mysql -uroot -ptestpass -e "
+if ! $COMPOSE exec -T mysql2 mysql -uroot -ptestpass -e "
     CREATE DATABASE IF NOT EXISTS extra_db;
     CREATE TABLE IF NOT EXISTS extra_db.test (id INT PRIMARY KEY AUTO_INCREMENT, val VARCHAR(100));
     INSERT INTO extra_db.test (val) VALUES ('channel-test');
-" 2>/dev/null
+" 2>/dev/null; then
+    fail "Failed to seed extra_db on mysql2"
+    summary
+fi

 # Add a named channel 'extra' on mysql3 replicating from mysql2
 CHANGE_SQL=$(mysql_change_source_channel_sql mysql2 3306 repl repl_pass extra)
 START_SQL=$(mysql_start_replica_sql)

-$COMPOSE exec -T mysql3 mysql -uroot -ptestpass -e "
+if ! $COMPOSE exec -T mysql3 mysql -uroot -ptestpass -e "
     $CHANGE_SQL
     $START_SQL
-" 2>/dev/null
+" 2>/dev/null; then
+    fail "Failed to configure named channel 'extra' on mysql3"
+    summary
+fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/test-named-channels.sh` around lines 26 - 39, The commands
that configure the extra DB and the named channel are silencing errors and not
checked; remove the stderr redirection and add explicit exit-status checks after
the COMPOSE exec calls that run the mysql statements (the blocks that use
$COMPOSE exec -T mysql2/mysql3 ... with $CHANGE_SQL and $START_SQL), or wrap
them so failures abort the test (e.g., test the return code ($?) or enable set
-e at top of the script); ensure the outputs of mysql_change_source_channel_sql
and mysql_start_replica_sql (and the CREATE/INSERT block) are executed and any
non-zero exit causes the test to fail with a clear error message.

4-4: ⚠️ Potential issue | 🟡 Minor

Guard cd to prevent silent failure.

If the cd fails, the script continues in the wrong directory, causing source tests/functional/lib.sh to fail or load the wrong file.

🛠️ Proposed fix
-cd "$(dirname "$0")/../.."
+cd "$(dirname "$0")/../.." || { echo "Failed to cd to repo root"; exit 1; }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/test-named-channels.sh` at line 4, The initial cd command
(cd "$(dirname "$0")/../..") must be guarded so the script fails fast if it
cannot change to the intended repo root; modify the test-named-channels.sh
startup so the cd is checked and the script exits with a clear error if cd fails
(e.g., test the return status and call exit 1 with an error message) before
attempting to source tests/functional/lib.sh, ensuring the script won't continue
in the wrong directory.
🧹 Nitpick comments (1)
tests/functional/setup-replication.sh (1)

9-22: Consider using shared helpers from lib.sh instead of duplicating version detection.

The version detection and SQL command construction here duplicates what lib.sh already provides via mysql_version(), mysql_is_57(), mysql_change_source_sql(), and mysql_start_replica_sql(). This creates a maintenance burden—changes to replication syntax must be made in two places.

♻️ Suggested refactor using lib.sh helpers
 COMPOSE="docker compose -f tests/functional/docker-compose.yml"
 
+# Source shared helpers
+source "$(dirname "$0")/lib.sh"
+
 echo "Setting up replication..."
 
-# Detect MySQL version
-MYSQL_FULL_VERSION=$($COMPOSE exec -T mysql1 mysql -uroot -ptestpass -Nse "SELECT VERSION()" 2>/dev/null | tr -d '[:space:]')
-MYSQL_MAJOR=$(echo "$MYSQL_FULL_VERSION" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
-echo "Detected MySQL version: $MYSQL_FULL_VERSION (major: $MYSQL_MAJOR)"
-
-if [ "$MYSQL_MAJOR" = "5.7" ]; then
-    CHANGE_SOURCE_CMD="CHANGE MASTER TO MASTER_HOST='mysql1', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='repl_pass', MASTER_AUTO_POSITION=1"
-    START_REPLICA_CMD="START SLAVE"
-    SHOW_REPLICA_CMD="SHOW SLAVE STATUS\G"
-else
-    CHANGE_SOURCE_CMD="CHANGE REPLICATION SOURCE TO SOURCE_HOST='mysql1', SOURCE_PORT=3306, SOURCE_USER='repl', SOURCE_PASSWORD='repl_pass', SOURCE_AUTO_POSITION=1, GET_SOURCE_PUBLIC_KEY=1"
-    START_REPLICA_CMD="START REPLICA"
-    SHOW_REPLICA_CMD="SHOW REPLICA STATUS\G"
-fi
+echo "Detected MySQL version: $(mysql_version)"
+CHANGE_SOURCE_CMD=$(mysql_change_source_sql mysql1 3306 repl repl_pass)
+START_REPLICA_CMD=$(mysql_start_replica_sql)
+if mysql_is_57; then
+    SHOW_REPLICA_CMD="SHOW SLAVE STATUS\G"
+else
+    SHOW_REPLICA_CMD="SHOW REPLICA STATUS\G"
+fi

Note: You may want to add a mysql_show_replica_status_sql() helper to lib.sh for completeness.

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

In `@tests/functional/setup-replication.sh` around lines 9 - 22, Replace the
duplicated MySQL version detection and SQL construction in setup-replication.sh
with the shared helpers from lib.sh: call mysql_version() or mysql_is_57() to
branch and use mysql_change_source_sql(), mysql_start_replica_sql(), and add/use
a mysql_show_replica_status_sql() helper in lib.sh for the SHOW ... STATUS
command; update setup-replication.sh to source lib.sh, invoke these helpers to
set CHANGE_SOURCE_CMD, START_REPLICA_CMD, and SHOW_REPLICA_CMD (or use their
returned strings directly), and add the new mysql_show_replica_status_sql()
implementation to lib.sh if missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@tests/functional/test-named-channels.sh`:
- Around line 26-39: The commands that configure the extra DB and the named
channel are silencing errors and not checked; remove the stderr redirection and
add explicit exit-status checks after the COMPOSE exec calls that run the mysql
statements (the blocks that use $COMPOSE exec -T mysql2/mysql3 ... with
$CHANGE_SQL and $START_SQL), or wrap them so failures abort the test (e.g., test
the return code ($?) or enable set -e at top of the script); ensure the outputs
of mysql_change_source_channel_sql and mysql_start_replica_sql (and the
CREATE/INSERT block) are executed and any non-zero exit causes the test to fail
with a clear error message.
- Line 4: The initial cd command (cd "$(dirname "$0")/../..") must be guarded so
the script fails fast if it cannot change to the intended repo root; modify the
test-named-channels.sh startup so the cd is checked and the script exits with a
clear error if cd fails (e.g., test the return status and call exit 1 with an
error message) before attempting to source tests/functional/lib.sh, ensuring the
script won't continue in the wrong directory.

---

Nitpick comments:
In `@tests/functional/setup-replication.sh`:
- Around line 9-22: Replace the duplicated MySQL version detection and SQL
construction in setup-replication.sh with the shared helpers from lib.sh: call
mysql_version() or mysql_is_57() to branch and use mysql_change_source_sql(),
mysql_start_replica_sql(), and add/use a mysql_show_replica_status_sql() helper
in lib.sh for the SHOW ... STATUS command; update setup-replication.sh to source
lib.sh, invoke these helpers to set CHANGE_SOURCE_CMD, START_REPLICA_CMD, and
SHOW_REPLICA_CMD (or use their returned strings directly), and add the new
mysql_show_replica_status_sql() implementation to lib.sh if missing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3d5eb54d-7793-4d64-b29c-b77ba290fcde

📥 Commits

Reviewing files that changed from the base of the PR and between e81056f and fa42679.

📒 Files selected for processing (13)
  • .github/workflows/functional.yml
  • docs/README.md
  • docs/toc.md
  • tests/functional/docker-compose.yml
  • tests/functional/lib.sh
  • tests/functional/mysql/master.cnf
  • tests/functional/mysql/replica.cnf
  • tests/functional/mysql/replica2.cnf
  • tests/functional/setup-replication.sh
  • tests/functional/test-failover.sh
  • tests/functional/test-named-channels.sh
  • tests/functional/test-postgresql.sh
  • tests/functional/test-smoke.sh
✅ Files skipped from review due to trivial changes (5)
  • docs/README.md
  • tests/functional/mysql/replica2.cnf
  • docs/toc.md
  • tests/functional/docker-compose.yml
  • tests/functional/test-postgresql.sh
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/functional/mysql/master.cnf
  • tests/functional/mysql/replica.cnf
  • tests/functional/test-smoke.sh
  • tests/functional/test-failover.sh

- Use /api/v2/instances/{host}/{port}/channels (actual endpoint)
  instead of nonexistent /api/v2/channels and /api/instance-channels
- Fix fail() function: use ${2:-} to avoid 'unbound variable' error
  with set -u when called with 1 argument
@renecannao renecannao merged commit 5b13080 into master Apr 9, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI: Functional tests for named replication channels CI: MySQL version matrix (5.7, 8.0, 8.4, 9.0, 9.2, 9.5, 9.6)

1 participant