diff --git a/upstream-xerial_sqlite-jdbc.manifest b/upstream-xerial_sqlite-jdbc.manifest index d58a8d7..a46d2ee 100644 --- a/upstream-xerial_sqlite-jdbc.manifest +++ b/upstream-xerial_sqlite-jdbc.manifest @@ -85,4 +85,4 @@ VERSION # divergence: src/test/java/org/sqlite/JSON1Test.java -- Hrana holds a namespace until its last connection closes, so the conformance copy closes the leaked per-test connections. # divergence: src/test/java/org/sqlite/CachedRowSetTest.java -- Hrana holds a namespace until its last connection closes, so the conformance copy closes the leaked connection and asserts the row it reads. # divergence: src/test/java/org/sqlite/InsertQueryTest.java -- upstream misuses the connection factory so the transaction is applied to a different connection and never asserts the result; the conformance copy reuses the transaction connection, asserts rollback and commit visibility, and asserts the final count (#51). -# divergence: src/test/java/org/sqlite/PreparedStatementThreadTest.java -- upstream swallows ExecutionException, which also wraps assertion failures; the conformance copy rethrows AssertionError so the race test can fail (#51). +# divergence: src/test/java/org/sqlite/PreparedStatementThreadTest.java -- upstream swallows every ExecutionException, which hides assertion failures and runtime exceptions from the close/execute race; Hrana serializes requests per stream, so the conformance copy awaits both futures and tolerates only an SQLException cause, and any runtime failure fails the test as the Java equivalent of the native crash it guards (#51, #118). diff --git a/upstream-xerial_sqlite-jdbc/CHECKSUMS.sha256 b/upstream-xerial_sqlite-jdbc/CHECKSUMS.sha256 index 4b493d5..5ff3d1f 100644 --- a/upstream-xerial_sqlite-jdbc/CHECKSUMS.sha256 +++ b/upstream-xerial_sqlite-jdbc/CHECKSUMS.sha256 @@ -21,7 +21,7 @@ ae4568fd773f158f04e89df8e0fe2326381b6af7ed1316193830d38f7cadbae5 ./src/test/jav # upstream 242bb51330240174bab5f443aa4d8de1049e6d947374e080a636c4aa4d0049ee ./src/test/java/org/sqlite/MetadataLeakTest.java 242bb51330240174bab5f443aa4d8de1049e6d947374e080a636c4aa4d0049ee ./src/test/java/org/sqlite/MetadataLeakTest.java # upstream 7af8ae0999a0bf26a20c96ab23131505bd79827e6af17742771e36e9d8d985f4 ./src/test/java/org/sqlite/PreparedStatementThreadTest.java -bc6d868d2069dcc5db54a7720e7ecd9f725c83dbf910ec8ec61222b98f6198c1 ./src/test/java/org/sqlite/PreparedStatementThreadTest.java +8e63f29bec87782e5705ebff748389cb9f5fe3a68d755c730a2beaccde9712a4 ./src/test/java/org/sqlite/PreparedStatementThreadTest.java # upstream d787e71bdf2b8d12a2669eb06c432cf2a39ac77f678a92459e3dd9b6c4519a43 ./src/test/java/org/sqlite/RSMetaDataTest.java d787e71bdf2b8d12a2669eb06c432cf2a39ac77f678a92459e3dd9b6c4519a43 ./src/test/java/org/sqlite/RSMetaDataTest.java # upstream 6065d284933c8462cc13217992820a9261075c0e9ee126df6cbe9961d90303f9 ./src/test/java/org/sqlite/ResultSetTest.java diff --git a/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/PreparedStatementThreadTest.java b/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/PreparedStatementThreadTest.java index 0d10163..1bb4c6a 100644 --- a/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/PreparedStatementThreadTest.java +++ b/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/PreparedStatementThreadTest.java @@ -42,7 +42,7 @@ static void afterAll() { * behavior */ @Test - public void testPreparedStmtConcurrentCloseSegFault() throws SQLException { + public void testPreparedStmtConcurrentCloseSegFault() throws SQLException, ExecutionException { connect(); try { for (int i = 0; i < 100; i++) { @@ -59,7 +59,8 @@ public void testPreparedStmtConcurrentCloseSegFault() throws SQLException { * undefined C behavior */ @Test - public void testPreparedStmtConcurrentCloseConnSegFault() throws SQLException { + public void testPreparedStmtConcurrentCloseConnSegFault() throws SQLException, + ExecutionException { for (int i = 0; i < 100; i++) { connect(); testRace(executorService, conn::close); @@ -76,7 +77,7 @@ public void close() throws SQLException { } private void testRace(ExecutorService executorService, CloseCallback closeCallback) - throws SQLException { + throws SQLException, ExecutionException { AtomicInteger countdown = new AtomicInteger(2); stat = conn.prepareStatement("select 1,2,3,4,5"); @@ -98,18 +99,32 @@ private void testRace(ExecutorService executorService, CloseCallback closeCallba closeCallback.close(); return true; }); + ExecutionException queryFailure = null; + ExecutionException closeFailure = null; try { assertThat(queryThread.get()).isTrue(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + fail("", e); + } catch (ExecutionException e) { + queryFailure = e; + } + // Await the close future even when the query failed, so neither side hides the other. + try { assertThat(closeThread.get()).isTrue(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); fail("", e); } catch (ExecutionException e) { - // A checked SQLException from the close race is expected. Assertion failures are - // not: ExecutionException wraps them, so rethrow them or the test cannot fail. - if (e.getCause() instanceof AssertionError assertionError) { - throw assertionError; - } + closeFailure = e; + } + // A checked SQLException from the close race is expected. Any other cause is the Java + // equivalent of the native crash this test guards, so it must fail the test. + if (queryFailure != null && !(queryFailure.getCause() instanceof SQLException)) { + throw queryFailure; + } + if (closeFailure != null && !(closeFailure.getCause() instanceof SQLException)) { + throw closeFailure; } }