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
24 changes: 24 additions & 0 deletions test/infra/control/ensure-infras.bash
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,27 @@
done

echo ">>> All required infrastructures for '${TAP_GROUP}' are READY (INFRA_ID: ${INFRA_ID})."

# 5. Derive DEFAULT_MYSQL_INFRA and DEFAULT_PGSQL_INFRA for hooks
# These are used by group-specific hooks to connect to backends
for INFRA_NAME in ${INFRAS}; do
if [[ "${INFRA_NAME}" == *mysql* ]] || [[ "${INFRA_NAME}" == *mariadb* ]]; then
export DEFAULT_MYSQL_INFRA="${DEFAULT_MYSQL_INFRA:-${INFRA_NAME}}"
fi
if [[ "${INFRA_NAME}" == *pgsql* ]] || [[ "${INFRA_NAME}" == *pgdb* ]]; then
export DEFAULT_PGSQL_INFRA="${DEFAULT_PGSQL_INFRA:-${INFRA_NAME}}"
fi
done

# 6. Execute group-specific setup hook if it exists
# This allows TAP groups to perform additional setup after all backends are running
SETUP_HOOK="${WORKSPACE}/test/tap/groups/${TAP_GROUP}/setup-infras.bash"

Choose a reason for hiding this comment

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

high

The script uses the BASE_GROUP variable (on line 98) to find a fallback setup hook, but it doesn't define this variable within the script. This relies on BASE_GROUP being present in the execution environment, which is risky and inconsistent with other scripts like run-tests-isolated.bash and destroy-infras.bash that derive it internally. To make the script more robust and self-contained, you should derive BASE_GROUP from TAP_GROUP before it's used. For consistency, it's best to use the same sed command used in destroy-infras.bash.

Suggested change
SETUP_HOOK="${WORKSPACE}/test/tap/groups/${TAP_GROUP}/setup-infras.bash"
BASE_GROUP=$(echo "${TAP_GROUP}" | sed -E "s/[-_]g[0-9]+.*//")
SETUP_HOOK="${WORKSPACE}/test/tap/groups/${TAP_GROUP}/setup-infras.bash"

if [ ! -f "${SETUP_HOOK}" ]; then

Check failure on line 96 in test/infra/control/ensure-infras.bash

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=sysown_proxysql&issues=AZ0K6xdgHsDk9CgwGjji&open=AZ0K6xdgHsDk9CgwGjji&pullRequest=5461
# Try base group if subgroup doesn't have the hook
SETUP_HOOK="${WORKSPACE}/test/tap/groups/${BASE_GROUP}/setup-infras.bash"
fi

if [ -f "${SETUP_HOOK}" ]; then

Check failure on line 101 in test/infra/control/ensure-infras.bash

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=sysown_proxysql&issues=AZ0K6xdgHsDk9CgwGjjj&open=AZ0K6xdgHsDk9CgwGjjj&pullRequest=5461
echo ">>> Executing group setup hook: ${SETUP_HOOK}"
"${SETUP_HOOK}"
fi
17 changes: 16 additions & 1 deletion test/infra/control/run-tests-isolated.bash
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

# 1. Determine Required Infras
INFRAS_TO_CHECK=""
BASE_GROUP="${TAP_GROUP%%-g[0-9]*}" # Strip -g1, -g2 etc.
BASE_GROUP=$(echo "${TAP_GROUP}" | sed -E "s/[-_]g[0-9]+.*//") # Strip -g1, -g2, _g1, _g2 etc.

if [ -n "${TAP_GROUP}" ]; then
if [ -f "${WORKSPACE}/test/tap/groups/${TAP_GROUP}/infras.lst" ]; then
Expand Down Expand Up @@ -138,6 +138,21 @@
python3 "${WORKSPACE}/test/scripts/bin/proxysql-tester.py"
"

# Execute group-specific pre-cleanup hook if it exists
# This runs before the test runner container is removed, allowing cleanup
# of ProxySQL-specific configuration while admin is still accessible
if [ -n "${TAP_GROUP}" ]; then

Check failure on line 144 in test/infra/control/run-tests-isolated.bash

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=sysown_proxysql&issues=AZ0K6xVZHsDk9CgwGjjf&open=AZ0K6xVZHsDk9CgwGjjf&pullRequest=5461
PRE_CLEANUP_HOOK="${WORKSPACE}/test/tap/groups/${TAP_GROUP}/pre-cleanup.bash"
if [ ! -f "${PRE_CLEANUP_HOOK}" ]; then

