From d9c6cdb6c6ccb604f89c275cb97501fa8ac7acaa Mon Sep 17 00:00:00 2001 From: Terry Chow <32403408+tkyc@users.noreply.github.com> Date: Thu, 23 May 2024 09:46:13 -0700 Subject: [PATCH] Managed Identity pipeline changes and test updates (#2430) * Updates for running tests with managed identity (#2416) * Updated tests for removal of secrets * Reverted TimeoutTests * AE config port * TimeoutTests update --------- Co-authored-by: lilgreenbird --- .../microsoft/sqlserver/jdbc/IOBuffer.java | 4 - .../jdbc/AlwaysEncrypted/AESetup.java | 13 +- .../CallableStatementTest.java | 2 +- .../jdbc/SQLServerConnectionTest.java | 37 +++- .../sqlserver/jdbc/TestResource.java | 6 +- .../microsoft/sqlserver/jdbc/TestUtils.java | 34 +++- .../jdbc/connection/PoolingTest.java | 4 + .../jdbc/connection/TimeoutTest.java | 162 ++++++++++-------- .../DatabaseMetaDataTest.java | 7 +- .../sqlserver/jdbc/fedauth/FedauthWithAE.java | 2 +- .../sqlserver/jdbc/fips/FipsTest.java | 18 +- .../jdbc/resiliency/ReflectiveTests.java | 2 +- .../jdbc/unit/SQLServerErrorTest.java | 5 + .../unit/statement/BatchExecutionTest.java | 6 + .../unit/statement/PreparedStatementTest.java | 4 +- .../sqlserver/testframework/AbstractTest.java | 37 ++-- .../sqlserver/testframework/Constants.java | 1 + 17 files changed, 236 insertions(+), 108 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index 1597d0cd3..6e09bd756 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -6912,10 +6912,6 @@ final boolean readPacket() throws SQLServerException { // if messageType is RPC or QUERY, then increment Counter's state if (tdsChannel.getWriter().checkIfTdsMessageTypeIsBatchOrRPC() && null != command) { - if (logger.isLoggable(Level.FINER)) { - logger.warning(toString() + ": increasing state of counter for TDS Command: " + command.toString()); - } - if (null == command.getCounter()) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_NullValue")); Object[] msgArgs1 = {"TDS command counter"}; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java index 541f2da16..3fbf0d4d8 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java @@ -186,6 +186,13 @@ static void setAEConnectionString(String serverName, String url, String protocol if (enclaveServer.length > 1) { System.out.println("Testing enclave: " + enclaveProperties); } + + // remove the password in connection string + // this is necessary as updateDataSource will only use 1st occurrence + String password = getConfiguredProperty("enclaveServerPassword"); + AETestConnectionString = TestUtils.removeProperty(AETestConnectionString, Constants.PASSWORD); + AETestConnectionString = TestUtils.addOrOverrideProperty(AETestConnectionString, Constants.PASSWORD, + password); } else { AETestConnectionString = connectionString + ";sendTimeAsDateTime=false;columnEncryptionSetting=enabled;"; } @@ -332,7 +339,7 @@ protected static void createTable(String tableName, String cekName, String table TestUtils.dropTableIfExists(tableName, stmt); sql = String.format(createSql, tableName, sql); stmt.execute(sql); - stmt.execute("DBCC FREEPROCCACHE"); + TestUtils.freeProcCache(stmt); } catch (SQLException e) { fail(e.getMessage()); } @@ -366,7 +373,7 @@ protected static void createPrecisionTable(String tableName, String table[][], S } sql = String.format(createSql, tableName, sql); stmt.execute(sql); - stmt.execute("DBCC FREEPROCCACHE"); + TestUtils.freeProcCache(stmt); } catch (SQLException e) { fail(e.getMessage()); } @@ -394,7 +401,7 @@ protected static void createScaleTable(String tableName, String table[][], Strin sql = String.format(createSql, tableName, sql); stmt.execute(sql); - stmt.execute("DBCC FREEPROCCACHE"); + TestUtils.freeProcCache(stmt); } catch (SQLException e) { fail(e.getMessage()); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/CallableStatementTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/CallableStatementTest.java index 95531d698..d259b35a5 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/CallableStatementTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/CallableStatementTest.java @@ -2201,7 +2201,7 @@ protected static void createDateTableCallableStatement(String cekName) throws SQ SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { TestUtils.dropTableIfExists(DATE_TABLE_AE, stmt); stmt.execute(sql); - stmt.execute("DBCC FREEPROCCACHE"); + TestUtils.freeProcCache(stmt); } catch (SQLException e) { fail(e.getMessage()); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java index eabbbb574..70e3a318d 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java @@ -481,7 +481,13 @@ public void testConnectCountInLoginAndCorrectRetryCount() { assertTrue(con == null, TestResource.getResource("R_shouldNotConnect")); } } catch (Exception e) { - assertTrue(e.getMessage().contains(TestResource.getResource("R_cannotOpenDatabase")), e.getMessage()); + assertTrue( + e.getMessage().contains(TestResource.getResource("R_cannotOpenDatabase")) + || (TestUtils.getProperty(connectionString, "msiClientId") != null && (e.getMessage() + .toLowerCase().contains(TestResource.getResource("R_loginFailedMI").toLowerCase()) + || e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_MInotAvailable").toLowerCase()))), + e.getMessage()); long totalTime = System.currentTimeMillis() - timerStart; // Maximum is unknown, but is needs to be less than longLoginTimeout or else this is an issue. @@ -756,13 +762,22 @@ public void testIncorrectDatabase() throws SQLException { assertTrue(timeDiff <= milsecs, form.format(msgArgs)); } } catch (Exception e) { - assertTrue(e.getMessage().contains(TestResource.getResource("R_cannotOpenDatabase")), e.getMessage()); + assertTrue( + e.getMessage().contains(TestResource.getResource("R_cannotOpenDatabase")) + || (TestUtils.getProperty(connectionString, "msiClientId") != null + && e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_loginFailedMI").toLowerCase())), + e.getMessage()); timerEnd = System.currentTimeMillis(); } } @Test public void testIncorrectUserName() throws SQLException { + String auth = TestUtils.getProperty(connectionString, "authentication"); + org.junit.Assume.assumeTrue(auth != null + && (auth.equalsIgnoreCase("SqlPassword") || auth.equalsIgnoreCase("ActiveDirectoryPassword"))); + long timerStart = 0; long timerEnd = 0; final long milsecs = threshHoldForNoRetryInMilliseconds; @@ -780,13 +795,22 @@ public void testIncorrectUserName() throws SQLException { assertTrue(timeDiff <= milsecs, form.format(msgArgs)); } } catch (Exception e) { - assertTrue(e.getMessage().contains(TestResource.getResource("R_loginFailed"))); + assertTrue( + e.getMessage().contains(TestResource.getResource("R_loginFailed")) + || (TestUtils.getProperty(connectionString, "msiClientId") != null + && e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_loginFailedMI").toLowerCase())), + e.getMessage()); timerEnd = System.currentTimeMillis(); } } @Test public void testIncorrectPassword() throws SQLException { + String auth = TestUtils.getProperty(connectionString, "authentication"); + org.junit.Assume.assumeTrue(auth != null + && (auth.equalsIgnoreCase("SqlPassword") || auth.equalsIgnoreCase("ActiveDirectoryPassword"))); + long timerStart = 0; long timerEnd = 0; final long milsecs = threshHoldForNoRetryInMilliseconds; @@ -804,7 +828,12 @@ public void testIncorrectPassword() throws SQLException { assertTrue(timeDiff <= milsecs, form.format(msgArgs)); } } catch (Exception e) { - assertTrue(e.getMessage().contains(TestResource.getResource("R_loginFailed"))); + assertTrue( + e.getMessage().contains(TestResource.getResource("R_loginFailed")) + || (TestUtils.getProperty(connectionString, "msiClientId") != null + && e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_loginFailedMI").toLowerCase())), + e.getMessage()); timerEnd = System.currentTimeMillis(); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/TestResource.java b/src/test/java/com/microsoft/sqlserver/jdbc/TestResource.java index e14bb671a..fe817797c 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/TestResource.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/TestResource.java @@ -212,5 +212,9 @@ protected Object[][] getContents() { {"R_failedFedauth", "Failed to acquire fedauth token: "}, {"R_noLoginModulesConfiguredForJdbcDriver", "javax.security.auth.login.LoginException (No LoginModules configured for SQLJDBCDriver)"}, - {"R_unexpectedThreadCount", "Thread count is higher than expected."}}; + {"R_unexpectedThreadCount", "Thread count is higher than expected."}, + {"R_expectedClassDoesNotMatchActualClass", + "Expected column class {0} does not match actual column class {1} for column {2}."}, + {"R_loginFailedMI", "Login failed for user ''"}, + {"R_MInotAvailable", "Managed Identity authentication is not available"},}; } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/TestUtils.java b/src/test/java/com/microsoft/sqlserver/jdbc/TestUtils.java index af5d54e19..f15fbfaf2 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/TestUtils.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/TestUtils.java @@ -523,7 +523,31 @@ public static void dropDatabaseIfExists(String databaseName, String connectionSt */ public static void dropSchemaIfExists(String schemaName, Statement stmt) throws SQLException { stmt.execute("if EXISTS (SELECT * FROM sys.schemas where name = '" + escapeSingleQuotes(schemaName) - + "') drop schema " + AbstractSQLGenerator.escapeIdentifier(schemaName)); + + "') DROP SCHEMA" + AbstractSQLGenerator.escapeIdentifier(schemaName)); + } + + /** + * mimic "DROP USER..." + * + * @param userName + * @param stmt + * @throws SQLException + */ + public static void dropUserIfExists(String userName, Statement stmt) throws SQLException { + stmt.execute("IF EXISTS (SELECT * FROM sys.sysusers where name = '" + escapeSingleQuotes(userName) + + "') DROP USER " + AbstractSQLGenerator.escapeIdentifier(userName)); + } + + /** + * mimic "DROP LOGIN..." + * + * @param userName + * @param stmt + * @throws SQLException + */ + public static void dropLoginIfExists(String userName, Statement stmt) throws SQLException { + stmt.execute("IF EXISTS (SELECT * FROM sys.sysusers where name = '" + escapeSingleQuotes(userName) + + "') DROP LOGIN " + AbstractSQLGenerator.escapeIdentifier(userName)); } /** @@ -1099,4 +1123,12 @@ public static String getConnectionID( SQLServerConnection conn = (SQLServerConnection) physicalConnection.get(pc); return (String) traceID.get(conn); } + + public static void freeProcCache(Statement stmt) { + try { + stmt.execute("DBCC FREEPROCCACHE"); + } catch (Exception e) { + // ignore error - some tests fails due to permission issues from managed identity, this does not seem to affect tests + } + } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java index d99d846ef..57a11a725 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java @@ -152,6 +152,10 @@ public void testConnectionPoolClose() throws SQLException { @Test public void testConnectionPoolClientConnectionId() throws SQLException { + String auth = TestUtils.getProperty(connectionString, "authentication"); + org.junit.Assume.assumeTrue(auth != null + && (auth.equalsIgnoreCase("SqlPassword") || auth.equalsIgnoreCase("ActiveDirectoryPassword"))); + SQLServerXADataSource ds = new SQLServerXADataSource(); ds.setURL(connectionString); PooledConnection pc = null; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java index af2bda8af..13064bf7f 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java @@ -60,10 +60,10 @@ public void testDefaultLoginTimeout() { timerEnd = System.currentTimeMillis(); assertTrue((e.getMessage().contains(TestResource.getResource("R_tcpipConnectionToHost"))) - || ((isSqlAzure() || isSqlAzureDW()) - ? e.getMessage().contains( - TestResource.getResource("R_connectTimedOut")) - : false), + || ((isSqlAzure() || isSqlAzureDW()) + ? e.getMessage().contains( + TestResource.getResource("R_connectTimedOut")) + : false), e.getMessage()); } @@ -83,10 +83,10 @@ public void testURLLoginTimeout() { timerEnd = System.currentTimeMillis(); assertTrue((e.getMessage().contains(TestResource.getResource("R_tcpipConnectionToHost"))) - || ((isSqlAzure() || isSqlAzureDW()) - ? e.getMessage().contains( - TestResource.getResource("R_connectTimedOut")) - : false), + || ((isSqlAzure() || isSqlAzureDW()) + ? e.getMessage().contains( + TestResource.getResource("R_connectTimedOut")) + : false), e.getMessage()); } @@ -107,10 +107,10 @@ public void testDMLoginTimeoutApplied() { timerEnd = System.currentTimeMillis(); assertTrue((e.getMessage().contains(TestResource.getResource("R_tcpipConnectionToHost"))) - || ((isSqlAzure() || isSqlAzureDW()) - ? e.getMessage().contains( - TestResource.getResource("R_connectTimedOut")) - : false), + || ((isSqlAzure() || isSqlAzureDW()) + ? e.getMessage().contains( + TestResource.getResource("R_connectTimedOut")) + : false), e.getMessage()); } @@ -134,10 +134,10 @@ public void testDMLoginTimeoutNotApplied() { assertTrue( (e.getMessage().contains(TestResource.getResource("R_tcpipConnectionToHost"))) || ((isSqlAzure() || isSqlAzureDW()) - ? e.getMessage() - .contains(TestResource - .getResource("R_connectTimedOut")) - : false), + ? e.getMessage() + .contains(TestResource + .getResource("R_connectTimedOut")) + : false), e.getMessage()); } verifyTimeout(timerEnd - timerStart, timeout); @@ -161,10 +161,10 @@ public void testConnectRetryBadServer() { timerEnd = System.currentTimeMillis(); assertTrue((e.getMessage().contains(TestResource.getResource("R_tcpipConnectionToHost"))) - || ((isSqlAzure() || isSqlAzureDW()) - ? e.getMessage().contains( - TestResource.getResource("R_connectTimedOut")) - : false), + || ((isSqlAzure() || isSqlAzureDW()) + ? e.getMessage().contains( + TestResource.getResource("R_connectTimedOut")) + : false), e.getMessage()); } @@ -174,89 +174,111 @@ public void testConnectRetryBadServer() { // Test connect retry for database error @Test public void testConnectRetryServerError() { - long timerEnd = 0; + String auth = TestUtils.getProperty(connectionString, "authentication"); + org.junit.Assume.assumeTrue(auth != null + && (auth.equalsIgnoreCase("SqlPassword") || auth.equalsIgnoreCase("ActiveDirectoryPassword"))); + + long totalTime = 0; long timerStart = System.currentTimeMillis(); + int interval = defaultTimeout; // long interval so we can tell if there was a retry + long timeout = defaultTimeout * 2; // long loginTimeout to accommodate the long interval - // non existent database with interval < loginTimeout this will generate a 4060 transient error and retry - int connectRetryCount = new Random().nextInt(256); - int connectRetryInterval = new Random().nextInt(defaultTimeout) + 1; + // non existent database with interval < loginTimeout this will generate a 4060 transient error and retry 1 time try (Connection con = PrepUtil.getConnection( TestUtils.addOrOverrideProperty(connectionString, "database", RandomUtil.getIdentifier("database")) - + ";logintimeout=" + defaultTimeout + ";connectRetryCount=" + connectRetryCount - + ";connectRetryInterval=" + connectRetryInterval)) { + + ";loginTimeout=" + timeout + ";connectRetryCount=" + 1 + ";connectRetryInterval=" + interval + + ";transparentNetworkIPResolution=false")) { fail(TestResource.getResource("R_shouldNotConnect")); } catch (Exception e) { - timerEnd = System.currentTimeMillis(); - - assertTrue((e.getMessage().contains(TestResource.getResource("R_cannotOpenDatabase"))) - || ((isSqlAzure() || isSqlAzureDW()) - ? e.getMessage().contains( - TestResource.getResource("R_connectTimedOut")) - : false), + totalTime = System.currentTimeMillis() - timerStart; + + assertTrue( + (e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_cannotOpenDatabase").toLowerCase())) + || (TestUtils.getProperty(connectionString, "msiClientId") != null && e.getMessage() + .toLowerCase().contains(TestResource.getResource("R_loginFailedMI").toLowerCase())) + || ((isSqlAzure() || isSqlAzureDW()) ? e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_connectTimedOut").toLowerCase()) : false), e.getMessage()); } - // connect + all retries should always be <= loginTimeout - verifyTimeout(timerEnd - timerStart, defaultTimeout); + // 1 retry should be at least 1 interval long but < 2 intervals + assertTrue(TimeUnit.SECONDS.toMillis(interval) < totalTime, + "interval: " + TimeUnit.SECONDS.toMillis(interval) + " total time: " + totalTime); + assertTrue(totalTime < TimeUnit.SECONDS.toMillis(2 * interval), + "total time: " + totalTime + " 2 * interval: " + TimeUnit.SECONDS.toMillis(interval)); } // Test connect retry for database error using Datasource @Test public void testConnectRetryServerErrorDS() { - long timerEnd = 0; - long timerStart = System.currentTimeMillis(); + String auth = TestUtils.getProperty(connectionString, "authentication"); + org.junit.Assume.assumeTrue(auth != null + && (auth.equalsIgnoreCase("SqlPassword") || auth.equalsIgnoreCase("ActiveDirectoryPassword"))); - // non existent database with interval < loginTimeout this will generate a 4060 transient error and retry - int connectRetryCount = new Random().nextInt(256); - int connectRetryInterval = new Random().nextInt(defaultTimeout) + 1; + long totalTime = 0; + long timerStart = System.currentTimeMillis(); + int interval = defaultTimeout; // long interval so we can tell if there was a retry + long loginTimeout = defaultTimeout * 2; // long loginTimeout to accommodate the long interval + // non existent database with interval < loginTimeout this will generate a 4060 transient error and retry 1 time SQLServerDataSource ds = new SQLServerDataSource(); String connectStr = TestUtils.addOrOverrideProperty(connectionString, "database", - RandomUtil.getIdentifier("database")) + ";logintimeout=" + defaultTimeout + ";connectRetryCount=" - + connectRetryCount + ";connectRetryInterval=" + connectRetryInterval; + RandomUtil.getIdentifier("database")) + ";logintimeout=" + loginTimeout + ";connectRetryCount=1" + + ";connectRetryInterval=" + interval; updateDataSource(connectStr, ds); try (Connection con = PrepUtil.getConnection(connectStr)) { fail(TestResource.getResource("R_shouldNotConnect")); } catch (Exception e) { - assertTrue((e.getMessage().contains(TestResource.getResource("R_cannotOpenDatabase"))) - || ((isSqlAzure() || isSqlAzureDW()) - ? e.getMessage().contains( - TestResource.getResource("R_connectTimedOut")) - : false), + assertTrue( + (e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_cannotOpenDatabase").toLowerCase())) + || (TestUtils.getProperty(connectionString, "msiClientId") != null && e.getMessage() + .toLowerCase().contains(TestResource.getResource("R_loginFailedMI").toLowerCase())) + || ((isSqlAzure() || isSqlAzureDW()) ? e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_connectTimedOut").toLowerCase()) : false), e.getMessage()); - timerEnd = System.currentTimeMillis(); + totalTime = System.currentTimeMillis() - timerStart; } - // connect + all retries should always be <= loginTimeout - verifyTimeout(timerEnd - timerStart, defaultTimeout); + // 1 retry should be at least 1 interval long but < 2 intervals + assertTrue(TimeUnit.SECONDS.toMillis(interval) < totalTime, + "interval: " + TimeUnit.SECONDS.toMillis(interval) + " total time: " + totalTime); + assertTrue(totalTime < TimeUnit.SECONDS.toMillis(2 * interval), + "total time: " + totalTime + " 2 * interval: " + TimeUnit.SECONDS.toMillis(2 * interval)); } // Test connect retry for database error with loginTimeout @Test public void testConnectRetryTimeout() { - long timerEnd = 0; + long totalTime = 0; long timerStart = System.currentTimeMillis(); + int interval = defaultTimeout; // long interval so we can tell if there was a retry int loginTimeout = 2; - // non existent database with very short loginTimeout so there is no time to do all retries + // non existent database with very short loginTimeout so there is no time to do any retry try (Connection con = PrepUtil.getConnection( TestUtils.addOrOverrideProperty(connectionString, "database", RandomUtil.getIdentifier("database")) - + "connectRetryCount=" + (new Random().nextInt(256)) + ";connectRetryInterval=" - + (new Random().nextInt(defaultTimeout - 1) + 1) + ";loginTimeout=" + loginTimeout)) { + + "connectRetryCount=" + (new Random().nextInt(256)) + ";connectRetryInterval=" + interval + + ";loginTimeout=" + loginTimeout)) { fail(TestResource.getResource("R_shouldNotConnect")); } catch (Exception e) { - timerEnd = System.currentTimeMillis(); - - assertTrue((e.getMessage().contains(TestResource.getResource("R_cannotOpenDatabase"))) - || ((isSqlAzure() || isSqlAzureDW()) - ? e.getMessage().contains( - TestResource.getResource("R_connectTimedOut")) - : false), + totalTime = System.currentTimeMillis() - timerStart; + + assertTrue( + (e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_cannotOpenDatabase").toLowerCase())) + || (TestUtils.getProperty(connectionString, "msiClientId") != null && e.getMessage() + .toLowerCase().contains(TestResource.getResource("R_loginFailedMI").toLowerCase())) + || ((isSqlAzure() || isSqlAzureDW()) ? e.getMessage().toLowerCase() + .contains(TestResource.getResource("R_connectTimedOut").toLowerCase()) : false), e.getMessage()); } - verifyTimeout(timerEnd - timerStart, loginTimeout); + // if there was a retry then it would take at least 1 interval long, so if < interval means there were no retries + assertTrue(totalTime < TimeUnit.SECONDS.toMillis(interval), + "total time: " + totalTime + " interval: " + TimeUnit.SECONDS.toMillis(interval)); } // Test for detecting Azure server for connection retries @@ -303,10 +325,10 @@ public void testFailoverInstanceResolution() throws SQLException { timerEnd = System.currentTimeMillis(); assertTrue((e.getMessage().contains(TestResource.getResource("R_tcpipConnectionToHost"))) - || ((isSqlAzure() || isSqlAzureDW()) - ? e.getMessage().contains( - TestResource.getResource("R_connectTimedOut")) - : false), + || ((isSqlAzure() || isSqlAzureDW()) + ? e.getMessage().contains( + TestResource.getResource("R_connectTimedOut")) + : false), e.getMessage()); } @@ -365,7 +387,7 @@ private void verifyTimeout(long timeDiff, int timeout) { /** * When query timeout occurs, the connection is still usable. - * + * * @throws Exception */ @Test @@ -402,7 +424,7 @@ public void testQueryTimeout() throws Exception { /** * Tests sanity of connection property. - * + * * @throws Exception */ @Test @@ -439,7 +461,7 @@ public void testCancelQueryTimeout() throws Exception { /** * Tests sanity of connection property. - * + * * @throws Exception */ @Test @@ -477,7 +499,7 @@ public void testCancelQueryTimeoutOnStatement() throws Exception { /** * When socketTimeout occurs, the connection will be marked as closed. - * + * * @throws Exception */ @Test diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java index ff2f2fc73..4e5214e52 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java @@ -158,6 +158,10 @@ public void testGetURL() throws SQLException { */ @Test public void testDBUserLogin() throws SQLException { + String auth = TestUtils.getProperty(connectionString, "authentication"); + org.junit.Assume.assumeTrue(auth != null + && (auth.equalsIgnoreCase("SqlPassword") || auth.equalsIgnoreCase("ActiveDirectoryPassword"))); + try (Connection conn = getConnection()) { DatabaseMetaData databaseMetaData = conn.getMetaData(); String connectionString = getConnectionString(); @@ -181,7 +185,8 @@ public void testDBUserLogin() throws SQLException { assertNotNull(userName, TestResource.getResource("R_userNameNull")); assertTrue(userName.equalsIgnoreCase(userFromConnectionString), - TestResource.getResource("R_userNameNotMatch")); + TestResource.getResource("R_userNameNotMatch") + "userName: " + userName + "from connectio string: " + + userFromConnectionString); } catch (Exception e) { fail(TestResource.getResource("R_unexpectedErrorMessage") + e.getMessage()); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/fedauth/FedauthWithAE.java b/src/test/java/com/microsoft/sqlserver/jdbc/fedauth/FedauthWithAE.java index bfd09d3b9..1e0112f02 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/fedauth/FedauthWithAE.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/fedauth/FedauthWithAE.java @@ -307,7 +307,7 @@ private void createCMK(String cmkName, String keyStoreName, String keyPath, Stat private void callDbccFreeProcCache() throws SQLException { try (Connection connection = DriverManager.getConnection(adPasswordConnectionStr); Statement stmt = connection.createStatement()) { - stmt.execute("DBCC FREEPROCCACHE"); + TestUtils.freeProcCache(stmt); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java index 10853f2f6..2e80407d3 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java @@ -50,7 +50,7 @@ public void fipsTrustServerCertificateTest() throws Exception { Assertions.fail(TestResource.getResource("R_expectedExceptionNotThrown")); } catch (SQLException e) { Assertions.assertTrue(e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), - TestResource.getResource("R_invalidTrustCert")); + TestResource.getResource("R_invalidTrustCert") + ": " + e.getMessage()); } } @@ -62,13 +62,18 @@ public void fipsTrustServerCertificateTest() throws Exception { */ @Test public void fipsEncryptTest() throws Exception { + // test doesn't apply to managed identity as encrypt is set to on by default + String auth = TestUtils.getProperty(connectionString, "authentication"); + org.junit.Assume.assumeTrue(auth != null && !(auth.equalsIgnoreCase("ActiveDirectoryManagedIdentity") + || auth.equalsIgnoreCase("ActiveDirectoryMSI"))); + Properties props = buildConnectionProperties(); props.setProperty(Constants.ENCRYPT, Boolean.FALSE.toString()); try (Connection con = PrepUtil.getConnection(connectionString, props)) { Assertions.fail(TestResource.getResource("R_expectedExceptionNotThrown")); } catch (SQLException e) { Assertions.assertTrue(e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), - TestResource.getResource("R_invalidEncrypt")); + TestResource.getResource("R_invalidTrustCert") + ": " + e.getMessage()); } } @@ -118,6 +123,11 @@ public void fipsDataSourcePropertyTest() throws Exception { */ @Test public void fipsDatSourceEncrypt() { + // test doesn't apply to managed identity as encrypt is set to on by default + String auth = TestUtils.getProperty(connectionString, "authentication"); + org.junit.Assume.assumeTrue(auth != null && !(auth.equalsIgnoreCase("ActiveDirectoryManagedIdentity") + || auth.equalsIgnoreCase("ActiveDirectoryMSI"))); + SQLServerDataSource ds = new SQLServerDataSource(); setDataSourceProperties(ds); ds.setEncrypt(Constants.FALSE); @@ -126,7 +136,7 @@ public void fipsDatSourceEncrypt() { Assertions.fail(TestResource.getResource("R_expectedExceptionNotThrown")); } catch (SQLException e) { Assertions.assertTrue(e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), - TestResource.getResource("R_invalidEncrypt")); + TestResource.getResource("R_invalidEncrypt") + ": " + e.getMessage()); } } @@ -146,7 +156,7 @@ public void fipsDataSourceTrustServerCertificateTest() throws Exception { Assertions.fail(TestResource.getResource("R_expectedExceptionNotThrown")); } catch (SQLException e) { Assertions.assertTrue(e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), - TestResource.getResource("R_invalidTrustCert")); + TestResource.getResource("R_invalidTrustCert") + ": " + e.getMessage()); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/resiliency/ReflectiveTests.java b/src/test/java/com/microsoft/sqlserver/jdbc/resiliency/ReflectiveTests.java index 92d7c852c..988490229 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/resiliency/ReflectiveTests.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/resiliency/ReflectiveTests.java @@ -88,7 +88,7 @@ public void testDefaultRetry() throws SQLException { // ensure count is not set to something else as this test assumes exactly just 1 retry // this is only true for non-Azure as retry counts gets auto changed for Azure servers - timeoutVariations(m, 6000, Optional.empty()); + timeoutVariations(m, 6500, Optional.empty()); } /* diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/SQLServerErrorTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/SQLServerErrorTest.java index b4ca10c04..7c7dc377e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/SQLServerErrorTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/SQLServerErrorTest.java @@ -42,6 +42,11 @@ public static void setupTests() throws Exception { @Test @Tag(Constants.xAzureSQLDW) public void testLoginFailedError() { + // test to remove password only valid for password auth + String auth = TestUtils.getProperty(connectionString, "authentication"); + org.junit.Assume.assumeTrue(auth != null + && (auth.equalsIgnoreCase("SqlPassword") || auth.equalsIgnoreCase("ActiveDirectoryPassword"))); + SQLServerDataSource ds = new SQLServerDataSource(); ds.setURL(connectionString); ds.setLoginTimeout(loginTimeOutInSeconds); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java index 0dace62b2..47b771dc3 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java @@ -188,6 +188,8 @@ public void testValidTimezonesDstTimestampBatchInsertWithBulkCopy() throws Excep pstmt.setTimestamp(1, timestamp, gmtCal); pstmt.addBatch(); pstmt.executeBatch(); + } catch (Exception e) { + fail(e.getMessage()); } // Insert Timestamp using bulkcopy for batch insert @@ -200,6 +202,8 @@ public void testValidTimezonesDstTimestampBatchInsertWithBulkCopy() throws Excep pstmt.setTimestamp(1, timestamp, gmtCal); pstmt.addBatch(); pstmt.executeBatch(); + } catch (Exception e) { + fail(e.getMessage()); } // Compare Timestamp values inserted, should be the same @@ -225,6 +229,8 @@ public void testValidTimezonesDstTimestampBatchInsertWithBulkCopy() throws Excep assertEquals(ts0, ts1, failureMsg); assertEquals(t0, t1, failureMsg); assertEquals(d0, d1, failureMsg); + } catch (Exception e) { + fail(e.getMessage()); } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PreparedStatementTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PreparedStatementTest.java index 79862dfcd..b21372c96 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PreparedStatementTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PreparedStatementTest.java @@ -258,7 +258,9 @@ public void testBatchedUnprepare() throws SQLException { con.setStatementPoolingCacheSize(0); // Clean-up proc cache - this.executeSQL(con, "DBCC FREEPROCCACHE;"); + try (Statement stmt = con.createStatement()) { + TestUtils.freeProcCache(stmt); + } String lookupUniqueifier = UUID.randomUUID().toString(); diff --git a/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java b/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java index e1a321c2f..29e5b36ad 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java @@ -5,6 +5,8 @@ package com.microsoft.sqlserver.testframework; +import static org.junit.jupiter.api.Assertions.fail; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -277,11 +279,7 @@ protected static void setupConnectionString() { connectionStringNTLM = TestUtils.addOrOverrideProperty(connectionStringNTLM, "user", user); } - if (null != password) { - connectionStringNTLM = TestUtils.addOrOverrideProperty(connectionStringNTLM, "password", password); - } - - if (null != user && null != password) { + if (null != user) { connectionStringNTLM = TestUtils.addOrOverrideProperty(connectionStringNTLM, "authenticationScheme", "NTLM"); connectionStringNTLM = TestUtils.addOrOverrideProperty(connectionStringNTLM, "integratedSecurity", "true"); @@ -304,19 +302,23 @@ protected static void setupConnectionString() { } protected static void setConnection() throws Exception { - setupConnectionString(); + try { + setupConnectionString(); - Assertions.assertNotNull(connectionString, TestResource.getResource("R_ConnectionStringNull")); - Class.forName(Constants.MSSQL_JDBC_PACKAGE + ".SQLServerDriver"); - if (!SQLServerDriver.isRegistered()) { - SQLServerDriver.register(); - } - if (null == connection || connection.isClosed()) { - connection = getConnection(); - } - isSqlAzureOrAzureDW(connection); + Assertions.assertNotNull(connectionString, TestResource.getResource("R_ConnectionStringNull")); + Class.forName(Constants.MSSQL_JDBC_PACKAGE + ".SQLServerDriver"); + if (!SQLServerDriver.isRegistered()) { + SQLServerDriver.register(); + } + if (null == connection || connection.isClosed()) { + connection = getConnection(); + } + isSqlAzureOrAzureDW(connection); - checkSqlOS(connection); + checkSqlOS(connection); + } catch (Exception e) { + fail("setConnection failed, connectionString=" + connectionString + "\nException: " + e.getMessage()); + } } /** @@ -350,6 +352,9 @@ protected static ISQLServerDataSource updateDataSource(String connectionString, case Constants.INTEGRATED_SECURITY: ds.setIntegratedSecurity(Boolean.parseBoolean(value)); break; + case Constants.SERVER_NAME: + ds.setServerName(value); + break; case Constants.USER: case Constants.USER_NAME: ds.setUser(value); diff --git a/src/test/java/com/microsoft/sqlserver/testframework/Constants.java b/src/test/java/com/microsoft/sqlserver/testframework/Constants.java index e4338fc92..7ffc68b45 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/Constants.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/Constants.java @@ -140,6 +140,7 @@ private Constants() {} public static final String DATABASE = "DATABASE"; public static final String DATABASE_NAME = "DATABASENAME"; public static final String COLUMN_ENCRYPTION_SETTING = "COLUMNENCRYPTIONSETTING"; + public static final String SERVER_NAME = "SERVERNAME"; public static final String DISABLE_STATEMENT_POOLING = "DISABLESTATEMENTPOOLING"; public static final String STATEMENT_POOLING_CACHE_SIZE = "STATEMENTPOOLINGCACHESIZE"; public static final String AUTHENTICATION = "AUTHENTICATION";