[PECOBLR-2086] MST transaction tests — parameterized for SEA/Thrift#1366
[PECOBLR-2086] MST transaction tests — parameterized for SEA/Thrift#1366vikrantpuppala wants to merge 20 commits intodatabricks:mainfrom
Conversation
Adds 37 new E2E integration tests to TransactionTests.java covering gaps identified in MST + xDBC metadata audit (LC-13424, LC-13425, LC-13427, LC-13428): - executeUpdate/executeLargeUpdate/executeBatch in transactions - DatabaseMetaData operations (getColumns, getTables, etc.) in active txn - PreparedStatement metadata before/after execute in transaction - MSTCheckRule-blocked SQL (SHOW/DESCRIBE/information_schema) in MST - Allowed operations (setCatalog, setSchema, DESCRIBE TABLE) in MST - Connection close with pending transaction (implicit rollback) - DDL behavior in transactions (CREATE/DROP/ALTER TABLE) - PreparedStatement parameterized DML in transactions - Concurrent DDL + parameterized DML (stale schema) - Edge cases: empty txn, read-only txn, holdability, timeout, retry Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
- Add ignoreTransactions=0 to JDBC URL to enable MST - Fix testCloseConnectionWithPendingTransaction: accept both auto-commit and rollback behaviors on close - Fix testGetFunctionsInsideActiveTransaction: catch known driver logging bug (IllegalFormatConversionException in getFunctions) Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
- setCatalog/setSchema/DESCRIBE TABLE are all blocked in MST via Thrift (SetCatalogCommand, SetNamespaceCommand, DescribeRelation) — tests now expect the exception - getPrimaryKeys/getCrossReference may poison transaction in MST — wrapped in try-catch - testParameterizedDMLAfterConcurrentAlterTable: catch driver logger bug - testCommitWithoutActiveTransaction: remove message content assertion - testTransactionContinuesAfterAllowedMetadataOp: use DML-only operations Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
- Add transactionTests.yml workflow to run TransactionTests and ExplicitTransactionStatementTests on push to main (same pattern as concurrencyExecutionTests.yml) - Update both e2e test classes to read credentials from env vars (DATABRICKS_HOST, DATABRICKS_TOKEN, DATABRICKS_HTTP_PATH, etc.) with fallback to hardcoded defaults for local development - Fake service replay mode not yet possible for transaction tests due to LC-13424 (SEA INLINE disposition bug with MST commands) Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
…edentials" This reverts commit dc758c7.
Documents the test architecture for MST transaction tests: - Operation categorization (broken vs stale vs works) per backend - Parameterized test class hierarchy (SEA + Thrift) - Shared correctness tests via abstract base class - Specialized test classes for metadata, blocked SQL, execute variants - Migration plan from current unstructured tests Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
Adds visual diagrams for: - Operation categorization (broken/stale/works) - Driver routing (SEA vs Thrift code paths) - Class hierarchy - Test execution flow across backends and transaction modes - Migration plan from current to new structure - Test count breakdown Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
docs/mst-test-design.md
Outdated
| | # | Test | Description | Expected | | ||
| |---|---|---|---| | ||
| | A.1 | `testDefaultAutoCommitIsTrue` | New connection defaults to autoCommit=true | Pass | | ||
| | A.2 | `testCommitSingleInsert` | Disable autocommit → INSERT → commit → verify from separate conn | Pass | |
There was a problem hiding this comment.
why does it say disable autocommit? it should depend on if it's running via api or explicit mode??
docs/mst-test-design.md
Outdated
| | A.4 | `testRollbackSingleInsert` | Disable autocommit → INSERT → rollback → verify not persisted | Pass | | ||
| | A.5 | `testMultipleSequentialTransactions` | 3 sequential txns (commit, commit, rollback) → verify only first two persist | Pass | | ||
| | A.6 | `testAutoStartAfterCommit` | Commit txn1 → insert+rollback txn2 → only txn1 data persists | Pass | | ||
| | A.7 | `testAutoStartAfterRollback` | Rollback txn1 → insert+commit txn2 → only txn2 data persists | Pass | |
There was a problem hiding this comment.
this should sit in ApiTests?
docs/mst-test-design.md
Outdated
| | A.15 | `testWriteConflictSingleTable` | Two concurrent txns on same table → first commits → second gets ConcurrentAppendException | Pass | | ||
| | A.16 | `testWriteSkewProvesSnapshotIsolation` | Two concurrent txns on different tables → both commit → proves Snapshot Isolation | Pass | | ||
| | A.17 | `testCommitWithoutActiveTxnThrows` | autocommit=true → commit() → expect exception | Pass | | ||
| | A.18 | `testRollbackWithoutActiveTxnBehavior` | autocommit=true → rollback() → document behavior (JDBC throws, explicit SQL is no-op) | Pass | |
There was a problem hiding this comment.
are we going to test 17 and 18 with both api and explicit? and do we mean SET AUTOCOMMIT or BEGIN TRANSACTION when running explicit sql tests? also are there scenarios when we'd like to test both?
docs/mst-test-design.md
Outdated
| | A.16 | `testWriteSkewProvesSnapshotIsolation` | Two concurrent txns on different tables → both commit → proves Snapshot Isolation | Pass | | ||
| | A.17 | `testCommitWithoutActiveTxnThrows` | autocommit=true → commit() → expect exception | Pass | | ||
| | A.18 | `testRollbackWithoutActiveTxnBehavior` | autocommit=true → rollback() → document behavior (JDBC throws, explicit SQL is no-op) | Pass | | ||
| | A.19 | `testSetAutoCommitDuringActiveTxnThrows` | In active txn → setAutoCommit(true) → expect exception | Pass | |
There was a problem hiding this comment.
again, will we try SET AUTOCOMMIT in case of explicit txn? and if not, shouldn't this be in api tests? imo explicit sql tests shouldn't even know about the SET command and they should just interact with transactions using BEGIN command
docs/mst-test-design.md
Outdated
| | A.18 | `testRollbackWithoutActiveTxnBehavior` | autocommit=true → rollback() → document behavior (JDBC throws, explicit SQL is no-op) | Pass | | ||
| | A.19 | `testSetAutoCommitDuringActiveTxnThrows` | In active txn → setAutoCommit(true) → expect exception | Pass | | ||
| | A.20 | `testUnsupportedIsolationLevel` | Set isolation to READ_UNCOMMITTED/READ_COMMITTED/SERIALIZABLE → expect exception | Pass | | ||
| | A.21 | `testSupportedIsolationLevel` | Set isolation to REPEATABLE_READ → verify | Pass | |
There was a problem hiding this comment.
aren't 20 and 21 api tests?
docs/mst-test-design.md
Outdated
| | A.29 | `testPreparedStatementUpdate` | Insert → parameterized UPDATE in txn → commit → verify | Pass | | ||
| | A.30 | `testPreparedStatementReuseAcrossTransactions` | Same PreparedStatement used in txn1 (commit) and txn2 (commit) → verify both rows | Pass | | ||
| | A.31 | `testPreparedStatementGetMetaDataAfterExecute` | Execute PreparedStatement SELECT → getMetaData() → verify column count | Pass | | ||
| | A.32 | `testGetParameterMetaData` | Create parameterized PreparedStatement → getParameterMetaData() → verify non-null | Pass | |
There was a problem hiding this comment.
i feel like there are duplications in the tests like maybe we're testing the same thing again and again or in different ways, is there scope to reduce the number of tests here?
docs/mst-test-design.md
Outdated
| | A.31 | `testPreparedStatementGetMetaDataAfterExecute` | Execute PreparedStatement SELECT → getMetaData() → verify column count | Pass | | ||
| | A.32 | `testGetParameterMetaData` | Create parameterized PreparedStatement → getParameterMetaData() → verify non-null | Pass | | ||
|
|
||
| ### B. ExplicitSqlTransactionTests — special tests |
There was a problem hiding this comment.
we should similarly just have api tests as highlighted in previous comments
docs/mst-test-design.md
Outdated
| 6. **Add** staleness tests (C.9, C.10) — new, didn't exist before | ||
| 7. **Parameterize** everything on SEA/Thrift | ||
|
|
||
| ### Tests being removed (and why) |
There was a problem hiding this comment.
why do we need to delete these? can we not add assertions instead?
- Move API-specific tests (setAutoCommit, isolation level) out of shared base into JdbcApiTransactionTests - Clarify ExplicitSqlTransactionTests uses BEGIN TRANSACTION only; SET AUTOCOMMIT tests cover implicit SQL mode as special cases - Remove duplicated tests (SET AUTOCOMMIT FALSE commit/rollback already covered by shared base via inherited tests) - Move setCatalog/setSchema to MstBlockedSqlTests (API calls, not shared correctness) - Make all shared test descriptions mode-agnostic (startTransaction instead of disable autocommit) - Keep DDL/empty-commit/retry tests as needing E2E validation instead of deleting them - Update class diagram, test counts, and execution flow diagrams Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
docs/mst-test-design.md
Outdated
| | A.5 | `testAutoStartAfterCommit` | Commit txn1 → insert+rollback txn2 → only txn1 data persists | Pass | | ||
| | A.6 | `testAutoStartAfterRollback` | Rollback txn1 → insert+commit txn2 → only txn2 data persists | Pass | |
There was a problem hiding this comment.
aren't these only applicable to setAutocommit and hence should be in api tests?
Auto-start after commit/rollback is specific to implicit transaction mode (setAutoCommit=false). With BEGIN TRANSACTION there is no auto-start — you need an explicit BEGIN for each transaction. Moved testAutoStartAfterCommit and testAutoStartAfterRollback from shared base (22 tests) to JdbcApiTransactionTests (now 10 API-specific tests). Updated class diagram, execution flow, and counts accordingly. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
Replace TransactionTests.java and ExplicitTransactionStatementTests.java with a structured, parameterized test hierarchy in the mst/ package: - AbstractMstTestBase: 22 shared correctness tests (mode-agnostic), parameterized by backend (SEA/Thrift) - JdbcApiTransactionTests: inherits shared + 10 API-specific tests (autocommit, isolation level, auto-start, PreparedStatement metadata) - ExplicitSqlTransactionTests: inherits shared + 7 SQL-specific tests (BEGIN TRANSACTION, SET AUTOCOMMIT command) - MstMetadataTests: 10 tests for metadata RPCs in MST with backend-aware assertions (SEA: xfail, Thrift: staleness) - MstBlockedSqlTests: 12 tests for MSTCheckRule-blocked SQL and API calls, verifying both exception and transaction abort - MstExecuteVariantTests: 4 tests for executeUpdate/executeBatch row counts (Thrift: correct, SEA: TBD after E2E) Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
- Remove @test from AbstractMstTestBase methods (JUnit was running them directly on gap test subclasses without initialization) - Use separate Statement objects for DROP and CREATE in createTestTable (Databricks JDBC driver closes statement after execution) - Default catalog/schema to main/default when env vars not set Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
SEA backend auto-closes statements after execution, so reusing a Statement for multiple execute() calls fails. Refactored all tests to use executeSql() helper which creates a fresh Statement per call. Also use unique table names per test class (based on class name) to allow parallel test execution without table collisions. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
MstMetadataTests: - Each test now starts its own fresh transaction (was sharing one) - getFunctions: both backends return ResultSet (not blocked by MSTCheckRule when issued with StatementType.METADATA). Thrift path catches known driver logging bug (IllegalFormatConversionException) - Staleness tests: flip assertions — Thrift RPCs ARE non-transactional and DO see concurrent DDL (proving they bypass transaction isolation) MstExecuteVariantTests: - SEA: wrap execute calls in assertThrows (LC-13424 confirmed — executeUpdate/executeBatch abort the transaction on SEA) - Thrift: keep existing correctness assertions JdbcApiTransactionTests: - PreparedStatementUpdate: use execute() instead of executeUpdate() to avoid LC-13424 on SEA Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
E2E shows executeUpdate and executeLargeUpdate work on SEA (return row count, don't abort transaction). Only executeBatch aborts on SEA. Use same assertion for both backends — verify commit and data persist. Row count may be stale on SEA (LC-13424). Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
E2E confirms executeUpdate and executeLargeUpdate on SEA succeed (return a row count) but silently poison the transaction — the subsequent commit() fails with TRANSACTION_ROLLBACK_REQUIRED. Assert this behavior: SEA expects commit to throw, Thrift expects normal commit and data persistence. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
SEA backend closes PreparedStatement after execute(), preventing reuse across transactions and getMetaData() after execution. Skip these tests on SEA with Assumptions.assumeTrue(isThrift()). Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
Major updates based on actual E2E results: - Thrift metadata RPCs are non-transactional (see concurrent DDL), not stale — flipped terminology and assertions - executeUpdate/executeLargeUpdate on SEA silently poison txn (commit fails), don't throw directly. executeBatch throws. - getFunctions not blocked on SEA (StatementType.METADATA bypass) - SEA closes PreparedStatement after execute — documented as implementation detail affecting test design - Added E2E results table, known issues section - Updated all diagrams to reflect verified behavior - Removed TBD/open items that are now resolved Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
E2E confirms getPrimaryKeys Thrift RPC also fails inside MST — the server routes TGetPrimaryKeysReq through GET_FUNCTIONS which is blocked. Changed from Thrift-pass/SEA-throw to assertThrows on both backends. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
…unts - getPrimaryKeys fails on both backends (server routes through GET_FUNCTIONS), not session poisoning — updated categorization - Fixed E2E results: 169 pass, 5 skip, 0 errors - Updated known issues: removed session poisoning, added getPrimaryKeys server routing issue - Corrected skip count: 3 in MstMetadataTests (D.7 Thrift, D.9 SEA, D.10 SEA) + 2 in JdbcApiTransactionTests (B.8, B.9) Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
Summary
setAutoCommit/commit/rollback) and Explicit SQL (BEGIN TRANSACTION/COMMIT/ROLLBACK) share a common abstract base classdocs/mst-test-design.mdfor full design, operation categorization, class hierarchy, and E2E resultsTest architecture
AbstractMstTestBase— 22 shared correctness tests (mode-agnostic, no@Test— invoked via parameterized wrappers)JdbcApiTransactionTests— inherits shared + 10 API-specific tests (autocommit, isolation, PreparedStatement)ExplicitSqlTransactionTests— inherits shared + 7 SQL-specific tests (BEGIN TRANSACTION, SET AUTOCOMMIT)MstMetadataTests— metadata RPCs with backend-aware assertions (SEA: assertThrows, Thrift: non-transactional freshness)MstBlockedSqlTests— MSTCheckRule-blocked SQL introspection + setCatalog/setSchema (assertThrows on both backends)MstExecuteVariantTests— executeUpdate/executeBatch (SEA: silently poisons txn or throws, Thrift: works correctly)E2E results (174 test executions)
execute()— B.8 PreparedStatement reuse, B.9 getMetaData after executegetFunctionsdriver logging bug (IllegalFormatConversionException) — D.7Key E2E findings
executeUpdate/executeLargeUpdatesilently poison the transaction (commit fails later);executeBatchthrows directlygetFunctionsvia SEA is not blocked by MSTCheckRule (SHOW FUNCTIONS IN CATALOGwithStatementType.METADATAbypasses the rule)getPrimaryKeysfails on both backends — server routes it through GET_FUNCTIONS which is blocked in MSTexecute()— tests useexecuteSql()helper with fresh Statement per callTest plan
NO_CHANGELOG=true
This pull request was AI-assisted by Isaac.