diff --git a/modules/jdbc/src/main/java/org/testcontainers/jdbc/JdbcDatabaseDelegate.java b/modules/jdbc/src/main/java/org/testcontainers/jdbc/JdbcDatabaseDelegate.java index 3c33eba8d5b..24c18944292 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/jdbc/JdbcDatabaseDelegate.java +++ b/modules/jdbc/src/main/java/org/testcontainers/jdbc/JdbcDatabaseDelegate.java @@ -6,6 +6,7 @@ import org.testcontainers.exception.ConnectionCreationException; import org.testcontainers.ext.ScriptUtils; +import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; @@ -17,6 +18,8 @@ public class JdbcDatabaseDelegate extends AbstractDatabaseDelegate { private JdbcDatabaseContainer container; + private Connection connection; + private String queryString; public JdbcDatabaseDelegate(JdbcDatabaseContainer container, String queryString) { @@ -27,7 +30,8 @@ public JdbcDatabaseDelegate(JdbcDatabaseContainer container, String queryString) @Override protected Statement createNewConnection() { try { - return container.createConnection(queryString).createStatement(); + connection = container.createConnection(queryString); + return connection.createStatement(); } catch (SQLException e) { log.error("Could not obtain JDBC connection"); throw new ConnectionCreationException("Could not obtain JDBC connection", e); @@ -65,6 +69,7 @@ public void execute( protected void closeConnectionQuietly(Statement statement) { try { statement.close(); + connection.close(); } catch (Exception e) { log.error("Could not close JDBC connection", e); } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/JdbcDatabaseDelegateTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/JdbcDatabaseDelegateTest.java new file mode 100644 index 00000000000..f3cf2d01d40 --- /dev/null +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/JdbcDatabaseDelegateTest.java @@ -0,0 +1,87 @@ +package org.testcontainers.jdbc; + +import lombok.NonNull; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.utility.DockerImageName; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class JdbcDatabaseDelegateTest { + + @Test + public void testLeakedConnections() { + final JdbcDatabaseContainerStub stub = new JdbcDatabaseContainerStub(DockerImageName.parse("something")); + try (JdbcDatabaseDelegate delegate = new JdbcDatabaseDelegate(stub, "")) { + delegate.execute("foo", null, 0, false, false); + } + Assert.assertEquals(0, stub.openConnectionsList.size()); + } + + static class JdbcDatabaseContainerStub extends JdbcDatabaseContainer { + + List openConnectionsList = new ArrayList<>(); + + public JdbcDatabaseContainerStub(@NonNull DockerImageName dockerImageName) { + super(dockerImageName); + } + + @Override + public String getDriverClassName() { + return null; + } + + @Override + public String getJdbcUrl() { + return null; + } + + @Override + public String getUsername() { + return null; + } + + @Override + public String getPassword() { + return null; + } + + @Override + protected String getTestQueryString() { + return null; + } + + @Override + public boolean isRunning() { + return true; + } + + @Override + public Connection createConnection(String queryString) throws NoDriverFoundException, SQLException { + final Connection connection = mock(Connection.class); + openConnectionsList.add(connection); + when(connection.createStatement()).thenReturn(mock(Statement.class)); + connection.close(); + Mockito.doAnswer(ignore -> openConnectionsList.remove(connection)).when(connection).close(); + return connection; + } + + @Override + protected Logger logger() { + return mock(Logger.class); + } + + @Override + public void setDockerImageName(@NonNull String dockerImageName) {} + } +}