This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-dbcp.git
commit 316ed1b324c141b82fb1e2d0cb4cbc91e94cb961 Author: Gary Gregory <[email protected]> AuthorDate: Sat Jul 2 09:17:57 2022 -0400 Refactor duplicate code --- .../dbcp2/managed/SynchronizationAdapter.java | 36 + .../commons/dbcp2/managed/TransactionContext.java | 7 +- .../dbcp2/managed/TestBasicManagedDataSource.java | 489 ++++++------ .../dbcp2/managed/TestManagedDataSourceInTx.java | 877 ++++++++++----------- 4 files changed, 715 insertions(+), 694 deletions(-) diff --git a/src/main/java/org/apache/commons/dbcp2/managed/SynchronizationAdapter.java b/src/main/java/org/apache/commons/dbcp2/managed/SynchronizationAdapter.java new file mode 100644 index 00000000..f5a0211d --- /dev/null +++ b/src/main/java/org/apache/commons/dbcp2/managed/SynchronizationAdapter.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.dbcp2.managed; + +import javax.transaction.Synchronization; + +/** + * Implements {@link Synchronization} for subclasses. + */ +class SynchronizationAdapter implements Synchronization { + + @Override + public void afterCompletion(final int status) { + // Noop + } + + @Override + public void beforeCompletion() { + // Noop + } + +} diff --git a/src/main/java/org/apache/commons/dbcp2/managed/TransactionContext.java b/src/main/java/org/apache/commons/dbcp2/managed/TransactionContext.java index aac64a01..e44a487d 100644 --- a/src/main/java/org/apache/commons/dbcp2/managed/TransactionContext.java +++ b/src/main/java/org/apache/commons/dbcp2/managed/TransactionContext.java @@ -91,16 +91,11 @@ public class TransactionContext { listener.afterCompletion(this, transaction != null && transaction.getStatus() == Status.STATUS_COMMITTED); return; } - final Synchronization s = new Synchronization() { + final Synchronization s = new SynchronizationAdapter() { @Override public void afterCompletion(final int status) { listener.afterCompletion(TransactionContext.this, status == Status.STATUS_COMMITTED); } - - @Override - public void beforeCompletion() { - // empty - } }; if (transactionSynchronizationRegistry != null) { transactionSynchronizationRegistry.registerInterposedSynchronization(s); diff --git a/src/test/java/org/apache/commons/dbcp2/managed/TestBasicManagedDataSource.java b/src/test/java/org/apache/commons/dbcp2/managed/TestBasicManagedDataSource.java index 8fa5e7bf..7dbc3cf2 100644 --- a/src/test/java/org/apache/commons/dbcp2/managed/TestBasicManagedDataSource.java +++ b/src/test/java/org/apache/commons/dbcp2/managed/TestBasicManagedDataSource.java @@ -1,247 +1,242 @@ -/* - - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ -package org.apache.commons.dbcp2.managed; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.fail; - -import java.sql.Connection; -import java.sql.SQLException; - -import javax.sql.XADataSource; -import javax.transaction.Synchronization; -import javax.transaction.TransactionManager; -import javax.transaction.TransactionSynchronizationRegistry; -import javax.transaction.xa.XAException; - -import org.apache.commons.dbcp2.BasicDataSource; -import org.apache.commons.dbcp2.TestBasicDataSource; -import org.apache.geronimo.transaction.manager.TransactionManagerImpl; -import org.h2.Driver; -import org.h2.jdbcx.JdbcDataSource; -import org.junit.jupiter.api.Test; - -import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple; -import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple; - -/** - * TestSuite for BasicManagedDataSource - */ -public class TestBasicManagedDataSource extends TestBasicDataSource { - - @Override - protected BasicDataSource createDataSource() throws Exception { - final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource(); - final TransactionManagerImpl transactionManager = new TransactionManagerImpl(); - basicManagedDataSource.setTransactionManager(transactionManager); - basicManagedDataSource.setTransactionSynchronizationRegistry(transactionManager); - return basicManagedDataSource; - } - - @Test - public void testCreateXaDataSourceNewInstance() throws SQLException, XAException { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - basicManagedDataSource.setXADataSource(JdbcDataSource.class.getCanonicalName()); - basicManagedDataSource.setDriverClassName(Driver.class.getName()); - basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); - assertNotNull(basicManagedDataSource.createConnectionFactory()); - } - } - - @Test - public void testCreateXaDataSourceNoInstanceSetAndNoDataSource() throws SQLException, XAException { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); - basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); - basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); - assertNotNull(basicManagedDataSource.createConnectionFactory()); - } - } - - /** - * JIRA: DBCP-294 - * Verify that PoolableConnections created by BasicManagedDataSource unregister themselves - * when reallyClosed. - */ - @Test - public void testReallyClose() throws Exception { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); - basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); - basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); - basicManagedDataSource.setUsername("userName"); - basicManagedDataSource.setPassword("password"); - basicManagedDataSource.setMaxIdle(1); - // Create two connections - final ManagedConnection<?> conn = (ManagedConnection<?>) basicManagedDataSource.getConnection(); - assertNotNull(basicManagedDataSource.getTransactionRegistry().getXAResource(conn)); - final ManagedConnection<?> conn2 = (ManagedConnection<?>) basicManagedDataSource.getConnection(); - conn2.close(); // Return one connection to the pool - conn.close(); // No room at the inn - this will trigger reallyClose(), which should unregister - try { - basicManagedDataSource.getTransactionRegistry().getXAResource(conn); - fail("Expecting SQLException - XAResources orphaned"); - } catch (final SQLException ex) { - // expected - } - conn2.close(); - } - } - - @Test - public void testRuntimeExceptionsAreRethrown() throws SQLException, XAException { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); - basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); - basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); - basicManagedDataSource.setUsername("userName"); - basicManagedDataSource.setPassword("password"); - basicManagedDataSource.setMaxIdle(1); - // results in a NPE - assertThrows(NullPointerException.class, () -> basicManagedDataSource.createPoolableConnectionFactory(null)); - } - } - - @Test - public void testSetDriverName() throws SQLException { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - basicManagedDataSource.setDriverClassName("adams"); - assertEquals("adams", basicManagedDataSource.getDriverClassName()); - basicManagedDataSource.setDriverClassName(null); - assertNull(basicManagedDataSource.getDriverClassName()); - } - } - - @Test - public void testSetNullXaDataSourceInstance() throws SQLException, XAException { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); - basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); - basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); - basicManagedDataSource.setUsername("userName"); - basicManagedDataSource.setPassword("password"); - basicManagedDataSource.setMaxIdle(1); - basicManagedDataSource.setXaDataSourceInstance(null); - assertNull(basicManagedDataSource.getXaDataSourceInstance()); - } - } - - /** DBCP-564 */ - @Test - public void testSetRollbackOnlyBeforeGetConnectionDoesNotLeak() throws Exception { - final TransactionManager transactionManager = ((BasicManagedDataSource) ds).getTransactionManager(); - final int n = 3; - ds.setMaxIdle(n); - ds.setMaxTotal(n); - - for (int i = 0; i <= n; i++) { // loop n+1 times - transactionManager.begin(); - transactionManager.setRollbackOnly(); - try (final Connection conn = getConnection()) { - assertNotNull(conn); - } - transactionManager.rollback(); - } - - assertEquals(0, ds.getNumActive()); - assertEquals(1, ds.getNumIdle()); - } - - @Test - public void testSetXaDataSourceInstance() throws SQLException, XAException { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); - basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); - basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); - basicManagedDataSource.setUsername("userName"); - basicManagedDataSource.setPassword("password"); - basicManagedDataSource.setMaxIdle(1); - basicManagedDataSource.setXaDataSourceInstance(new JdbcDataSource()); - assertNotNull(basicManagedDataSource.createConnectionFactory()); - } - } - - @Test - public void testTransactionManagerNotSet() throws SQLException { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - assertThrows(SQLException.class, basicManagedDataSource::createConnectionFactory); - } - } - - @Test - public void testTransactionSynchronizationRegistry() throws Exception { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - basicManagedDataSource.setTransactionManager(new TransactionManagerImple()); - final TransactionSynchronizationRegistry tsr = new TransactionSynchronizationRegistryImple(); - basicManagedDataSource.setTransactionSynchronizationRegistry(tsr); - final JdbcDataSource xaDataSource = new JdbcDataSource(); - xaDataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); - basicManagedDataSource.setXaDataSourceInstance(xaDataSource); - basicManagedDataSource.setMaxIdle(1); - - final TransactionManager tm = basicManagedDataSource.getTransactionManager(); - tm.begin(); - tsr.registerInterposedSynchronization(new Synchronization() { - @Override - public void afterCompletion(final int i) { - - } - - @Override - public void beforeCompletion() { - Connection connection = null; - try { - connection = basicManagedDataSource.getConnection(); - assertNotNull(connection); - } catch (final SQLException e) { - fail(e.getMessage()); - } finally { - if (connection != null) { - try { - connection.close(); - } catch (final SQLException e) { - fail(e.getMessage()); - } - } - } - } - }); - tm.commit(); - } - } - - @Test - public void testXADataSource() throws SQLException { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - basicManagedDataSource.setXADataSource("anything"); - assertEquals("anything", basicManagedDataSource.getXADataSource()); - } - } - - @Test - public void testXaDataSourceInstance() throws SQLException { - try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { - final XADataSource ds = new JdbcDataSource(); - basicManagedDataSource.setXaDataSourceInstance(ds); - assertEquals(ds, basicManagedDataSource.getXaDataSourceInstance()); - } - } -} +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +package org.apache.commons.dbcp2.managed; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.sql.XADataSource; +import javax.transaction.Synchronization; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; +import javax.transaction.xa.XAException; + +import org.apache.commons.dbcp2.BasicDataSource; +import org.apache.commons.dbcp2.TestBasicDataSource; +import org.apache.geronimo.transaction.manager.TransactionManagerImpl; +import org.h2.Driver; +import org.h2.jdbcx.JdbcDataSource; +import org.junit.jupiter.api.Test; + +import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple; +import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple; + +/** + * TestSuite for BasicManagedDataSource + */ +public class TestBasicManagedDataSource extends TestBasicDataSource { + + @Override + protected BasicDataSource createDataSource() throws Exception { + final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource(); + final TransactionManagerImpl transactionManager = new TransactionManagerImpl(); + basicManagedDataSource.setTransactionManager(transactionManager); + basicManagedDataSource.setTransactionSynchronizationRegistry(transactionManager); + return basicManagedDataSource; + } + + @Test + public void testCreateXaDataSourceNewInstance() throws SQLException, XAException { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + basicManagedDataSource.setXADataSource(JdbcDataSource.class.getCanonicalName()); + basicManagedDataSource.setDriverClassName(Driver.class.getName()); + basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); + assertNotNull(basicManagedDataSource.createConnectionFactory()); + } + } + + @Test + public void testCreateXaDataSourceNoInstanceSetAndNoDataSource() throws SQLException, XAException { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); + basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); + basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); + assertNotNull(basicManagedDataSource.createConnectionFactory()); + } + } + + /** + * JIRA: DBCP-294 + * Verify that PoolableConnections created by BasicManagedDataSource unregister themselves + * when reallyClosed. + */ + @Test + public void testReallyClose() throws Exception { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); + basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); + basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); + basicManagedDataSource.setUsername("userName"); + basicManagedDataSource.setPassword("password"); + basicManagedDataSource.setMaxIdle(1); + // Create two connections + final ManagedConnection<?> conn = (ManagedConnection<?>) basicManagedDataSource.getConnection(); + assertNotNull(basicManagedDataSource.getTransactionRegistry().getXAResource(conn)); + final ManagedConnection<?> conn2 = (ManagedConnection<?>) basicManagedDataSource.getConnection(); + conn2.close(); // Return one connection to the pool + conn.close(); // No room at the inn - this will trigger reallyClose(), which should unregister + try { + basicManagedDataSource.getTransactionRegistry().getXAResource(conn); + fail("Expecting SQLException - XAResources orphaned"); + } catch (final SQLException ex) { + // expected + } + conn2.close(); + } + } + + @Test + public void testRuntimeExceptionsAreRethrown() throws SQLException, XAException { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); + basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); + basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); + basicManagedDataSource.setUsername("userName"); + basicManagedDataSource.setPassword("password"); + basicManagedDataSource.setMaxIdle(1); + // results in a NPE + assertThrows(NullPointerException.class, () -> basicManagedDataSource.createPoolableConnectionFactory(null)); + } + } + + @Test + public void testSetDriverName() throws SQLException { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + basicManagedDataSource.setDriverClassName("adams"); + assertEquals("adams", basicManagedDataSource.getDriverClassName()); + basicManagedDataSource.setDriverClassName(null); + assertNull(basicManagedDataSource.getDriverClassName()); + } + } + + @Test + public void testSetNullXaDataSourceInstance() throws SQLException, XAException { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); + basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); + basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); + basicManagedDataSource.setUsername("userName"); + basicManagedDataSource.setPassword("password"); + basicManagedDataSource.setMaxIdle(1); + basicManagedDataSource.setXaDataSourceInstance(null); + assertNull(basicManagedDataSource.getXaDataSourceInstance()); + } + } + + /** DBCP-564 */ + @Test + public void testSetRollbackOnlyBeforeGetConnectionDoesNotLeak() throws Exception { + final TransactionManager transactionManager = ((BasicManagedDataSource) ds).getTransactionManager(); + final int n = 3; + ds.setMaxIdle(n); + ds.setMaxTotal(n); + + for (int i = 0; i <= n; i++) { // loop n+1 times + transactionManager.begin(); + transactionManager.setRollbackOnly(); + try (final Connection conn = getConnection()) { + assertNotNull(conn); + } + transactionManager.rollback(); + } + + assertEquals(0, ds.getNumActive()); + assertEquals(1, ds.getNumIdle()); + } + + @Test + public void testSetXaDataSourceInstance() throws SQLException, XAException { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + basicManagedDataSource.setTransactionManager(new TransactionManagerImpl()); + basicManagedDataSource.setDriverClassName("org.apache.commons.dbcp2.TesterDriver"); + basicManagedDataSource.setUrl("jdbc:apache:commons:testdriver"); + basicManagedDataSource.setUsername("userName"); + basicManagedDataSource.setPassword("password"); + basicManagedDataSource.setMaxIdle(1); + basicManagedDataSource.setXaDataSourceInstance(new JdbcDataSource()); + assertNotNull(basicManagedDataSource.createConnectionFactory()); + } + } + + @Test + public void testTransactionManagerNotSet() throws SQLException { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + assertThrows(SQLException.class, basicManagedDataSource::createConnectionFactory); + } + } + + @Test + public void testTransactionSynchronizationRegistry() throws Exception { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + basicManagedDataSource.setTransactionManager(new TransactionManagerImple()); + final TransactionSynchronizationRegistry tsr = new TransactionSynchronizationRegistryImple(); + basicManagedDataSource.setTransactionSynchronizationRegistry(tsr); + final JdbcDataSource xaDataSource = new JdbcDataSource(); + xaDataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); + basicManagedDataSource.setXaDataSourceInstance(xaDataSource); + basicManagedDataSource.setMaxIdle(1); + + final TransactionManager tm = basicManagedDataSource.getTransactionManager(); + tm.begin(); + tsr.registerInterposedSynchronization(new SynchronizationAdapter() { + @Override + public void beforeCompletion() { + Connection connection = null; + try { + connection = basicManagedDataSource.getConnection(); + assertNotNull(connection); + } catch (final SQLException e) { + fail(e.getMessage()); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (final SQLException e) { + fail(e.getMessage()); + } + } + } + } + }); + tm.commit(); + } + } + + @Test + public void testXADataSource() throws SQLException { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + basicManagedDataSource.setXADataSource("anything"); + assertEquals("anything", basicManagedDataSource.getXADataSource()); + } + } + + @Test + public void testXaDataSourceInstance() throws SQLException { + try (final BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource()) { + final XADataSource ds = new JdbcDataSource(); + basicManagedDataSource.setXaDataSourceInstance(ds); + assertEquals(ds, basicManagedDataSource.getXaDataSourceInstance()); + } + } +} diff --git a/src/test/java/org/apache/commons/dbcp2/managed/TestManagedDataSourceInTx.java b/src/test/java/org/apache/commons/dbcp2/managed/TestManagedDataSourceInTx.java index dc6b6f75..d6db5efb 100644 --- a/src/test/java/org/apache/commons/dbcp2/managed/TestManagedDataSourceInTx.java +++ b/src/test/java/org/apache/commons/dbcp2/managed/TestManagedDataSourceInTx.java @@ -1,441 +1,436 @@ -/* - - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ -package org.apache.commons.dbcp2.managed; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import javax.transaction.Synchronization; -import javax.transaction.Transaction; - -import org.apache.commons.dbcp2.DelegatingConnection; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -/** - * Tests ManagedDataSource with an active transaction in progress. - */ -public class TestManagedDataSourceInTx extends TestManagedDataSource { - - // can't actually test close in a transaction - @Override - protected void assertBackPointers(final Connection conn, final Statement statement) throws SQLException { - assertFalse(conn.isClosed()); - assertFalse(isClosed(statement)); - - assertSame(conn, statement.getConnection(), - "statement.getConnection() should return the exact same connection instance that was used to create the statement"); - - final ResultSet resultSet = statement.getResultSet(); - assertFalse(isClosed(resultSet)); - assertSame(statement, resultSet.getStatement(), - "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); - - final ResultSet executeResultSet = statement.executeQuery("select * from dual"); - assertFalse(isClosed(executeResultSet)); - assertSame(statement, executeResultSet.getStatement(), - "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); - - final ResultSet keysResultSet = statement.getGeneratedKeys(); - assertFalse(isClosed(keysResultSet)); - assertSame(statement, keysResultSet.getStatement(), - "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); - - ResultSet preparedResultSet = null; - if (statement instanceof PreparedStatement) { - final PreparedStatement preparedStatement = (PreparedStatement) statement; - preparedResultSet = preparedStatement.executeQuery(); - assertFalse(isClosed(preparedResultSet)); - assertSame(statement, preparedResultSet.getStatement(), - "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); - } - - - resultSet.getStatement().getConnection().close(); - } - - @Override - @BeforeEach - public void setUp() throws Exception { - super.setUp(); - transactionManager.begin(); - } - - @Override - @AfterEach - public void tearDown() throws Exception { - if (transactionManager.getTransaction() != null) { - transactionManager.commit(); - } - super.tearDown(); - } - - @Override - @Test - public void testAutoCommitBehavior() throws Exception { - final Connection connection = newConnection(); - - // auto commit should be off - assertFalse(connection.getAutoCommit(), "Auto-commit should be disabled"); - - // attempt to set auto commit - try { - connection.setAutoCommit(true); - fail("setAutoCommit method should be disabled while enlisted in a transaction"); - } catch (final SQLException e) { - // expected - } - - // make sure it is still disabled - assertFalse(connection.getAutoCommit(), "Auto-commit should be disabled"); - - // close connection - connection.close(); - } - - @Override - @Test - public void testClearWarnings() throws Exception { - // open a connection - Connection connection = newConnection(); - assertNotNull(connection); - - // generate SQLWarning on connection - final CallableStatement statement = connection.prepareCall("warning"); - assertNotNull(connection.getWarnings()); - - // create a new shared connection - final Connection sharedConnection = newConnection(); - - // shared connection should see warning - assertNotNull(sharedConnection.getWarnings()); - - // close and allocate a new (original) connection - connection.close(); - connection = newConnection(); - - // warnings should not have been cleared by closing the connection - assertNotNull(connection.getWarnings()); - assertNotNull(sharedConnection.getWarnings()); - - statement.close(); - connection.close(); - sharedConnection.close(); - } - - @Test - public void testCloseInTransaction() throws Exception { - final DelegatingConnection<?> connectionA = (DelegatingConnection<?>) newConnection(); - final DelegatingConnection<?> connectionB = (DelegatingConnection<?>) newConnection(); - - assertNotEquals(connectionA, connectionB); - assertNotEquals(connectionB, connectionA); - assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); - assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); - - connectionA.close(); - connectionB.close(); - - final Connection connection = newConnection(); - - assertFalse(connection.isClosed(), "Connection should be open"); - - connection.close(); - - assertTrue(connection.isClosed(), "Connection should be closed"); - } - - @Test - public void testCommit() throws Exception { - final Connection connection = newConnection(); - - // connection should be open - assertFalse(connection.isClosed(), "Connection should be open"); - - // attempt commit directly - try { - connection.commit(); - fail("commit method should be disabled while enlisted in a transaction"); - } catch (final SQLException e) { - // expected - } - - // make sure it is still open - assertFalse(connection.isClosed(), "Connection should be open"); - - // close connection - connection.close(); - } - - @Override - @Test - public void testConnectionReturnOnCommit() throws Exception { - // override with no-op test - } - - @Override - @Test - public void testConnectionsAreDistinct() throws Exception { - final Connection[] conn = new Connection[getMaxTotal()]; - for(int i=0;i<conn.length;i++) { - conn[i] = newConnection(); - for(int j=0;j<i;j++) { - // two connections should be distinct instances - Assertions.assertNotSame(conn[j], conn[i]); - // neither should they should be equivalent even though they are - // sharing the same underlying connection - Assertions.assertNotEquals(conn[j], conn[i]); - // Check underlying connection is the same - Assertions.assertEquals(((DelegatingConnection<?>) conn[j]).getInnermostDelegateInternal(), - ((DelegatingConnection<?>) conn[i]).getInnermostDelegateInternal()); - } - } - for (final Connection element : conn) { - element.close(); - } - } - - @Test - public void testDoubleReturn() throws Exception { - transactionManager.getTransaction().registerSynchronization(new Synchronization() { - private ManagedConnection<?> conn; - - @Override - public void afterCompletion(final int i) { - final int numActive = pool.getNumActive(); - try { - conn.checkOpen(); - } catch (final Exception e) { - // Ignore - } - assertEquals(numActive, pool.getNumActive()); - try { - conn.close(); - } catch (final Exception e) { - fail("Should have been able to close the connection"); - } - // TODO Requires DBCP-515 assertTrue(numActive -1 == pool.getNumActive()); - } - - @Override - public void beforeCompletion() { - try { - conn = (ManagedConnection<?>) ds.getConnection(); - assertNotNull(conn); - } catch (final SQLException e) { - fail("Could not get connection"); - } - } - }); - transactionManager.commit(); - } - - @Test - public void testGetConnectionInAfterCompletion() throws Exception { - - final DelegatingConnection<?> connection = (DelegatingConnection<?>) newConnection(); - // Don't close so we can check it for warnings in afterCompletion - transactionManager.getTransaction().registerSynchronization(new Synchronization() { - @Override - public void afterCompletion(final int i) { - try { - final Connection connection1 = ds.getConnection(); - try { - connection1.getWarnings(); - fail("Could operate on closed connection"); - } catch (final SQLException e) { - // This is expected - } - } catch (final SQLException e) { - fail("Should have been able to get connection"); - } - } - - @Override - public void beforeCompletion() { - // empty - } - }); - connection.close(); - transactionManager.commit(); - } - - @Override - @Test - public void testHashCode() throws Exception { - final Connection conn1 = newConnection(); - assertNotNull(conn1); - final Connection conn2 = newConnection(); - assertNotNull(conn2); - - // shared connections should not have the same hashcode - Assertions.assertNotEquals(conn1.hashCode(), conn2.hashCode()); - } - - /** - * @see #testSharedConnection() - */ - @Override - @Test - public void testManagedConnectionEqualsFail() throws Exception { - // this test is invalid for managed connections since because - // two connections to the same datasource are supposed to share - // a single connection - } - - @Override - @Test - public void testMaxTotal() throws Exception { - final Transaction[] transactions = new Transaction[getMaxTotal()]; - final Connection[] c = new Connection[getMaxTotal()]; - for (int i = 0; i < c.length; i++) { - // create a new connection in the current transaction - c[i] = newConnection(); - assertNotNull(c[i]); - - // suspend the current transaction and start a new one - transactions[i] = transactionManager.suspend(); - assertNotNull(transactions[i]); - transactionManager.begin(); - } - - try { - newConnection(); - fail("Allowed to open more than DefaultMaxTotal connections."); - } catch (final java.sql.SQLException e) { - // should only be able to open 10 connections, so this test should - // throw an exception - } finally { - transactionManager.commit(); - for (int i = 0; i < c.length; i++) { - transactionManager.resume(transactions[i]); - c[i].close(); - transactionManager.commit(); - } - } - } - - @Override - @Test - public void testNestedConnections() { - // Not supported - } - - @Test - public void testReadOnly() throws Exception { - final Connection connection = newConnection(); - - // NOTE: This test class uses connections that are read-only by default - - // connection should be read only - assertTrue(connection.isReadOnly(), "Connection be read-only"); - - // attempt to setReadOnly - try { - connection.setReadOnly(true); - fail("setReadOnly method should be disabled while enlisted in a transaction"); - } catch (final SQLException e) { - // expected - } - - // make sure it is still read-only - assertTrue(connection.isReadOnly(), "Connection be read-only"); - - // attempt to setReadonly - try { - connection.setReadOnly(false); - fail("setReadOnly method should be disabled while enlisted in a transaction"); - } catch (final SQLException e) { - // expected - } - - // make sure it is still read-only - assertTrue(connection.isReadOnly(), "Connection be read-only"); - - // close connection - connection.close(); - } - - @Override - @Test - public void testSharedConnection() throws Exception { - final DelegatingConnection<?> connectionA = (DelegatingConnection<?>) newConnection(); - final DelegatingConnection<?> connectionB = (DelegatingConnection<?>) newConnection(); - - assertNotEquals(connectionA, connectionB); - assertNotEquals(connectionB, connectionA); - assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); - assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); - - connectionA.close(); - connectionB.close(); - } - - @Test - public void testSharedTransactionConversion() throws Exception { - final DelegatingConnection<?> connectionA = (DelegatingConnection<?>) newConnection(); - final DelegatingConnection<?> connectionB = (DelegatingConnection<?>) newConnection(); - - // in a transaction the inner connections should be equal - assertNotEquals(connectionA, connectionB); - assertNotEquals(connectionB, connectionA); - assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); - assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); - - transactionManager.commit(); - - // use the connection so it adjusts to the completed transaction - connectionA.getAutoCommit(); - connectionB.getAutoCommit(); - - // no there is no transaction so inner connections should not be equal - assertNotEquals(connectionA, connectionB); - assertNotEquals(connectionB, connectionA); - assertFalse(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); - assertFalse(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); - - transactionManager.begin(); - - // use the connection so it adjusts to the new transaction - connectionA.getAutoCommit(); - connectionB.getAutoCommit(); - - // back in a transaction so inner connections should be equal again - assertNotEquals(connectionA, connectionB); - assertNotEquals(connectionB, connectionA); - assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); - assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); - - connectionA.close(); - connectionB.close(); - } -} +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +package org.apache.commons.dbcp2.managed; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import javax.transaction.Synchronization; +import javax.transaction.Transaction; + +import org.apache.commons.dbcp2.DelegatingConnection; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Tests ManagedDataSource with an active transaction in progress. + */ +public class TestManagedDataSourceInTx extends TestManagedDataSource { + + // can't actually test close in a transaction + @Override + protected void assertBackPointers(final Connection conn, final Statement statement) throws SQLException { + assertFalse(conn.isClosed()); + assertFalse(isClosed(statement)); + + assertSame(conn, statement.getConnection(), + "statement.getConnection() should return the exact same connection instance that was used to create the statement"); + + final ResultSet resultSet = statement.getResultSet(); + assertFalse(isClosed(resultSet)); + assertSame(statement, resultSet.getStatement(), + "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); + + final ResultSet executeResultSet = statement.executeQuery("select * from dual"); + assertFalse(isClosed(executeResultSet)); + assertSame(statement, executeResultSet.getStatement(), + "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); + + final ResultSet keysResultSet = statement.getGeneratedKeys(); + assertFalse(isClosed(keysResultSet)); + assertSame(statement, keysResultSet.getStatement(), + "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); + + ResultSet preparedResultSet = null; + if (statement instanceof PreparedStatement) { + final PreparedStatement preparedStatement = (PreparedStatement) statement; + preparedResultSet = preparedStatement.executeQuery(); + assertFalse(isClosed(preparedResultSet)); + assertSame(statement, preparedResultSet.getStatement(), + "resultSet.getStatement() should return the exact same statement instance that was used to create the result set"); + } + + + resultSet.getStatement().getConnection().close(); + } + + @Override + @BeforeEach + public void setUp() throws Exception { + super.setUp(); + transactionManager.begin(); + } + + @Override + @AfterEach + public void tearDown() throws Exception { + if (transactionManager.getTransaction() != null) { + transactionManager.commit(); + } + super.tearDown(); + } + + @Override + @Test + public void testAutoCommitBehavior() throws Exception { + final Connection connection = newConnection(); + + // auto commit should be off + assertFalse(connection.getAutoCommit(), "Auto-commit should be disabled"); + + // attempt to set auto commit + try { + connection.setAutoCommit(true); + fail("setAutoCommit method should be disabled while enlisted in a transaction"); + } catch (final SQLException e) { + // expected + } + + // make sure it is still disabled + assertFalse(connection.getAutoCommit(), "Auto-commit should be disabled"); + + // close connection + connection.close(); + } + + @Override + @Test + public void testClearWarnings() throws Exception { + // open a connection + Connection connection = newConnection(); + assertNotNull(connection); + + // generate SQLWarning on connection + final CallableStatement statement = connection.prepareCall("warning"); + assertNotNull(connection.getWarnings()); + + // create a new shared connection + final Connection sharedConnection = newConnection(); + + // shared connection should see warning + assertNotNull(sharedConnection.getWarnings()); + + // close and allocate a new (original) connection + connection.close(); + connection = newConnection(); + + // warnings should not have been cleared by closing the connection + assertNotNull(connection.getWarnings()); + assertNotNull(sharedConnection.getWarnings()); + + statement.close(); + connection.close(); + sharedConnection.close(); + } + + @Test + public void testCloseInTransaction() throws Exception { + final DelegatingConnection<?> connectionA = (DelegatingConnection<?>) newConnection(); + final DelegatingConnection<?> connectionB = (DelegatingConnection<?>) newConnection(); + + assertNotEquals(connectionA, connectionB); + assertNotEquals(connectionB, connectionA); + assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); + assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); + + connectionA.close(); + connectionB.close(); + + final Connection connection = newConnection(); + + assertFalse(connection.isClosed(), "Connection should be open"); + + connection.close(); + + assertTrue(connection.isClosed(), "Connection should be closed"); + } + + @Test + public void testCommit() throws Exception { + final Connection connection = newConnection(); + + // connection should be open + assertFalse(connection.isClosed(), "Connection should be open"); + + // attempt commit directly + try { + connection.commit(); + fail("commit method should be disabled while enlisted in a transaction"); + } catch (final SQLException e) { + // expected + } + + // make sure it is still open + assertFalse(connection.isClosed(), "Connection should be open"); + + // close connection + connection.close(); + } + + @Override + @Test + public void testConnectionReturnOnCommit() throws Exception { + // override with no-op test + } + + @Override + @Test + public void testConnectionsAreDistinct() throws Exception { + final Connection[] conn = new Connection[getMaxTotal()]; + for(int i=0;i<conn.length;i++) { + conn[i] = newConnection(); + for(int j=0;j<i;j++) { + // two connections should be distinct instances + Assertions.assertNotSame(conn[j], conn[i]); + // neither should they should be equivalent even though they are + // sharing the same underlying connection + Assertions.assertNotEquals(conn[j], conn[i]); + // Check underlying connection is the same + Assertions.assertEquals(((DelegatingConnection<?>) conn[j]).getInnermostDelegateInternal(), + ((DelegatingConnection<?>) conn[i]).getInnermostDelegateInternal()); + } + } + for (final Connection element : conn) { + element.close(); + } + } + + @Test + public void testDoubleReturn() throws Exception { + transactionManager.getTransaction().registerSynchronization(new Synchronization() { + private ManagedConnection<?> conn; + + @Override + public void afterCompletion(final int i) { + final int numActive = pool.getNumActive(); + try { + conn.checkOpen(); + } catch (final Exception e) { + // Ignore + } + assertEquals(numActive, pool.getNumActive()); + try { + conn.close(); + } catch (final Exception e) { + fail("Should have been able to close the connection"); + } + // TODO Requires DBCP-515 assertTrue(numActive -1 == pool.getNumActive()); + } + + @Override + public void beforeCompletion() { + try { + conn = (ManagedConnection<?>) ds.getConnection(); + assertNotNull(conn); + } catch (final SQLException e) { + fail("Could not get connection"); + } + } + }); + transactionManager.commit(); + } + + @Test + public void testGetConnectionInAfterCompletion() throws Exception { + + final DelegatingConnection<?> connection = (DelegatingConnection<?>) newConnection(); + // Don't close so we can check it for warnings in afterCompletion + transactionManager.getTransaction().registerSynchronization(new SynchronizationAdapter() { + @Override + public void afterCompletion(final int i) { + try { + final Connection connection1 = ds.getConnection(); + try { + connection1.getWarnings(); + fail("Could operate on closed connection"); + } catch (final SQLException e) { + // This is expected + } + } catch (final SQLException e) { + fail("Should have been able to get connection"); + } + } + }); + connection.close(); + transactionManager.commit(); + } + + @Override + @Test + public void testHashCode() throws Exception { + final Connection conn1 = newConnection(); + assertNotNull(conn1); + final Connection conn2 = newConnection(); + assertNotNull(conn2); + + // shared connections should not have the same hashcode + Assertions.assertNotEquals(conn1.hashCode(), conn2.hashCode()); + } + + /** + * @see #testSharedConnection() + */ + @Override + @Test + public void testManagedConnectionEqualsFail() throws Exception { + // this test is invalid for managed connections since because + // two connections to the same datasource are supposed to share + // a single connection + } + + @Override + @Test + public void testMaxTotal() throws Exception { + final Transaction[] transactions = new Transaction[getMaxTotal()]; + final Connection[] c = new Connection[getMaxTotal()]; + for (int i = 0; i < c.length; i++) { + // create a new connection in the current transaction + c[i] = newConnection(); + assertNotNull(c[i]); + + // suspend the current transaction and start a new one + transactions[i] = transactionManager.suspend(); + assertNotNull(transactions[i]); + transactionManager.begin(); + } + + try { + newConnection(); + fail("Allowed to open more than DefaultMaxTotal connections."); + } catch (final java.sql.SQLException e) { + // should only be able to open 10 connections, so this test should + // throw an exception + } finally { + transactionManager.commit(); + for (int i = 0; i < c.length; i++) { + transactionManager.resume(transactions[i]); + c[i].close(); + transactionManager.commit(); + } + } + } + + @Override + @Test + public void testNestedConnections() { + // Not supported + } + + @Test + public void testReadOnly() throws Exception { + final Connection connection = newConnection(); + + // NOTE: This test class uses connections that are read-only by default + + // connection should be read only + assertTrue(connection.isReadOnly(), "Connection be read-only"); + + // attempt to setReadOnly + try { + connection.setReadOnly(true); + fail("setReadOnly method should be disabled while enlisted in a transaction"); + } catch (final SQLException e) { + // expected + } + + // make sure it is still read-only + assertTrue(connection.isReadOnly(), "Connection be read-only"); + + // attempt to setReadonly + try { + connection.setReadOnly(false); + fail("setReadOnly method should be disabled while enlisted in a transaction"); + } catch (final SQLException e) { + // expected + } + + // make sure it is still read-only + assertTrue(connection.isReadOnly(), "Connection be read-only"); + + // close connection + connection.close(); + } + + @Override + @Test + public void testSharedConnection() throws Exception { + final DelegatingConnection<?> connectionA = (DelegatingConnection<?>) newConnection(); + final DelegatingConnection<?> connectionB = (DelegatingConnection<?>) newConnection(); + + assertNotEquals(connectionA, connectionB); + assertNotEquals(connectionB, connectionA); + assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); + assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); + + connectionA.close(); + connectionB.close(); + } + + @Test + public void testSharedTransactionConversion() throws Exception { + final DelegatingConnection<?> connectionA = (DelegatingConnection<?>) newConnection(); + final DelegatingConnection<?> connectionB = (DelegatingConnection<?>) newConnection(); + + // in a transaction the inner connections should be equal + assertNotEquals(connectionA, connectionB); + assertNotEquals(connectionB, connectionA); + assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); + assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); + + transactionManager.commit(); + + // use the connection so it adjusts to the completed transaction + connectionA.getAutoCommit(); + connectionB.getAutoCommit(); + + // no there is no transaction so inner connections should not be equal + assertNotEquals(connectionA, connectionB); + assertNotEquals(connectionB, connectionA); + assertFalse(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); + assertFalse(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); + + transactionManager.begin(); + + // use the connection so it adjusts to the new transaction + connectionA.getAutoCommit(); + connectionB.getAutoCommit(); + + // back in a transaction so inner connections should be equal again + assertNotEquals(connectionA, connectionB); + assertNotEquals(connectionB, connectionA); + assertTrue(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate())); + assertTrue(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate())); + + connectionA.close(); + connectionB.close(); + } +}
