Skip to content

refactor: split monolithic test_integration.py into per-driver files#99

Open
HenryNebula wants to merge 93 commits intomasterfrom
refactor-tests
Open

refactor: split monolithic test_integration.py into per-driver files#99
HenryNebula wants to merge 93 commits intomasterfrom
refactor-tests

Conversation

@HenryNebula
Copy link
Copy Markdown
Owner

Summary

  • Split test_integration.py (2171 lines, 12 classes) into individual per-driver files: test_hsqldb, test_postgres, test_mysql, test_mssql, test_trino, test_oracle, test_db2, test_drill, test_sqlite
  • Extract shared test base into test/_base.py (IntegrationTestBase)
  • Consolidate duplicated infrastructure tests (fork safety, JAR path spaces, dynamic classpath, JPype reflection) into test_infrastructure.py using parameterized base classes with HSQLDB and MockDriver concrete subclasses
  • Fix CI gap where infrastructure tests (ForkSafetyTest, JarPathSpacesIntegrationTest, DynamicClasspathIntegrationTest, JavaSqlTypesReflectionTest) were never included in any tox environment
  • Update tox.ini, .github/workflows/publish.yml, CLAUDE.md, and pre-push hook to reference new module names

Test plan

  • Mock tests pass: CLASSPATH="test/jars/*:test/mock-jars/*" uv run python -m unittest test.test_mock (104 OK, 1 skipped)
  • Infrastructure tests pass: CLASSPATH="test/jars/*:test/mock-jars/*" uv run python -m unittest test.test_infrastructure (30 OK, 1 skipped)
  • HSQLDB tests pass: CLASSPATH="test/jars/*" uv run python -m unittest test.test_hsqldb.HsqldbTest (41 OK)
  • Combined run via python -m unittest: 175 OK, 2 skipped
  • Pre-push hook passes

🤖 Generated with Claude Code

HenryNebula and others added 30 commits April 22, 2026 14:09
When binding NULL parameters via _set_stmt_parms_fallback, use
setNull(i, Types.NULL) instead of setObject(i, null). Some JDBC
drivers (notably Teradata) reject setObject with null and require
the explicit setNull() call.

Fixes #22 (legacy baztian/jaydebeapi#57)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use raw string r'\d+\.\d+' instead of '\d+\.\d+' to avoid
SyntaxWarning/DeprecationWarning in Python 3.8+.

Fixes #30

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…quence

Fix: invalid escape sequence in regex pattern (legacy #129)
Fix: use setNull() for NULL parameter binding
Legacy bug: TIMESTAMP with 90000 microseconds became 900000 due to
string-based parsing. Dodged in our Arrow-based path. Add 5 regression
tests covering edge cases: 0, 90000, 123456, 200000, 999999 µs.

Also adds mockTimestampResult() helper to MockConnection for
configurable timestamp mocking.

Closes #18

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The bump-my-version tool handles version changes. Revert manual
bumps from 2.1.3dev1 → 2.1.3rc0 → 2.1.3 back to 2.1.3dev1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses PR review feedback requesting integration tests beyond
the mock driver. Tests that various microsecond values (including
edge cases like 90000, 999999, 0) round-trip correctly through
the Arrow path against a real HSQLDB database.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drill does not support parameterized TIMESTAMP INSERT, and Trino's
JDBC driver cannot convert TIMESTAMP to LocalDateTime. Both databases
fail on test_timestamp_microsecond_precision for driver-specific
reasons unrelated to the bug being verified.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SQLite Xerial JDBC uses date_string_format which truncates
microsecond precision, making this test inapplicable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…TAMPTZ)

Address reviewer feedback: verify timestamp microsecond precision on an
external database. The PostgresTest override tests both TIMESTAMP and
TIMESTAMPTZ columns with the same edge cases from the base class test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The version was prematurely bumped from 2.1.3dev1 to 2.1.3 via
feature branch PR #23. Restoring to the last intentional dev version.
…-microseconds