Check failure on line 146 in test/infra/control/run-tests-isolated.bash

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=sysown_proxysql&issues=AZ0K6xVZHsDk9CgwGjjg&open=AZ0K6xVZHsDk9CgwGjjg&pullRequest=5461
PRE_CLEANUP_HOOK="${WORKSPACE}/test/tap/groups/${BASE_GROUP}/pre-cleanup.bash"
fi

if [ -f "${PRE_CLEANUP_HOOK}" ]; then

Check failure on line 150 in test/infra/control/run-tests-isolated.bash

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=sysown_proxysql&issues=AZ0K6xVZHsDk9CgwGjjh&open=AZ0K6xVZHsDk9CgwGjjh&pullRequest=5461
echo ">>> Executing group pre-cleanup hook: ${PRE_CLEANUP_HOOK}"
"${PRE_CLEANUP_HOOK}" || true # Allow cleanup to fail
fi
fi
Comment on lines +141 to +154
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

Because this script runs with set -e, a non-zero exit from the docker run test runner will terminate the script before this pre-cleanup hook executes. That means MCP/group cleanup won’t happen on test failures (the main time you want cleanup), and the runner container cleanup below also won’t run. Consider capturing the docker run exit code (temporarily disabling -e), running the hook + container cleanup unconditionally, then exiting with the original test exit code.

Copilot uses AI. Check for mistakes.

# Clean up only the runner container
echo ">>> Cleaning up Test Runner container"
docker rm -f "${TEST_CONTAINER}" >/dev/null 2>&1 || true
16 changes: 16 additions & 0 deletions test/tap/groups/ai-g1/env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# AI-g1 Subgroup Environment Configuration
# Inherits from parent ai group - duplicated here for POSIX sh compatibility
Comment on lines +1 to +2
Copy link

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:

#!/bin/bash
# Verify shell declaration presence in this file.
sed -n '1,3p' test/tap/groups/ai-g1/env.sh

Repository: sysown/proxysql

Length of output: 179


🏁 Script executed:

# Find other env.sh files in the project and check how they handle shell declarations
fd 'env\.sh' test/tap -type f | head -10 | xargs -I {} sh -c 'echo "=== {} ===" && head -3 {}'

Repository: sysown/proxysql

Length of output: 229


🏁 Script executed:

# Find other env.sh files in the test/tap directory and check their shell declarations
fd 'env\.sh' test/tap --type f | head -15 | while read file; do echo "=== $file ===" && head -3 "$file"; done

Repository: sysown/proxysql

Length of output: 2011


🏁 Script executed:

# Search for how these env.sh files are sourced in the codebase
rg -n 'test/tap/groups.*env\.sh|source.*env\.sh|\. .*env\.sh' test/ --type sh --type bash -A 2 | head -50

Repository: sysown/proxysql

Length of output: 87


🏁 Script executed:

# Search for how env.sh files are sourced
rg -n 'test/tap/groups.*env\.sh|source.*env\.sh|\. .*env\.sh' test/ -A 2 | head -60

Repository: sysown/proxysql

Length of output: 2642


🏁 Script executed:

# Check how proxysql-tester.py sources the env files
sed -n '655,680p' test/scripts/bin/proxysql-tester.py

Repository: sysown/proxysql

Length of output: 1788


Declare the shell dialect for lint stability.

Line 1 triggers ShellCheck SC2148 because the script type is unspecified. Since this file is sourced in /bin/sh context (via the test harness), add # shellcheck shell=sh at the top to match the file's stated POSIX sh compatibility.

Proposed patch
+# shellcheck shell=sh
 # AI-g1 Subgroup Environment Configuration
 # Inherits from parent ai group - duplicated here for POSIX sh compatibility
📝 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
# AI-g1 Subgroup Environment Configuration
# Inherits from parent ai group - duplicated here for POSIX sh compatibility
# shellcheck shell=sh
# AI-g1 Subgroup Environment Configuration
# Inherits from parent ai group - duplicated here for POSIX sh compatibility
🧰 Tools
🪛 Shellcheck (0.11.0)

[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.

(SC2148)

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

In `@test/tap/groups/ai-g1/env.sh` around lines 1 - 2, Add a ShellCheck dialect
declaration to the script header to silence SC2148: insert the comment "#
shellcheck shell=sh" as the first line of the file (before the existing
descriptive comments) so the linter knows this is POSIX sh; this change targets
the environment script's header used by the test harness.


