Skip to content

Commit

Permalink
NO-JIRA Testsuite speedup: proper JDBC drop from derby
Browse files Browse the repository at this point in the history
  • Loading branch information
clebertsuconic committed Mar 18, 2023
1 parent aaa8627 commit d730d1a
Show file tree
Hide file tree
Showing 24 changed files with 309 additions and 366 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,21 @@
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.hamcrest.MatcherAssert;
import org.hamcrest.core.IsInstanceOf;
import org.junit.After;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.instanceOf;

public class HAPolicyConfigurationTest extends ActiveMQTestBase {

@Override
@After
public void tearDown() throws Exception {
super.tearDown();

shutdownDerby();
}

@Test
public void shouldNotUseJdbcNodeManagerWithoutHAPolicy() throws Exception {
Configuration configuration = createConfiguration("database-store-no-hapolicy-config.xml");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,26 @@
*/
package org.apache.activemq.artemis.core.server.impl.jdbc;

import java.sql.DriverManager;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.activemq.artemis.core.config.storage.DatabaseStorageConfiguration;
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RunWith(Parameterized.class)
public class JdbcNodeManagerTest extends ActiveMQTestBase {

private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

@Parameterized.Parameter
public boolean useAuthentication;
private DatabaseStorageConfiguration dbConf;
Expand All @@ -50,51 +50,27 @@ public static Collection<Object[]> data() {
public void configure() {
if (useAuthentication) {
System.setProperty("derby.connection.requireAuthentication", "true");
System.setProperty("derby.user." + getJdbcUser(), getJdbcPassword());
System.setProperty("derby.user." + getJDBCUser(), getJDBCPassword());
}
dbConf = createDefaultDatabaseStorageConfiguration();
dbConf.setJdbcUser(getJdbcUser());
dbConf.setJdbcPassword(getJdbcPassword());
dbConf.setJdbcUser(getJDBCUser());
dbConf.setJdbcPassword(getJDBCPassword());
leaseLockExecutor = Executors.newSingleThreadScheduledExecutor();
runAfter(leaseLockExecutor::shutdownNow);
}

@After
public void shutdownExecutors() throws InterruptedException {
try {
final CountDownLatch latch = new CountDownLatch(1);
leaseLockExecutor.execute(latch::countDown);
Assert.assertTrue("the scheduler of the lease lock has some pending task in ", latch.await(10, TimeUnit.SECONDS));
} finally {
leaseLockExecutor.shutdownNow();
}
}

@After
@Override
public void shutdownDerby() {
try {
if (useAuthentication) {
DriverManager.getConnection("jdbc:derby:;shutdown=true", getJdbcUser(), getJdbcPassword());
} else {
DriverManager.getConnection("jdbc:derby:;shutdown=true");
}
} catch (Exception ignored) {
}
if (useAuthentication) {
System.clearProperty("derby.connection.requireAuthentication");
System.clearProperty("derby.user." + getJdbcUser());
}
}

protected String getJdbcUser() {
protected String getJDBCUser() {
if (useAuthentication) {
return System.getProperty("jdbc.user", "testuser");
} else {
return null;
}
}

protected String getJdbcPassword() {
@Override
protected String getJDBCPassword() {
if (useAuthentication) {
return System.getProperty("jdbc.password", "testpassword");
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,8 @@
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.lang.ref.WeakReference;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -138,8 +134,6 @@
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.activemq.artemis.core.settings.impl.PageFullMessagePolicy;
import org.apache.activemq.artemis.core.transaction.impl.XidImpl;
import org.apache.activemq.artemis.jdbc.store.drivers.JDBCUtils;
import org.apache.activemq.artemis.jdbc.store.sql.SQLProvider;
import org.apache.activemq.artemis.json.JsonObject;
import org.apache.activemq.artemis.nativo.jlibaio.LibaioContext;
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
Expand All @@ -160,6 +154,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
Expand All @@ -178,12 +173,6 @@
*/
public abstract class ActiveMQTestBase extends Assert {

public MBeanServer getMBeanServer() {
MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer();
runAfter(() -> MBeanServerFactory.releaseMBeanServer(mBeanServer));
return mBeanServer;
}

private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

static {
Expand Down Expand Up @@ -235,29 +224,64 @@ public MBeanServer getMBeanServer() {
// There is a verification about thread leakages. We only fail a single thread when this happens
private static Set<Thread> alreadyFailedThread = new HashSet<>();

private LinkedList<RunnableEx> runAfter;
private List<RunnableEx> runAfter;

/**
* Use this method to cleanup your resources by passing lambdas.
* Exceptions thrown from your lambdas will just be logged and not passed as failures.
* @param lambda A RunnableEX instance that will be passed possibly from a lambda method
*/
protected void runAfter(RunnableEx lambda) {
runAfterEx(() -> {
try {
lambda.run();
} catch (Throwable e) {
logger.warn("Lambda {} is throwing an exception", lambda.toString(), e);
}
});
}

protected synchronized void runAfter(RunnableEx run) {
Assert.assertNotNull(run);
/**
* Use this method to cleanup your resources and validating exceptional results by passing lambdas.
* Exceptions thrown from your lambdas will be sent straight to JUNIT.
* If more than one lambda threw an exception they will all be executed, however only the exception of the first one will
* sent to the junit runner.
* @param lambda A RunnableEX instance that will be passed possibly from a lambda method
*/
protected synchronized void runAfterEx(RunnableEx lambda) {
Assert.assertNotNull(lambda);
if (runAfter == null) {
runAfter = new LinkedList();
runAfter = new ArrayList<>();
}
runAfter.add(run);
runAfter.add(lambda);
}

@After
public void runAfter() {
if (runAfter != null) {
runAfter.forEach((r) -> {
public synchronized void runAfter() throws Throwable {
ArrayList<Throwable> throwables = new ArrayList<>();
List<RunnableEx> localRunAfter = runAfter;
runAfter = null;
if (localRunAfter != null) {
localRunAfter.forEach((r) -> {
try {
r.run();
} catch (Exception e) {
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
throwables.add(e);
}
});
}

if (!throwables.isEmpty()) {
throw throwables.get(0);
}
}

public MBeanServer createMBeanServer() {
MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer();
runAfter(() -> MBeanServerFactory.releaseMBeanServer(mBeanServer));
return mBeanServer;
}

protected void clearServers() {
servers.clear();
Expand Down Expand Up @@ -300,16 +324,50 @@ protected void finished(Description description) {
}
};

@After
public void shutdownDerby() {
// Static variable used by dropDerby
private static final String EXPECTED_DERBY_DROP_STATE = "08006";

// Static variable used by dropDerby
private static final String EXPECTED_DERBY_SHUTDOWN_STATE = "XJ015";

/** This method will be passed as a lambda into runAfter from createDefaultDatabaseStorageConfiguration */
protected final void dropDerby() throws Exception {
String user = getJDBCUser();
String password = getJDBCPassword();
try {
DriverManager.getConnection("jdbc:derby:" + getEmbeddedDataBaseName() + ";destroy=true");
} catch (Exception ignored) {
if (user == null) {
DriverManager.getConnection("jdbc:derby:" + getEmbeddedDataBaseName() + ";drop=true");
} else {
DriverManager.getConnection("jdbc:derby:" + getEmbeddedDataBaseName() + ";drop=true", user, password);
}
} catch (SQLException sqlE) {
if (!sqlE.getSQLState().equals(EXPECTED_DERBY_DROP_STATE)) {
logger.warn("{} / {}", sqlE.getMessage(), sqlE.getSQLState());
throw sqlE;
} else {
logger.info("{} / {}", sqlE.getMessage(), sqlE.getSQLState());

}
}
}

/** Some tests may be using file database as they share the database with a process.
* these tests will call shutdown Derby only */
protected void shutdownDerby() throws SQLException {
String user = getJDBCUser();
String password = getJDBCPassword();
try {
DriverManager.getConnection("jdbc:derby:;shutdown=true");
} catch (Exception ignored) {
// it always throws an exception on shutdown
if (user == null) {
DriverManager.getConnection("jdbc:derby:;shutdown=true;deregister=false");
} else {
DriverManager.getConnection("jdbc:derby:;shutdown=true;deregister=false", user, password);
}
} catch (SQLException sqlE) {
Assert.assertEquals("XJ015", sqlE.getSQLState());
logger.debug("{} / {}", sqlE.getMessage(), sqlE.getSQLState());
if (!sqlE.getSQLState().equals(EXPECTED_DERBY_SHUTDOWN_STATE)) {
throw sqlE;
}
}
}

Expand Down Expand Up @@ -560,9 +618,22 @@ protected void setDBStoreType(Configuration configuration) {
configuration.setStoreConfiguration(createDefaultDatabaseStorageConfiguration());
}

private boolean derbyDropped = false;

protected DatabaseStorageConfiguration createDefaultDatabaseStorageConfiguration() {
DatabaseStorageConfiguration dbStorageConfiguration = new DatabaseStorageConfiguration();
dbStorageConfiguration.setJdbcConnectionUrl(getTestJDBCConnectionUrl());
String connectionURI = getTestJDBCConnectionUrl();

/** The connectionURI could be passed into the testsuite as a system property (say you are testing against Oracle).
* So, we only schedule the drop on Derby if we are using a derby memory database */
if (connectionURI.contains("derby") && connectionURI.contains("memory") && !derbyDropped) {
// some tests will reinitialize the server and call this method more than one time
// and we should only schedule one task
derbyDropped = true;
runAfterEx(this::dropDerby);
runAfterEx(this::shutdownDerby);
}
dbStorageConfiguration.setJdbcConnectionUrl(connectionURI);
dbStorageConfiguration.setBindingsTableName("BINDINGS");
dbStorageConfiguration.setMessageTableName("MESSAGE");
dbStorageConfiguration.setLargeMessageTableName("LARGE_MESSAGE");
Expand Down Expand Up @@ -590,55 +661,6 @@ protected long getJdbcLockRenewPeriodMillis() {
return Long.getLong("jdbc.lock.renew", 200);
}

public void destroyTables(List<String> tableNames) throws Exception {
Driver driver = getDriver(getJDBCClassName());
Connection connection = driver.connect(getTestJDBCConnectionUrl(), null);
Statement statement = connection.createStatement();
try {
for (String tableName : tableNames) {
connection.setAutoCommit(false);
SQLProvider sqlProvider = JDBCUtils.getSQLProvider(getJDBCClassName(), tableName, SQLProvider.DatabaseStoreType.LARGE_MESSAGE);
try (ResultSet rs = connection.getMetaData().getTables(null, null, sqlProvider.getTableName(), null)) {
if (rs.next()) {
statement.execute("DROP TABLE " + sqlProvider.getTableName());
}
connection.commit();
} catch (SQLException e) {
connection.rollback();
}
}
connection.setAutoCommit(true);
} catch (Throwable e) {
e.printStackTrace();
} finally {
connection.close();
}
}

private Driver getDriver(String className) throws Exception {
try {
Driver driver = (Driver) Class.forName(className).newInstance();

// Shutdown the derby if using the derby embedded driver.
if (className.equals("org.apache.derby.jdbc.EmbeddedDriver")) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
DriverManager.getConnection("jdbc:derby:;shutdown=true");
} catch (Exception e) {
}
}
});
}
return driver;
} catch (ClassNotFoundException cnfe) {
throw new RuntimeException("Could not find class: " + className);
} catch (Exception e) {
throw new RuntimeException("Unable to instantiate driver class: ", e);
}
}

protected Map<String, Object> generateInVMParams(final int node) {
Map<String, Object> params = new HashMap<>();

Expand Down Expand Up @@ -672,7 +694,7 @@ protected static final ClusterConnectionConfiguration basicClusterConnectionConf

protected final OrderedExecutorFactory getOrderedExecutor() {
final ExecutorService executor = Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName()));
executorSet.add(executor);
runAfter(executor::shutdownNow);
return new OrderedExecutorFactory(executor);
}

Expand Down Expand Up @@ -897,7 +919,7 @@ protected String getEmbeddedDataBaseName() {
return "memory:" + getTestDir();
}

protected final String getTestJDBCConnectionUrl() {
private String getTestJDBCConnectionUrl() {
return System.getProperty("jdbc.connection.url", "jdbc:derby:" + getEmbeddedDataBaseName() + ";create=true");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public class AmqpClientTestSupport extends AmqpTestSupport {

protected ActiveMQServer server;

protected MBeanServer mBeanServer = getMBeanServer();
protected MBeanServer mBeanServer = createMBeanServer();

@Before
@Override
Expand Down

0 comments on commit d730d1a

Please sign in to comment.