Skip to content

Commit b4c883d

Browse files
authored
test: add MySQL MCP tests (#2157)
* chore: add JDBC MySQL MCP tests
1 parent e0c22f3 commit b4c883d

File tree

4 files changed

+280
-45
lines changed

4 files changed

+280
-45
lines changed

.ci/cloudbuild.yaml

Lines changed: 75 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,57 +18,87 @@ steps:
1818
env:
1919
- "IP_TYPE=${_IP_TYPE}"
2020
- "JOB_TYPE=integration"
21-
secretEnv: ["MYSQL_CONNECTION_NAME", "MYSQL_USER", "MYSQL_IAM_USER", "MYSQL_PASS", "MYSQL_DB", "POSTGRES_CONNECTION_NAME", "POSTGRES_USER", "POSTGRES_IAM_USER", "POSTGRES_PASS", "POSTGRES_DB", "POSTGRES_CAS_CONNECTION_NAME", "POSTGRES_CAS_PASS", "POSTGRES_CUSTOMER_CAS_CONNECTION_NAME", "POSTGRES_CUSTOMER_CAS_PASS", "POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME","POSTGRES_CUSTOMER_CAS_PASS_INVALID_DOMAIN_NAME","SQLSERVER_CONNECTION_NAME", "SQLSERVER_USER", "SQLSERVER_PASS", "SQLSERVER_DB", "QUOTA_PROJECT", "IMPERSONATED_USER"]
21+
secretEnv:
22+
[
23+
"MYSQL_CONNECTION_NAME",
24+
"MYSQL_USER",
25+
"MYSQL_IAM_USER",
26+
"MYSQL_PASS",
27+
"MYSQL_DB",
28+
"MYSQL_MCP_CONNECTION_NAME",
29+
"MYSQL_MCP_PASS",
30+
"POSTGRES_CONNECTION_NAME",
31+
"POSTGRES_USER",
32+
"POSTGRES_IAM_USER",
33+
"POSTGRES_PASS",
34+
"POSTGRES_DB",
35+
"POSTGRES_CAS_CONNECTION_NAME",
36+
"POSTGRES_CAS_PASS",
37+
"POSTGRES_CUSTOMER_CAS_CONNECTION_NAME",
38+
"POSTGRES_CUSTOMER_CAS_PASS",
39+
"POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME",
40+
"POSTGRES_CUSTOMER_CAS_PASS_INVALID_DOMAIN_NAME",
41+
"SQLSERVER_CONNECTION_NAME",
42+
"SQLSERVER_USER",
43+
"SQLSERVER_PASS",
44+
"SQLSERVER_DB",
45+
"QUOTA_PROJECT",
46+
"IMPERSONATED_USER"
47+
]
2248
args:
2349
- "-c"
2450
- |
2551
./.github/scripts/run_tests.sh
2652
availableSecrets:
2753
secretManager:
28-
- versionName: 'projects/$PROJECT_ID/secrets/MYSQL_CONNECTION_NAME/versions/latest'
29-
env: 'MYSQL_CONNECTION_NAME'
30-
- versionName: 'projects/$PROJECT_ID/secrets/MYSQL_USER/versions/latest'
31-
env: 'MYSQL_USER'
32-
- versionName: 'projects/$PROJECT_ID/secrets/CLOUD_BUILD_MYSQL_IAM_USER/versions/latest'
33-
env: 'MYSQL_IAM_USER'
34-
- versionName: 'projects/$PROJECT_ID/secrets/MYSQL_PASS/versions/latest'
35-
env: 'MYSQL_PASS'
36-
- versionName: 'projects/$PROJECT_ID/secrets/MYSQL_DB/versions/latest'
37-
env: 'MYSQL_DB'
38-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_CONNECTION_NAME/versions/latest'
39-
env: 'POSTGRES_CONNECTION_NAME'
40-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_USER/versions/latest'
41-
env: 'POSTGRES_USER'
42-
- versionName: 'projects/$PROJECT_ID/secrets/CLOUD_BUILD_POSTGRES_IAM_USER/versions/latest'
43-
env: 'POSTGRES_IAM_USER'
44-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_PASS/versions/latest'
45-
env: 'POSTGRES_PASS'
46-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_DB/versions/latest'
47-
env: 'POSTGRES_DB'
48-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_CAS_CONNECTION_NAME/versions/latest'
49-
env: 'POSTGRES_CAS_CONNECTION_NAME'
50-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_CAS_PASS/versions/latest'
51-
env: 'POSTGRES_CAS_PASS'
52-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_CUSTOMER_CAS_CONNECTION_NAME/versions/latest'
53-
env: 'POSTGRES_CUSTOMER_CAS_CONNECTION_NAME'
54-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_CUSTOMER_CAS_PASS/versions/latest'
55-
env: 'POSTGRES_CUSTOMER_CAS_PASS'
56-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME/versions/latest'
57-
env: 'POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME'
58-
- versionName: 'projects/$PROJECT_ID/secrets/POSTGRES_CUSTOMER_CAS_PASS_INVALID_DOMAIN_NAME/versions/latest'
59-
env: 'POSTGRES_CUSTOMER_CAS_PASS_INVALID_DOMAIN_NAME'
60-
- versionName: 'projects/$PROJECT_ID/secrets/SQLSERVER_CONNECTION_NAME/versions/latest'
61-
env: 'SQLSERVER_CONNECTION_NAME'
62-
- versionName: 'projects/$PROJECT_ID/secrets/SQLSERVER_USER/versions/latest'
63-
env: 'SQLSERVER_USER'
64-
- versionName: 'projects/$PROJECT_ID/secrets/SQLSERVER_PASS/versions/latest'
65-
env: 'SQLSERVER_PASS'
66-
- versionName: 'projects/$PROJECT_ID/secrets/SQLSERVER_DB/versions/latest'
67-
env: 'SQLSERVER_DB'
68-
- versionName: 'projects/$PROJECT_ID/secrets/QUOTA_PROJECT/versions/latest'
69-
env: 'QUOTA_PROJECT'
70-
- versionName: 'projects/$PROJECT_ID/secrets/CLOUD_BUILD_SA/versions/latest'
71-
env: 'IMPERSONATED_USER'
54+
- versionName: "projects/$PROJECT_ID/secrets/MYSQL_CONNECTION_NAME/versions/latest"
55+
env: "MYSQL_CONNECTION_NAME"
56+
- versionName: "projects/$PROJECT_ID/secrets/MYSQL_USER/versions/latest"
57+
env: "MYSQL_USER"
58+
- versionName: "projects/$PROJECT_ID/secrets/CLOUD_BUILD_MYSQL_IAM_USER/versions/latest"
59+
env: "MYSQL_IAM_USER"
60+
- versionName: "projects/$PROJECT_ID/secrets/MYSQL_PASS/versions/latest"
61+
env: "MYSQL_PASS"
62+
- versionName: "projects/$PROJECT_ID/secrets/MYSQL_DB/versions/latest"
63+
env: "MYSQL_DB"
64+
- versionName: "projects/$PROJECT_ID/secrets/MYSQL_MCP_CONNECTION_NAME/versions/latest"
65+
env: "MYSQL_MCP_CONNECTION_NAME"
66+
- versionName: "projects/$PROJECT_ID/secrets/MYSQL_MCP_PASS/versions/latest"
67+
env: "MYSQL_MCP_PASS"
68+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_CONNECTION_NAME/versions/latest"
69+
env: "POSTGRES_CONNECTION_NAME"
70+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_USER/versions/latest"
71+
env: "POSTGRES_USER"
72+
- versionName: "projects/$PROJECT_ID/secrets/CLOUD_BUILD_POSTGRES_IAM_USER/versions/latest"
73+
env: "POSTGRES_IAM_USER"
74+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_PASS/versions/latest"
75+
env: "POSTGRES_PASS"
76+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_DB/versions/latest"
77+
env: "POSTGRES_DB"
78+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_CAS_CONNECTION_NAME/versions/latest"
79+
env: "POSTGRES_CAS_CONNECTION_NAME"
80+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_CAS_PASS/versions/latest"
81+
env: "POSTGRES_CAS_PASS"
82+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_CUSTOMER_CAS_CONNECTION_NAME/versions/latest"
83+
env: "POSTGRES_CUSTOMER_CAS_CONNECTION_NAME"
84+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_CUSTOMER_CAS_PASS/versions/latest"
85+
env: "POSTGRES_CUSTOMER_CAS_PASS"
86+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME/versions/latest"
87+
env: "POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME"
88+
- versionName: "projects/$PROJECT_ID/secrets/POSTGRES_CUSTOMER_CAS_PASS_INVALID_DOMAIN_NAME/versions/latest"
89+
env: "POSTGRES_CUSTOMER_CAS_PASS_INVALID_DOMAIN_NAME"
90+
- versionName: "projects/$PROJECT_ID/secrets/SQLSERVER_CONNECTION_NAME/versions/latest"
91+
env: "SQLSERVER_CONNECTION_NAME"
92+
- versionName: "projects/$PROJECT_ID/secrets/SQLSERVER_USER/versions/latest"
93+
env: "SQLSERVER_USER"
94+
- versionName: "projects/$PROJECT_ID/secrets/SQLSERVER_PASS/versions/latest"
95+
env: "SQLSERVER_PASS"
96+
- versionName: "projects/$PROJECT_ID/secrets/SQLSERVER_DB/versions/latest"
97+
env: "SQLSERVER_DB"
98+
- versionName: "projects/$PROJECT_ID/secrets/QUOTA_PROJECT/versions/latest"
99+
env: "QUOTA_PROJECT"
100+
- versionName: "projects/$PROJECT_ID/secrets/CLOUD_BUILD_SA/versions/latest"
101+
env: "IMPERSONATED_USER"
72102
substitutions:
73103
_MAVEN_VERSION: ${_VERSION}
74104
_IP_TYPE: ${_IP_TYPE}

.github/workflows/tests.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ jobs:
130130
MYSQL_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_USER
131131
MYSQL_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_PASS
132132
MYSQL_DB:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_DB
133+
MYSQL_MCP_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT}}/MYSQL_MCP_CONNECTION_NAME
134+
MYSQL_MCP_PASS:${{ vars.GOOGLE_CLOUD_PROJECT}}/MYSQL_MCP_PASS
133135
MYSQL_IAM_USER_JAVA:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_USER_IAM_JAVA
134136
POSTGRES_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CONNECTION_NAME
135137
POSTGRES_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER
@@ -154,6 +156,8 @@ jobs:
154156
MYSQL_USER: "${{ steps.secrets.outputs.MYSQL_USER }}"
155157
MYSQL_PASS: "${{ steps.secrets.outputs.MYSQL_PASS }}"
156158
MYSQL_DB: "${{ steps.secrets.outputs.MYSQL_DB }}"
159+
MYSQL_MCP_CONNECTION_NAME: "${{ steps.secrets.outputs.MYSQL_MCP_CONNECTION_NAME }}"
160+
MYSQL_MCP_PASS: "${{ steps.secrets.outputs.MYSQL_MCP_PASS }}"
157161
MYSQL_IAM_USER: "${{ steps.secrets.outputs.MYSQL_IAM_USER_JAVA }}"
158162
POSTGRES_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_CONNECTION_NAME }}"
159163
POSTGRES_USER: "${{ steps.secrets.outputs.POSTGRES_USER }}"
@@ -237,6 +241,8 @@ jobs:
237241
MYSQL_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_USER
238242
MYSQL_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_PASS
239243
MYSQL_DB:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_DB
244+
MYSQL_MCP_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT}}/MYSQL_MCP_CONNECTION_NAME
245+
MYSQL_MCP_PASS:${{ vars.GOOGLE_CLOUD_PROJECT}}/MYSQL_MCP_PASS
240246
MYSQL_IAM_USER_JAVA:${{ vars.GOOGLE_CLOUD_PROJECT }}/MYSQL_USER_IAM_JAVA
241247
POSTGRES_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CONNECTION_NAME
242248
POSTGRES_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER
@@ -262,6 +268,8 @@ jobs:
262268
MYSQL_USER: "${{ steps.secrets.outputs.MYSQL_USER }}"
263269
MYSQL_PASS: "${{ steps.secrets.outputs.MYSQL_PASS }}"
264270
MYSQL_DB: "${{ steps.secrets.outputs.MYSQL_DB }}"
271+
MYSQL_MCP_CONNECTION_NAME: "${{ steps.secrets.outputs.MYSQL_MCP_CONNECTION_NAME }}"
272+
MYSQL_MCP_PASS: "${{ steps.secrets.outputs.MYSQL_MCP_PASS }}"
265273
MYSQL_IAM_USER: "${{ steps.secrets.outputs.MYSQL_IAM_USER_JAVA }}"
266274
POSTGRES_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_CONNECTION_NAME }}"
267275
POSTGRES_USER: "${{ steps.secrets.outputs.POSTGRES_USER }}"
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.sql.mysql;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
import static com.google.common.truth.Truth.assertWithMessage;
21+
22+
import com.google.common.collect.ImmutableList;
23+
import com.zaxxer.hikari.HikariConfig;
24+
import com.zaxxer.hikari.HikariDataSource;
25+
import java.sql.*;
26+
import java.util.ArrayList;
27+
import java.util.List;
28+
import java.util.Properties;
29+
import java.util.concurrent.TimeUnit;
30+
import org.junit.Before;
31+
import org.junit.BeforeClass;
32+
import org.junit.Rule;
33+
import org.junit.Test;
34+
import org.junit.rules.Timeout;
35+
import org.junit.runner.RunWith;
36+
import org.junit.runners.JUnit4;
37+
38+
@RunWith(JUnit4.class)
39+
public class JdbcMysqlJ8McpIamAuthIntegrationTests {
40+
41+
private static final String CONNECTION_NAME = System.getenv("MYSQL_MCP_CONNECTION_NAME");
42+
private static final String DB_NAME = System.getenv("MYSQL_DB");
43+
private static final String DB_USER = System.getenv("MYSQL_IAM_USER");
44+
private static final String IP_TYPE =
45+
System.getenv("IP_TYPE") == null ? "PUBLIC" : System.getenv("IP_TYPE");
46+
47+
private static final ImmutableList<String> requiredEnvVars =
48+
ImmutableList.of("MYSQL_IAM_USER", "MYSQL_DB", "MYSQL_MCP_CONNECTION_NAME");
49+
@Rule public Timeout globalTimeout = new Timeout(80, TimeUnit.SECONDS);
50+
private HikariDataSource connectionPool;
51+
52+
@BeforeClass
53+
public static void checkEnvVars() {
54+
// Check that required env vars are set
55+
requiredEnvVars.forEach(
56+
(varName) ->
57+
assertWithMessage(
58+
String.format(
59+
"Environment variable '%s' must be set to perform these tests.", varName))
60+
.that(System.getenv(varName))
61+
.isNotEmpty());
62+
}
63+
64+
@Before
65+
public void setUpPool() throws SQLException {
66+
// Set up URL parameters
67+
String jdbcURL = String.format("jdbc:mysql:///%s", DB_NAME);
68+
Properties connProps = new Properties();
69+
connProps.setProperty("user", DB_USER);
70+
connProps.setProperty("sslmode", "disable");
71+
connProps.setProperty("socketFactory", "com.google.cloud.sql.mysql.SocketFactory");
72+
connProps.setProperty("cloudSqlInstance", CONNECTION_NAME);
73+
connProps.setProperty("ipTypes", IP_TYPE);
74+
connProps.setProperty("enableIamAuth", "true");
75+
76+
// Initialize connection pool
77+
HikariConfig config = new HikariConfig();
78+
config.setJdbcUrl(jdbcURL);
79+
config.setDataSourceProperties(connProps);
80+
config.setConnectionTimeout(10000); // 10s
81+
82+
this.connectionPool = new HikariDataSource(config);
83+
}
84+
85+
@Test
86+
public void pooledConnectionTest() throws SQLException {
87+
88+
List<Timestamp> rows = new ArrayList<>();
89+
try (Connection conn = connectionPool.getConnection()) {
90+
try (PreparedStatement selectStmt = conn.prepareStatement("SELECT NOW() as TS")) {
91+
ResultSet rs = selectStmt.executeQuery();
92+
while (rs.next()) {
93+
rows.add(rs.getTimestamp("TS"));
94+
}
95+
}
96+
}
97+
assertThat(rows.size()).isEqualTo(1);
98+
}
99+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.sql.mysql;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
import static com.google.common.truth.Truth.assertWithMessage;
21+
22+
import com.google.common.collect.ImmutableList;
23+
import com.zaxxer.hikari.HikariConfig;
24+
import com.zaxxer.hikari.HikariDataSource;
25+
import java.sql.*;
26+
import java.util.ArrayList;
27+
import java.util.List;
28+
import java.util.Properties;
29+
import java.util.concurrent.TimeUnit;
30+
import org.junit.Before;
31+
import org.junit.BeforeClass;
32+
import org.junit.Rule;
33+
import org.junit.Test;
34+
import org.junit.rules.Timeout;
35+
import org.junit.runner.RunWith;
36+
import org.junit.runners.JUnit4;
37+
38+
@RunWith(JUnit4.class)
39+
public class JdbcMysqlJ8McpIntegrationTests {
40+
41+
private static final String CONNECTION_NAME = System.getenv("MYSQL_MCP_CONNECTION_NAME");
42+
private static final String DB_NAME = System.getenv("MYSQL_DB");
43+
private static final String DB_USER = System.getenv("MYSQL_USER");
44+
private static final String DB_PASSWORD = System.getenv("MYSQL_MCP_PASS");
45+
private static final String IP_TYPE =
46+
System.getenv("IP_TYPE") == null ? "PUBLIC" : System.getenv("IP_TYPE");
47+
private static final ImmutableList<String> requiredEnvVars =
48+
ImmutableList.of("MYSQL_USER", "MYSQL_MCP_PASS", "MYSQL_DB", "MYSQL_MCP_CONNECTION_NAME");
49+
@Rule public Timeout globalTimeout = new Timeout(80, TimeUnit.SECONDS);
50+
private HikariDataSource connectionPool;
51+
52+
@BeforeClass
53+
public static void checkEnvVars() {
54+
// Check that required env vars are set
55+
requiredEnvVars.forEach(
56+
(varName) ->
57+
assertWithMessage(
58+
String.format(
59+
"Environment variable '%s' must be set to perform these tests.", varName))
60+
.that(System.getenv(varName))
61+
.isNotEmpty());
62+
}
63+
64+
@Before
65+
public void setUpPool() throws SQLException {
66+
// Set up URL parameters
67+
String jdbcURL = String.format("jdbc:mysql://db.example.com/%s", DB_NAME);
68+
Properties connProps = new Properties();
69+
connProps.setProperty("user", DB_USER);
70+
connProps.setProperty("password", DB_PASSWORD);
71+
connProps.setProperty("socketFactory", "com.google.cloud.sql.mysql.SocketFactory");
72+
connProps.setProperty("ipTypes", IP_TYPE);
73+
connProps.setProperty("cloudSqlInstance", CONNECTION_NAME);
74+
75+
// Initialize connection pool
76+
HikariConfig config = new HikariConfig();
77+
config.setJdbcUrl(jdbcURL);
78+
config.setDataSourceProperties(connProps);
79+
config.setConnectionTimeout(10000); // 10s
80+
81+
this.connectionPool = new HikariDataSource(config);
82+
}
83+
84+
@Test
85+
public void pooledConnectionTest() throws SQLException {
86+
87+
List<Timestamp> rows = new ArrayList<>();
88+
try (Connection conn = connectionPool.getConnection()) {
89+
try (PreparedStatement selectStmt = conn.prepareStatement("SELECT NOW() as TS")) {
90+
ResultSet rs = selectStmt.executeQuery();
91+
while (rs.next()) {
92+
rows.add(rs.getTimestamp("TS"));
93+
}
94+
}
95+
}
96+
assertThat(rows.size()).isEqualTo(1);
97+
}
98+
}

0 commit comments

Comments
 (0)