export DEFAULT_MYSQL_INFRA="infra-mysql84"
export DEFAULT_PGSQL_INFRA="docker-pgsql16-single"

export TAP_MCPPORT="${TAP_MCPPORT:-6071}"
export MCP_TARGET_ID="${MCP_TARGET_ID:-tap_mysql_default}"
export MCP_AUTH_PROFILE_ID="${MCP_AUTH_PROFILE_ID:-tap_mysql_auth}"
export MCP_PGSQL_TARGET_ID="${MCP_PGSQL_TARGET_ID:-tap_pgsql_default}"
export MCP_PGSQL_AUTH_PROFILE_ID="${MCP_PGSQL_AUTH_PROFILE_ID:-tap_pgsql_auth}"
export MCP_MYSQL_HOSTGROUP_ID="${MCP_MYSQL_HOSTGROUP_ID:-9100}"
export MCP_PGSQL_HOSTGROUP_ID="${MCP_PGSQL_HOSTGROUP_ID:-9200}"

export MYSQL_DATABASE="${MYSQL_DATABASE:-test}"
export PGSQL_DATABASE="${PGSQL_DATABASE:-postgres}"
199 changes: 147 additions & 52 deletions test/tap/groups/ai/README.md
Original file line number Diff line number Diff line change
@@ -1,80 +1,175 @@
# AI TAP Group Local Infra
# AI TAP Group

This group supports running AI/MCP TAP tests with an isolated local backend infra, without relying on Jenkins helper repos.
This group runs AI/MCP TAP tests using the **Unified CI Infrastructure** pattern, with isolated Docker network and automated infrastructure management.

## What it starts
## Architecture

- MySQL 9.0 on `127.0.0.1:13306`
- PostgreSQL 16 on `127.0.0.1:15432`
The AI group uses the standard `test/infra/` pattern:

Both are started from `test/tap/groups/ai/docker-compose.yml`.
- **MySQL Backend**: `infra-mysql84` (3-node MySQL 8.4 cluster with replication)
- **PostgreSQL Backend**: `docker-pgsql16-single` (single PostgreSQL 16 instance)
- **MCP Server**: Configured on port 6071 with MySQL and PostgreSQL targets
- **Network**: Isolated Docker network `${INFRA_ID}_backend`

## Group hooks
## Group Structure

- `pre-proxysql.bash`
- starts local containers (`docker-compose-init.bash`)
- seeds deterministic static-harvest datasets on both backends:
- MySQL: `tap_mysql_static_customers`, `tap_mysql_static_orders`
- PostgreSQL: `tap_pgsql_static_accounts`, `tap_pgsql_static_events`
- enables MCP
- configures backend hostgroups and MCP profiles/targets:
- MySQL target: `tap_mysql_default`
- PostgreSQL target: `tap_pgsql_default`
- `post-proxysql.bash`
- removes group-specific MCP profiles/targets/hostgroups
- destroys local containers (`docker-compose-destroy.bash`)
The `ai` group follows the **supergroup/subgroup** pattern:
- `ai` is the supergroup (defines infrastructure and shared configuration)
- `ai-g1`, `ai-g2`, etc. are subgroups (define specific test sets in `groups.json`)

## Manual run (without Jenkins)
When running with `TAP_GROUP=ai-g1`, the system:
1. Looks for `test/tap/groups/ai/infras.lst` (infrastructure requirements)
2. Looks for `test/tap/groups/ai/env.sh` (environment configuration)
3. Runs only tests tagged with `ai-g1` in `groups.json`

From repository root:
## Infrastructure Files

```bash
source test/tap/groups/ai/env.sh
bash test/tap/groups/ai/pre-proxysql.bash
# run your TAP tests here
bash test/tap/groups/ai/post-proxysql.bash
```
| File | Purpose |
|------|---------|
| `infras.lst` | Lists required infrastructures (`infra-mysql84`, `docker-pgsql16-single`) |
| `env.sh` | Environment variables for MCP configuration |
| `mcp-config.sql` | SQL template for MCP setup (variables substituted at runtime) |
| `cleanup.sql` | SQL template for MCP cleanup after tests |
| `seed-mysql.sql` | Test data for MySQL (seeded on mysql1, replicated to others) |
| `seed-pgsql.sql` | Test data for PostgreSQL |
| `setup-infras.bash` | **Group hook**: Configures MCP and seeds test data after infrastructure is ready |
| `pre-cleanup.bash` | **Group hook**: Removes MCP configuration before test runner cleanup |

