diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index ac4231216..81e832ff5 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -41,8 +41,12 @@ import org.junit.Test; import java.io.File; import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; +import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -2347,6 +2351,63 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { db.close(); } + + @Test + public void testShutdownGracefully() throws Exception { + CountDownLatch closing = new CountDownLatch(1); + CountDownLatch closed = new CountDownLatch(1); + AtomicBoolean transactionFinished = new AtomicBoolean(false); + AtomicBoolean error = new AtomicBoolean(false); + Database db = open(false); + + // Start a transaction + Connection txn = db.startTransaction(); + // In another thread, close the database + Thread close = new Thread(() -> { + try { + closing.countDown(); + db.close(); + if (!transactionFinished.get()) error.set(true); + closed.countDown(); + } catch (Exception e) { + error.set(true); + } + }); + close.start(); + closing.await(); + // Do whatever the transaction needs to do + Thread.sleep(10); + transactionFinished.set(true); + // Abort the transaction + db.abortTransaction(txn); + // The other thread should now terminate + assertTrue(closed.await(5, SECONDS)); + // Check that the other thread didn't encounter an error + assertFalse(error.get()); + + open(true); + assertFalse(db.wasDirtyOnInitialisation()); + } + + @Test + public void testShutdownDirty() throws Exception { + Database db = open(false); + + List unloadedDrivers = unloadDrivers(); + + try { + db.close(); + fail(); + } catch (Exception e) { + // continue + } + + reloadDrivers(unloadedDrivers); + + db = open(true); + assertTrue(db.wasDirtyOnInitialisation()); + } + private Database open(boolean resume) throws Exception { return open(resume, new TestMessageFactory(), new SystemClock()); } @@ -2402,6 +2463,30 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { rootKey, alice); } + private List unloadDrivers() { + Enumeration drivers = DriverManager.getDrivers(); + List unloaded = new ArrayList<>(); + while (drivers.hasMoreElements()) { + Driver d = drivers.nextElement(); + try { + DriverManager.deregisterDriver(d); + unloaded.add(d.getClass().getName()); + } catch (SQLException e) { + e.printStackTrace(); + } + } + return unloaded; + } + + private void reloadDrivers(List unloadedDrivers) + throws ClassNotFoundException, IllegalAccessException, + InstantiationException, SQLException { + for (String driverName : unloadedDrivers) { + DriverManager.registerDriver( + (Driver) Class.forName(driverName).newInstance()); + } + } + @After public void tearDown() { deleteTestDirectory(testDir);