This is an automated email from the ASF dual-hosted git repository.
terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new ecb7c87c9da Run MCP E2E tests by wildcard (#38791)
ecb7c87c9da is described below
commit ecb7c87c9da4e20986e993a3eb303176b5fd4bcd
Author: Liang Zhang <[email protected]>
AuthorDate: Thu Jun 4 10:48:59 2026 +0800
Run MCP E2E tests by wildcard (#38791)
- Replace hardcoded MCP E2E test class list with *E2ETest
- Remove MCP-specific enable flags and llm-e2e profile
- Use e2e-env.properties with system property overrides for MCP E2E config
- Build MCP distribution image before workflow E2E execution
- Stabilize LLM resource discovery and MySQL readiness in full Docker E2E
---
.github/workflows/e2e-mcp.yml | 32 ++++++--------
.github/workflows/release-mcp.yml | 15 +++----
.../content/test-manual/mcp-e2e-test/_index.cn.md | 31 ++++++++------
.../content/test-manual/mcp-e2e-test/_index.en.md | 31 ++++++++------
test/e2e/mcp/pom.xml | 29 -------------
.../test/e2e/mcp/env/MCPE2ECondition.java | 40 ++----------------
.../test/e2e/mcp/env/MCPE2ETestConfiguration.java | 37 ++--------------
.../e2e/mcp/env/MCPE2ETestConfigurationTest.java | 45 ++++++--------------
.../e2e/mcp/llm/config/LLME2EConfiguration.java | 40 +++++++++---------
.../LLMMCPModelFacingToolResponseFormatter.java | 13 ++++++
...LLMMCPModelFacingToolResponseFormatterTest.java | 49 ++++++++++++++++++++++
.../e2e/mcp/llm/suite/smoke/LLMSmokeE2ETest.java | 2 +-
.../suite/usability/LLMUsabilitySuiteE2ETest.java | 2 +-
.../AbstractProductionMySQLRuntimeE2ETest.java | 11 +----
.../HttpProductionProxyEncryptWorkflowE2ETest.java | 30 ++++++-------
.../HttpProductionProxyMaskWorkflowE2ETest.java | 19 +++++----
.../production/PackagedDistributionE2ETest.java | 15 +++----
.../ExecuteQueryTransactionE2ETest.java | 2 +-
.../HttpTransportApprovalSafetyE2ETest.java | 2 +-
.../HttpTransportBaselineContractE2ETest.java | 2 +-
.../HttpTransportCompletionE2ETest.java | 2 +-
.../programmatic/HttpTransportContractE2ETest.java | 2 +-
.../HttpTransportProtocolContractE2ETest.java | 2 +-
.../programmatic/HttpTransportRecoveryE2ETest.java | 2 +-
.../programmatic/HttpTransportSecurityE2ETest.java | 2 +-
.../HttpTransportSessionLifecycleE2ETest.java | 2 +-
.../programmatic/MetadataDiscoveryE2ETest.java | 2 +-
.../PackagedDistributionTestSupport.java | 6 ++-
.../PackagedDistributionTestSupportTest.java | 2 +-
.../support/runtime/MySQLRuntimeTestSupport.java | 27 +++++++++---
.../mcp/src/test/resources/env/e2e-env.properties | 25 ++++++++---
31 files changed, 254 insertions(+), 267 deletions(-)
diff --git a/.github/workflows/e2e-mcp.yml b/.github/workflows/e2e-mcp.yml
index d5c9a094ac1..0580713a9e4 100644
--- a/.github/workflows/e2e-mcp.yml
+++ b/.github/workflows/e2e-mcp.yml
@@ -44,11 +44,8 @@ permissions:
env:
MAVEN_OPTS: -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false
-Dmaven.wagon.http.retryHandler.class=standard
-Dmaven.wagon.http.retryHandler.count=3 -Dspotless.apply.skip=true
- MCP_LLM_READY_TIMEOUT_SECONDS: '900'
- MCP_LLM_REQUEST_TIMEOUT_SECONDS: '300'
- MCP_LLM_ARTIFACT_ROOT: test/e2e/mcp/target/llm-e2e
MCP_LLM_SERVER_IMAGE: apache/shardingsphere-mcp-llm-runtime:local
- MCP_LLM_BASE_SERVER_IMAGE_DIGEST:
sha256:988d2695631987e28a29d98970aaf0e979e23b843a26824abb790ac4245d1d57
+ MCP_DISTRIBUTION_IMAGE: apache/shardingsphere-mcp-e2e:local
jobs:
e2e-mcp-mysql-runtime:
@@ -56,8 +53,6 @@ jobs:
if: github.repository == 'apache/shardingsphere'
runs-on: ubuntu-latest
timeout-minutes: 60
- env:
- MCP_LLM_RUN_ID: gha-${{ github.run_id }}-${{ github.run_attempt }}
steps:
- uses: actions/[email protected]
- uses: ./.github/workflows/resources/actions/setup-build-environment
@@ -79,30 +74,29 @@ jobs:
with:
context: test/e2e/mcp/src/test/resources/docker/llm-runtime
file: test/e2e/mcp/src/test/resources/docker/llm-runtime/Dockerfile
- build-args: |
- BASE_IMAGE=ghcr.io/ggml-org/llama.cpp@${{
env.MCP_LLM_BASE_SERVER_IMAGE_DIGEST }}
tags: ${{ env.MCP_LLM_SERVER_IMAGE }}
load: true
cache-from: type=gha,scope=mcp-llm-runtime
cache-to: type=gha,mode=max,scope=mcp-llm-runtime,ignore-error=true
- name: Build MCP E2E Test Dependencies
run: ./mvnw -pl test/e2e/mcp -am install -DskipTests -DskipITs
-Dspotless.skip=true -B -ntp
- - name: Run MCP MySQL Runtime E2E
+ - name: Package MCP Distribution
+ run: ./mvnw -pl distribution/mcp -am -DskipTests package -B -ntp
+ - name: Build MCP Distribution Image
+ run: docker build -f distribution/mcp/Dockerfile -t "${{
env.MCP_DISTRIBUTION_IMAGE }}" distribution/mcp/target
+ - name: Run MCP E2E
shell: bash
run: |
set -euo pipefail
-
MCP_E2E_TESTS=HttpTransportContractE2ETest,HttpTransportProtocolContractE2ETest,HttpTransportBaselineContractE2ETest
- MCP_E2E_TESTS="${MCP_E2E_TESTS},ProductionMySQLRuntimeE2ETest"
-
MCP_E2E_TESTS="${MCP_E2E_TESTS},HttpProductionProxyEncryptWorkflowE2ETest"
-
MCP_E2E_TESTS="${MCP_E2E_TESTS},HttpProductionProxyMaskWorkflowE2ETest,LLMUsabilitySuiteE2ETest"
./mvnw -pl test/e2e/mcp test -DskipITs -Dspotless.skip=true \
- -Dtest="${MCP_E2E_TESTS}" \
+ -Dtest='*E2ETest' \
-Dsurefire.failIfNoSpecifiedTests=true \
- -Dmcp.e2e.contract.enabled=true \
- -Dmcp.e2e.production.mysql.enabled=true \
- -Dmcp.e2e.production.stdio.enabled=true \
- -Dmcp.e2e.llm.enabled=true \
- -Dmcp.e2e.llm.excludedGroups= \
+ -De2e.run.type=DOCKER \
+ -Dmcp.e2e.container.image="${{ env.MCP_DISTRIBUTION_IMAGE }}" \
+ -Dmcp.llm.ready-timeout-seconds=900 \
+ -Dmcp.llm.request-timeout-seconds=300 \
+ -Dmcp.llm.artifact-root="${{ github.workspace
}}/test/e2e/mcp/target/llm-e2e" \
+ -Dmcp.llm.run-id=gha-${{ github.run_id }}-${{ github.run_attempt
}} \
-B -ntp
- name: Upload MCP E2E Artifacts
if: always()
diff --git a/.github/workflows/release-mcp.yml
b/.github/workflows/release-mcp.yml
index 0ae027ee54a..dd20ef53332 100644
--- a/.github/workflows/release-mcp.yml
+++ b/.github/workflows/release-mcp.yml
@@ -37,8 +37,6 @@ permissions:
env:
MAVEN_OPTS: -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false
-Dmaven.wagon.http.retryHandler.class=standard
-Dmaven.wagon.http.retryHandler.count=3 -Dspotless.apply.skip=true
MCP_IMAGE: ghcr.io/apache/shardingsphere-mcp
- MCP_PUBLISHER_LINUX_AMD64_SHA256:
ab128162b0616090b47cf245afe0a23f3ef08936fdce19074f5ba0a4469281ac
- MCP_PUBLISHER_LINUX_ARM64_SHA256:
04f5199b3deef8e6fc4d6ed98c56a74f799def53edca3fe6d4862ecd4397c172
MCP_PUBLISHER_VERSION: v1.7.9
MCP_SERVER_NAME: io.github.apache/shardingsphere-mcp
@@ -104,7 +102,7 @@ jobs:
./mvnw -pl test/e2e/mcp test -DskipITs -Dspotless.skip=true \
-Dtest=PackagedDistributionE2ETest \
-Dsurefire.failIfNoSpecifiedTests=true \
- -Dmcp.e2e.distribution.enabled=true \
+ -De2e.run.type=DOCKER \
-Dmcp.e2e.container.image=shardingsphere-mcp-release:local \
-Dmcp.distribution.home="${DISTRIBUTION_HOME}" \
-B -ntp
@@ -162,7 +160,7 @@ jobs:
./mvnw -pl test/e2e/mcp test -DskipITs -Dspotless.skip=true \
-Dtest=PackagedDistributionE2ETest#assertLaunchContainerOverHttp+assertLaunchContainerOverStdio
\
-Dsurefire.failIfNoSpecifiedTests=true \
- -Dmcp.e2e.distribution.enabled=true \
+ -De2e.run.type=DOCKER \
-Dmcp.e2e.container.image="${{ env.MCP_IMAGE }}@${{
steps.push-image.outputs.digest }}" \
-B -ntp
- name: Install MCP Publisher
@@ -172,20 +170,23 @@ jobs:
case "$(uname -m)" in
x86_64 | amd64)
MCP_PUBLISHER_ARCHIVE="mcp-publisher_linux_amd64.tar.gz"
- MCP_PUBLISHER_SHA256="${MCP_PUBLISHER_LINUX_AMD64_SHA256}"
;;
aarch64 | arm64)
MCP_PUBLISHER_ARCHIVE="mcp-publisher_linux_arm64.tar.gz"
- MCP_PUBLISHER_SHA256="${MCP_PUBLISHER_LINUX_ARM64_SHA256}"
;;
*)
echo "Unsupported MCP Publisher architecture: $(uname -m)" 1>&2
exit 1
;;
esac
+
MCP_PUBLISHER_CHECKSUMS="registry_${MCP_PUBLISHER_VERSION#v}_checksums.txt"
curl -fsSL --retry 3 --output "${MCP_PUBLISHER_ARCHIVE}" \
"https://github.com/modelcontextprotocol/registry/releases/download/${MCP_PUBLISHER_VERSION}/${MCP_PUBLISHER_ARCHIVE}"
- printf '%s %s\n' "${MCP_PUBLISHER_SHA256}"
"${MCP_PUBLISHER_ARCHIVE}" | sha256sum -c -
+ curl -fsSL --retry 3 --output "${MCP_PUBLISHER_CHECKSUMS}" \
+
"https://github.com/modelcontextprotocol/registry/releases/download/${MCP_PUBLISHER_VERSION}/${MCP_PUBLISHER_CHECKSUMS}"
+ awk -v archive="${MCP_PUBLISHER_ARCHIVE}" '$2 == archive {print;
found = 1} END {exit found ? 0 : 1}' \
+ "${MCP_PUBLISHER_CHECKSUMS}" > "${MCP_PUBLISHER_ARCHIVE}.sha256"
+ sha256sum -c "${MCP_PUBLISHER_ARCHIVE}.sha256"
tar xzf "${MCP_PUBLISHER_ARCHIVE}" mcp-publisher
- name: Authenticate to MCP Registry
working-directory: mcp
diff --git a/docs/document/content/test-manual/mcp-e2e-test/_index.cn.md
b/docs/document/content/test-manual/mcp-e2e-test/_index.cn.md
index 0031d7fa1fd..b4e099eb7d4 100644
--- a/docs/document/content/test-manual/mcp-e2e-test/_index.cn.md
+++ b/docs/document/content/test-manual/mcp-e2e-test/_index.cn.md
@@ -27,6 +27,13 @@ chapter = true
./mvnw -pl test/e2e/mcp -am install -DskipTests -DskipITs -Dspotless.skip=true
-B -ntp
```
+打包 MCP distribution 并构建本地 distribution image:
+
+```bash
+./mvnw -pl distribution/mcp -am -DskipTests package -B -ntp
+docker build -f distribution/mcp/Dockerfile -t
apache/shardingsphere-mcp-e2e:local distribution/mcp/target
+```
+
## LLM Runtime
MCP LLM lane 默认使用本地 Docker image 承载 OpenAI-compatible endpoint。
@@ -50,27 +57,24 @@ sh
test/e2e/mcp/src/test/resources/docker/llm-runtime/build-local.sh
## 运行 MCP Runtime E2E
+MCP E2E 运行配置集中在 `test/e2e/mcp/src/test/resources/env/e2e-env.properties`。
+本地运行时可以直接修改该文件,也可以使用同名 `-D` 系统参数覆盖。
+
```bash
-MCP_E2E_TESTS=HttpTransportContractE2ETest,HttpTransportProtocolContractE2ETest,HttpTransportBaselineContractE2ETest
-MCP_E2E_TESTS="${MCP_E2E_TESTS},ProductionMySQLRuntimeE2ETest"
-MCP_E2E_TESTS="${MCP_E2E_TESTS},HttpProductionProxyEncryptWorkflowE2ETest"
-MCP_E2E_TESTS="${MCP_E2E_TESTS},HttpProductionProxyMaskWorkflowE2ETest,LLMUsabilitySuiteE2ETest"
./mvnw -pl test/e2e/mcp test -DskipITs -Dspotless.skip=true \
- -Dtest="${MCP_E2E_TESTS}" \
+ -Dtest='*E2ETest' \
-Dsurefire.failIfNoSpecifiedTests=true \
- -Dmcp.e2e.contract.enabled=true \
- -Dmcp.e2e.production.mysql.enabled=true \
- -Dmcp.e2e.production.stdio.enabled=true \
- -Dmcp.e2e.llm.enabled=true \
- -Dmcp.e2e.llm.excludedGroups=
+ -De2e.run.type=DOCKER \
+ -Dmcp.e2e.container.image=apache/shardingsphere-mcp-e2e:local
```
## 运行 LLM Usability Suite
```bash
-./mvnw -pl test/e2e/mcp -Pllm-e2e test -DskipITs -Dspotless.skip=true \
+./mvnw -pl test/e2e/mcp test -DskipITs -Dspotless.skip=true \
-Dtest=LLMUsabilitySuiteE2ETest \
- -Dsurefire.failIfNoSpecifiedTests=true
+ -Dsurefire.failIfNoSpecifiedTests=true \
+ -De2e.run.type=DOCKER
```
## External Debug
@@ -78,8 +82,9 @@
MCP_E2E_TESTS="${MCP_E2E_TESTS},HttpProductionProxyMaskWorkflowE2ETest,LLMUsabil
仅本地调试时,可以连接已经运行的 OpenAI-compatible endpoint:
```bash
-./mvnw -pl test/e2e/mcp -Pllm-e2e test -DskipITs -Dspotless.skip=true \
+./mvnw -pl test/e2e/mcp test -DskipITs -Dspotless.skip=true \
-Dtest=LLMUsabilitySuiteE2ETest \
+ -De2e.run.type=DOCKER \
-Dmcp.llm.runtime-mode=external-debug \
-Dmcp.llm.base-url=http://127.0.0.1:8080/v1 \
-Dsurefire.failIfNoSpecifiedTests=true
diff --git a/docs/document/content/test-manual/mcp-e2e-test/_index.en.md
b/docs/document/content/test-manual/mcp-e2e-test/_index.en.md
index b9afe93aff5..c7661e40b2c 100644
--- a/docs/document/content/test-manual/mcp-e2e-test/_index.en.md
+++ b/docs/document/content/test-manual/mcp-e2e-test/_index.en.md
@@ -27,6 +27,13 @@ Install MCP E2E dependency modules into the local repository
first:
./mvnw -pl test/e2e/mcp -am install -DskipTests -DskipITs -Dspotless.skip=true
-B -ntp
```
+Package the MCP distribution and build the local distribution image:
+
+```bash
+./mvnw -pl distribution/mcp -am -DskipTests package -B -ntp
+docker build -f distribution/mcp/Dockerfile -t
apache/shardingsphere-mcp-e2e:local distribution/mcp/target
+```
+
## LLM Runtime
The MCP LLM lane uses a local Docker image to host an OpenAI-compatible
endpoint.
@@ -50,27 +57,24 @@ sh
test/e2e/mcp/src/test/resources/docker/llm-runtime/build-local.sh
## Run MCP Runtime E2E
+MCP E2E runtime configuration is centralized in
`test/e2e/mcp/src/test/resources/env/e2e-env.properties`.
+For local runs, edit that file or override the same keys with `-D` system
properties.
+
```bash
-MCP_E2E_TESTS=HttpTransportContractE2ETest,HttpTransportProtocolContractE2ETest,HttpTransportBaselineContractE2ETest
-MCP_E2E_TESTS="${MCP_E2E_TESTS},ProductionMySQLRuntimeE2ETest"
-MCP_E2E_TESTS="${MCP_E2E_TESTS},HttpProductionProxyEncryptWorkflowE2ETest"
-MCP_E2E_TESTS="${MCP_E2E_TESTS},HttpProductionProxyMaskWorkflowE2ETest,LLMUsabilitySuiteE2ETest"
./mvnw -pl test/e2e/mcp test -DskipITs -Dspotless.skip=true \
- -Dtest="${MCP_E2E_TESTS}" \
+ -Dtest='*E2ETest' \
-Dsurefire.failIfNoSpecifiedTests=true \
- -Dmcp.e2e.contract.enabled=true \
- -Dmcp.e2e.production.mysql.enabled=true \
- -Dmcp.e2e.production.stdio.enabled=true \
- -Dmcp.e2e.llm.enabled=true \
- -Dmcp.e2e.llm.excludedGroups=
+ -De2e.run.type=DOCKER \
+ -Dmcp.e2e.container.image=apache/shardingsphere-mcp-e2e:local
```
## Run LLM Usability Suite
```bash
-./mvnw -pl test/e2e/mcp -Pllm-e2e test -DskipITs -Dspotless.skip=true \
+./mvnw -pl test/e2e/mcp test -DskipITs -Dspotless.skip=true \
-Dtest=LLMUsabilitySuiteE2ETest \
- -Dsurefire.failIfNoSpecifiedTests=true
+ -Dsurefire.failIfNoSpecifiedTests=true \
+ -De2e.run.type=DOCKER
```
## External Debug
@@ -78,8 +82,9 @@
MCP_E2E_TESTS="${MCP_E2E_TESTS},HttpProductionProxyMaskWorkflowE2ETest,LLMUsabil
For local debugging only, connect to an already running OpenAI-compatible
endpoint:
```bash
-./mvnw -pl test/e2e/mcp -Pllm-e2e test -DskipITs -Dspotless.skip=true \
+./mvnw -pl test/e2e/mcp test -DskipITs -Dspotless.skip=true \
-Dtest=LLMUsabilitySuiteE2ETest \
+ -De2e.run.type=DOCKER \
-Dmcp.llm.runtime-mode=external-debug \
-Dmcp.llm.base-url=http://127.0.0.1:8080/v1 \
-Dsurefire.failIfNoSpecifiedTests=true
diff --git a/test/e2e/mcp/pom.xml b/test/e2e/mcp/pom.xml
index 3269956432a..84f4129ebaf 100644
--- a/test/e2e/mcp/pom.xml
+++ b/test/e2e/mcp/pom.xml
@@ -32,9 +32,6 @@
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.release>${java.version}</maven.compiler.release>
<maven.deploy.skip>true</maven.deploy.skip>
- <mcp.e2e.llm.groups />
- <mcp.e2e.llm.excludedGroups>llm-e2e</mcp.e2e.llm.excludedGroups>
- <mcp.e2e.llm.enabled>false</mcp.e2e.llm.enabled>
</properties>
<dependencies>
@@ -80,30 +77,4 @@
<scope>test</scope>
</dependency>
</dependencies>
-
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <groups>${mcp.e2e.llm.groups}</groups>
-
<excludedGroups>${mcp.e2e.llm.excludedGroups}</excludedGroups>
- <systemPropertyVariables>
-
<mcp.e2e.llm.enabled>${mcp.e2e.llm.enabled}</mcp.e2e.llm.enabled>
- </systemPropertyVariables>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <profiles>
- <profile>
- <id>llm-e2e</id>
- <properties>
- <mcp.e2e.llm.groups>llm-e2e</mcp.e2e.llm.groups>
- <mcp.e2e.llm.excludedGroups />
- <mcp.e2e.llm.enabled>true</mcp.e2e.llm.enabled>
- </properties>
- </profile>
- </profiles>
</project>
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ECondition.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ECondition.java
index 76c2341f1b0..2653f7ec1f9 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ECondition.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ECondition.java
@@ -23,43 +23,11 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class MCPE2ECondition {
- public static boolean isContractEnabled() {
- return isContractEnabled(MCPE2ETestConfiguration.getInstance());
+ public static boolean isDockerEnabled() {
+ return isDockerEnabled(MCPE2ETestConfiguration.getInstance());
}
- static boolean isContractEnabled(final MCPE2ETestConfiguration config) {
- return config.isContractEnabled();
- }
-
- public static boolean isProductionMySQLEnabled() {
- return isProductionMySQLEnabled(MCPE2ETestConfiguration.getInstance());
- }
-
- static boolean isProductionMySQLEnabled(final MCPE2ETestConfiguration
config) {
- return config.isProductionMySQLEnabled();
- }
-
- public static boolean isProductionMySQLStdioEnabled() {
- return
isProductionMySQLStdioEnabled(MCPE2ETestConfiguration.getInstance());
- }
-
- static boolean isProductionMySQLStdioEnabled(final MCPE2ETestConfiguration
config) {
- return config.isProductionMySQLEnabled() &&
config.isProductionStdioEnabled();
- }
-
- public static boolean isDistributionEnabled() {
- return isDistributionEnabled(MCPE2ETestConfiguration.getInstance());
- }
-
- static boolean isDistributionEnabled(final MCPE2ETestConfiguration config)
{
- return config.isDistributionEnabled();
- }
-
- public static boolean isLLMEnabled() {
- return isLLMEnabled(MCPE2ETestConfiguration.getInstance());
- }
-
- static boolean isLLMEnabled(final MCPE2ETestConfiguration config) {
- return config.isLLMEnabled();
+ static boolean isDockerEnabled(final MCPE2ETestConfiguration config) {
+ return config.isDockerRunType();
}
}
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ETestConfiguration.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ETestConfiguration.java
index d1763458402..88a99274b96 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ETestConfiguration.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ETestConfiguration.java
@@ -27,7 +27,7 @@ import java.util.Properties;
@RequiredArgsConstructor
final class MCPE2ETestConfiguration {
- private static final MCPE2ETestConfiguration INSTANCE = new
MCPE2ETestConfiguration(EnvironmentPropertiesLoader.loadProperties("env/e2e-env.properties"));
+ private static final MCPE2ETestConfiguration INSTANCE = new
MCPE2ETestConfiguration(EnvironmentPropertiesLoader.loadProperties());
private final Properties props;
@@ -35,38 +35,7 @@ final class MCPE2ETestConfiguration {
return INSTANCE;
}
- boolean isContractEnabled() {
- return getBoolean("mcp.e2e.contract.enabled", false);
- }
-
- boolean isProductionMySQLEnabled() {
- return getBoolean("mcp.e2e.production.mysql.enabled", false);
- }
-
- boolean isProductionStdioEnabled() {
- return getBoolean("mcp.e2e.production.stdio.enabled", false);
- }
-
- boolean isDistributionEnabled() {
- return getBoolean("mcp.e2e.distribution.enabled", false);
- }
-
- boolean isLLMEnabled() {
- return getBoolean("mcp.e2e.llm.enabled", false);
- }
-
- private boolean getBoolean(final String key, final boolean defaultValue) {
- String value = props.getProperty(key);
- if (null == value) {
- return defaultValue;
- }
- String trimmedValue = value.trim().toLowerCase(Locale.ENGLISH);
- if ("true".equals(trimmedValue)) {
- return true;
- }
- if ("false".equals(trimmedValue)) {
- return false;
- }
- return defaultValue;
+ boolean isDockerRunType() {
+ return EnvironmentPropertiesLoader.getListValue(props,
"e2e.run.type").stream().map(each ->
each.toUpperCase(Locale.ENGLISH)).anyMatch("DOCKER"::equals);
}
}
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ETestConfigurationTest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ETestConfigurationTest.java
index b160b80e392..d00f5f61cf7 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ETestConfigurationTest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/env/MCPE2ETestConfigurationTest.java
@@ -27,52 +27,33 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
class MCPE2ETestConfigurationTest {
@Test
- void assertDefaultLaneValues() {
+ void assertDefaultRunType() {
MCPE2ETestConfiguration config = new MCPE2ETestConfiguration(new
Properties());
- assertFalse(config.isContractEnabled());
- assertFalse(config.isProductionMySQLEnabled());
- assertFalse(config.isProductionStdioEnabled());
- assertFalse(config.isDistributionEnabled());
- assertFalse(config.isLLMEnabled());
+ assertFalse(config.isDockerRunType());
}
@Test
- void assertExplicitLaneOverrides() {
+ void assertDockerRunType() {
Properties props = new Properties();
- props.setProperty("mcp.e2e.contract.enabled", "true");
- props.setProperty("mcp.e2e.production.mysql.enabled", "true");
- props.setProperty("mcp.e2e.production.stdio.enabled", "true");
- props.setProperty("mcp.e2e.distribution.enabled", "true");
- props.setProperty("mcp.e2e.llm.enabled", "true");
+ props.setProperty("e2e.run.type", "DOCKER");
MCPE2ETestConfiguration config = new MCPE2ETestConfiguration(props);
- assertTrue(config.isContractEnabled());
- assertTrue(config.isProductionMySQLEnabled());
- assertTrue(config.isProductionStdioEnabled());
- assertTrue(config.isDistributionEnabled());
- assertTrue(config.isLLMEnabled());
+ assertTrue(config.isDockerRunType());
}
@Test
- void assertInvalidBooleanFallsBackToDefault() {
+ void assertCommaSeparatedRunTypes() {
Properties props = new Properties();
- props.setProperty("mcp.e2e.contract.enabled", "invalid");
- props.setProperty("mcp.e2e.production.mysql.enabled", "invalid");
+ props.setProperty("e2e.run.type", "NATIVE, docker");
MCPE2ETestConfiguration config = new MCPE2ETestConfiguration(props);
- assertFalse(config.isContractEnabled());
- assertFalse(config.isProductionMySQLEnabled());
+ assertTrue(config.isDockerRunType());
}
@Test
- void assertCompositeMySQLStdioCondition() {
- Properties mysqlOnlyProps = new Properties();
- mysqlOnlyProps.setProperty("mcp.e2e.production.mysql.enabled", "true");
- MCPE2ETestConfiguration mysqlOnlyConfig = new
MCPE2ETestConfiguration(mysqlOnlyProps);
- Properties bothProps = new Properties();
- bothProps.setProperty("mcp.e2e.production.mysql.enabled", "true");
- bothProps.setProperty("mcp.e2e.production.stdio.enabled", "true");
- MCPE2ETestConfiguration bothConfig = new
MCPE2ETestConfiguration(bothProps);
-
assertFalse(MCPE2ECondition.isProductionMySQLStdioEnabled(mysqlOnlyConfig));
- assertTrue(MCPE2ECondition.isProductionMySQLStdioEnabled(bothConfig));
+ void assertNativeRunType() {
+ Properties props = new Properties();
+ props.setProperty("e2e.run.type", "NATIVE");
+ MCPE2ETestConfiguration config = new MCPE2ETestConfiguration(props);
+ assertFalse(config.isDockerRunType());
}
}
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/config/LLME2EConfiguration.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/config/LLME2EConfiguration.java
index 5afacce9659..314d7d2559b 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/config/LLME2EConfiguration.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/config/LLME2EConfiguration.java
@@ -17,6 +17,8 @@
package org.apache.shardingsphere.test.e2e.mcp.llm.config;
+import
org.apache.shardingsphere.test.e2e.env.runtime.EnvironmentPropertiesLoader;
+
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -27,6 +29,7 @@ import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
+import java.util.Properties;
import java.util.UUID;
/**
@@ -80,20 +83,21 @@ public final class LLME2EConfiguration {
* @return LLM E2E configuration
*/
public static LLME2EConfiguration load() {
- RuntimeMode runtimeMode =
RuntimeMode.from(readString("mcp.llm.runtime-mode", "MCP_LLM_RUNTIME_MODE",
RuntimeMode.DOCKER.getValue()));
+ Properties props = EnvironmentPropertiesLoader.loadProperties();
+ RuntimeMode runtimeMode = RuntimeMode.from(readString(props,
"mcp.llm.runtime-mode", RuntimeMode.DOCKER.getValue()));
return new LLME2EConfiguration(
- normalizeBaseUrl(readString("mcp.llm.base-url",
"MCP_LLM_BASE_URL", DEFAULT_BASE_URL)),
- readString("mcp.llm.provider", "MCP_LLM_PROVIDER",
"openai-compatible"),
- readString("mcp.llm.model", "MCP_LLM_MODEL",
DEFAULT_MODEL_NAME),
- readString("mcp.llm.api-key", "MCP_LLM_API_KEY",
DEFAULT_API_KEY),
- readInteger("mcp.llm.ready-timeout-seconds",
"MCP_LLM_READY_TIMEOUT_SECONDS", 600),
- readInteger("mcp.llm.request-timeout-seconds",
"MCP_LLM_REQUEST_TIMEOUT_SECONDS", 240),
- readInteger("mcp.llm.max-turns", "MCP_LLM_MAX_TURNS", 10),
- Paths.get(readString("mcp.llm.artifact-root",
"MCP_LLM_ARTIFACT_ROOT", "target/llm-e2e")),
- readString("mcp.llm.run-id", "MCP_LLM_RUN_ID",
createDefaultRunId()),
+ normalizeBaseUrl(readString(props, "mcp.llm.base-url",
DEFAULT_BASE_URL)),
+ readString(props, "mcp.llm.provider", "openai-compatible"),
+ readString(props, "mcp.llm.model", DEFAULT_MODEL_NAME),
+ readString(props, "mcp.llm.api-key", DEFAULT_API_KEY),
+ readInteger(props, "mcp.llm.ready-timeout-seconds", 600),
+ readInteger(props, "mcp.llm.request-timeout-seconds", 240),
+ readInteger(props, "mcp.llm.max-turns", 10),
+ Paths.get(readString(props, "mcp.llm.artifact-root",
"target/llm-e2e")),
+ readString(props, "mcp.llm.run-id", createDefaultRunId()),
runtimeMode,
- readString("mcp.llm.server-image", "MCP_LLM_SERVER_IMAGE",
DEFAULT_SERVER_IMAGE),
- readString("mcp.llm.base-server-image-digest",
"MCP_LLM_BASE_SERVER_IMAGE_DIGEST",
getDefaultBaseServerImageDigest(runtimeMode)));
+ readString(props, "mcp.llm.server-image",
DEFAULT_SERVER_IMAGE),
+ readString(props, "mcp.llm.base-server-image-digest",
getDefaultBaseServerImageDigest(runtimeMode)));
}
/**
@@ -162,17 +166,13 @@ public final class LLME2EConfiguration {
return baseUrl + "/models";
}
- private static String readString(final String propertyName, final String
environmentName, final String defaultValue) {
- String result = System.getProperty(propertyName);
- if (null != result && !result.trim().isEmpty()) {
- return result.trim();
- }
- result = System.getenv(environmentName);
+ private static String readString(final Properties props, final String
propertyName, final String defaultValue) {
+ String result = props.getProperty(propertyName);
return null == result || result.trim().isEmpty() ? defaultValue :
result.trim();
}
- private static int readInteger(final String propertyName, final String
environmentName, final int defaultValue) {
- String result = readString(propertyName, environmentName,
String.valueOf(defaultValue));
+ private static int readInteger(final Properties props, final String
propertyName, final int defaultValue) {
+ String result = readString(props, propertyName,
String.valueOf(defaultValue));
try {
return Integer.parseInt(result);
} catch (final NumberFormatException ignored) {
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatter.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatter.java
index 2f38a301c8e..abe2c6c9782 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatter.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatter.java
@@ -57,6 +57,19 @@ final class LLMMCPModelFacingToolResponseFormatter {
copyIfPresent(response, result, "total_match_count");
copyIfPresent(response, result, "search_context");
copyIfPresent(response, result, "ambiguity_state");
+ List<Map<String, Object>> resources =
LLMMCPJsonValues.castToList(response.get("resources"));
+ if (!resources.isEmpty()) {
+ List<Map<String, Object>> compactResources = new LinkedList<>();
+ for (Map<String, Object> each : resources) {
+ Map<String, Object> compactResource = new LinkedHashMap<>(8,
1F);
+ copyIfPresent(each, compactResource, "uri");
+ copyIfPresent(each, compactResource, "name");
+ copyIfPresent(each, compactResource, "title");
+ copyIfPresent(each, compactResource, "mimeType");
+ compactResources.add(compactResource.isEmpty() ? each :
compactResource);
+ }
+ result.put("resources", compactResources);
+ }
copyPromptList(response, result);
copyPromptMessages(response, result);
copyCompactItems(response, result);
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatterTest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatterTest.java
new file mode 100644
index 00000000000..6581919ea48
--- /dev/null
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatterTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.test.e2e.mcp.llm.conversation;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.apache.shardingsphere.infra.util.json.JsonUtils;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+class LLMMCPModelFacingToolResponseFormatterTest {
+
+ @Test
+ void assertFormat() {
+ Map<String, Object> actual =
JsonUtils.fromJsonString(LLMMCPModelFacingToolResponseFormatter.format(Map.of("resources",
List.of(Map.of(
+ "uri", "shardingsphere://databases",
+ "name", "logical-databases",
+ "title", "Logical Databases",
+ "description", "Long model-facing description.",
+ "mimeType", "application/json",
+ "_meta", Map.of("org.apache.shardingsphere/resource-kind",
"list"))))), new TypeReference<>() {
+ });
+ Map<String, Object> expected = Map.of("resources", List.of(Map.of(
+ "uri", "shardingsphere://databases",
+ "name", "logical-databases",
+ "title", "Logical Databases",
+ "mimeType", "application/json")));
+ assertThat(actual, is(expected));
+ }
+}
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/smoke/LLMSmokeE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/smoke/LLMSmokeE2ETest.java
index 62ad0ab4894..e16872f461e 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/smoke/LLMSmokeE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/smoke/LLMSmokeE2ETest.java
@@ -96,7 +96,7 @@ class LLMSmokeE2ETest extends
AbstractConfigBackedRuntimeE2ETest {
}
private static boolean isEnabled() {
- return MCPE2ECondition.isLLMEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
static Stream<Arguments> getTestCases() {
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteE2ETest.java
index 98b3da31b59..f550e2f9018 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteE2ETest.java
@@ -89,7 +89,7 @@ class LLMUsabilitySuiteE2ETest extends
AbstractConfigBackedRuntimeE2ETest {
}
private static boolean isEnabled() {
- return MCPE2ECondition.isLLMEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
static Stream<Arguments> getTestCases() {
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/AbstractProductionMySQLRuntimeE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/AbstractProductionMySQLRuntimeE2ETest.java
index 498e927094d..24904c31217 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/AbstractProductionMySQLRuntimeE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/AbstractProductionMySQLRuntimeE2ETest.java
@@ -123,7 +123,7 @@ abstract class AbstractProductionMySQLRuntimeE2ETest
extends AbstractTransportPa
}
protected static boolean isEnabled() {
- return MCPE2ECondition.isProductionMySQLEnabled() ||
MCPE2ECondition.isProductionMySQLStdioEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
protected static Stream<Arguments> transports() {
@@ -155,14 +155,7 @@ abstract class AbstractProductionMySQLRuntimeE2ETest
extends AbstractTransportPa
}
protected static Stream<RuntimeTransport> runtimeTransports() {
- Stream.Builder<RuntimeTransport> result = Stream.builder();
- if (MCPE2ECondition.isProductionMySQLEnabled()) {
- result.add(RuntimeTransport.HTTP);
- }
- if (MCPE2ECondition.isProductionMySQLStdioEnabled()) {
- result.add(RuntimeTransport.STDIO);
- }
- return result.build();
+ return Stream.of(RuntimeTransport.HTTP, RuntimeTransport.STDIO);
}
protected static String getTransportName(final RuntimeTransport transport)
{
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/HttpProductionProxyEncryptWorkflowE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/HttpProductionProxyEncryptWorkflowE2ETest.java
index a5fbcc08c45..1fece035a64 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/HttpProductionProxyEncryptWorkflowE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/HttpProductionProxyEncryptWorkflowE2ETest.java
@@ -24,6 +24,8 @@ import
org.apache.shardingsphere.test.e2e.mcp.support.transport.client.MCPIntera
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIf;
+import java.io.IOException;
+import java.sql.SQLException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -53,11 +55,11 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
private static final String TABLE_RULES_RESOURCE_URI =
"shardingsphere://features/encrypt/databases/%s/tables/%s/rules";
private static boolean isEnabled() {
- return MCPE2ECondition.isProductionMySQLEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
- void assertCompleteEncryptAlgorithmThroughProxy() throws Exception {
+ void assertCompleteEncryptAlgorithmThroughProxy() throws IOException,
InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actual =
interactionClient.complete(Map.of("type", "ref/prompt", "name",
PLAN_PROMPT_NAME), "algorithm_type", "AE", Map.of());
assertThat(getStringList(getMap(actual.get("completion")).get("values")),
hasItem("AES"));
@@ -65,7 +67,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void assertPlanApplyAndValidateEncryptWorkflowThroughProxy() throws
Exception {
+ void assertPlanApplyAndValidateEncryptWorkflowThroughProxy() throws
IOException, InterruptedException, SQLException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> clarifyingResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("table", "orders", "column", "status",
"natural_language_intent", "encrypt status with reversible encryption, no
equality, no like"));
@@ -116,7 +118,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void assertPlanRecommendsAssistedQueryEncryptWorkflowThroughProxy() throws
Exception {
+ void assertPlanRecommendsAssistedQueryEncryptWorkflowThroughProxy() throws
IOException, InterruptedException, SQLException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualClarifyingResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -168,7 +170,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void assertPlanReportsLikeQueryCapabilityConflictThroughProxy() throws
Exception {
+ void assertPlanReportsLikeQueryCapabilityConflictThroughProxy() throws
IOException, InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualPlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -184,7 +186,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void
assertPlanAutoRenamesDerivedColumnWhenCipherColumnConflictsThroughProxy()
throws Exception {
+ void
assertPlanAutoRenamesDerivedColumnWhenCipherColumnConflictsThroughProxy()
throws IOException, InterruptedException, SQLException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
interactionClient.call("database_gateway_execute_update",
Map.of("database", getLogicalDatabaseName(), "schema",
"public",
@@ -210,7 +212,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void assertPlanRejectsUnsupportedSecondEncryptColumnThroughProxy() throws
Exception {
+ void assertPlanRejectsUnsupportedSecondEncryptColumnThroughProxy() throws
IOException, InterruptedException, SQLException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualFirstPlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -239,7 +241,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void assertApplySupportsManualOnlyExecutionModeThroughProxy() throws
Exception {
+ void assertApplySupportsManualOnlyExecutionModeThroughProxy() throws
IOException, InterruptedException, SQLException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualPlannedResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -263,7 +265,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void assertApplySupportsApprovedStepsThroughProxy() throws Exception {
+ void assertApplySupportsApprovedStepsThroughProxy() throws IOException,
InterruptedException, SQLException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualPlannedResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -292,7 +294,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void assertPlanRejectsUnsupportedEncryptAlterExpansionThroughProxy()
throws Exception {
+ void assertPlanRejectsUnsupportedEncryptAlterExpansionThroughProxy()
throws IOException, InterruptedException, SQLException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
createEncryptRuleWithoutEquality(interactionClient);
Map<String, Object> actualAlterPlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
@@ -310,7 +312,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void assertPlanApplyAndValidateEncryptDropWorkflowThroughProxy() throws
Exception {
+ void assertPlanApplyAndValidateEncryptDropWorkflowThroughProxy() throws
IOException, InterruptedException, SQLException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
createEncryptRuleWithoutEquality(interactionClient);
Map<String, Object> actualDropPlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
@@ -335,7 +337,7 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
@Test
- void
assertPlanApplyValidateAndReadEncryptResourcesWithCustomAlgorithmThroughProxy()
throws Exception {
+ void
assertPlanApplyValidateAndReadEncryptResourcesWithCustomAlgorithmThroughProxy()
throws IOException, InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualPlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -357,11 +359,11 @@ class HttpProductionProxyEncryptWorkflowE2ETest extends
AbstractProductionProxyW
}
}
- private void createEncryptRuleWithoutEquality(final MCPInteractionClient
interactionClient) throws Exception {
+ private void createEncryptRuleWithoutEquality(final MCPInteractionClient
interactionClient) throws IOException, InterruptedException {
createEncryptRuleWithoutEquality(interactionClient, "status",
"base-secret");
}
- private void createEncryptRuleWithoutEquality(final MCPInteractionClient
interactionClient, final String columnName, final String secret) throws
Exception {
+ private void createEncryptRuleWithoutEquality(final MCPInteractionClient
interactionClient, final String columnName, final String secret) throws
IOException, InterruptedException {
Map<String, Object> actualCreatePlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", columnName,
"natural_language_intent", String.format("encrypt %s
with reversible encryption, no equality, no like", columnName),
"algorithm_type", "AES",
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/HttpProductionProxyMaskWorkflowE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/HttpProductionProxyMaskWorkflowE2ETest.java
index 8ef5e7f394d..78a6689491a 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/HttpProductionProxyMaskWorkflowE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/HttpProductionProxyMaskWorkflowE2ETest.java
@@ -24,6 +24,7 @@ import
org.apache.shardingsphere.test.e2e.mcp.support.transport.client.MCPIntera
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIf;
+import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -52,11 +53,11 @@ class HttpProductionProxyMaskWorkflowE2ETest extends
AbstractProductionProxyWork
private static final String TABLE_RULES_RESOURCE_URI =
"shardingsphere://features/mask/databases/%s/tables/%s/rules";
private static boolean isEnabled() {
- return MCPE2ECondition.isProductionMySQLEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
- void assertCompleteMaskAlgorithmThroughProxy() throws Exception {
+ void assertCompleteMaskAlgorithmThroughProxy() throws IOException,
InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actual =
interactionClient.complete(Map.of("type", "ref/prompt", "name",
PLAN_PROMPT_NAME), "algorithm_type", "KEEP", Map.of());
assertThat(getStringList(getMap(actual.get("completion")).get("values")),
hasItem("KEEP_FIRST_N_LAST_M"));
@@ -64,7 +65,7 @@ class HttpProductionProxyMaskWorkflowE2ETest extends
AbstractProductionProxyWork
}
@Test
- void assertPlanApplyAndValidateMaskCreateAlterWorkflowThroughProxy()
throws Exception {
+ void assertPlanApplyAndValidateMaskCreateAlterWorkflowThroughProxy()
throws IOException, InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualCreatePlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -94,7 +95,7 @@ class HttpProductionProxyMaskWorkflowE2ETest extends
AbstractProductionProxyWork
}
@Test
- void assertPlanApplyAndValidateMaskDropWorkflowThroughProxy() throws
Exception {
+ void assertPlanApplyAndValidateMaskDropWorkflowThroughProxy() throws
IOException, InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
createMaskRule(interactionClient);
Map<String, Object> actualDropPlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
@@ -110,7 +111,7 @@ class HttpProductionProxyMaskWorkflowE2ETest extends
AbstractProductionProxyWork
}
@Test
- void assertPlanRejectsUnsupportedSecondMaskColumnThroughProxy() throws
Exception {
+ void assertPlanRejectsUnsupportedSecondMaskColumnThroughProxy() throws
IOException, InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
createMaskRule(interactionClient);
Map<String, Object> actualSecondCreatePlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
@@ -129,7 +130,7 @@ class HttpProductionProxyMaskWorkflowE2ETest extends
AbstractProductionProxyWork
}
@Test
- void
assertPlanRecommendApplyAndValidateMaskWorkflowFromNaturalLanguageThroughProxy()
throws Exception {
+ void
assertPlanRecommendApplyAndValidateMaskWorkflowFromNaturalLanguageThroughProxy()
throws IOException, InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualClarifyingResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -153,7 +154,7 @@ class HttpProductionProxyMaskWorkflowE2ETest extends
AbstractProductionProxyWork
}
@Test
- void assertApplySupportsApprovedStepsThroughProxy() throws Exception {
+ void assertApplySupportsApprovedStepsThroughProxy() throws IOException,
InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualPlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -178,7 +179,7 @@ class HttpProductionProxyMaskWorkflowE2ETest extends
AbstractProductionProxyWork
}
@Test
- void
assertPlanApplyValidateAndReadMaskResourcesWithCustomAlgorithmThroughProxy()
throws Exception {
+ void
assertPlanApplyValidateAndReadMaskResourcesWithCustomAlgorithmThroughProxy()
throws IOException, InterruptedException {
try (MCPInteractionClient interactionClient =
createOpenedInteractionClient()) {
Map<String, Object> actualPlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
@@ -200,7 +201,7 @@ class HttpProductionProxyMaskWorkflowE2ETest extends
AbstractProductionProxyWork
}
}
- private void createMaskRule(final MCPInteractionClient interactionClient)
throws Exception {
+ private void createMaskRule(final MCPInteractionClient interactionClient)
throws IOException, InterruptedException {
Map<String, Object> actualCreatePlanResponse =
interactionClient.call(PLAN_TOOL_NAME,
Map.of("database", getLogicalDatabaseName(), "table",
"orders", "column", "status",
"operation_type", "create", "algorithm_type",
"KEEP_FIRST_N_LAST_M",
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/PackagedDistributionE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/PackagedDistributionE2ETest.java
index a0dae6017a6..9185a4b7dfa 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/PackagedDistributionE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/PackagedDistributionE2ETest.java
@@ -21,6 +21,7 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
+import
org.apache.shardingsphere.test.e2e.env.runtime.EnvironmentPropertiesLoader;
import org.apache.shardingsphere.test.e2e.mcp.env.MCPE2ECondition;
import org.apache.shardingsphere.test.e2e.mcp.support.OfficialMCPToolNames;
import
org.apache.shardingsphere.test.e2e.mcp.support.distribution.DockerImageHttpRuntime;
@@ -91,7 +92,7 @@ class PackagedDistributionE2ETest {
}
private static boolean isEnabled() {
- return MCPE2ECondition.isDistributionEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
@@ -138,10 +139,9 @@ class PackagedDistributionE2ETest {
@Test
void assertLaunchContainerOverHttp() throws IOException,
InterruptedException, SQLException {
- assumeContainerImageConfigured();
Path configFile = createDockerConfigurationFile(RuntimeTransport.HTTP);
try (
- DockerImageHttpRuntime runtime = new
DockerImageHttpRuntime(System.getProperty(IMAGE_PROPERTY), configFile);
+ DockerImageHttpRuntime runtime = new
DockerImageHttpRuntime(getConfiguredContainerImage(), configFile);
MCPInteractionClient interactionClient =
runtime.openInteractionClient()) {
assertContainerRuntime(RuntimeTransport.HTTP, interactionClient);
}
@@ -149,9 +149,8 @@ class PackagedDistributionE2ETest {
@Test
void assertLaunchContainerOverStdio() throws IOException,
InterruptedException, SQLException {
- assumeContainerImageConfigured();
Path configFile =
createDockerConfigurationFile(RuntimeTransport.STDIO);
- try (MCPInteractionClient interactionClient = new
DockerImageStdioInteractionClient(System.getProperty(IMAGE_PROPERTY),
configFile)) {
+ try (MCPInteractionClient interactionClient = new
DockerImageStdioInteractionClient(getConfiguredContainerImage(), configFile)) {
interactionClient.open();
assertContainerRuntime(RuntimeTransport.STDIO, interactionClient);
}
@@ -180,8 +179,10 @@ class PackagedDistributionE2ETest {
MySQLRuntimeTestSupport.initializeDatabase(mysqlContainer);
}
- private void assumeContainerImageConfigured() {
- Assumptions.assumeFalse(System.getProperty(IMAGE_PROPERTY,
"").isBlank(), "Set -D" + IMAGE_PROPERTY + " to run MCP container distribution
E2E.");
+ private String getConfiguredContainerImage() {
+ String result =
EnvironmentPropertiesLoader.loadProperties().getProperty(IMAGE_PROPERTY,
"").trim();
+ Assumptions.assumeFalse(result.isBlank(), "Set " + IMAGE_PROPERTY + "
in env/e2e-env.properties or pass -D" + IMAGE_PROPERTY + " to run MCP container
distribution E2E.");
+ return result;
}
private void assertOfficialRuntime(final Path distributionHome, final
RuntimeTransport transport,
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/ExecuteQueryTransactionE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/ExecuteQueryTransactionE2ETest.java
index 7bb5808d988..d3504efa8a8 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/ExecuteQueryTransactionE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/ExecuteQueryTransactionE2ETest.java
@@ -39,7 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
class ExecuteQueryTransactionE2ETest extends
AbstractHttpProgrammaticRuntimeE2ETest {
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportApprovalSafetyE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportApprovalSafetyE2ETest.java
index a1e3a5127cc..6abc482af19 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportApprovalSafetyE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportApprovalSafetyE2ETest.java
@@ -38,7 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
class HttpTransportApprovalSafetyE2ETest extends
AbstractHttpProgrammaticRuntimeE2ETest {
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportBaselineContractE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportBaselineContractE2ETest.java
index fc050735ad3..fef006781dd 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportBaselineContractE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportBaselineContractE2ETest.java
@@ -40,7 +40,7 @@ class HttpTransportBaselineContractE2ETest extends
AbstractHttpProgrammaticRunti
private static final String BASELINE_RESOURCE_PATH =
"baseline-contract/model-contract/";
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportCompletionE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportCompletionE2ETest.java
index dde9dea638a..cc2fc4e0b29 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportCompletionE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportCompletionE2ETest.java
@@ -40,7 +40,7 @@ class HttpTransportCompletionE2ETest extends
AbstractHttpProgrammaticRuntimeE2ET
private static final String PLAN_MASK_PROMPT_NAME = "plan_mask_rule";
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportContractE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportContractE2ETest.java
index 341197afbb2..12c045fba7e 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportContractE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportContractE2ETest.java
@@ -50,7 +50,7 @@ class HttpTransportContractE2ETest extends
AbstractHttpProgrammaticRuntimeE2ETes
private static final String PLAN_MASK_TOOL_NAME =
"database_gateway_plan_mask_rule";
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportProtocolContractE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportProtocolContractE2ETest.java
index 57b68ce3070..ff3276a4b33 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportProtocolContractE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportProtocolContractE2ETest.java
@@ -38,7 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
class HttpTransportProtocolContractE2ETest extends
AbstractHttpProgrammaticRuntimeE2ETest {
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportRecoveryE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportRecoveryE2ETest.java
index e6c4e3d11dd..e4aa767fd19 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportRecoveryE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportRecoveryE2ETest.java
@@ -43,7 +43,7 @@ class HttpTransportRecoveryE2ETest extends
AbstractHttpProgrammaticRuntimeE2ETes
private static final String RECOVERY_SECRET = "recovery-secret-value";
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportSecurityE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportSecurityE2ETest.java
index 91d260b5ce7..8ae4eee531c 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportSecurityE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportSecurityE2ETest.java
@@ -39,7 +39,7 @@ class HttpTransportSecurityE2ETest extends
AbstractHttpProgrammaticRuntimeE2ETes
private boolean remoteBinding;
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Override
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportSessionLifecycleE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportSessionLifecycleE2ETest.java
index b345322088f..ff41ec73476 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportSessionLifecycleE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportSessionLifecycleE2ETest.java
@@ -33,7 +33,7 @@ import static org.hamcrest.Matchers.is;
class HttpTransportSessionLifecycleE2ETest extends
AbstractHttpProgrammaticRuntimeE2ETest {
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/MetadataDiscoveryE2ETest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/MetadataDiscoveryE2ETest.java
index d12c72ff4d2..7e8fbae144d 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/MetadataDiscoveryE2ETest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/MetadataDiscoveryE2ETest.java
@@ -41,7 +41,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
class MetadataDiscoveryE2ETest extends AbstractHttpProgrammaticRuntimeE2ETest {
private static boolean isEnabled() {
- return MCPE2ECondition.isContractEnabled();
+ return MCPE2ECondition.isDockerEnabled();
}
@Test
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupport.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupport.java
index e3e1ad22084..0b00365e19a 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupport.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupport.java
@@ -24,6 +24,7 @@ import
org.apache.shardingsphere.mcp.bootstrap.config.MCPTransportType;
import
org.apache.shardingsphere.mcp.bootstrap.config.loader.MCPConfigurationLoader;
import
org.apache.shardingsphere.mcp.bootstrap.config.yaml.swapper.YamlMCPLaunchConfigurationSwapper;
import
org.apache.shardingsphere.mcp.support.database.metadata.jdbc.RuntimeDatabaseConfiguration;
+import
org.apache.shardingsphere.test.e2e.env.runtime.EnvironmentPropertiesLoader;
import org.apache.shardingsphere.test.e2e.mcp.support.runtime.RuntimeTransport;
import java.io.IOException;
@@ -136,11 +137,12 @@ public final class PackagedDistributionTestSupport {
private static IllegalStateException
createMissingDistributionHomeException() {
Path expectedTargetDirectory =
findRepositoryRoot().resolve("distribution/mcp/target");
return new IllegalStateException("Packaged MCP distribution was not
found. Run `" + DISTRIBUTION_PACKAGE_COMMAND
- + "` first or set
`-Dmcp.distribution.home=/path/to/apache-shardingsphere-mcp-*`. Checked `" +
expectedTargetDirectory + "`.");
+ + "` first or set `mcp.distribution.home` in
env/e2e-env.properties or pass "
+ +
"`-Dmcp.distribution.home=/path/to/apache-shardingsphere-mcp-*`. Checked `" +
expectedTargetDirectory + "`.");
}
private static Optional<Path> resolveConfiguredDistributionHome() {
- String configuredHome = System.getProperty("mcp.distribution.home",
"").trim();
+ String configuredHome =
EnvironmentPropertiesLoader.loadProperties().getProperty("mcp.distribution.home",
"").trim();
if (configuredHome.isEmpty()) {
return Optional.empty();
}
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupportTest.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupportTest.java
index c08bdca004b..3d64d8b19e9 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupportTest.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupportTest.java
@@ -124,7 +124,7 @@ class PackagedDistributionTestSupportTest {
IllegalStateException actual =
assertThrows(IllegalStateException.class,
() ->
PackagedDistributionTestSupport.prepare(tempDir.resolve("missing-distribution"),
RuntimeTransport.HTTP));
assertThat(actual.getMessage(), is("Packaged MCP distribution was
not found. Run `./mvnw -pl distribution/mcp -am -DskipTests package` first"
- + " or set
`-Dmcp.distribution.home=/path/to/apache-shardingsphere-mcp-*`. Checked `"
+ + " or set `mcp.distribution.home` in
env/e2e-env.properties or pass
`-Dmcp.distribution.home=/path/to/apache-shardingsphere-mcp-*`. Checked `"
+
repositoryRoot.resolve("distribution/mcp/target").toAbsolutePath().normalize()
+ "`."));
} finally {
restoreDistributionHome(actualOriginalHome);
diff --git
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupport.java
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupport.java
index 42e7ff6235b..089d27cadae 100644
---
a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupport.java
+++
b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupport.java
@@ -22,6 +22,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import
org.apache.shardingsphere.mcp.support.database.metadata.jdbc.RuntimeDatabaseConfiguration;
+import
org.apache.shardingsphere.test.e2e.env.runtime.EnvironmentPropertiesLoader;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
@@ -45,7 +46,7 @@ import java.util.Optional;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class MySQLRuntimeTestSupport {
- private static final Duration JDBC_READY_TIMEOUT = Duration.ofSeconds(30);
+ private static final Duration DEFAULT_JDBC_READY_TIMEOUT =
Duration.ofSeconds(90);
private static final String MYSQL_READY_LOG_PATTERN = ".*ready for
connections.*port: 3306.*\\n";
@@ -315,9 +316,25 @@ public final class MySQLRuntimeTestSupport {
private static Connection getConnection(final GenericContainer<?>
container, final String databaseName) throws SQLException {
String jdbcUrl = createJdbcUrl(container.getHost(),
container.getMappedPort(3306), databaseName);
+ String configuredJdbcReadyTimeoutSeconds =
EnvironmentPropertiesLoader.loadProperties().getProperty("mcp.e2e.mysql.ready-timeout-seconds",
"").trim();
+ long jdbcReadyTimeoutMillis;
try {
- return new ReadinessProbe(JDBC_READY_TIMEOUT.toMillis(),
JDBC_READY_INITIAL_INTERVAL_MILLIS, JDBC_READY_MAX_INTERVAL_MILLIS)
- .waitUntilReady(() -> getConnectionIfReady(jdbcUrl),
MySQLRuntimeTestSupport::createJdbcReadyException);
+ if (configuredJdbcReadyTimeoutSeconds.isEmpty()) {
+ jdbcReadyTimeoutMillis = DEFAULT_JDBC_READY_TIMEOUT.toMillis();
+ } else {
+ int parsedJdbcReadyTimeoutSeconds =
Integer.parseInt(configuredJdbcReadyTimeoutSeconds);
+ if (0 >= parsedJdbcReadyTimeoutSeconds) {
+ throw new IllegalArgumentException("MCP E2E MySQL JDBC
readiness timeout must be positive.");
+ }
+ jdbcReadyTimeoutMillis =
Duration.ofSeconds(parsedJdbcReadyTimeoutSeconds).toMillis();
+ }
+ } catch (final NumberFormatException ex) {
+ throw new IllegalArgumentException("MCP E2E MySQL JDBC readiness
timeout must be an integer.", ex);
+ }
+ try {
+ return new ReadinessProbe(jdbcReadyTimeoutMillis,
JDBC_READY_INITIAL_INTERVAL_MILLIS, JDBC_READY_MAX_INTERVAL_MILLIS)
+ .waitUntilReady(() -> getConnectionIfReady(jdbcUrl),
+ (cause, attemptCount, elapsedMillis) ->
createJdbcReadyException(cause, attemptCount, elapsedMillis,
jdbcReadyTimeoutMillis));
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new SQLException("Interrupted while waiting for MySQL JDBC
readiness.", ex);
@@ -332,9 +349,9 @@ public final class MySQLRuntimeTestSupport {
}
}
- private static SQLException createJdbcReadyException(final Exception
cause, final int attemptCount, final long elapsedMillis) {
+ private static SQLException createJdbcReadyException(final Exception
cause, final int attemptCount, final long elapsedMillis, final long
jdbcReadyTimeoutMillis) {
String result = String.format("MySQL JDBC connection did not become
ready after %d attempt(s), elapsedMillis=%d, timeoutMillis=%d.",
- attemptCount, elapsedMillis, JDBC_READY_TIMEOUT.toMillis());
+ attemptCount, elapsedMillis, jdbcReadyTimeoutMillis);
return null == cause || null == cause.getMessage() ||
cause.getMessage().isBlank()
? new SQLException(result)
: new SQLException(result + " Last readiness failure: " +
cause.getMessage(), cause);
diff --git a/test/e2e/mcp/src/test/resources/env/e2e-env.properties
b/test/e2e/mcp/src/test/resources/env/e2e-env.properties
index 0875f59dc26..0e769a0ea69 100644
--- a/test/e2e/mcp/src/test/resources/env/e2e-env.properties
+++ b/test/e2e/mcp/src/test/resources/env/e2e-env.properties
@@ -16,8 +16,23 @@
#
e2e.timezone=UTC
-mcp.e2e.contract.enabled=false
-mcp.e2e.production.mysql.enabled=false
-mcp.e2e.production.stdio.enabled=false
-mcp.e2e.distribution.enabled=false
-mcp.e2e.llm.enabled=false
+
+#e2e.run.type=DOCKER
+e2e.run.type=
+
+mcp.e2e.container.image=
+mcp.e2e.mysql.ready-timeout-seconds=90
+mcp.distribution.home=
+
+mcp.llm.runtime-mode=docker
+mcp.llm.base-url=http://127.0.0.1:8080/v1
+mcp.llm.provider=openai-compatible
+mcp.llm.model=ggml-org/Qwen3-1.7B-GGUF:Q4_K_M
+mcp.llm.api-key=mcp-llm-score
+mcp.llm.ready-timeout-seconds=600
+mcp.llm.request-timeout-seconds=240
+mcp.llm.max-turns=10
+mcp.llm.artifact-root=target/llm-e2e
+mcp.llm.run-id=
+mcp.llm.server-image=apache/shardingsphere-mcp-llm-runtime:local
+mcp.llm.base-server-image-digest=