From 54dcbf2978b26f42a38d4e73af1665d25ae81703 Mon Sep 17 00:00:00 2001 From: Magnus Persson <1431685+magnusp@users.noreply.github.com> Date: Thu, 22 Oct 2026 00:52:31 +0200 Subject: [PATCH] test(conformance): strengthen weak assertions and add xerial control run (#51) --- libsql-conformance/pom.xml | 38 ++++++ .../libsql/conformance/XerialControl.java | 78 +++++++++++ .../XerialLauncherSessionListener.java | 4 + upstream-xerial_sqlite-jdbc.manifest | 57 +++++++- upstream-xerial_sqlite-jdbc/CHECKSUMS.sha256 | 8 +- .../java/org/sqlite/CachedRowSetTest.java | 7 + .../test/java/org/sqlite/InsertQueryTest.java | 129 ++++++++++-------- .../sqlite/PreparedStatementThreadTest.java | 6 +- .../src/test/java/org/sqlite/TypeMapTest.java | 33 ----- 9 files changed, 262 insertions(+), 98 deletions(-) create mode 100644 libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialControl.java delete mode 100644 upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/TypeMapTest.java diff --git a/libsql-conformance/pom.xml b/libsql-conformance/pom.xml index f1eba3d..9389524 100644 --- a/libsql-conformance/pom.xml +++ b/libsql-conformance/pom.xml @@ -15,6 +15,7 @@ ${project.build.directory}/docker-config + 3.53.4.0 @@ -155,4 +156,41 @@ + + + + + xerial-control + + + org.xerial + sqlite-jdbc + ${xerial.version} + test + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Test.java + + + **/com/github/magnusp/**/*Test.java + + + xerial + + + + + + + diff --git a/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialControl.java b/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialControl.java new file mode 100644 index 0000000..59c1540 --- /dev/null +++ b/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialControl.java @@ -0,0 +1,78 @@ +package com.github.magnusp.libsql.conformance; + +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Enumeration; + +/** + * Selects the upstream xerial driver for the parity control run. + * + *

The control run compiles the same vendored test manifest as the libSQL run but executes it + * against sqlite-jdbc 3.53.4.0. Both drivers are on the test class path, so the control run first + * removes every driver visible to this class loader and then registers the pinned xerial driver + * explicitly. That keeps {@code jdbc:sqlite:} URLs from reaching the libSQL driver. + */ +final class XerialControl { + + static final String ENABLED_PROPERTY = "conformance.control.driver"; + static final String XERIAL_DRIVER = "org.sqlite.JDBC"; + + private static final String PROBE_URL = "jdbc:sqlite::memory:"; + + private XerialControl() {} + + static boolean isEnabled() { + return "xerial".equals(System.getProperty(ENABLED_PROPERTY)); + } + + static void register() { + deregisterVisibleDrivers(); + try { + Driver driver = + (Driver) Class.forName(XERIAL_DRIVER).getConstructor().newInstance(); + DriverManager.registerDriver(driver); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException( + "Xerial control run could not load " + XERIAL_DRIVER, e); + } catch (SQLException e) { + throw new IllegalStateException( + "Xerial control run could not register " + XERIAL_DRIVER, e); + } + verify(); + } + + private static void deregisterVisibleDrivers() { + ClassLoader classLoader = XerialControl.class.getClassLoader(); + Enumeration drivers = DriverManager.getDrivers(); + while (drivers.hasMoreElements()) { + Driver driver = drivers.nextElement(); + if (driver.getClass().getClassLoader() == classLoader) { + try { + DriverManager.deregisterDriver(driver); + } catch (SQLException e) { + throw new IllegalStateException( + "Xerial control run could not deregister " + driver, e); + } + } + } + } + + private static void verify() { + try { + Driver driver = DriverManager.getDriver(PROBE_URL); + if (!XERIAL_DRIVER.equals(driver.getClass().getName())) { + throw new IllegalStateException( + "Xerial control run resolved " + + driver.getClass().getName() + + " for " + + PROBE_URL + + " instead of " + + XERIAL_DRIVER); + } + } catch (SQLException e) { + throw new IllegalStateException( + "Xerial control run found no driver for " + PROBE_URL, e); + } + } +} diff --git a/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialLauncherSessionListener.java b/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialLauncherSessionListener.java index 9838895..9448905 100644 --- a/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialLauncherSessionListener.java +++ b/libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialLauncherSessionListener.java @@ -7,6 +7,10 @@ public final class XerialLauncherSessionListener implements LauncherSessionListe @Override public void launcherSessionOpened(LauncherSession session) { + if (XerialControl.isEnabled()) { + XerialControl.register(); + return; + } XerialConformanceDriver.register(); LibsqlConformanceGuard.verify(); } diff --git a/upstream-xerial_sqlite-jdbc.manifest b/upstream-xerial_sqlite-jdbc.manifest index 847eeda..d58a8d7 100644 --- a/upstream-xerial_sqlite-jdbc.manifest +++ b/upstream-xerial_sqlite-jdbc.manifest @@ -8,12 +8,63 @@ # # divergence: -- # Use the reason to say which libSQL or Hrana behavior makes parity impossible. # +# Selection rationale. The conformance suite selects tests that exercise JDBC +# behavior through ordinary SQL, so the Hrana transport can satisfy them +# unchanged. Tests that drive sqlite-jdbc's native extension API, connection +# configuration surface, or known libSQL parity gaps stay upstream. Each +# selected and rejected class from the pinned 3.53.4.0 test tree is listed. + +# Selected support code. +# selected: src/test/java/org/sqlite/Utils.java -- compile-option assumptions shared by selected tests; not a test class. + +# Selected tests. +# selected: src/test/java/org/sqlite/ResultSetTest.java -- ResultSet navigation and getter conversions over ordinary SQL. +# selected: src/test/java/org/sqlite/InsertQueryTest.java -- transaction reuse and commit visibility across shared and independent connections. +# selected: src/test/java/org/sqlite/FetchSizeTest.java -- fetch-size configuration and stable result ordering. +# selected: src/test/java/org/sqlite/CachedRowSetTest.java -- disconnected CachedRowSet population through a JDBC connection. +# selected: src/test/java/org/sqlite/JSON1Test.java -- SQL JSON function output and text conversion. +# selected: src/test/java/org/sqlite/MetadataLeakTest.java -- metadata result sets close the statement that produced them. +# selected: src/test/java/org/sqlite/PreparedStatementThreadTest.java -- concurrent execute and close must not crash or hide failures. +# selected: src/test/java/org/sqlite/ResultSetWithoutResultsTest.java -- statement result-kind transitions leave no stale result set. +# selected: src/test/java/org/sqlite/RSMetaDataTest.java -- ResultSetMetaData column names, types, and nullability. + +# Rejected tests. +# rejected: src/test/java/org/sqlite/TypeMapTest.java -- removed: libSQL accepts but ignores type maps (tracked by #48), so a parity assertion would be red; asserting the no-op would be a weak test. +# rejected: src/test/java/org/sqlite/BackupTest.java -- drives sqlite-jdbc's native backup API; Hrana exposes no backup primitive. +# rejected: src/test/java/org/sqlite/BusyHandlerTest.java -- registers native busy-handler callbacks that Hrana does not expose. +# rejected: src/test/java/org/sqlite/CollationTest.java -- registers JVM collations through sqlite-jdbc's native extension API. +# rejected: src/test/java/org/sqlite/ConnectionTest.java -- exercises sqlite-jdbc URL, open-mode, and resource-loading configuration that has no Hrana equivalent; covered JDBC paths are asserted by selected tests. +# rejected: src/test/java/org/sqlite/DBMetaDataTest.java -- DatabaseMetaData parity is tracked by #41, #42, and #50; selecting it now would be red. +# rejected: src/test/java/org/sqlite/ErrorMessageTest.java -- asserts sqlite-jdbc wording and native result codes; sqld returns different messages and error codes. +# rejected: src/test/java/org/sqlite/ExtendedCommandTest.java -- exercises sqlite-jdbc's dot-command parser, not the JDBC API. +# rejected: src/test/java/org/sqlite/ExtensionTest.java -- loads native SQLite extensions; the libSQL server does not permit extension loading. +# rejected: src/test/java/org/sqlite/JDBCTest.java -- mixes driver URL handling, extension loading, and sqlite-jdbc read-only configuration; broad driver-level coverage is asserted by selected tests. +# rejected: src/test/java/org/sqlite/ListenerTest.java -- update, commit, rollback, and authorizer hooks require native callbacks unavailable over Hrana. +# rejected: src/test/java/org/sqlite/MathFunctionsTest.java -- passes only when the server binary was compiled with SQLITE_ENABLE_MATH_FUNCTIONS; the sqld image build is not pinned to that option. +# rejected: src/test/java/org/sqlite/MultipleClassLoaderTest.java -- verifies sqlite-jdbc's native library loading per class loader; libSQL has no native library. +# rejected: src/test/java/org/sqlite/PrepStmtTest.java -- includes getGeneratedKeys (#39) and CLOB/binary binding parity that are not yet implemented; selected prepared-statement paths cover the rest. +# rejected: src/test/java/org/sqlite/ProgressHandlerTest.java -- registers native progress callbacks that Hrana does not expose. +# rejected: src/test/java/org/sqlite/QueryTest.java -- date/time and blob conversion cases belong to the value-conversion lane (#31, #32, #33, #34); selecting it now would mix known gaps into the parity baseline. +# rejected: src/test/java/org/sqlite/ReadUncommittedTest.java -- depends on sqlite-jdbc shared-cache and read-uncommitted connection configuration; sqld does not expose it. +# rejected: src/test/java/org/sqlite/SavepointTest.java -- savepoints are not implemented by the libSQL driver. +# rejected: src/test/java/org/sqlite/SerializeTest.java -- serializes and restores a native database image; Hrana has no equivalent. +# rejected: src/test/java/org/sqlite/SQLiteConfigTest.java -- tests sqlite-jdbc's configuration object, not the JDBC API. +# rejected: src/test/java/org/sqlite/SQLiteConnectionPoolDataSourceTest.java -- tests sqlite-jdbc DataSource and pooling classes that libSQL does not provide. +# rejected: src/test/java/org/sqlite/SQLiteDataSourceTest.java -- tests sqlite-jdbc DataSource classes that libSQL does not provide. +# rejected: src/test/java/org/sqlite/SQLiteJDBCLoaderTest.java -- tests the native SQLite library loader. +# rejected: src/test/java/org/sqlite/StatementTest.java -- statement reuse and lifecycle parity is tracked by #47; selected ResultSet tests cover the current read paths. +# rejected: src/test/java/org/sqlite/TransactionTest.java -- asserts SQLite file-locking and multi-connection wait behavior that a single sqld server cannot reproduce; commit visibility is covered by InsertQueryTest. +# rejected: src/test/java/org/sqlite/UDFCustomErrorTest.java -- registers JVM UDFs and inspects native error callbacks. +# rejected: src/test/java/org/sqlite/UDFTest.java -- registers JVM UDFs through sqlite-jdbc's native extension API. +# rejected: src/test/java/org/sqlite/util/OSInfoTest.java -- tests sqlite-jdbc's OS and native-library detection utility. +# rejected: src/test/java/org/sqlite/architecture/CodingRulesTest.java -- ArchUnit rules over sqlite-jdbc source conventions; not runtime JDBC behavior. +# rejected: src/test/java/org/sqlite/architecture/TestCodingRulesTest.java -- ArchUnit rules over sqlite-jdbc test conventions; not runtime JDBC behavior. + # First conformance batch. src/test/java/org/sqlite/Utils.java src/test/java/org/sqlite/ResultSetTest.java src/test/java/org/sqlite/InsertQueryTest.java src/test/java/org/sqlite/FetchSizeTest.java -src/test/java/org/sqlite/TypeMapTest.java src/test/java/org/sqlite/CachedRowSetTest.java # Second batch: metadata, JSON, threading, and empty result sets. @@ -32,4 +83,6 @@ VERSION # when its last connection closes, so the conformance tests must close every # connection they open; leaving one open leaks the namespace for the whole run. # 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. +# 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). diff --git a/upstream-xerial_sqlite-jdbc/CHECKSUMS.sha256 b/upstream-xerial_sqlite-jdbc/CHECKSUMS.sha256 index 95607c9..4b493d5 100644 --- a/upstream-xerial_sqlite-jdbc/CHECKSUMS.sha256 +++ b/upstream-xerial_sqlite-jdbc/CHECKSUMS.sha256 @@ -11,24 +11,22 @@ a0670cf020edf700524c43c85321c2ba027a8bace5682001db60875d4a9fe52b ./NOTICE # upstream 0a60829ce6edd56de46fb87303401c5c1e1e666da5631056340f5c5ce902dcdf ./VERSION 0a60829ce6edd56de46fb87303401c5c1e1e666da5631056340f5c5ce902dcdf ./VERSION # upstream 1351fdca2644e90ac9028ed99c6096c9ecee82ccb7d45cedd9bb454887fd2c6b ./src/test/java/org/sqlite/CachedRowSetTest.java -9e896e20522e4c5f4bc786ad7f8c5b6765428ad531fc0c07130b5f0beb81756f ./src/test/java/org/sqlite/CachedRowSetTest.java +e1743294d2e5e781fae3b647d0bfc2eeeeb856c5276efe308f8b58979b3ab178 ./src/test/java/org/sqlite/CachedRowSetTest.java # upstream 9fb0f2df7de66cac0a46b241c0c1cd3311a80646d0431d377097741b99053760 ./src/test/java/org/sqlite/FetchSizeTest.java 9fb0f2df7de66cac0a46b241c0c1cd3311a80646d0431d377097741b99053760 ./src/test/java/org/sqlite/FetchSizeTest.java # upstream 6dfcecb209e01829ba0aea782b47351443e3970ad1d33ac4c3fb979e6dff1f40 ./src/test/java/org/sqlite/InsertQueryTest.java -6dfcecb209e01829ba0aea782b47351443e3970ad1d33ac4c3fb979e6dff1f40 ./src/test/java/org/sqlite/InsertQueryTest.java +ae4568fd773f158f04e89df8e0fe2326381b6af7ed1316193830d38f7cadbae5 ./src/test/java/org/sqlite/InsertQueryTest.java # upstream bb07398946480ca44c70d03e6f8c399f53506b44c83a312e2d28aebd239c0238 ./src/test/java/org/sqlite/JSON1Test.java 075745907a5174b922db6a45b9c29f45901af1835af27a0014f5fac835b41d0f ./src/test/java/org/sqlite/JSON1Test.java # 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 -7af8ae0999a0bf26a20c96ab23131505bd79827e6af17742771e36e9d8d985f4 ./src/test/java/org/sqlite/PreparedStatementThreadTest.java +bc6d868d2069dcc5db54a7720e7ecd9f725c83dbf910ec8ec61222b98f6198c1 ./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 6065d284933c8462cc13217992820a9261075c0e9ee126df6cbe9961d90303f9 ./src/test/java/org/sqlite/ResultSetTest.java # upstream 958c1f2ff5ca2f1257dfd847207ea793839969b234d140576b51af346697233c ./src/test/java/org/sqlite/ResultSetWithoutResultsTest.java 958c1f2ff5ca2f1257dfd847207ea793839969b234d140576b51af346697233c ./src/test/java/org/sqlite/ResultSetWithoutResultsTest.java -# upstream ed2fb4bf7319bcba0662b83707375501337173956bae7c57dda6e6a2c46b7505 ./src/test/java/org/sqlite/TypeMapTest.java -ed2fb4bf7319bcba0662b83707375501337173956bae7c57dda6e6a2c46b7505 ./src/test/java/org/sqlite/TypeMapTest.java # upstream bef3eddca2a6b80472050a3a52d5e7246128f0644d29c24ed091709b0ed6f121 ./src/test/java/org/sqlite/Utils.java bef3eddca2a6b80472050a3a52d5e7246128f0644d29c24ed091709b0ed6f121 ./src/test/java/org/sqlite/Utils.java diff --git a/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/CachedRowSetTest.java b/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/CachedRowSetTest.java index 7b9de8d..5d18c6e 100644 --- a/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/CachedRowSetTest.java +++ b/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/CachedRowSetTest.java @@ -1,5 +1,7 @@ package org.sqlite; +import static org.assertj.core.api.Assertions.assertThat; + import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; @@ -22,6 +24,11 @@ public void gh_224() throws SQLException { try (CachedRowSet crs = factory.createCachedRowSet()) { crs.setCommand("select * from person"); crs.execute(connection); + + assertThat(crs.next()).isTrue(); + assertThat(crs.getInt("id")).isEqualTo(1); + assertThat(crs.getString("name")).isEqualTo("leo"); + assertThat(crs.next()).isFalse(); } } } diff --git a/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/InsertQueryTest.java b/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/InsertQueryTest.java index a4b2ade..b1e8dd2 100644 --- a/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/InsertQueryTest.java +++ b/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/InsertQueryTest.java @@ -9,6 +9,9 @@ // -------------------------------------- package org.sqlite; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.File; import java.sql.*; import java.util.ArrayList; @@ -114,73 +117,85 @@ public void insertLockTestUsingIndependentConnection() throws Exception { void insertAndQuery(ConnectionFactory factory) throws SQLException { try { - Statement st = factory.getConnection().createStatement(); - st.executeUpdate( - "CREATE TABLE IF NOT EXISTS data (fid VARCHAR(255) PRIMARY KEY, type VARCHAR(64), data BLOB);"); - st.executeUpdate( - "CREATE TABLE IF NOT EXISTS ResourcesTags (bd_fid VARCHAR(255), name VARCHAR(64), version INTEGER);"); - st.close(); + Connection transactionConnection = factory.getConnection(); + try (Statement st = transactionConnection.createStatement()) { + st.executeUpdate( + "CREATE TABLE IF NOT EXISTS data (fid VARCHAR(255) PRIMARY KEY, type VARCHAR(64), data BLOB);"); + st.executeUpdate( + "CREATE TABLE IF NOT EXISTS ResourcesTags (bd_fid VARCHAR(255), name VARCHAR(64), version INTEGER);"); + } - factory.getConnection().setAutoCommit(false); + transactionConnection.setAutoCommit(false); // Object Serialization - PreparedStatement statAddBD = - factory.getConnection() - .prepareStatement("INSERT OR REPLACE INTO data values (?, ?, ?)"); - PreparedStatement statDelRT = - factory.getConnection() - .prepareStatement("DELETE FROM ResourcesTags WHERE bd_fid = ?"); - PreparedStatement statAddRT = - factory.getConnection() - .prepareStatement("INSERT INTO ResourcesTags values (?, ?, ?)"); - - for (int i = 0; i < 10; i++) { - BD item = new BD(Integer.toHexString(i), Integer.toString(i)); - - // SQLite database insertion - statAddBD.setString(1, item.getFullId()); - statAddBD.setString(2, item.getType()); - statAddBD.setBytes(3, BD.serializeBD(item)); - statAddBD.execute(); - - // Then, its resources tags - statDelRT.setString(1, item.getFullId()); - statDelRT.execute(); - - statAddRT.setString(1, item.getFullId()); - - for (int j = 0; j < 2; j++) { - statAddRT.setString(2, "1"); - statAddRT.setLong(3, 1L); - statAddRT.execute(); - } + try (PreparedStatement statAddBD = + transactionConnection.prepareStatement( + "INSERT OR REPLACE INTO data values (?, ?, ?)"); + PreparedStatement statDelRT = + transactionConnection.prepareStatement( + "DELETE FROM ResourcesTags WHERE bd_fid = ?"); + PreparedStatement statAddRT = + transactionConnection.prepareStatement( + "INSERT INTO ResourcesTags values (?, ?, ?)")) { + + insertRows(statAddBD, statDelRT, statAddRT, 10); + + // Rolling back on the transaction connection proves the inserts ran there. + // Statements executed on another connection would already be committed. + transactionConnection.rollback(); + assertRowCount(factory, 0, "rollback must discard the inserted rows"); + + insertRows(statAddBD, statDelRT, statAddRT, 10); + transactionConnection.commit(); + assertRowCount(factory, 10, "commit must persist the inserted rows"); } - factory.getConnection().setAutoCommit(true); - - statAddBD.close(); - statDelRT.close(); - statAddRT.close(); - - // - PreparedStatement stat; - Long result = 0L; - String query = "SELECT COUNT(fid) FROM data"; - - stat = factory.getConnection().prepareStatement(query); - ResultSet rs = stat.executeQuery(); - - rs.next(); - result = rs.getLong(1); - // System.out.println("count = " + result); - - rs.close(); - stat.close(); + transactionConnection.setAutoCommit(true); } finally { factory.dispose(); } } + private void insertRows( + PreparedStatement statAddBD, + PreparedStatement statDelRT, + PreparedStatement statAddRT, + int rows) + throws SQLException { + for (int i = 0; i < rows; i++) { + BD item = new BD(Integer.toHexString(i), Integer.toString(i)); + + // SQLite database insertion + statAddBD.setString(1, item.getFullId()); + statAddBD.setString(2, item.getType()); + statAddBD.setBytes(3, BD.serializeBD(item)); + statAddBD.execute(); + + // Then, its resources tags + statDelRT.setString(1, item.getFullId()); + statDelRT.execute(); + + statAddRT.setString(1, item.getFullId()); + + for (int j = 0; j < 2; j++) { + statAddRT.setString(2, "1"); + statAddRT.setLong(3, 1L); + statAddRT.execute(); + } + } + } + + private void assertRowCount(ConnectionFactory factory, long expected, String message) + throws SQLException { + Connection verificationConnection = factory.getConnection(); + try (PreparedStatement stat = + verificationConnection.prepareStatement("SELECT COUNT(fid) FROM data"); + ResultSet rs = stat.executeQuery()) { + assertTrue(rs.next(), "COUNT query must return a row"); + assertEquals(expected, rs.getLong(1), message); + } + } + @Disabled("Not sure this worked recently, the second query cannot find the table 'sample'") @Test public void reproduceDatabaseLocked() throws SQLException { 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 69685b0..0d10163 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 @@ -105,7 +105,11 @@ private void testRace(ExecutorService executorService, CloseCallback closeCallba Thread.currentThread().interrupt(); fail("", e); } catch (ExecutionException e) { - // this is OK, so long as we don't seg fault + // 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; + } } } diff --git a/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/TypeMapTest.java b/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/TypeMapTest.java deleted file mode 100644 index 66bf9e4..0000000 --- a/upstream-xerial_sqlite-jdbc/src/test/java/org/sqlite/TypeMapTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.sqlite; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.Map; -import org.junit.jupiter.api.Test; - -public class TypeMapTest { - - public Connection getConnection() throws SQLException { - return DriverManager.getConnection("jdbc:sqlite::memory:"); - } - - @Test - public void getTypeMap() throws Exception { - Connection conn = getConnection(); - - Map> m = conn.getTypeMap(); - - conn.close(); - } - - @Test - public void setTypeMap() throws Exception { - Connection conn = getConnection(); - - Map> m = conn.getTypeMap(); - conn.setTypeMap(m); - - conn.close(); - } -}