diff --git a/java-bigquery/.cloudbuild/scripts/jdbc-nightly.sh b/java-bigquery/.cloudbuild/scripts/jdbc-nightly.sh index 1bccb96f03f7..dea0728cbb7a 100644 --- a/java-bigquery/.cloudbuild/scripts/jdbc-nightly.sh +++ b/java-bigquery/.cloudbuild/scripts/jdbc-nightly.sh @@ -5,5 +5,4 @@ source .kokoro/common.sh install_modules java-bigquery cd ${ROOT_FOLDER}/java-bigquery/google-cloud-bigquery-jdbc -make integration-test test=ITBigQueryJDBCTest -make integration-test test=ITNightlyBigQueryTest +make integration-test test=ITNightlyTests diff --git a/java-bigquery/.cloudbuild/scripts/jdbc-presubmit.sh b/java-bigquery/.cloudbuild/scripts/jdbc-presubmit.sh index 58164962a23f..1fb645b8e3d8 100644 --- a/java-bigquery/.cloudbuild/scripts/jdbc-presubmit.sh +++ b/java-bigquery/.cloudbuild/scripts/jdbc-presubmit.sh @@ -5,4 +5,4 @@ source .kokoro/common.sh install_modules java-bigquery cd ${ROOT_FOLDER}/java-bigquery/google-cloud-bigquery-jdbc -make integration-test test=ITBigQueryJDBCTest +make integration-test test=ITPresubmitTests diff --git a/java-bigquery/google-cloud-bigquery-jdbc/.gitignore b/java-bigquery/google-cloud-bigquery-jdbc/.gitignore new file mode 100644 index 000000000000..b023676c0793 --- /dev/null +++ b/java-bigquery/google-cloud-bigquery-jdbc/.gitignore @@ -0,0 +1 @@ +drivers/ \ No newline at end of file diff --git a/java-bigquery/google-cloud-bigquery-jdbc/Makefile b/java-bigquery/google-cloud-bigquery-jdbc/Makefile index 6adcb7e8a48d..db3a62e4637f 100644 --- a/java-bigquery/google-cloud-bigquery-jdbc/Makefile +++ b/java-bigquery/google-cloud-bigquery-jdbc/Makefile @@ -35,7 +35,7 @@ integration-test: -DskipSurefire=$(skipSurefire) \ -Dclirr.skip=true \ -Denforcer.skip=true \ - -Dit.failIfNoSpecifiedTests=false \ + -Dit.failIfNoSpecifiedTests=true \ -Dit.test=$(test) \ integration-test diff --git a/java-bigquery/google-cloud-bigquery-jdbc/pom-it.xml b/java-bigquery/google-cloud-bigquery-jdbc/pom-it.xml new file mode 100644 index 000000000000..fcf489c17e2c --- /dev/null +++ b/java-bigquery/google-cloud-bigquery-jdbc/pom-it.xml @@ -0,0 +1,138 @@ + + + 4.0.0 + com.google.cloud + google-cloud-bigquery-jdbc-it-standalone + + 1.0-SNAPSHOT + jar + BigQuery JDBC Standalone IT Tests + + + UTF-8 + 8 + 8 + + + + + + com.google.cloud + google-cloud-bigquery-jdbc + 0.4.1-SNAPSHOT + test-jar + compile + + + + + org.junit.platform + junit-platform-console-standalone + 1.11.4 + compile + + + + + com.google.truth + truth + 1.4.4 + compile + + + org.junit.jupiter + junit-jupiter-api + 5.11.4 + compile + + + org.junit.jupiter + junit-jupiter-engine + 5.11.4 + compile + + + org.junit.jupiter + junit-jupiter-params + 5.11.4 + compile + + + org.mockito + mockito-core + 4.11.0 + compile + + + org.mockito + mockito-junit-jupiter + 4.11.0 + compile + + + org.junit.platform + junit-platform-suite-api + 1.11.4 + compile + + + org.junit.platform + junit-platform-suite-engine + 1.11.4 + compile + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.2 + + + package + + shade + + + + false + + + com.google.cloud:google-cloud-bigquery + com.google.cloud:google-cloud-bigquerystorage + io.grpc:* + com.google.protobuf:* + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + META-INF/services/java.sql.Driver + + + + + + org.junit.platform.console.ConsoleLauncher + + + + + + + + + diff --git a/java-bigquery/google-cloud-bigquery-jdbc/pom.xml b/java-bigquery/google-cloud-bigquery-jdbc/pom.xml index 11cfa93e59e9..fdba762cbb32 100644 --- a/java-bigquery/google-cloud-bigquery-jdbc/pom.xml +++ b/java-bigquery/google-cloud-bigquery-jdbc/pom.xml @@ -61,6 +61,13 @@ true + + + org.apache.maven.surefire + surefire-junit-platform + 3.5.2 + + org.jacoco @@ -78,9 +85,9 @@ io.grpc:* - - - org.apache.maven.plugins + + + org.apache.maven.plugins maven-shade-plugin 3.5.2 @@ -300,6 +307,17 @@ mockito-junit-jupiter test + + org.junit.platform + junit-platform-suite-api + 1.11.4 + test + + + org.junit.platform + junit-platform-suite-engine + test + @@ -324,6 +342,13 @@ --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED + + org.apache.maven.plugins + maven-failsafe-plugin + + --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED + + diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITAuthTests.java b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITAuthTests.java new file mode 100644 index 000000000000..f57493a997de --- /dev/null +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITAuthTests.java @@ -0,0 +1,374 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed 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 com.google.cloud.bigquery.jdbc.it; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.google.cloud.ServiceOptions; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +public class ITAuthTests extends ITBase { + static final String PROJECT_ID = ServiceOptions.getDefaultProjectId(); + + private JsonObject getAuthJson() throws IOException { + final String secret = requireEnvVar("SA_SECRET"); + JsonObject authJson; + // Supporting both formats of SA_SECRET: + // - Local runs can point to a json file + // - Cloud Build has JSON value + try { + InputStream stream = Files.newInputStream(Paths.get(secret)); + InputStreamReader reader = new InputStreamReader(stream); + authJson = JsonParser.parseReader(reader).getAsJsonObject(); + } catch (IOException e) { + authJson = JsonParser.parseString(secret).getAsJsonObject(); + } + assertTrue(authJson.has("client_email")); + assertTrue(authJson.has("private_key")); + assertTrue(authJson.has("project_id")); + return authJson; + } + + private void validateConnection(String connection_uri) throws SQLException { + Connection connection = DriverManager.getConnection(connection_uri); + assertNotNull(connection); + assertFalse(connection.isClosed()); + String query = + "SELECT DISTINCT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT" + + " 850"; + Statement statement = connection.createStatement(); + ResultSet jsonResultSet = statement.executeQuery(query); + int totalRows = 0; + while (jsonResultSet.next()) { + totalRows += 1; + } + assertEquals(totalRows, 850); + connection.close(); + } + + @Test + public void testValidServiceAccountAuthentication() throws SQLException, IOException { + final JsonObject authJson = getAuthJson(); + File tempFile = File.createTempFile("auth", ".json"); + tempFile.deleteOnExit(); + Files.write(tempFile.toPath(), authJson.toString().getBytes()); + + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "ProjectId=" + + authJson.get("project_id").getAsString() + + ";OAuthType=0;" + + ";OAuthServiceAcctEmail=;" + + "OAuthPvtKeyPath=" + + tempFile.toPath() + + ";"; + + validateConnection(connection_uri); + } + + @Test + public void testServiceAccountAuthenticationMissingOAuthPvtKeyPath() throws SQLException { + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "ProjectId=" + + PROJECT_ID + + ";OAuthType=0;"; + + try { + DriverManager.getConnection(connection_uri); + Assertions.fail(); + } catch (Exception ex) { + assertTrue(ex.getMessage() != null); + } + } + + @Test + public void testValidServiceAccountAuthenticationOAuthPvtKeyAsPath() + throws SQLException, IOException { + final JsonObject authJson = getAuthJson(); + File tempFile = File.createTempFile("auth", ".json"); + tempFile.deleteOnExit(); + Files.write(tempFile.toPath(), authJson.toString().getBytes()); + + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "ProjectId=" + + authJson.get("project_id").getAsString() + + ";OAuthType=0;" + + "OAuthServiceAcctEmail=;" + + ";OAuthPvtKey=" + + tempFile.toPath() + + ";"; + validateConnection(connection_uri); + } + + @Test + public void testValidServiceAccountAuthenticationViaEmailAndPkcs8Key() + throws SQLException, IOException { + final JsonObject authJson = getAuthJson(); + + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "ProjectId=" + + authJson.get("project_id").getAsString() + + ";OAuthType=0;" + + "OAuthServiceAcctEmail=" + + authJson.get("client_email").getAsString() + + ";OAuthPvtKey=" + + authJson.get("private_key").getAsString() + + ";"; + validateConnection(connection_uri); + } + + @Test + public void testValidServiceAccountAuthenticationOAuthPvtKeyAsJson() + throws SQLException, IOException { + final JsonObject authJson = getAuthJson(); + + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" + + "ProjectId=" + + authJson.get("project_id").getAsString() + + ";OAuthType=0;" + + "OAuthServiceAcctEmail=;" + + ";OAuthPvtKey=" + + authJson.toString() + + ";"; + validateConnection(connection_uri); + } + + // TODO(kirl): Enable this test when pipeline has p12 secret available. + @Test + @Disabled + public void testValidServiceAccountAuthenticationP12() throws SQLException, IOException { + final JsonObject authJson = getAuthJson(); + final String p12_file = requireEnvVar("SA_SECRET_P12"); + + final String connectionUri = + getBaseUri(0, authJson.get("project_id").getAsString()) + .append("OAuthServiceAcctEmail", authJson.get("client_email").getAsString()) + .append("OAuthPvtKeyPath", p12_file) + .toString(); + validateConnection(connectionUri); + } + + @Test + @Disabled + public void testValidGoogleUserAccountAuthentication() throws SQLException { + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" + + PROJECT_ID + + ";OAuthType=1;OAuthClientId=client_id;OAuthClientSecret=client_secret;"; + + Connection connection = DriverManager.getConnection(connection_uri); + assertNotNull(connection); + assertFalse(connection.isClosed()); + + Statement statement = connection.createStatement(); + ResultSet resultSet = + statement.executeQuery( + "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); + + assertEquals(50, resultSetRowCount(resultSet)); + connection.close(); + } + + @Test + @Disabled + public void testValidExternalAccountAuthentication() throws SQLException { + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" + + PROJECT_ID + + ";OAUTHTYPE=4;" + + "BYOID_AudienceUri=//iam.googleapis.com/projects//locations//workloadIdentityPools//providers/;" + + "BYOID_SubjectTokenType=;BYOID_CredentialSource={\"file\":\"/path/to/file\"};" + + "BYOID_SA_Impersonation_Uri=;BYOID_TokenUri=;"; + + Connection connection = DriverManager.getConnection(connection_uri); + assertNotNull(connection); + assertFalse(connection.isClosed()); + + Statement statement = connection.createStatement(); + ResultSet resultSet = + statement.executeQuery( + "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); + + assertEquals(50, resultSetRowCount(resultSet)); + connection.close(); + } + + @Test + @Disabled + public void testValidExternalAccountAuthenticationFromFile() throws SQLException { + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" + + PROJECT_ID + + ";OAUTHTYPE=4;" + + "OAuthPvtKeyPath=/path/to/file;"; + + Connection connection = DriverManager.getConnection(connection_uri); + assertNotNull(connection); + assertFalse(connection.isClosed()); + + Statement statement = connection.createStatement(); + ResultSet resultSet = + statement.executeQuery( + "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); + + assertEquals(50, resultSetRowCount(resultSet)); + connection.close(); + } + + @Test + @Disabled + public void testValidExternalAccountAuthenticationRawJson() throws SQLException { + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" + + PROJECT_ID + + ";OAUTHTYPE=4;OAuthPvtKey={\n" + + " \"universe_domain\": \"googleapis.com\",\n" + + " \"type\": \"external_account\",\n" + + " \"audience\":" + + " \"//iam.googleapis.com/projects//locations//workloadIdentityPools//providers/\",\n" + + " \"subject_token_type\": \"\",\n" + + " \"token_url\": \"\",\n" + + " \"credential_source\": {\n" + + " \"file\": \"/path/to/file\"\n" + + " },\n" + + " \"service_account_impersonation_url\": \"\"\n" + + "};"; + + Connection connection = DriverManager.getConnection(connection_uri); + assertNotNull(connection); + assertFalse(connection.isClosed()); + + Statement statement = connection.createStatement(); + ResultSet resultSet = + statement.executeQuery( + "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); + + assertEquals(50, resultSetRowCount(resultSet)); + connection.close(); + } + + // TODO(farhan): figure out how to programmatically generate an access token and test + @Test + @Disabled + public void testValidPreGeneratedAccessTokenAuthentication() throws SQLException { + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" + + PROJECT_ID + + ";OAUTHTYPE=2;OAuthAccessToken=access_token;"; + + Connection connection = DriverManager.getConnection(connection_uri); + assertNotNull(connection); + assertFalse(connection.isClosed()); + + Statement statement = connection.createStatement(); + ResultSet resultSet = + statement.executeQuery( + "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); + + assertEquals(50, resultSetRowCount(resultSet)); + connection.close(); + } + + // TODO(obada): figure out how to programmatically generate a refresh token and test + @Test + @Disabled + public void testValidRefreshTokenAuthentication() throws SQLException { + String connection_uri = + "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" + + PROJECT_ID + + ";OAUTHTYPE=2;OAuthRefreshToken=refresh_token;" + + ";OAuthClientId=client;OAuthClientSecret=secret;"; + + Connection connection = DriverManager.getConnection(connection_uri); + assertNotNull(connection); + assertFalse(connection.isClosed()); + + Statement statement = connection.createStatement(); + ResultSet resultSet = + statement.executeQuery( + "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); + + assertEquals(50, resultSetRowCount(resultSet)); + connection.close(); + } + + @Test + public void testValidApplicationDefaultCredentialsAuthentication() throws SQLException { + String connection_uri = getBaseUri(3, PROJECT_ID).toString(); + + Connection connection = DriverManager.getConnection(connection_uri); + assertNotNull(connection); + assertFalse(connection.isClosed()); + connection.close(); + } + + // This test is useing the same client email as a main authorization & impersonation. + // It requires account to have 'tokenCreator' permission, see + // https://cloud.google.com/docs/authentication/use-service-account-impersonation#required-roles + @Test + public void testServiceAccountAuthenticationWithImpersonation() throws IOException, SQLException { + final JsonObject authJson = getAuthJson(); + + String connection_uri = + getBaseUri(0, authJson.get("project_id").getAsString()) + .append("OAuthServiceAcctEmail", authJson.get("client_email").getAsString()) + .append("OAuthPvtKey", authJson.get("private_key").getAsString()) + .append("ServiceAccountImpersonationEmail", authJson.get("client_email").getAsString()) + .toString(); + validateConnection(connection_uri); + } + + // This test uses the same client email for the main authorization and a chain of impersonations. + // It requires the account to have 'tokenCreator' permission on itself. + @Test + public void testServiceAccountAuthenticationWithChainedImpersonation() + throws IOException, SQLException { + final JsonObject authJson = getAuthJson(); + String clientEmail = authJson.get("client_email").getAsString(); + + String connection_uri = + getBaseUri(0, authJson.get("project_id").getAsString()) + .append("OAuthServiceAcctEmail", clientEmail) + .append("OAuthPvtKey", authJson.get("private_key").getAsString()) + .append("ServiceAccountImpersonationEmail", clientEmail) + .append("ServiceAccountImpersonationChain", clientEmail + "," + clientEmail) + .toString(); + validateConnection(connection_uri); + } +} diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITBase.java b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITBase.java index 5aa41b297512..ba92e2d70aec 100644 --- a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITBase.java +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITBase.java @@ -16,6 +16,27 @@ package com.google.cloud.bigquery.jdbc.it; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import com.google.cloud.bigquery.jdbc.BigQueryJdbcBaseTest; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class ITBase extends BigQueryJdbcBaseTest { + + protected static String requireEnvVar(String varName) { + String value = System.getenv(varName); + assertNotNull( + System.getenv(varName), + "Environment variable " + varName + " is required to perform these tests."); + return value; + } -public class ITBase extends BigQueryJdbcBaseTest {} + protected int resultSetRowCount(ResultSet resultSet) throws SQLException { + int rowCount = 0; + while (resultSet.next()) { + rowCount++; + } + return rowCount; + } +} diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITBigQueryJDBCTest.java b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITBigQueryJDBCTest.java index 184b4d3d45d6..6cd75a49ecf5 100644 --- a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITBigQueryJDBCTest.java +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITBigQueryJDBCTest.java @@ -33,7 +33,6 @@ import com.google.cloud.bigquery.JobInfo; import com.google.cloud.bigquery.QueryJobConfiguration; import com.google.cloud.bigquery.exception.BigQueryJdbcException; -import com.google.cloud.bigquery.exception.BigQueryJdbcRuntimeException; import com.google.cloud.bigquery.exception.BigQueryJdbcSqlFeatureNotSupportedException; import com.google.cloud.bigquery.exception.BigQueryJdbcSqlSyntaxErrorException; import com.google.cloud.bigquery.jdbc.BigQueryConnection; @@ -43,15 +42,9 @@ import com.google.cloud.bigquery.jdbc.PooledConnectionListener; import com.google.cloud.bigquery.jdbc.utils.TestUtilities.TestConnectionListener; import com.google.common.collect.ImmutableMap; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.math.BigDecimal; -import java.nio.file.Files; -import java.nio.file.Paths; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DatabaseMetaData; @@ -81,7 +74,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; public class ITBigQueryJDBCTest extends ITBase { @@ -124,49 +116,6 @@ public class ITBigQueryJDBCTest extends ITBase { private static final Long CUSTOM_CONN_POOL_SIZE = 5L; private static final Object EXCEPTION_REPLACEMENT = "EXCEPTION-WAS-RAISED"; - private static String requireEnvVar(String varName) { - String value = System.getenv(varName); - assertNotNull( - System.getenv(varName), - "Environment variable " + varName + " is required to perform these tests."); - return value; - } - - private JsonObject getAuthJson() throws IOException { - final String secret = requireEnvVar("SA_SECRET"); - JsonObject authJson; - // Supporting both formats of SA_SECRET: - // - Local runs can point to a json file - // - Cloud Build has JSON value - try { - InputStream stream = Files.newInputStream(Paths.get(secret)); - InputStreamReader reader = new InputStreamReader(stream); - authJson = JsonParser.parseReader(reader).getAsJsonObject(); - } catch (IOException e) { - authJson = JsonParser.parseString(secret).getAsJsonObject(); - } - assertTrue(authJson.has("client_email")); - assertTrue(authJson.has("private_key")); - assertTrue(authJson.has("project_id")); - return authJson; - } - - private void validateConnection(String connection_uri) throws SQLException { - Connection connection = DriverManager.getConnection(connection_uri); - assertNotNull(connection); - assertFalse(connection.isClosed()); - assertEquals( - "GOOGLE_SERVICE_ACCOUNT", - ((BigQueryConnection) connection).getAuthProperties().get("OAuthType")); - String query = - "SELECT DISTINCT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT" - + " 850"; - Statement statement = connection.createStatement(); - ResultSet jsonResultSet = statement.executeQuery(query); - assertTrue(jsonResultSet.getClass().getName().contains("BigQueryJsonResultSet")); - connection.close(); - } - @BeforeAll public static void beforeClass() throws SQLException { bigQueryConnection = DriverManager.getConnection(connection_uri, new Properties()); @@ -187,320 +136,6 @@ public static void afterClass() throws SQLException { bigQueryConnectionNoReadApi.close(); } - @Test - public void testValidServiceAccountAuthentication() throws SQLException, IOException { - final JsonObject authJson = getAuthJson(); - File tempFile = File.createTempFile("auth", ".json"); - tempFile.deleteOnExit(); - Files.write(tempFile.toPath(), authJson.toString().getBytes()); - - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" - + "ProjectId=" - + authJson.get("project_id").getAsString() - + ";OAuthType=0;" - + "OAuthPvtKeyPath=" - + tempFile.toPath() - + ";"; - - validateConnection(connection_uri); - } - - @Test - public void testServiceAccountAuthenticationMissingOAuthPvtKeyPath() throws SQLException { - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" - + "ProjectId=" - + PROJECT_ID - + ";OAuthType=0;"; - - try { - DriverManager.getConnection(connection_uri); - Assertions.fail(); - } catch (BigQueryJdbcRuntimeException ex) { - assertTrue(ex.getMessage().contains("No valid credentials provided.")); - } - } - - @Test - public void testValidServiceAccountAuthenticationOAuthPvtKeyAsPath() - throws SQLException, IOException { - final JsonObject authJson = getAuthJson(); - File tempFile = File.createTempFile("auth", ".json"); - tempFile.deleteOnExit(); - Files.write(tempFile.toPath(), authJson.toString().getBytes()); - - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" - + "ProjectId=" - + authJson.get("project_id").getAsString() - + ";OAuthType=0;" - + "OAuthServiceAcctEmail=;" - + ";OAuthPvtKey=" - + tempFile.toPath() - + ";"; - validateConnection(connection_uri); - } - - @Test - public void testValidServiceAccountAuthenticationViaEmailAndPkcs8Key() - throws SQLException, IOException { - final JsonObject authJson = getAuthJson(); - - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" - + "ProjectId=" - + authJson.get("project_id").getAsString() - + ";OAuthType=0;" - + "OAuthServiceAcctEmail=" - + authJson.get("client_email").getAsString() - + ";OAuthPvtKey=" - + authJson.get("private_key").getAsString() - + ";"; - validateConnection(connection_uri); - } - - @Test - public void testValidServiceAccountAuthenticationOAuthPvtKeyAsJson() - throws SQLException, IOException { - final JsonObject authJson = getAuthJson(); - - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;" - + "ProjectId=" - + authJson.get("project_id").getAsString() - + ";OAuthType=0;" - + "OAuthServiceAcctEmail=;" - + ";OAuthPvtKey=" - + authJson.toString() - + ";"; - validateConnection(connection_uri); - } - - // TODO(kirl): Enable this test when pipeline has p12 secret available. - @Test - @Disabled - public void testValidServiceAccountAuthenticationP12() throws SQLException, IOException { - final JsonObject authJson = getAuthJson(); - final String p12_file = requireEnvVar("SA_SECRET_P12"); - - final String connectionUri = - getBaseUri(0, authJson.get("project_id").getAsString()) - .append("OAuthServiceAcctEmail", authJson.get("client_email").getAsString()) - .append("OAuthPvtKeyPath", p12_file) - .toString(); - validateConnection(connectionUri); - } - - @Test - @Disabled - public void testValidGoogleUserAccountAuthentication() throws SQLException { - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" - + PROJECT_ID - + ";OAuthType=1;OAuthClientId=client_id;OAuthClientSecret=client_secret;"; - - Connection connection = DriverManager.getConnection(connection_uri); - assertNotNull(connection); - assertFalse(connection.isClosed()); - assertEquals( - "GOOGLE_USER_ACCOUNT", - ((BigQueryConnection) connection).getAuthProperties().get("OAuthType")); - - Statement statement = connection.createStatement(); - ResultSet resultSet = - statement.executeQuery( - "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); - - assertEquals(50, resultSetRowCount(resultSet)); - connection.close(); - } - - @Test - @Disabled - public void testValidExternalAccountAuthentication() throws SQLException { - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" - + PROJECT_ID - + ";OAUTHTYPE=4;" - + "BYOID_AudienceUri=//iam.googleapis.com/projects//locations//workloadIdentityPools//providers/;" - + "BYOID_SubjectTokenType=;BYOID_CredentialSource={\"file\":\"/path/to/file\"};" - + "BYOID_SA_Impersonation_Uri=;BYOID_TokenUri=;"; - - Connection connection = DriverManager.getConnection(connection_uri); - assertNotNull(connection); - assertFalse(connection.isClosed()); - assertEquals( - "EXTERNAL_ACCOUNT_AUTH", - ((BigQueryConnection) connection).getAuthProperties().get("OAuthType")); - - Statement statement = connection.createStatement(); - ResultSet resultSet = - statement.executeQuery( - "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); - - assertEquals(50, resultSetRowCount(resultSet)); - connection.close(); - } - - @Test - @Disabled - public void testValidExternalAccountAuthenticationFromFile() throws SQLException { - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" - + PROJECT_ID - + ";OAUTHTYPE=4;" - + "OAuthPvtKeyPath=/path/to/file;"; - - Connection connection = DriverManager.getConnection(connection_uri); - assertNotNull(connection); - assertFalse(connection.isClosed()); - assertEquals( - "EXTERNAL_ACCOUNT_AUTH", - ((BigQueryConnection) connection).getAuthProperties().get("OAuthType")); - - Statement statement = connection.createStatement(); - ResultSet resultSet = - statement.executeQuery( - "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); - - assertEquals(50, resultSetRowCount(resultSet)); - connection.close(); - } - - @Test - @Disabled - public void testValidExternalAccountAuthenticationRawJson() throws SQLException { - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" - + PROJECT_ID - + ";OAUTHTYPE=4;OAuthPvtKey={\n" - + " \"universe_domain\": \"googleapis.com\",\n" - + " \"type\": \"external_account\",\n" - + " \"audience\":" - + " \"//iam.googleapis.com/projects//locations//workloadIdentityPools//providers/\",\n" - + " \"subject_token_type\": \"\",\n" - + " \"token_url\": \"\",\n" - + " \"credential_source\": {\n" - + " \"file\": \"/path/to/file\"\n" - + " },\n" - + " \"service_account_impersonation_url\": \"\"\n" - + "};"; - - Connection connection = DriverManager.getConnection(connection_uri); - assertNotNull(connection); - assertFalse(connection.isClosed()); - assertEquals( - "EXTERNAL_ACCOUNT_AUTH", - ((BigQueryConnection) connection).getAuthProperties().get("OAuthType")); - - Statement statement = connection.createStatement(); - ResultSet resultSet = - statement.executeQuery( - "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); - - assertEquals(50, resultSetRowCount(resultSet)); - connection.close(); - } - - // TODO(farhan): figure out how to programmatically generate an access token and test - @Test - @Disabled - public void testValidPreGeneratedAccessTokenAuthentication() throws SQLException { - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" - + PROJECT_ID - + ";OAUTHTYPE=2;OAuthAccessToken=access_token;"; - - Connection connection = DriverManager.getConnection(connection_uri); - assertNotNull(connection); - assertFalse(connection.isClosed()); - assertEquals( - "PRE_GENERATED_TOKEN", - ((BigQueryConnection) connection).getAuthProperties().get("OAuthType")); - - Statement statement = connection.createStatement(); - ResultSet resultSet = - statement.executeQuery( - "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); - - assertEquals(50, resultSetRowCount(resultSet)); - connection.close(); - } - - // TODO(obada): figure out how to programmatically generate a refresh token and test - @Test - @Disabled - public void testValidRefreshTokenAuthentication() throws SQLException { - String connection_uri = - "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;PROJECTID=" - + PROJECT_ID - + ";OAUTHTYPE=2;OAuthRefreshToken=refresh_token;" - + ";OAuthClientId=client;OAuthClientSecret=secret;"; - - Connection connection = DriverManager.getConnection(connection_uri); - assertNotNull(connection); - assertFalse(connection.isClosed()); - assertEquals( - "PRE_GENERATED_TOKEN", - ((BigQueryConnection) connection).getAuthProperties().get("OAuthType")); - - Statement statement = connection.createStatement(); - ResultSet resultSet = - statement.executeQuery( - "SELECT repository_name FROM `bigquery-public-data.samples.github_timeline` LIMIT 50"); - - assertEquals(50, resultSetRowCount(resultSet)); - connection.close(); - } - - @Test - public void testValidApplicationDefaultCredentialsAuthentication() throws SQLException { - String connection_uri = getBaseUri(3, PROJECT_ID).toString(); - - Connection connection = DriverManager.getConnection(connection_uri); - assertNotNull(connection); - assertFalse(connection.isClosed()); - assertEquals( - "APPLICATION_DEFAULT_CREDENTIALS", - ((BigQueryConnection) connection).getAuthProperties().get("OAuthType")); - connection.close(); - } - - // This test is useing the same client email as a main authorization & impersonation. - // It requires account to have 'tokenCreator' permission, see - // https://cloud.google.com/docs/authentication/use-service-account-impersonation#required-roles - @Test - public void testServiceAccountAuthenticationWithImpersonation() throws IOException, SQLException { - final JsonObject authJson = getAuthJson(); - - String connection_uri = - getBaseUri(0, authJson.get("project_id").getAsString()) - .append("OAuthServiceAcctEmail", authJson.get("client_email").getAsString()) - .append("OAuthPvtKey", authJson.get("private_key").getAsString()) - .append("ServiceAccountImpersonationEmail", authJson.get("client_email").getAsString()) - .toString(); - validateConnection(connection_uri); - } - - // This test uses the same client email for the main authorization and a chain of impersonations. - // It requires the account to have 'tokenCreator' permission on itself. - @Test - public void testServiceAccountAuthenticationWithChainedImpersonation() - throws IOException, SQLException { - final JsonObject authJson = getAuthJson(); - String clientEmail = authJson.get("client_email").getAsString(); - - String connection_uri = - getBaseUri(0, authJson.get("project_id").getAsString()) - .append("OAuthServiceAcctEmail", clientEmail) - .append("OAuthPvtKey", authJson.get("private_key").getAsString()) - .append("ServiceAccountImpersonationEmail", clientEmail) - .append("ServiceAccountImpersonationChain", clientEmail + "," + clientEmail) - .toString(); - validateConnection(connection_uri); - } - @Test public void testFastQueryPathSmall() throws SQLException { String query = @@ -4428,12 +4063,4 @@ public void validateGetObjectNullValues() throws Exception { } } } - - private int resultSetRowCount(ResultSet resultSet) throws SQLException { - int rowCount = 0; - while (resultSet.next()) { - rowCount++; - } - return rowCount; - } } diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/suites/ITDriverAgnosticTests.java b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/suites/ITDriverAgnosticTests.java new file mode 100644 index 000000000000..fe20abcbb2c3 --- /dev/null +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/suites/ITDriverAgnosticTests.java @@ -0,0 +1,25 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed 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 com.google.cloud.bigquery.jdbc.it.suites; + +import com.google.cloud.bigquery.jdbc.it.ITAuthTests; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; + +@Suite +@SelectClasses({ITAuthTests.class}) +public class ITDriverAgnosticTests {} diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/suites/ITNightlyTests.java b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/suites/ITNightlyTests.java new file mode 100644 index 000000000000..2700c18adbbd --- /dev/null +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/suites/ITNightlyTests.java @@ -0,0 +1,27 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed 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 com.google.cloud.bigquery.jdbc.it.suites; + +import com.google.cloud.bigquery.jdbc.it.ITAuthTests; +import com.google.cloud.bigquery.jdbc.it.ITBigQueryJDBCTest; +import com.google.cloud.bigquery.jdbc.it.ITNightlyBigQueryTest; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; + +@Suite +@SelectClasses({ITAuthTests.class, ITBigQueryJDBCTest.class, ITNightlyBigQueryTest.class}) +public class ITNightlyTests {} diff --git a/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/suites/ITPresubmitTests.java b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/suites/ITPresubmitTests.java new file mode 100644 index 000000000000..5f0517f17399 --- /dev/null +++ b/java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/suites/ITPresubmitTests.java @@ -0,0 +1,26 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed 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 com.google.cloud.bigquery.jdbc.it.suites; + +import com.google.cloud.bigquery.jdbc.it.ITAuthTests; +import com.google.cloud.bigquery.jdbc.it.ITBigQueryJDBCTest; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; + +@Suite +@SelectClasses({ITAuthTests.class, ITBigQueryJDBCTest.class}) +public class ITPresubmitTests {} diff --git a/java-bigquery/pom.xml b/java-bigquery/pom.xml index c512c269c1a7..b65f6b7a3e35 100644 --- a/java-bigquery/pom.xml +++ b/java-bigquery/pom.xml @@ -133,6 +133,8 @@ com.google.api:gax org.junit.jupiter:junit-jupiter-engine + + org.junit.platform:junit-platform-suite-engine javax.annotation:javax.annotation-api