## MCP Configuration

The MCP (Model Context Protocol) is automatically configured with:

- **MySQL Target**: `tap_mysql_default` (hostgroup 9100)
- **PostgreSQL Target**: `tap_pgsql_default` (hostgroup 9200)
- **Port**: 6071 (SSL enabled)

Test data includes:
- MySQL: `test.tap_mysql_static_customers`, `test.tap_mysql_static_orders`
- PostgreSQL: `public.tap_pgsql_static_accounts`, `public.tap_pgsql_static_events`

For MCP query-rules suite:
## Usage

### Running the Full AI Group

```bash
source test/tap/groups/ai/env.sh
bash test/tap/groups/ai/pre-proxysql.bash
bash test/tap/tests/test_mcp_query_rules-t.sh
bash test/tap/groups/ai/post-proxysql.bash
# Set unique INFRA_ID to avoid conflicts with other runs
export INFRA_ID="ai-test-$(date +%s)"
export TAP_GROUP="ai-g1"
export WORKSPACE=$(pwd)

# Source common environment
source test/infra/common/env.sh

# Start infrastructure (ProxySQL + MySQL + PostgreSQL)
./test/infra/control/ensure-infras.bash

# Run tests
./test/infra/control/run-tests-isolated.bash

# Cleanup
./test/infra/control/stop-proxysql-isolated.bash
./test/infra/control/destroy-infras.bash
```

For static-harvest phase-A suite (mysql + pgsql targets):
### Running a Single Test

```bash
source test/tap/groups/ai/env.sh
bash test/tap/groups/ai/pre-proxysql.bash
bash test/tap/tests/test_mcp_static_harvest-t.sh
bash test/tap/groups/ai/post-proxysql.bash
export INFRA_ID="ai-single-$(date +%s)"
export TAP_GROUP="ai-g1"
export TEST_PY_TAP_INCL="mcp_module-t"
export WORKSPACE=$(pwd)

source test/infra/common/env.sh
./test/infra/control/ensure-infras.bash
./test/infra/control/run-tests-isolated.bash
./test/infra/control/stop-proxysql-isolated.bash
./test/infra/control/destroy-infras.bash
```

For phase-B MCP discovery primitives (agent/llm/catalog tools, CI-safe):
### Running Specific MCP Test Suites

**MCP Static Harvest (MySQL + PostgreSQL):**
```bash
source test/tap/groups/ai/env.sh
bash test/tap/groups/ai/pre-proxysql.bash
bash test/tap/tests/test_mcp_llm_discovery_phaseb-t.sh
bash test/tap/groups/ai/post-proxysql.bash
export INFRA_ID="ai-harvest-$(date +%s)"
export TAP_GROUP="ai-g1"
export TEST_PY_TAP_INCL="test_mcp_static_harvest-t"
export WORKSPACE=$(pwd)

source test/infra/common/env.sh
./test/infra/control/ensure-infras.bash
./test/infra/control/run-tests-isolated.bash
./test/infra/control/stop-proxysql-isolated.bash
./test/infra/control/destroy-infras.bash
```

For Claude headless flow smoke (dry-run + optional real Claude execution):
**MCP Discovery Phase B:**
```bash
export INFRA_ID="ai-discovery-$(date +%s)"
export TAP_GROUP="ai-g1"
export TEST_PY_TAP_INCL="test_mcp_llm_discovery_phaseb-t"
export WORKSPACE=$(pwd)

source test/infra/common/env.sh
./test/infra/control/ensure-infras.bash
./test/infra/control/run-tests-isolated.bash
./test/infra/control/stop-proxysql-isolated.bash
./test/infra/control/destroy-infras.bash
```

**Claude Headless Flow:**
```bash
source test/tap/groups/ai/env.sh
bash test/tap/groups/ai/pre-proxysql.bash
bash test/tap/tests/test_mcp_claude_headless_flow-t.sh
# Optional real run:
# TAP_RUN_REAL_CLAUDE=1 TAP_CLAUDE_MCP_CONFIG=./scripts/mcp/DiscoveryAgent/ClaudeCode_Headless/mcp_config.json \
# bash test/tap/tests/test_mcp_claude_headless_flow-t.sh
bash test/tap/groups/ai/post-proxysql.bash
export INFRA_ID="ai-claude-$(date +%s)"
export TAP_GROUP="ai-g1"
export TEST_PY_TAP_INCL="test_mcp_claude_headless_flow-t"
export WORKSPACE=$(pwd)

source test/infra/common/env.sh
./test/infra/control/ensure-infras.bash
./test/infra/control/run-tests-isolated.bash
./test/infra/control/stop-proxysql-isolated.bash
./test/infra/control/destroy-infras.bash

# Optional: Run with real Claude execution
# export TAP_RUN_REAL_CLAUDE=1
# export TAP_CLAUDE_MCP_CONFIG=./scripts/mcp/DiscoveryAgent/ClaudeCode_Headless/mcp_config.json
```