Verify: TIMESTAMP microsecond precision (legacy #229)
Legacy bug: BIGINT values returned as raw jpype._jclass.java.lang.Long
objects instead of Python ints. Dodged in our Arrow-based path which
handles BIGINT natively via Int64 type.

Add mockBigIntResult() helper to MockConnection and regression tests
covering edge cases: 0, -1, Long.MAX_VALUE, Long.MIN_VALUE.

Closes #32

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Oracle does not support BIGINT as a SQL type (uses NUMBER instead).
Drill does not support CREATE TABLE with BIGINT. Add skipTest
for these database-specific test classes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
testsuite.py appends a tox env suffix to class names (e.g.
OracleTest_py314-driver-oracle), so exact match fails.
Use startswith() instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The initial commit accidentally included DOUBLE-related tests
(test_double_column_returns_float, test_double_type_returns_float,
test_double_edge_values) and mockDoubleResult() helper that belong
in PR #25 (legacy #243). These caused CI failures on MSSQL where
DOUBLE is not a valid T-SQL type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The legacy issue (baztian/jaydebeapi#147) about BINARY types being
decoded as UTF-8 strings does not affect jaydebeapiarrow — the Arrow
JDBC adapter handles binary types natively and returns Python bytes.

Add mockBinaryResult to MockConnection and three test cases that
verify binary data round-trips correctly, including non-UTF-8 byte
sequences (0x80, 0xff, 0xfe) and all 256 byte values.

Closes #20

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses PR review feedback requesting integration tests beyond
the mock driver. Tests that binary data containing non-UTF-8
bytes (0x80, 0xff, 0xfe) round-trips correctly through the Arrow
path against a real HSQLDB database.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address reviewer feedback: verify binary data integrity on an external
database. The PostgresTest override tests the full 256-byte spectrum
and common non-UTF-8 sequences that historically get corrupted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rebase onto dev restored timestamp tests that were previously removed.
Add Drill-specific test_binary_non_utf8_roundtrip using CTAS (Drill
doesn't support parameterized INSERT for binary). Skip on Trino since
the memory connector doesn't support VARBINARY round-trip via CTAS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drill cannot create VARBINARY columns with non-UTF-8 bytes via CTAS
(hex literal conversion is unsupported). Binary data integrity is
already verified via mock tests, HSQLDB, and PostgreSQL integration
tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verify: BINARY types preserve data integrity (legacy #147)
…vert

Verify: BIGINT columns return Python int (legacy #63)
Legacy jaydebeapi returned raw java.lang.Double objects for JDBC DOUBLE
columns. Our Arrow-based path handles this natively via PyArrow's
to_pylist() which converts Arrow DOUBLE to Python float.

Add mockDoubleResult() to MockConnection, mock tests for type and edge
cases, and HSQLDB integration test for DOUBLE round-trip.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These databases don't support the DOUBLE column type keyword:
- MSSQL uses FLOAT
- Oracle uses BINARY_DOUBLE
- Drill doesn't support DOUBLE in CREATE TABLE

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The skip override was accidentally placed in TrinoTest instead of
MSSQLTest. Move it to the correct class.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…f skipping

Replace skipTest() calls with proper _double_create_sql() overrides:
- MSSQL: FLOAT instead of DOUBLE
- Oracle: BINARY_DOUBLE instead of DOUBLE
- Drill: CTAS with DOUBLE (no INSERT support)

Extract _double_populate() helper so Drill can override it as no-op
since CTAS populates the table during creation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mockito.mock() creates a CGLIB subclass where JPype cannot resolve
final methods with long/byte[] parameters. Using CALLS_REAL_METHODS
ensures the real MockConnection methods are invoked while Mockito
still handles stubbing for abstract Connection methods.

This fixes pre-existing mock test failures for mockBinaryResult and
mockBigIntResult that existed on the dev branch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drill CTAS (CREATE TABLE AS SELECT) fails when executed through
jaydebeapiarrow's cursor.execute() because it wraps the SQL in a
metadata query (SELECT * FROM (...) LIMIT 0). Use direct JDBC
statement execution for DDL, matching the pattern used by other
Drill tests in setUpSql/tearDown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HenryNebula and others added 30 commits April 24, 2026 22:33
HSQLDB 2.5.2 has a known timestamp precision bug (#1585) that returns
epoch (1970-01-01). The fix shipped in 2.6.0+, but those versions'
main JAR requires Java 11. HSQLDB 2.6.0+ ships an alternative
-jdk8 JAR that is Java 8 compatible. Use hsqldb-2.7.4-jdk8.jar
which has all fixes and is class file version 52.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…VMStarted

Fix: add _is_jvm_started() wrapper for JPype 1.6.0+ compatibility
cursor.description was using ResultSetMetaData.getColumnName() which
returns the underlying table column name, ignoring SQL AS aliases.
Switch to getColumnLabel() which returns the alias when present,
falling back to the column name otherwise. This matches PEP-249
behavior and other Python DB-API drivers.

Fixes #66

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add regression tests verifying java.sql.Types constants are accessed
via standard Java Reflection API (field.get/getModifiers/getName)
rather than the deprecated JPype getStaticAttribute() which was
removed in newer JPype versions, causing AttributeError.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix: use getColumnLabel() for cursor.description AS alias support
…e-conversion

Verify: timestamp timezone preservation dodged legacy bug (legacy #73)
…-attribute

Verify: JPype field reflection API works correctly (legacy #111)
Add tests verifying that VARCHAR columns return actual string data,
not empty strings. The original bug (baztian/jaydebeapi#119) was
caused by jaydebeapi using getObject() which could return driver-specific
types (e.g., oracle.sql.CHAR) that JPype couldn't convert. jaydebeapiarrow's
Arrow JDBC adapter uses getString() for VARCHAR columns, avoiding this issue.

- Add mock test for single-column VARCHAR data retrieval
- Add mock test for mixed VARCHAR + numeric column queries
- Add HSQLDB integration test inserting and querying VARCHAR data
- Add mockMultiColumnResult helper to MockConnection for multi-column tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded PostgreSQL connection settings with environment
variables (BENCH_DB_HOST, BENCH_DB_PORT, BENCH_DB_NAME, BENCH_DB_USER,
BENCH_DB_PASS) so benchmarks work across different setups without
modifying source files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow skipping the slow original jaydebeapi baseline when running
benchmarks via `--skip-original`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix: make benchmark DB connection configurable via env vars
…mpty-fields

Verify: VARCHAR columns return data correctly (legacy #119)
SQLXML columns were returned as raw Java objects instead of Python strings.
Map SQLXML type to VARCHAR in ExplicitTypeMapper (same pattern as ARRAY).
Also detect XML columns reported as Types.OTHER by type name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses review feedback: add integration tests for databases that
support storing XML data. PostgreSQL has native XML type support and
CI coverage, making it the right target for this test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…to-string

Fix: map SQLXML columns to VARCHAR for string retrieval (legacy #223)
…fixes #86)

Use JPype's native `classpath` parameter instead of manually constructing
`-Djava.class.path=...` which failed when paths contained spaces.
This fixes the "class name not found" error when JDBC driver JARs are
located in directories with spaces or special characters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix: handle JAR paths containing spaces (fixes #86)
Closes #84

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When autocommit is enabled, calling commit() or rollback() raises
exceptions on databases like PostgreSQL. Now these methods check
jconn.getAutoCommit() first and return early if True, matching the
behavior of other DB-API drivers like psycopg2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix: skip commit/rollback when autocommit is enabled
Fix: add missing lastrowid attribute to Cursor for PEP-249 compliance
JPype does not support fork after JVM start — the native library state
is corrupted in child processes, causing 'already loaded in another
classloader' errors in Gunicorn and similar pre-fork servers. Track the
PID at JVM start time and raise InterfaceError with actionable guidance
if a forked process attempts to connect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow loading JDBC drivers from JARs after the JVM has already started,
using a DriverShim proxy (java.sql.Driver implemented via JPype
@JImplements) that delegates to a driver loaded through URLClassLoader.

This bypasses the fork-after-JVM-start guard, enabling use in gunicorn
--preload workers. Opt in with experimental={'dynamic_classpath': True}.

Closes #71

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These files are build artifacts that were previously committed. They
are now in .gitignore and removed from tracking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- test_hsqldb_fails_without_dynamic_classpath: verifies HSQLDB driver
  is NOT available when JVM starts with only mock driver on classpath
- test_dynamic_load_hsqldb_after_jvm_start: starts JVM with mock-only
  classpath, confirms HSQLDB fails first, then loads it dynamically and
  runs real SQL (CREATE TABLE, INSERT, SELECT, DROP)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…sloader

Fix: fork-after-JVM-start detection + experimental dynamic classpath loading
Extract each DB driver test class into its own module (test_hsqldb,
test_postgres, test_mysql, test_mssql, test_trino, test_oracle,
test_db2, test_drill, test_sqlite) and consolidate duplicated
infrastructure tests (fork safety, JAR path spaces, dynamic classpath,
JPype reflection) into test_infrastructure.py using parameterized
base classes. This fixes a CI gap where infrastructure tests were
never included in any tox environment.

Shared test methods live in test/_base.py (IntegrationTestBase).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move 12 tests that only use common ACCOUNT columns from test_hsqldb.py
to the shared base class so all drivers inherit them automatically. Add
skip overrides in Drill and Trino for INSERT-dependent tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add experimental['jvm_args'] to connect() so callers can pass extra
JVM arguments on first connect. Tests use this to suppress noisy
Java loggers (slf4j-simple and java.util.logging) via a bundled
logging.properties file, keeping the library itself opinion-free.

Also moves 12 HSQLDB-specific tests into the shared IntegrationTestBase
and adds skip overrides for Drill/Trino on INSERT-dependent tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant