package io.vertx.ext.jdbc; import io.vertx.core.AbstractVerticle; import io.vertx.core.DeploymentOptions; import io.vertx.core.json.JsonObject; import io.vertx.ext.jdbc.spi.DataSourceProvider; import io.vertx.ext.jdbc.spi.impl.C3P0DataSourceProvider; import io.vertx.ext.sql.SQLClient; import io.vertx.ext.sql.SQLConnection; import org.junit.Test; import javax.sql.DataSource; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.stream.Collectors; import static java.util.concurrent.TimeUnit.*; /** * @author <a href="mailto:julien@julienviet.com">Julien Viet</a> */ public class CloseTest extends JDBCClientTestBase { private static final JsonObject theConfig = config(); public static class NonSharedClientVerticle extends AbstractVerticle { @Override public void start(io.vertx.core.Future<Void> f) throws Exception { SQLClient client = JDBCClient.createNonShared(vertx, theConfig); String sql = "SELECT ID, FNAME, LNAME FROM select_table ORDER BY ID"; client.getConnection(ar1 -> { if (ar1.succeeded()) { SQLConnection conn = ar1.result(); conn.query(sql, ar2 -> { if (ar2.succeeded()) { f.complete(); } else { f.fail(ar2.cause()); } }); } else { f.fail(ar1.cause()); } }); } } @Test public void testUsingNonSharedInVerticle() throws Exception { CompletableFuture<String> id = new CompletableFuture<>(); vertx.deployVerticle(NonSharedClientVerticle.class.getName(), onSuccess(id::complete)); close(id.get(10, TimeUnit.SECONDS), false); } @Test public void testUsingNonSharedInVerticle2() throws Exception { CompletableFuture<String> id = new CompletableFuture<>(); vertx.deployVerticle(NonSharedClientVerticle.class.getName(), new DeploymentOptions().setInstances(2), onSuccess(id::complete)); close(id.get(10, TimeUnit.SECONDS), false); } public static class SharedClientVerticle extends AbstractVerticle { @Override public void start(io.vertx.core.Future<Void> f) throws Exception { SQLClient client = JDBCClient.createShared(vertx, theConfig); String sql = "SELECT ID, FNAME, LNAME FROM select_table ORDER BY ID"; client.getConnection(ar1 -> { if (ar1.succeeded()) { SQLConnection conn = ar1.result(); conn.query(sql, ar2 -> { if (ar2.succeeded()) { f.complete(); } else { f.fail(ar2.cause()); } }); } else { f.fail(ar1.cause()); } }); } } @Test public void testUsingSharedInVerticle() throws Exception { CompletableFuture<String> id = new CompletableFuture<>(); vertx.deployVerticle(SharedClientVerticle.class.getName(), new DeploymentOptions().setInstances(1), onSuccess(id::complete)); close(id.get(10, TimeUnit.SECONDS), false); } @Test public void testUsingSharedInVerticle2() throws Exception { CompletableFuture<String> id = new CompletableFuture<>(); vertx.deployVerticle(SharedClientVerticle.class.getName(), new DeploymentOptions().setInstances(2), onSuccess(id::complete)); close(id.get(10, TimeUnit.SECONDS), false); } private static DataSource ds; public static class ProvidedDataSourceVerticle extends AbstractVerticle { @Override public void start(io.vertx.core.Future<Void> f) throws Exception { SQLClient client = JDBCClient.create(vertx, ds); String sql = "SELECT ID, FNAME, LNAME FROM select_table ORDER BY ID"; client.getConnection(ar1 -> { if (ar1.succeeded()) { SQLConnection conn = ar1.result(); conn.query(sql, ar2 -> { if (ar2.succeeded()) { f.complete(); } else { f.fail(ar2.cause()); } }); } else { f.fail(ar1.cause()); } }); } } @Test public void testUsingProvidedDataSourceVerticle() throws Exception { DataSourceProvider provider = new C3P0DataSourceProvider(); ds = provider.getDataSource(theConfig); CompletableFuture<String> id = new CompletableFuture<>(); vertx.deployVerticle(ProvidedDataSourceVerticle.class.getName(), new DeploymentOptions().setInstances(1), onSuccess(id::complete)); close(id.get(10, TimeUnit.SECONDS), true); } private void close(String deploymentId, boolean expectedDsThreadStatus) throws Exception { List<Thread> getConnThread = findThreads(t -> t.getName().equals("vertx-jdbc-service-get-connection-thread")); assertTrue(getConnThread.size() > 0); List<Thread> poolThreads = findThreads(t -> t.getName().startsWith("C3P0PooledConnectionPoolManager")); assertTrue(poolThreads.size() > 0); CountDownLatch closeLatch = new CountDownLatch(1); vertx.undeploy(deploymentId, onSuccess(v -> { closeLatch.countDown(); })); awaitLatch(closeLatch); long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < 5000) { if (!getConnThread.get(0).isAlive() && poolThreads.stream().allMatch(t -> t.isAlive() == expectedDsThreadStatus)) { return; } MILLISECONDS.sleep(10); } fail("Timeout waiting for connection threads to be dead"); } private List<Thread> findThreads(Predicate<Thread> predicate) { return Thread.getAllStackTraces() .keySet() .stream() .filter(predicate) .collect(Collectors.toList()); } }