## Test Categories

Tests included in the AI group (defined in `groups.json`):

- **AI Module Tests**: `ai_validation-t`, `ai_error_handling_edge_cases-t`, `ai_llm_retry_scenarios-t`
- **Anomaly Detection**: `anomaly_detection-t`, `anomaly_detector_unit-t`, `anomaly_detection_integration-t`
- **GenAI Tests**: `genai_module-t`, `genai_async-t`, `genai_embedding_rerank-t`, `genai_live_validation-t`
- **MCP Tests**: `mcp_module-t`, `mcp_query_rules-t`, `mcp_stats_refresh-t`, `mcp_semantic_lifecycle-t`, etc.
- **NL2SQL Tests**: `nl2sql_integration-t`, `nl2sql_prompt_builder-t`, `nl2sql_model_selection-t`, etc.
- **Vector Tests**: `vector_features-t`, `vector_db_performance-t`

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `TAP_MCPPORT` | 6071 | MCP server port |
| `MCP_TARGET_ID` | tap_mysql_default | MySQL MCP target ID |
| `MCP_PGSQL_TARGET_ID` | tap_pgsql_default | PostgreSQL MCP target ID |
| `MCP_MYSQL_HOSTGROUP_ID` | 9100 | MySQL hostgroup for MCP |
| `MCP_PGSQL_HOSTGROUP_ID` | 9200 | PostgreSQL hostgroup for MCP |
| `TEST_PY_TAP_INCL` | (see env.sh) | Test filter pattern |

## Notes

- All variables can be overridden from the environment before running hooks.
- The scripts still work in Jenkins-driven TAP flows because they do not require Jenkins-only paths.
- All containers run on an isolated Docker network (`${INFRA_ID}_backend`)
- MySQL replication automatically propagates seed data from mysql1 to mysql2/mysql3
- MCP configuration is applied by the group-specific `setup-infras.bash` hook and cleaned up by `pre-cleanup.bash`
- The `INFRA_ID` must be unique for each test run to avoid conflicts

## Group-Specific Hooks

The AI group uses the generic hook system provided by the Unified CI Infrastructure:

| Hook | Executed By | Purpose |
|------|-------------|---------|
| `setup-infras.bash` | `ensure-infras.bash` after backends start | Configures MCP, seeds test data |
| `pre-cleanup.bash` | `run-tests-isolated.bash` before cleanup | Removes MCP configuration |

These hooks are group-specific and live in the `test/tap/groups/ai/` directory. They are discovered and executed automatically by the infrastructure scripts based on `TAP_GROUP`.
15 changes: 15 additions & 0 deletions test/tap/groups/ai/cleanup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- AI Group MCP Cleanup
-- Removes MCP configuration after tests complete
-- Variables are substituted using envsubst before execution

DELETE FROM mcp_target_profiles WHERE target_id IN ('${MCP_TARGET_ID}', '${MCP_PGSQL_TARGET_ID}');
DELETE FROM mcp_auth_profiles WHERE auth_profile_id IN ('${MCP_AUTH_PROFILE_ID}', '${MCP_PGSQL_AUTH_PROFILE_ID}');
LOAD MCP PROFILES TO RUNTIME;
SAVE MCP PROFILES TO DISK;

DELETE FROM mysql_servers WHERE hostgroup_id IN (${MCP_MYSQL_HOSTGROUP_ID});
DELETE FROM pgsql_servers WHERE hostgroup_id IN (${MCP_PGSQL_HOSTGROUP_ID});
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
LOAD PGSQL SERVERS TO RUNTIME;
SAVE PGSQL SERVERS TO DISK;
23 changes: 0 additions & 23 deletions test/tap/groups/ai/docker-compose-destroy.bash

This file was deleted.

55 changes: 0 additions & 55 deletions test/tap/groups/ai/docker-compose-init.bash

This file was deleted.

Loading