diff --git a/documents/xa/XA_INTEGRATION_TEST_COVERAGE_ANALYSIS.md b/documents/xa/XA_INTEGRATION_TEST_COVERAGE_ANALYSIS.md new file mode 100644 index 000000000..97456798c --- /dev/null +++ b/documents/xa/XA_INTEGRATION_TEST_COVERAGE_ANALYSIS.md @@ -0,0 +1,671 @@ +# Analysis: XA Integration Test Coverage Requirements + +## Executive Summary + +This document analyzes the requirements and options for executing all current integration tests against all supported databases twice: once with normal (non-XA) connections and once with XA connections. The goal is to achieve the same test coverage with XA connections and transactions that we currently have with normal connections. + +**Current State:** +- **75 total test files** across 8 database types +- **Only 2 dedicated XA tests** (PostgresXAIntegrationTest, OracleXAIntegrationTest) +- **4 databases with XA support**: PostgreSQL, MySQL, Oracle, SQL Server (plus DB2 and CockroachDB potentially) +- **Most tests use non-XA connections** by default + +**Recommendation:** Hybrid approach combining CSV-based parameterization for shared tests with dedicated XA test classes for complex scenarios. + +--- + +## 1. Current Test Infrastructure Analysis + +### 1.1 Test Distribution by Database + +| Database | Test Count | XA Tests | XA Support Available | +|----------|------------|----------|---------------------| +| H2 | 5 | 0 | No (embedded) | +| PostgreSQL | 10 | 1 | **Yes** | +| MySQL | 6 | 0 | **Yes** | +| MariaDB | 1 | 0 | Yes (MySQL compatible) | +| Oracle | 12 | 1 | **Yes** | +| SQL Server | 11 | 0 | **Yes** | +| CockroachDB | 11 | 0 | **Yes** (PostgreSQL protocol) | +| DB2 | 11 | 0 | **Yes** | +| **Database-agnostic** | 9 | 0 | Varies | +| **TOTAL** | **75** | **2** | **6 of 8** | + +### 1.2 Test Categories + +| Test Type | Count | Notes | +|-----------|-------|-------| +| Connection Tests | 7 | Core JDBC connection functionality | +| Statement Tests | 15 | SQL statement execution | +| PreparedStatement Tests | 7 | Parameterized queries | +| DatabaseMetaData Tests | 7 | Schema introspection | +| ResultSet Tests | 10 | Result handling and metadata | +| Savepoint Tests | 5 | Transaction savepoints | +| BLOB/Stream Tests | 10 | Large object handling | +| MultipleTypes Tests | 7 | Data type coverage | +| XA Tests | 2 | Distributed transactions | +| Other | 5 | Specialized tests | + +### 1.3 Current XA Infrastructure + +**Client Side (ojp-jdbc-driver):** +- `OjpXADataSource` - Entry point for JTA transaction managers +- `OjpXAConnection` - Manages XA connections +- `OjpXAResource` - Implements XA protocol +- `TestDBUtils.ConnectionResult` - Helper that supports both XA and non-XA connections + +**Server Side (ojp-server):** +- `XADataSourceFactory` - Creates database-specific XA datasources +- `XAServiceImpl` - gRPC service for XA operations +- `XaSessionManager` - Manages XA sessions + +**Supported Databases (confirmed in code):** +- ✅ PostgreSQL (`PGXADataSource`) +- ✅ MySQL (`MysqlXADataSource`) +- ✅ Oracle (`OracleXADataSource`) +- ✅ SQL Server (`SQLServerXADataSource`) +- ✅ DB2 (`DB2XADataSource`) +- ✅ CockroachDB (uses PostgreSQL XA) +- ❌ H2 (no XA support - embedded database) +- ❌ MariaDB (uses MySQL XA - compatible) + +### 1.4 Test Configuration Mechanism + +Tests use CSV files for parameterization with JUnit 5's `@CsvFileSource`: + +```java +@ParameterizedTest +@CsvFileSource(resources = "/h2_postgres_mysql_mariadb_oracle_sqlserver_connections.csv") +public void testMethod(String driverClass, String url, String user, String pwd, boolean isXA) +``` + +**Current CSV Structure:** +- Some CSV files already include an `isXA` boolean column (e.g., `h2_postgres_mysql_mariadb_oracle_sqlserver_connections.csv`) +- Many database-specific CSV files do NOT have the `isXA` column +- The `TestDBUtils.createConnection()` method already supports the `isXA` parameter + +**Example from h2_postgres_mysql_mariadb_oracle_sqlserver_connections.csv:** +``` +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword,true +``` + +--- + +## 2. Gap Analysis + +### 2.1 Tests WITHOUT XA Coverage + +**By Category:** +- **Statement Tests**: 15 tests × 6 XA databases = 90 missing test scenarios +- **PreparedStatement Tests**: 7 tests × 6 XA databases = 42 missing test scenarios +- **DatabaseMetaData Tests**: 7 tests × 6 XA databases = 42 missing test scenarios +- **ResultSet Tests**: 10 tests × 6 XA databases = 60 missing test scenarios +- **Savepoint Tests**: 5 tests × 6 XA databases = 30 missing test scenarios +- **BLOB/Stream Tests**: 10 tests × 6 XA databases = 60 missing test scenarios +- **MultipleTypes Tests**: 7 tests × 6 XA databases = 42 missing test scenarios +- **Connection Tests**: 7 tests × 6 XA databases = 42 missing test scenarios + +**Total Missing Scenarios: ~408 test scenarios** + +### 2.2 XA-Specific Considerations + +Not all tests are suitable for XA execution: +- **H2 tests** cannot use XA (embedded database, no XA support) +- **Metadata tests** may not need XA coverage (read-only operations) +- **Some performance tests** might behave differently with XA overhead + +**Realistic Missing Coverage: ~350 test scenarios** + +--- + +## 3. Implementation Options + +### Option 1: CSV-Based Approach (Minimal Code Changes) + +**Description:** Extend existing CSV files to include XA variants for all XA-capable databases. + +**Pros:** +- ✅ Minimal code changes required +- ✅ Leverages existing infrastructure +- ✅ Test methods already support `isXA` parameter in many cases +- ✅ Easy to control which tests run with XA +- ✅ Maintains consistency with existing test patterns + +**Cons:** +- ❌ CSV files become longer and harder to maintain +- ❌ Cannot easily add XA-specific test logic +- ❌ Some tests may need refactoring to accept `isXA` parameter +- ❌ Doesn't handle XA-specific edge cases well + +**Effort Estimate:** +- Update ~20 CSV files to add XA variants +- Refactor ~40 test methods to accept `isXA` parameter +- Update test setup/teardown to handle XA properly +- **Total: 2-3 weeks** for 1 developer + +**Example Implementation:** +```csv +# postgres_connection.csv - BEFORE +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword + +# postgres_connection.csv - AFTER +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword,true +``` + +```java +// Test method update +@ParameterizedTest +@CsvFileSource(resources = "/postgres_connection.csv") +public void testConnectionProperties(String driverClass, String url, String user, String pwd, boolean isXA) { + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); + + // Test logic remains the same + // TestDBUtils handles XA vs non-XA transparently + + connResult.close(); +} +``` + +--- + +### Option 2: Dedicated XA Test Classes + +**Description:** Create separate XA-specific test classes for each database (e.g., `PostgresConnectionExtensiveXATests`, `MySQLStatementXATests`). + +**Pros:** +- ✅ Clear separation of XA vs non-XA tests +- ✅ Easy to add XA-specific test scenarios +- ✅ No changes to existing tests +- ✅ Can test XA-specific edge cases (prepare, commit, rollback, recover) + +**Cons:** +- ❌ Massive code duplication (~350 test methods duplicated) +- ❌ Maintenance burden: changes need to be made in two places +- ❌ Doubles the number of test files (~75 additional files) +- ❌ Longer CI/CD times (more test classes to run) + +**Effort Estimate:** +- Create ~60 new test classes (excluding metadata tests) +- Copy and adapt ~350 test methods +- Update CI workflows to run new tests +- **Total: 6-8 weeks** for 1 developer + +**Example Structure:** +``` +PostgresConnectionExtensiveTests.java (existing, non-XA) +PostgresConnectionExtensiveXATests.java (new, XA-only) +PostgresStatementExtensiveTests.java (existing, non-XA) +PostgresStatementExtensiveXATests.java (new, XA-only) +... +``` + +--- + +### Option 3: Parameterized Test Framework + +**Description:** Create a custom JUnit 5 extension that automatically runs each test with both XA and non-XA configurations. + +**Pros:** +- ✅ Zero code duplication +- ✅ Automatic XA coverage for all annotated tests +- ✅ Centralized XA handling logic +- ✅ Easy to exclude tests from XA execution via annotation + +**Cons:** +- ❌ Requires building custom test infrastructure +- ❌ More complex debugging (parameterization is implicit) +- ❌ Learning curve for contributors +- ❌ May not work well with existing CSV-based tests + +**Effort Estimate:** +- Design and implement custom JUnit extension +- Refactor all tests to use new framework +- Update documentation and contributor guidelines +- **Total: 8-10 weeks** for 1 developer + +**Example Implementation:** +```java +@ExtendWith(XAParameterizedExtension.class) +@XATestDatabases({"postgresql", "mysql", "oracle", "sqlserver", "db2", "cockroachdb"}) +public class ConnectionExtensiveTests { + + @XAParameterizedTest + @ExcludeFromXA(reason = "Metadata operations don't need XA") + public void testGetMetaData(ConnectionContext ctx) { + Connection conn = ctx.getConnection(); // auto-created as XA or non-XA + DatabaseMetaData meta = conn.getMetaData(); + assertNotNull(meta); + } +} +``` + +--- + +### Option 4: Hybrid Approach (RECOMMENDED) + +**Description:** Combine CSV-based approach for most tests with dedicated XA test classes for complex XA-specific scenarios. + +**Strategy:** +1. **Update CSV files** to add XA variants for databases that support XA +2. **Refactor shared test methods** to accept `isXA` parameter where applicable +3. **Create dedicated XA test classes** for: + - Complex transaction scenarios (multi-statement transactions, rollback, savepoints) + - XA-specific operations (prepare, commit, recover, forget) + - Multinode XA failover scenarios +4. **Exclude inappropriate tests** from XA execution (e.g., H2, some metadata tests) + +**Pros:** +- ✅ Balances code reuse with XA-specific testing +- ✅ Minimal duplication for simple tests +- ✅ Allows deep XA testing where needed +- ✅ Incremental implementation possible +- ✅ Clear separation of concerns + +**Cons:** +- ❌ Mixed approach may confuse new contributors +- ❌ Requires careful planning of what goes where +- ❌ Still some CSV maintenance burden + +**Effort Estimate:** +- Update ~20 CSV files (1 week) +- Refactor ~30 test methods to accept `isXA` (1 week) +- Create ~10 dedicated XA test classes with ~50 XA-specific methods (2 weeks) +- Update CI workflows and documentation (1 week) +- **Total: 5-6 weeks** for 1 developer + +--- + +## 4. Detailed Breakdown: Hybrid Approach + +### 4.1 Phase 1: CSV-Based XA Coverage (Weeks 1-2) + +**Update these CSV files to add XA variants:** + +| CSV File | Databases | Lines to Add | Priority | +|----------|-----------|--------------|----------| +| `postgres_connection.csv` | PostgreSQL | 1 | High | +| `mysql_mariadb_connection.csv` | MySQL, MariaDB | 2 | High | +| `oracle_connections.csv` | Oracle | 1 | High | +| `sqlserver_connections.csv` | SQL Server | 1 | High | +| `db2_connection.csv` | DB2 | 1 | Medium | +| `cockroachdb_connection.csv` | CockroachDB | 1 | Medium | +| `h2_postgres_connections.csv` | H2, PostgreSQL | 1 | High | +| `h2_mysql_mariadb_connections.csv` | H2, MySQL, MariaDB | 2 | High | +| `h2_oracle_connections.csv` | H2, Oracle | 1 | High | +| All `*_with_record_counts.csv` | Various | ~10 | Low | + +**Refactor these test classes to accept isXA:** + +Category | Test Classes | Estimated Methods | Complexity +---------|-------------|-------------------|------------ +Connection | 7 classes | ~50 methods | Medium +Statement | 15 classes | ~100 methods | Medium +PreparedStatement | 7 classes | ~50 methods | Medium +ResultSet | 10 classes | ~60 methods | Low +BLOB/Stream | 10 classes | ~40 methods | Medium +MultipleTypes | 7 classes | ~35 methods | Low +Savepoint | 5 classes | ~25 methods | High + +**Total: ~360 methods to update (many already support `isXA`)** + +### 4.2 Phase 2: Dedicated XA Test Classes (Weeks 3-4) + +**Create these new XA-specific test classes:** + +1. **PostgresXATransactionTests** - Complex multi-statement transactions +2. **MySQLXATransactionTests** - MySQL-specific XA scenarios +3. **OracleXATransactionTests** - Oracle-specific XA scenarios (extend existing) +4. **SQLServerXATransactionTests** - SQL Server XA scenarios +5. **DB2XATransactionTests** - DB2 XA scenarios +6. **CockroachDBXATransactionTests** - CockroachDB distributed scenarios +7. **XASavepointTests** - XA-specific savepoint behavior +8. **XAFailoverTests** - XA connection failover and recovery +9. **XAPerformanceTests** - XA performance benchmarking +10. **XAConcurrencyTests** - XA under concurrent load + +**Test Scenarios to Cover:** +- Two-phase commit (prepare → commit) +- One-phase commit optimization +- Rollback after prepare +- Transaction recovery (`XAResource.recover()`) +- Transaction timeout handling +- Concurrent XA transactions +- XA with savepoints +- XA failover during prepare/commit +- XA resource manager identification (`isSameRM()`) +- Large transactions with XA overhead + +### 4.3 Phase 3: CI/CD Integration (Week 5) + +**Update GitHub Actions workflows:** + +1. **Extend database-specific jobs** to run XA tests: + ```yaml + - name: Test PostgreSQL with XA + run: mvn test -pl ojp-jdbc-driver -DenablePostgresTests=true -DenableXATests=true + ``` + +2. **Add dedicated XA test job** (optional): + ```yaml + xa-tests: + name: XA Integration Tests + needs: [build-test] + runs-on: ubuntu-latest + strategy: + matrix: + database: [postgres, mysql, oracle, sqlserver, db2, cockroachdb] + ``` + +3. **Update test result reporting** to show XA vs non-XA coverage separately + +### 4.4 Phase 4: Documentation (Week 6) + +**Create/update documentation:** +- `documents/guides/RUNNING_XA_TESTS.md` - How to run XA tests locally +- `documents/guides/ADDING_XA_TEST_COVERAGE.md` - How to add XA coverage to new tests +- Update `CONTRIBUTING.md` with XA testing guidelines +- Add XA coverage badges to README + +--- + +## 5. Risks and Mitigation + +### 5.1 Identified Risks + +| Risk | Impact | Probability | Mitigation | +|------|--------|-------------|------------| +| **XA tests are slower** (2PC overhead) | High | High | Run XA tests in parallel; optimize test database setup | +| **CI time increases significantly** | High | High | Run XA tests only for XA-capable databases; use matrix parallelization | +| **Some tests may fail with XA** (edge cases) | Medium | Medium | Identify and mark XA-incompatible tests; create XA-specific variants | +| **Maintenance burden doubles** | High | Medium | Use hybrid approach to minimize duplication; automate where possible | +| **Database-specific XA quirks** | Medium | High | Create database-specific XA test classes; document limitations | +| **XA configuration is complex** | Low | Medium | Use `TestDBUtils` abstraction; document XA setup in guides | + +### 5.2 Database-Specific XA Limitations + +**PostgreSQL:** +- Requires `max_prepared_transactions > 0` (already configured in CI) +- XA transactions cannot execute DDL statements +- ✅ Well-supported and tested + +**MySQL:** +- XA support varies by storage engine (InnoDB only) +- Some XA operations not supported in older versions +- ⚠️ Needs version-specific testing + +**Oracle:** +- Requires specific XA permissions (`XA_RECOVER_ADMIN` role) +- Already configured in CI +- ✅ Well-supported + +**SQL Server:** +- Requires MSDTC (Microsoft Distributed Transaction Coordinator) +- TestContainers may not support MSDTC +- ⚠️ May need alternative test setup + +**DB2:** +- XA support available but not extensively tested +- May require specific DB2 configuration +- ⚠️ Needs validation + +**CockroachDB:** +- Uses PostgreSQL protocol, should inherit PostgreSQL XA support +- Distributed nature may affect XA behavior +- ⚠️ Needs validation + +--- + +## 6. Effort and Timeline Estimates + +### 6.1 Hybrid Approach (RECOMMENDED) + +| Phase | Tasks | Effort | Dependencies | +|-------|-------|--------|--------------| +| **Phase 1** | Update CSV files + refactor tests | 2 weeks | None | +| **Phase 2** | Create dedicated XA test classes | 2 weeks | Phase 1 | +| **Phase 3** | CI/CD integration | 1 week | Phase 1 | +| **Phase 4** | Documentation | 1 week | Phase 2 | +| **TOTAL** | | **6 weeks** | Sequential | + +**Team Size:** 1 developer full-time + +**Parallelization Potential:** +- Phase 1 can be split by database (2 developers → 1 week) +- Phase 2 can be split by database (2 developers → 1 week) +- Phases 3-4 can run in parallel (2 developers → 1 week) +- **Total with 2 developers: 3-4 weeks** + +### 6.2 Alternative Options Comparison + +| Option | Effort | Code Duplication | Maintainability | XA Coverage | Risk | +|--------|--------|------------------|-----------------|-------------|------| +| **CSV-Based** | 2-3 weeks | Low | High | Good | Low | +| **Dedicated Classes** | 6-8 weeks | High | Low | Excellent | Medium | +| **Parameterized Framework** | 8-10 weeks | None | High | Excellent | High | +| **Hybrid** (recommended) | 5-6 weeks | Low | Medium-High | Excellent | Medium | + +--- + +## 7. Recommendations + +### 7.1 Primary Recommendation: Hybrid Approach + +**Rationale:** +1. **Pragmatic**: Balances code reuse with XA-specific needs +2. **Incremental**: Can be implemented in phases +3. **Flexible**: Allows optimization based on learnings +4. **Maintainable**: Minimizes duplication while maximizing coverage + +### 7.2 Implementation Phases + +**Priority 1 (Must Have):** +- Update CSV files for PostgreSQL, MySQL, Oracle, SQL Server +- Refactor Connection, Statement, PreparedStatement tests +- Create basic XA transaction tests for each database + +**Priority 2 (Should Have):** +- Add DB2 and CockroachDB XA coverage +- Create XA savepoint and failover tests +- Update CI workflows + +**Priority 3 (Nice to Have):** +- XA performance benchmarking +- XA concurrency stress tests +- Advanced XA recovery scenarios + +### 7.3 Success Criteria + +**Coverage Metrics:** +- ✅ 90%+ of non-XA tests have XA equivalents for XA-capable databases +- ✅ All major test categories covered (Connection, Statement, PreparedStatement, ResultSet, Savepoints, BLOB) +- ✅ XA-specific scenarios tested (prepare, commit, rollback, recover, timeout) + +**Quality Metrics:** +- ✅ All XA tests pass on all supported databases +- ✅ CI time increase < 50% +- ✅ Zero code duplication for simple tests +- ✅ < 5% code duplication overall + +**Process Metrics:** +- ✅ Documentation complete and reviewed +- ✅ Contributors can easily add XA coverage to new tests +- ✅ XA test failures are easy to debug + +--- + +## 8. Next Steps + +### 8.1 Decision Points + +**Before Starting Implementation:** +1. ☐ Approve hybrid approach or select alternative +2. ☐ Confirm database priority (PostgreSQL → MySQL → Oracle → SQL Server → DB2 → CockroachDB) +3. ☐ Decide on CI strategy (parallel jobs vs extended runtime) +4. ☐ Allocate developer resources (1 or 2 developers?) + +### 8.2 Preparation Tasks + +**Week 0 (Before Phase 1):** +1. ☐ Validate XA support on all target databases in test environment +2. ☐ Document XA-specific database configurations +3. ☐ Create test plan template for each database +4. ☐ Set up local XA test environment for development + +### 8.3 Implementation Kickoff + +**Phase 1 Starts:** +1. ☐ Create feature branch: `feature/xa-test-coverage` +2. ☐ Update CSV files for PostgreSQL (validate before proceeding) +3. ☐ Refactor 5 test classes as proof of concept +4. ☐ Review and adjust approach based on learnings + +--- + +## 9. Appendix + +### 9.1 Test Class Inventory + +**Database-Specific Tests (67 total):** + +**H2 (5):** No XA needed +- H2ConnectionExtensiveTests +- H2DatabaseMetaDataExtensiveTests +- H2MultipleTypesIntegrationTest +- H2PreparedStatementExtensiveTests +- H2StatementExtensiveTests + +**PostgreSQL (10):** ✅ XA supported, 1 XA test exists +- PostgresCallableStatementTests +- PostgresConnectionExtensiveTests +- PostgresDatabaseMetaDataExtensiveTests +- PostgresMiniStressTest +- PostgresMultipleTypesIntegrationTest +- PostgresPreparedStatementExtensiveTests +- PostgresSavepointTests +- PostgresSlowQuerySegregationTest +- PostgresStatementExtensiveTests +- PostgresXAIntegrationTest (existing XA test) + +**MySQL (6):** ✅ XA supported, 0 XA tests exist +- MySQLDatabaseMetaDataExtensiveTests +- MySQLMariaDBConnectionExtensiveTests +- MySQLMultipleTypesIntegrationTest +- MySQLPreparedStatementExtensiveTests +- MySQLSpecificFeaturesIntegrationTest +- MySQLStatementExtensiveTests + +**Oracle (12):** ✅ XA supported, 1 XA test exists +- OracleBinaryStreamIntegrationTest +- OracleBlobIntegrationTest +- OracleConnectionExtensiveTests +- OracleDatabaseMetaDataExtensiveTests +- OracleMultipleTypesIntegrationTest +- OraclePreparedStatementExtensiveTests +- OracleReadMultipleBlocksOfDataIntegrationTest +- OracleResultSetMetaDataExtensiveTests +- OracleResultSetTest +- OracleSavepointTests +- OracleStatementExtensiveTests +- OracleXAIntegrationTest (existing XA test) + +**SQL Server (11):** ✅ XA supported, 0 XA tests exist +- SQLServerBinaryStreamIntegrationTest +- SQLServerBlobIntegrationTest +- SQLServerConnectionExtensiveTests +- SQLServerDatabaseMetaDataExtensiveTests +- SQLServerMultipleTypesIntegrationTest +- SQLServerPreparedStatementExtensiveTests +- SQLServerReadMultipleBlocksOfDataIntegrationTest +- SQLServerResultSetMetaDataExtensiveTests +- SQLServerResultSetTest +- SQLServerSavepointTests +- SQLServerStatementExtensiveTests + +**CockroachDB (11):** ✅ XA supported (PostgreSQL protocol), 0 XA tests exist +- CockroachDBBinaryStreamIntegrationTest +- CockroachDBBlobIntegrationTest +- CockroachDBConnectionExtensiveTests +- CockroachDBDatabaseMetaDataExtensiveTests +- CockroachDBMultipleTypesIntegrationTest +- CockroachDBPreparedStatementExtensiveTests +- CockroachDBReadMultipleBlocksOfDataIntegrationTest +- CockroachDBResultSetMetaDataExtensiveTests +- CockroachDBResultSetTest +- CockroachDBSavepointTests +- CockroachDBStatementExtensiveTests + +**DB2 (11):** ✅ XA supported, 0 XA tests exist +- Db2BinaryStreamIntegrationTest +- Db2BlobIntegrationTest +- Db2ConnectionExtensiveTests +- Db2DatabaseMetaDataExtensiveTests +- Db2MultipleTypesIntegrationTest +- Db2PreparedStatementExtensiveTests +- Db2ReadMultipleBlocksOfDataIntegrationTest +- Db2ResultSetMetaDataExtensiveTests +- Db2ResultSetTest +- Db2SavepointTests +- Db2StatementExtensiveTests + +**Database-Agnostic (9):** +- BasicCrudIntegrationTest (already supports XA via CSV) +- BinaryStreamIntegrationTest +- BlobIntegrationTest +- ConcurrencyTimeoutTest +- HydratedLobValidationTest +- MultiDataSourceIntegrationTest +- ReadMultipleBlocksOfDataIntegrationTest +- ResultSetMetaDataExtensiveTests +- ResultSetTest + +### 9.2 CSV File Inventory + +**Files with isXA column (6):** +- h2_postgres_connections.csv (2 lines, 1 XA) +- h2_postgres_connections_with_record_counts.csv (17 lines, 6 XA) +- h2_postgres_mysql_mariadb_oracle_sqlserver_connections.csv (8 lines, 1 XA) +- mysql_mariadb_connection.csv (1 line, 0 XA) +- postgres_connection.csv (0 lines, 0 XA) +- sqlserver_connections.csv (0 lines, 0 XA) + +**Files without isXA column (13):** +- cockroachdb_connection.csv +- db2_connection.csv +- db2_connections_with_record_counts.csv +- h2_cockroachdb_connections.csv +- h2_connection.csv +- h2_mysql_mariadb_connections.csv +- h2_mysql_mariadb_oracle_connections.csv +- h2_oracle_connections.csv +- multinode_connection.csv +- oracle_connections.csv +- oracle_connections_with_record_counts.csv +- oracle_xa_connection.csv +- postgres_xa_connection.csv + +### 9.3 References + +**Documentation:** +- `/documents/xa/XA_SUPPORT.md` - XA implementation overview +- `/documents/xa/XA_TRANSACTION_FLOW.md` - XA transaction flow +- `/documents/xa/XA_MULTINODE_FAILOVER.md` - XA failover scenarios +- `/documents/xa/ATOMIKOS_XA_INTEGRATION.md` - Atomikos integration +- `/documents/guides/ADDING_DATABASE_XA_SUPPORT.md` - Adding XA support + +**Code:** +- `ojp-jdbc-driver/src/main/java/org/openjproxy/jdbc/xa/` - Client XA implementation +- `ojp-server/src/main/java/org/openjproxy/grpc/server/xa/` - Server XA implementation +- `ojp-jdbc-driver/src/test/java/openjproxy/jdbc/testutil/TestDBUtils.java` - Test utilities + +--- + +## Document Information + +**Author:** GitHub Copilot (AI Analysis) +**Date:** 2025-12-16 +**Version:** 1.0 +**Status:** Draft for Review +**Purpose:** Requirements analysis and options evaluation for XA test coverage expansion diff --git a/documents/xa/XA_TEST_IMPLEMENTATION_GUIDE.md b/documents/xa/XA_TEST_IMPLEMENTATION_GUIDE.md new file mode 100644 index 000000000..709df67f0 --- /dev/null +++ b/documents/xa/XA_TEST_IMPLEMENTATION_GUIDE.md @@ -0,0 +1,536 @@ +# XA Test Implementation Guide + +## Overview + +This guide documents the implementation of Option 1 (CSV-based XA coverage) to run all integration tests against databases with both normal and XA connections. + +## Implementation Status + +### Completed +✅ **CSV Files Updated** (3 files) +- `postgres_connection.csv` - Added XA variant +- `mysql_mariadb_connection.csv` - Added XA variants for both MySQL and MariaDB +- `oracle_connections.csv` - Added XA variant + +✅ **Test Classes Refactored** (2 of 27) +- `PostgresSavepointTests.java` +- `PostgresMultipleTypesIntegrationTest.java` + +### In Progress +⏳ **Test Classes Remaining** (25 of 27) + +**PostgreSQL (11 remaining):** +- PostgresCallableStatementTests +- PostgresConnectionExtensiveTests +- PostgresDatabaseMetaDataExtensiveTests +- PostgresMiniStressTest +- PostgresPreparedStatementExtensiveTests +- PostgresSlowQuerySegregationTest +- PostgresStatementExtensiveTests +- PostgresCall ableStatementTests +- PostgresDatabaseMetaDataExtensiveTests +- And 2 others + +**MySQL/MariaDB (6 remaining):** +- MySQLDatabaseMetaDataExtensiveTests +- MySQLMariaDBConnectionExtensiveTests +- MySQLMultipleTypesIntegrationTest +- MySQLPreparedStatementExtensiveTests +- MySQLSpecificFeaturesIntegrationTest +- MySQLStatementExtensiveTests + +**Oracle (11 remaining):** +- OracleBinaryStreamIntegrationTest +- OracleBlobIntegrationTest +- OracleConnectionExtensiveTests +- OracleDatabaseMetaDataExtensiveTests +- OracleMultipleTypesIntegrationTest +- OraclePreparedStatementExtensiveTests +- OracleReadMultipleBlocksOfDataIntegrationTest +- OracleResultSetMetaDataExtensiveTests +- OracleResultSetTest +- OracleSavepointTests +- OracleStatementExtensiveTests + +## Refactoring Pattern + +### Before (Non-XA only) +```java +public class PostgresSavepointTests { + private Connection connection; + + public void setUp(String driverClass, String url, String user, String pwd) throws SQLException { + connection = DriverManager.getConnection(url, user, pwd); + connection.setAutoCommit(false); + // ... table setup ... + } + + @AfterEach + public void tearDown() throws Exception { + if (connection != null) connection.close(); + } + + @ParameterizedTest + @CsvFileSource(resources = "/postgres_connection.csv") + public void testSavepoint(String driverClass, String url, String user, String pwd) throws SQLException { + setUp(driverClass, url, user, pwd); + // ... test logic ... + } +} +``` + +### After (Supports both Non-XA and XA) +```java +public class PostgresSavepointTests { + private ConnectionResult connectionResult; + private Connection connection; + + public void setUp(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false + if (!isXA) { + connection.setAutoCommit(false); + } + + // Start transaction for table setup + connectionResult.startXATransactionIfNeeded(); + // ... table setup ... + connectionResult.commit(); + } + + @AfterEach + public void tearDown() throws Exception { + if (connectionResult != null) { + connectionResult.close(); + } + } + + @ParameterizedTest + @CsvFileSource(resources = "/postgres_connection.csv") + public void testSavepoint(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); + + // Start transaction for test + connectionResult.startXATransactionIfNeeded(); + // ... test logic ... + connectionResult.commit(); + } +} +``` + +## Step-by-Step Refactoring Instructions + +### Step 1: Add Imports +Add `ConnectionResult` import if not already present: +```java +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; +``` + +### Step 2: Update Fields +Replace: +```java +private Connection connection; +``` + +With: +```java +private ConnectionResult connectionResult; +private Connection connection; +``` + +### Step 3: Update setUp Method Signature +Add `boolean isXA` parameter: +```java +// Before +public void setUp(String driverClass, String url, String user, String password) + +// After +public void setUp(String driverClass, String url, String user, String password, boolean isXA) +``` + +### Step 4: Replace Connection Creation +Replace `DriverManager.getConnection()` with `TestDBUtils.createConnection()`: +```java +// Before +connection = DriverManager.getConnection(url, user, password); + +// After +connectionResult = TestDBUtils.createConnection(url, user, password, isXA); +connection = connectionResult.getConnection(); +``` + +### Step 5: Handle AutoCommit +For non-XA connections, set autocommit to false: +```java +if (!isXA) { + connection.setAutoCommit(false); +} +``` + +### Step 6: Wrap DDL/DML in Transactions +Wrap table creation, inserts, updates, deletes in transactions: +```java +// Start transaction +connectionResult.startXATransactionIfNeeded(); + +// Execute DDL/DML +connection.createStatement().execute("CREATE TABLE ..."); +// or +statement.executeUpdate("INSERT INTO ..."); + +// Commit transaction +connectionResult.commit(); +``` + +**Important:** In PostgreSQL and most databases, DDL statements (CREATE, DROP, ALTER) cannot be executed within XA transactions. Handle this carefully: + +```java +// For DDL, try-catch and rollback on error +try { + connectionResult.startXATransactionIfNeeded(); + connection.createStatement().execute("DROP TABLE IF EXISTS test_table"); + connectionResult.commit(); +} catch (Exception e) { + try { + connectionResult.rollback(); + } catch (Exception ex) { + // Ignore rollback errors + } +} + +// For DML, normal transaction handling +connectionResult.startXATransactionIfNeeded(); +statement.executeUpdate("INSERT INTO test_table VALUES (...)"); +connectionResult.commit(); +``` + +### Step 7: Update Test Method Signatures +Add `boolean isXA` parameter to all `@ParameterizedTest` methods: +```java +// Before +@ParameterizedTest +@CsvFileSource(resources = "/postgres_connection.csv") +public void testMethod(String driverClass, String url, String user, String pwd) + +// After +@ParameterizedTest +@CsvFileSource(resources = "/postgres_connection.csv") +public void testMethod(String driverClass, String url, String user, String pwd, boolean isXA) +``` + +### Step 8: Update setUp Calls +Pass `isXA` parameter when calling setUp: +```java +// Before +setUp(driverClass, url, user, pwd); + +// After +setUp(driverClass, url, user, pwd, isXA); +``` + +### Step 9: Update tearDown/Cleanup +Replace `connection.close()` with `connectionResult.close()`: +```java +// Before +@AfterEach +public void tearDown() throws Exception { + if (connection != null) connection.close(); +} + +// After +@AfterEach +public void tearDown() throws Exception { + if (connectionResult != null) { + connectionResult.close(); + } +} +``` + +### Step 10: Update Inline Connection Usage +For tests that create local connections (not using setUp), apply the same pattern: +```java +// Before +Connection conn = DriverManager.getConnection(url, user, pwd); +try { + // ... test logic ... +} finally { + conn.close(); +} + +// After +ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); +Connection conn = connResult.getConnection(); + +if (!isXA) { + conn.setAutoCommit(false); +} + +try { + connResult.startXATransactionIfNeeded(); + // ... test logic ... + connResult.commit(); +} finally { + connResult.close(); +} +``` + +## XA-Specific Considerations + +### 1. Transaction Boundaries +XA transactions must be explicitly started, ended, and committed: +- Non-XA: `connection.commit()` commits the transaction +- XA: Must call `xaResource.end()` then `xaResource.commit()` + +`ConnectionResult` handles this automatically: +```java +connectionResult.commit(); // Calls XAResource.commit() for XA, Connection.commit() for non-XA +connectionResult.rollback(); // Calls XAResource.rollback() for XA, Connection.rollback() for non-XA +``` + +### 2. DDL in XA Transactions +Many databases (PostgreSQL, MySQL, Oracle) do NOT allow DDL statements within XA transactions: +- CREATE TABLE +- DROP TABLE +- ALTER TABLE + +**Solution:** Execute DDL outside of XA transactions or in separate transactions: +```java +// Option 1: Try-catch pattern +try { + connectionResult.startXATransactionIfNeeded(); + connection.createStatement().execute("DROP TABLE IF EXISTS test_table"); + connectionResult.commit(); +} catch (Exception e) { + // If DDL fails in XA, rollback and continue + try { + connectionResult.rollback(); + } catch (Exception ex) { + // Ignore + } +} + +// Option 2: Use non-XA connection for DDL (not recommended - creates separate connection) +``` + +### 3. Savepoints in XA +XA transactions support savepoints, but behavior may vary by database: +- PostgreSQL: Supports savepoints in XA transactions +- MySQL: Limited savepoint support in XA +- Oracle: Supports savepoints in XA transactions + +Test savepoint functionality with both XA and non-XA connections to ensure compatibility. + +### 4. AutoCommit +XA connections should NEVER have autocommit enabled: +```java +// XA connections automatically have autocommit disabled +// No need to call connection.setAutoCommit(false) for XA + +// Non-XA connections may need explicit setting +if (!isXA) { + connection.setAutoCommit(false); +} +``` + +### 5. Transaction Timeout +XA transactions can have timeouts. The `ConnectionResult` helper doesn't currently set timeouts, but this can be added if needed: +```java +// In XAResource +xaResource.setTransactionTimeout(300); // 5 minutes +``` + +## Testing Your Refactored Tests + +### 1. Run with Non-XA Connections +```bash +mvn test -pl ojp-jdbc-driver -Dtest=PostgresSavepointTests -DenablePostgresTests=true +``` + +This should execute the test twice (non-XA and XA from CSV) and both should pass. + +### 2. Run with Specific Database +```bash +# PostgreSQL +mvn test -pl ojp-jdbc-driver -Dtest=Postgres* -DenablePostgresTests=true + +# MySQL +mvn test -pl ojp-jdbc-driver -Dtest=MySQL* -DenableMySQLTests=true + +# Oracle +mvn test -pl ojp-jdbc-driver -Dtest=Oracle* -DenableOracleTests=true +``` + +### 3. Check Test Output +Verify that tests run twice per database: +``` +[INFO] Running openjproxy.jdbc.PostgresSavepointTests +Testing for url -> jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb (XA: false) +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 +Testing for url -> jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb (XA: true) +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 +``` + +### 4. Debug XA Failures +If XA tests fail, check: +1. **Server logs** (`/tmp/ojp-server.log`) for XA-specific errors +2. **Database configuration**: Ensure max_prepared_transactions > 0 for PostgreSQL +3. **XA permissions**: Ensure database user has XA permissions (especially Oracle) +4. **DDL in XA**: Check if DDL statements are being executed within XA transactions + +Common XA errors: +- `ERROR: prepared transactions are disabled` → PostgreSQL needs `max_prepared_transactions > 0` +- `ORA-24756: transaction does not exist` → Oracle XA transaction management issue +- `DDL not allowed in XA transaction` → Move DDL outside of XA transaction + +## Automation Script + +For bulk refactoring, a Python script can automate most changes: + +```python +#!/usr/bin/env python3 +import re +import sys + +def refactor_test_file(filepath): + with open(filepath, 'r') as f: + content = f.read() + + # Skip if already refactored + if 'ConnectionResult' in content: + return False + + # Add ConnectionResult import + if 'import openjproxy.jdbc.testutil.TestDBUtils;' in content: + content = content.replace( + 'import openjproxy.jdbc.testutil.TestDBUtils;', + 'import openjproxy.jdbc.testutil.TestDBUtils;\nimport openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult;' + ) + + # Replace Connection field + content = re.sub( + r'(\s+)private Connection connection;', + r'\1private ConnectionResult connectionResult;\n\1private Connection connection;', + content + ) + + # Update setUp signature + content = re.sub( + r'public void setUp\(String driverClass, String url, String user, String (password|pwd)\)', + r'public void setUp(String driverClass, String url, String user, String \1, boolean isXA)', + content + ) + + # Replace DriverManager.getConnection + content = re.sub( + r'connection = DriverManager\.getConnection\(url, user, (password|pwd)\);', + r'connectionResult = TestDBUtils.createConnection(url, user, \1, isXA);\n connection = connectionResult.getConnection();', + content + ) + + # Update test method signatures + content = re.sub( + r'(@ParameterizedTest[^}]+?public void \w+\(String driverClass, String url, String user, String (?:password|pwd))(\))', + r'\1, boolean isXA\2', + content, + flags=re.DOTALL + ) + + # Update setUp calls + content = re.sub( + r'setUp\(driverClass, url, user, (password|pwd)\);', + r'setUp(driverClass, url, user, \1, isXA);', + content + ) + + # Replace connection.close() in tearDown + content = re.sub( + r'if \(connection != null\) connection\.close\(\);', + r'if (connectionResult != null) {\n connectionResult.close();\n }', + content + ) + + with open(filepath, 'w') as f: + f.write(content) + + return True + +if __name__ == '__main__': + for filepath in sys.argv[1:]: + if refactor_test_file(filepath): + print(f"✓ Refactored: {filepath}") + else: + print(f"- Skipped: {filepath}") +``` + +**Note:** This script handles the mechanical refactoring but MANUAL REVIEW IS REQUIRED to: +1. Add transaction boundaries (`startXATransactionIfNeeded()` / `commit()`) +2. Handle DDL statements properly (DDL cannot be in XA transactions) +3. Add `if (!isXA) { conn.setAutoCommit(false); }` where needed +4. Verify test logic still works with both XA and non-XA + +## Completion Checklist + +### Phase 1: CSV Files ✅ +- [x] postgres_connection.csv +- [x] mysql_mariadb_connection.csv +- [x] oracle_connections.csv + +### Phase 2: PostgreSQL Tests (2 of 13) +- [x] PostgresSavepointTests +- [x] PostgresMultipleTypesIntegrationTest +- [ ] PostgresCallableStatementTests +- [ ] PostgresConnectionExtensiveTests +- [ ] PostgresDatabaseMetaDataExtensiveTests +- [ ] PostgresMiniStressTest +- [ ] PostgresPreparedStatementExtensiveTests +- [ ] PostgresSlowQuerySegregationTest +- [ ] PostgresStatementExtensiveTests +- [ ] And 4 others + +### Phase 3: MySQL/MariaDB Tests (0 of 6) +- [ ] MySQLDatabaseMetaDataExtensiveTests +- [ ] MySQLMariaDBConnectionExtensiveTests +- [ ] MySQLMultipleTypesIntegrationTest +- [ ] MySQLPreparedStatementExtensiveTests +- [ ] MySQLSpecificFeaturesIntegrationTest +- [ ] MySQLStatementExtensiveTests + +### Phase 4: Oracle Tests (0 of 11) +- [ ] All Oracle tests + +### Phase 5: Shared Tests (0 of 1) +- [ ] BlobIntegrationTest (uses h2_mysql_mariadb_oracle_connections.csv) + +## Expected Benefits + +Once implementation is complete: + +1. **2x Test Coverage**: Every database-specific test runs with both normal and XA connections +2. **No Code Duplication**: Single test class executes both scenarios +3. **Inline Execution**: Tests run sequentially, no parallelization needed +4. **XA Bug Detection**: Will catch XA-specific issues early +5. **Transaction Validation**: Ensures proper transaction handling for both modes + +## Timeline Estimate + +- **Completed**: CSV files + 2 test classes (2 hours) +- **Remaining**: 25 test classes × 30 mins each = **12.5 hours** +- **Testing & Validation**: 2-3 hours +- **Total**: **15-18 hours** of development work + +## Next Steps + +1. Continue refactoring test classes using the pattern above +2. Test each refactored class individually before moving to next +3. Update this guide with any issues or edge cases discovered +4. Once all tests refactored, run full test suite to validate +5. Document any database-specific XA limitations found during testing + +## References + +- `TestDBUtils.java` - Connection helper utilities +- `XA_SUPPORT.md` - XA transaction support documentation +- `XA_TRANSACTION_FLOW.md` - XA transaction flow details +- `BasicCrudIntegrationTest.java` - Reference implementation (already supports isXA) diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/BlobIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/BlobIntegrationTest.java index 0488e44d6..06205c8cf 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/BlobIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/BlobIntegrationTest.java @@ -12,6 +12,8 @@ import java.sql.Blob; import java.sql.Connection; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -26,6 +28,7 @@ public class BlobIntegrationTest { private static boolean isMariaDBTestEnabled; private static boolean isOracleTestEnabled; private String tableName; + private ConnectionResult connectionResult; private Connection conn; @BeforeAll @@ -36,7 +39,7 @@ public static void checkTestConfiguration() { isOracleTestEnabled = Boolean.parseBoolean(System.getProperty("enableOracleTests", "false")); } - public void setUp(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void setUp(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { this.tableName = "blob_test_blob"; if (url.toLowerCase().contains("mysql")) { @@ -53,13 +56,17 @@ public void setUp(String driverClass, String url, String user, String pwd) throw this.tableName += "_h2"; } Class.forName(driverClass); - this.conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + this.conn = connectionResult.getConnection(); + + // Keep autocommit=true initially for DDL operations (CREATE/DROP TABLE) + // Will be set to false later for DML operations } @ParameterizedTest @CsvFileSource(resources = "/h2_mysql_mariadb_oracle_connections.csv") - public void createAndReadingBLOBsSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - this.setUp(driverClass, url, user, pwd); + public void createAndReadingBLOBsSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { + this.setUp(driverClass, url, user, pwd, isXA); System.out.println("Testing for url -> " + url); try { @@ -76,6 +83,14 @@ public void createAndReadingBLOBsSuccessful(String driverClass, String url, Stri ")" ); + // After DDL is complete, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } + + // Start XA transaction after DDL is complete (must be called AFTER DDL to avoid MySQL/MariaDB XAER_RMFAIL) + connectionResult.startXATransactionIfNeeded(); + PreparedStatement psInsert = conn.prepareStatement( " insert into " + tableName + " (val_blob, val_blob2, val_blob3) values (?, ?, ?)" ); @@ -127,13 +142,13 @@ public void createAndReadingBLOBsSuccessful(String driverClass, String url, Stri resultSet.close(); psSelect.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/h2_mysql_mariadb_oracle_connections.csv") - public void creatingAndReadingLargeBLOBsSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, IOException, ClassNotFoundException { - this.setUp(driverClass, url, user, pwd); + public void creatingAndReadingLargeBLOBsSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, IOException, ClassNotFoundException { + this.setUp(driverClass, url, user, pwd, isXA); System.out.println("Testing for url -> " + url); try { @@ -148,6 +163,14 @@ public void creatingAndReadingLargeBLOBsSuccessful(String driverClass, String ur ")" ); + // After DDL is complete, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } + + // Start XA transaction after DDL is complete (must be called AFTER DDL to avoid MySQL/MariaDB XAER_RMFAIL) + connectionResult.startXATransactionIfNeeded(); + PreparedStatement psInsert = conn.prepareStatement( "insert into " + tableName + " (val_blob) values (?)" ); @@ -179,7 +202,7 @@ public void creatingAndReadingLargeBLOBsSuccessful(String driverClass, String ur resultSet.close(); psSelect.close(); - conn.close(); + connectionResult.close(); } } diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLDatabaseMetaDataExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLDatabaseMetaDataExtensiveTests.java index 8e95cb26d..183054737 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLDatabaseMetaDataExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLDatabaseMetaDataExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.Assert; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -18,6 +19,7 @@ public class MySQLDatabaseMetaDataExtensiveTests { private static boolean isMySQLTestEnabled; private static boolean isMariaDBTestEnabled; + private static ConnectionResult connectionResult; private static Connection connection; @BeforeAll @@ -26,22 +28,30 @@ public static void checkTestConfiguration() { isMariaDBTestEnabled = Boolean.parseBoolean(System.getProperty("enableMariaDBTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(!isMySQLTestEnabled, "MySQL tests are not enabled"); assumeFalse(!isMariaDBTestEnabled, "MariaDB tests are not enabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } TestDBUtils.createBasicTestTable(connection, "mysql_db_metadata_test", TestDBUtils.SqlSyntax.MYSQL, true); } @AfterAll public static void teardown() throws Exception { - TestDBUtils.closeQuietly(connection); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testBasicDatabaseMetaDataProperties(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBasicDatabaseMetaDataProperties(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // Basic database properties @@ -68,8 +78,8 @@ public void testBasicDatabaseMetaDataProperties(String driverClass, String url, @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testSupportFeatures(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testSupportFeatures(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // MySQL typically supports these features @@ -98,8 +108,8 @@ public void testSupportFeatures(String driverClass, String url, String user, Str @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testIdentifierProperties(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testIdentifierProperties(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // MySQL identifier properties @@ -119,8 +129,8 @@ public void testIdentifierProperties(String driverClass, String url, String user @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testTransactionSupport(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testTransactionSupport(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // Transaction isolation levels @@ -137,8 +147,8 @@ public void testTransactionSupport(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testFunctionSupport(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testFunctionSupport(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // Function lists should not be null @@ -160,8 +170,8 @@ public void testFunctionSupport(String driverClass, String url, String user, Str @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testResultSetSupport(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testResultSetSupport(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // ResultSet type support @@ -181,8 +191,8 @@ public void testResultSetSupport(String driverClass, String url, String user, St @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetTables(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetTables(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // Test getTables method @@ -204,8 +214,8 @@ public void testGetTables(String driverClass, String url, String user, String pa @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetColumns(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetColumns(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // Test getColumns method @@ -231,8 +241,8 @@ public void testGetColumns(String driverClass, String url, String user, String p @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetPrimaryKeys(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetPrimaryKeys(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // Test getPrimaryKeys method @@ -255,8 +265,8 @@ public void testGetPrimaryKeys(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetTypeInfo(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetTypeInfo(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // Test getTypeInfo method @@ -280,8 +290,8 @@ public void testGetTypeInfo(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testMySQLSpecificMetaData(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testMySQLSpecificMetaData(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // MySQL specific features @@ -308,8 +318,8 @@ public void testMySQLSpecificMetaData(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testLimitsAndSizes(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testLimitsAndSizes(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // Test various limits - these should return reasonable values or 0 if unlimited diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLMariaDBConnectionExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLMariaDBConnectionExtensiveTests.java index abcf5e752..e88a38b8f 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLMariaDBConnectionExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLMariaDBConnectionExtensiveTests.java @@ -2,6 +2,7 @@ import lombok.SneakyThrows; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; @@ -28,6 +29,8 @@ public class MySQLMariaDBConnectionExtensiveTests { private static boolean isMySQLTestEnabled; private static boolean isMariaDBTestEnabled; + private ConnectionResult connectionResult; + private Connection connection; @BeforeAll @@ -37,21 +40,29 @@ public static void checkTestConfiguration() { } @SneakyThrows - public void setUp(String driverClass, String url, String user, String password) throws SQLException { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { assumeFalse(!isMySQLTestEnabled, "MySQL tests are not enabled"); assumeFalse(!isMariaDBTestEnabled, "MariaDB tests are not enabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } } @AfterEach public void tearDown() throws SQLException { - TestDBUtils.closeQuietly(connection); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testCreateStatement(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testCreateStatement(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); Statement statement = connection.createStatement(); Assert.assertNotNull(statement); @@ -60,8 +71,8 @@ public void testCreateStatement(String driverClass, String url, String user, Str @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testPrepareStatement(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testPrepareStatement(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); PreparedStatement preparedStatement = connection.prepareStatement("SELECT 1"); Assert.assertNotNull(preparedStatement); @@ -70,8 +81,8 @@ public void testPrepareStatement(String driverClass, String url, String user, St @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testPrepareCall(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testPrepareCall(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); // MySQL supports callable statements, though syntax may differ try { @@ -86,8 +97,8 @@ public void testPrepareCall(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testNativeSQL(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testNativeSQL(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); String nativeSQL = connection.nativeSQL("SELECT {fn NOW()}"); Assert.assertNotNull(nativeSQL); @@ -97,8 +108,8 @@ public void testNativeSQL(String driverClass, String url, String user, String pa @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testAutoCommit(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testAutoCommit(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); // Test getting and setting auto-commit boolean originalAutoCommit = connection.getAutoCommit(); @@ -115,8 +126,8 @@ public void testAutoCommit(String driverClass, String url, String user, String p @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testCommitAndRollback(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testCommitAndRollback(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); // Test commit and rollback operations connection.setAutoCommit(false); @@ -130,8 +141,8 @@ public void testCommitAndRollback(String driverClass, String url, String user, S @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testIsClosed(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testIsClosed(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); Assert.assertEquals(false, connection.isClosed()); @@ -141,8 +152,8 @@ public void testIsClosed(String driverClass, String url, String user, String pas @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetMetaData(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testGetMetaData(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); DatabaseMetaData metaData = connection.getMetaData(); Assert.assertNotNull(metaData); @@ -157,8 +168,8 @@ public void testGetMetaData(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testReadOnly(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testReadOnly(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); // Test read-only mode boolean originalReadOnly = connection.isReadOnly(); @@ -178,8 +189,8 @@ public void testReadOnly(String driverClass, String url, String user, String pas @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testCatalog(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testCatalog(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); String catalog = connection.getCatalog(); // Catalog might be null or the database name @@ -193,8 +204,8 @@ public void testCatalog(String driverClass, String url, String user, String pass @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testTransactionIsolation(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testTransactionIsolation(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); int isolationLevel = connection.getTransactionIsolation(); Assert.assertTrue(isolationLevel >= Connection.TRANSACTION_NONE && isolationLevel <= Connection.TRANSACTION_SERIALIZABLE); @@ -209,8 +220,8 @@ public void testTransactionIsolation(String driverClass, String url, String user @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testWarnings(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testWarnings(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); // Test warning operations SQLWarning warnings = connection.getWarnings(); @@ -222,8 +233,8 @@ public void testWarnings(String driverClass, String url, String user, String pas @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testCreateStatementWithParameters(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testCreateStatementWithParameters(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); Statement statement = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); Assert.assertNotNull(statement); @@ -236,8 +247,8 @@ public void testCreateStatementWithParameters(String driverClass, String url, St @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testPrepareStatementWithParameters(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testPrepareStatementWithParameters(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); PreparedStatement ps = connection.prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); Assert.assertNotNull(ps); @@ -250,8 +261,8 @@ public void testPrepareStatementWithParameters(String driverClass, String url, S @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testHoldability(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testHoldability(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); int holdability = connection.getHoldability(); Assert.assertTrue(holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT || holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT); @@ -263,8 +274,8 @@ public void testHoldability(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testSavepoints(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testSavepoints(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); connection.setAutoCommit(false); @@ -289,8 +300,8 @@ public void testSavepoints(String driverClass, String url, String user, String p @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testClientInfo(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testClientInfo(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); Properties clientInfo = connection.getClientInfo(); Assert.assertNotNull(clientInfo); @@ -306,8 +317,8 @@ public void testClientInfo(String driverClass, String url, String user, String p @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testValid(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testValid(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); boolean isValid = connection.isValid(5); Assert.assertTrue(isValid); @@ -320,8 +331,8 @@ public void testValid(String driverClass, String url, String user, String passwo @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testUnsupportedOperations(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testUnsupportedOperations(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); // Test operations that might not be supported Assert.assertThrows(SQLException.class, () -> { diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLMultipleTypesIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLMultipleTypesIntegrationTest.java index cb6332192..ebc03ae1c 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLMultipleTypesIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLMultipleTypesIntegrationTest.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.Assert; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -23,6 +24,7 @@ public class MySQLMultipleTypesIntegrationTest { private static boolean isMySQLTestEnabled; private static boolean isMariaDBTestEnabled; + private ConnectionResult connectionResult; @BeforeAll public static void checkTestConfiguration() { @@ -32,7 +34,7 @@ public static void checkTestConfiguration() { @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void typesCoverageTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, ParseException { + public void typesCoverageTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, ParseException { // Skip MySQL tests if not enabled if (url.toLowerCase().contains("mysql") && !isMySQLTestEnabled) { assumeFalse(true, "Skipping MySQL tests"); @@ -43,12 +45,22 @@ public void typesCoverageTestSuccessful(String driverClass, String url, String u assumeFalse(true, "Skipping MariaDB tests"); } - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); System.out.println("Testing for url -> " + url); + // Execute DDL with autocommit=true (default) TestDBUtils.createMultiTypeTestTable(conn, "mysql_multi_types_test", TestDBUtils.SqlSyntax.MYSQL); + // After DDL is complete, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } + + // Start XA transaction after DDL is complete (must be called AFTER DDL to avoid MySQL/MariaDB XAER_RMFAIL) + connectionResult.startXATransactionIfNeeded(); + java.sql.PreparedStatement psInsert = conn.prepareStatement( "insert into mysql_multi_types_test (val_int, val_varchar, val_double_precision, val_bigint, val_tinyint, " + "val_smallint, val_boolean, val_decimal, val_float, val_byte, val_binary, val_date, val_time, " + @@ -122,28 +134,38 @@ public void typesCoverageTestSuccessful(String driverClass, String url, String u resultSet.close(); psSelect.close(); psInsert.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void mysqlSpecificTypesTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void mysqlSpecificTypesTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { // Skip MySQL tests if not enabled if (url.toLowerCase().contains("mysql") && !isMySQLTestEnabled) { assumeFalse(true, "Skipping MySQL tests"); } - // Skip MariaDB tests if not enabled + // Skip MariaDB tests if not enabled if (url.toLowerCase().contains("mariadb") && !isMariaDBTestEnabled) { assumeFalse(true, "Skipping MariaDB tests"); } - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); System.out.println("Testing MySQL-specific types for url -> " + url); + // Execute DDL with autocommit=true (default) TestDBUtils.createMySQLSpecificTestTable(conn, "mysql_specific_types_test"); + // After DDL is complete, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } + + // Start XA transaction after DDL is complete (must be called AFTER DDL to avoid MySQL/MariaDB XAER_RMFAIL) + connectionResult.startXATransactionIfNeeded(); + java.sql.PreparedStatement psInsert = conn.prepareStatement( "insert into mysql_specific_types_test (enum_col, json_col, text_col, mediumtext_col, " + "longtext_col, blob_col, mediumblob_col, longblob_col, set_col, year_col, bit_col) " + @@ -199,6 +221,6 @@ public void mysqlSpecificTypesTestSuccessful(String driverClass, String url, Str resultSet.close(); psSelect.close(); psInsert.close(); - conn.close(); + connectionResult.close(); } } \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLPreparedStatementExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLPreparedStatementExtensiveTests.java index 8718f8b1a..720196b85 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLPreparedStatementExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLPreparedStatementExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; @@ -29,6 +30,8 @@ public class MySQLPreparedStatementExtensiveTests { private static boolean isMySQLTestEnabled; private static boolean isMariaDBTestEnabled; + private ConnectionResult connectionResult; + private Connection connection; private PreparedStatement ps; @@ -38,11 +41,17 @@ public static void checkTestConfiguration() { isMariaDBTestEnabled = Boolean.parseBoolean(System.getProperty("enableMariaDBTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(!isMySQLTestEnabled, "MySQL tests are not enabled"); assumeFalse(!isMariaDBTestEnabled, "MariaDB tests are not enabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } Statement stmt = connection.createStatement(); try { stmt.execute("DROP TABLE mysql_prepared_stmt_test"); @@ -66,8 +75,8 @@ public void tearDown() throws Exception { @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testBasicParameterSetters(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBasicParameterSetters(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); @@ -90,8 +99,8 @@ public void testBasicParameterSetters(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testNumericParameterSetters(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testNumericParameterSetters(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); @@ -119,8 +128,8 @@ public void testNumericParameterSetters(String driverClass, String url, String u @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testDateTimeParameterSetters(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testDateTimeParameterSetters(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, dt, tm, ts) VALUES (?, ?, ?, ?, ?)"); @@ -148,8 +157,8 @@ public void testDateTimeParameterSetters(String driverClass, String url, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testBinaryParameterSetters(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBinaryParameterSetters(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, data) VALUES (?, ?, ?)"); @@ -177,8 +186,8 @@ public void testBinaryParameterSetters(String driverClass, String url, String us @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testTextParameterSetters(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testTextParameterSetters(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, info) VALUES (?, ?, ?)"); @@ -205,8 +214,8 @@ public void testTextParameterSetters(String driverClass, String url, String user @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testNullParameterSetters(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testNullParameterSetters(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, age, data, info) VALUES (?, ?, ?, ?, ?)"); @@ -232,8 +241,8 @@ public void testNullParameterSetters(String driverClass, String url, String user @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testExecuteQuery(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteQuery(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Insert test data ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); @@ -257,8 +266,8 @@ public void testExecuteQuery(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testExecuteUpdate(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteUpdate(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Test INSERT ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); @@ -281,8 +290,8 @@ public void testExecuteUpdate(String driverClass, String url, String user, Strin @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testExecute(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecute(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Test execute with query ps = connection.prepareStatement("SELECT COUNT(*) FROM mysql_prepared_stmt_test"); @@ -303,8 +312,8 @@ public void testExecute(String driverClass, String url, String user, String pass @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testBatch(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBatch(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); @@ -341,8 +350,8 @@ public void testBatch(String driverClass, String url, String user, String passwo @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testClearParameters(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testClearParameters(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); ps.setInt(1, 90); @@ -357,8 +366,8 @@ public void testClearParameters(String driverClass, String url, String user, Str @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testMetaData(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testMetaData(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("SELECT id, name, age FROM mysql_prepared_stmt_test WHERE id = ?"); ResultSetMetaData metaData = ps.getMetaData(); @@ -371,8 +380,8 @@ public void testMetaData(String driverClass, String url, String user, String pas @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testParameterMetaData(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testParameterMetaData(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO mysql_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); try { @@ -388,8 +397,8 @@ public void testParameterMetaData(String driverClass, String url, String user, S @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGeneratedKeys(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGeneratedKeys(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Create table with auto-increment Statement stmt = connection.createStatement(); diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLSpecificFeaturesIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLSpecificFeaturesIntegrationTest.java index 110f11235..c2f0ec633 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLSpecificFeaturesIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLSpecificFeaturesIntegrationTest.java @@ -7,6 +7,8 @@ import java.sql.Connection; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -21,6 +23,7 @@ public class MySQLSpecificFeaturesIntegrationTest { private static boolean isMySQLTestEnabled; private static boolean isMariaDBTestEnabled; + private ConnectionResult connectionResult; @BeforeAll public static void checkTestConfiguration() { @@ -30,7 +33,7 @@ public static void checkTestConfiguration() { @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void onDuplicateKeyUpdateTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void onDuplicateKeyUpdateTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { // Skip MySQL tests if not enabled if (url.toLowerCase().contains("mysql") && !isMySQLTestEnabled) { assumeFalse(true, "Skipping MySQL tests"); @@ -41,26 +44,36 @@ public void onDuplicateKeyUpdateTestSuccessful(String driverClass, String url, S assumeFalse(true, "Skipping MariaDB tests"); } - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); System.out.println("Testing ON DUPLICATE KEY UPDATE for url -> " + url); try (Statement stmt = conn.createStatement()) { - // Drop table if exists + // Drop table if exists (DDL with autocommit=true) try { stmt.execute("DROP TABLE mysql_upsert_test"); } catch (SQLException e) { // Ignore - table might not exist } - // Create table with unique constraint + // Create table with unique constraint (DDL with autocommit=true) stmt.execute("CREATE TABLE mysql_upsert_test (" + "id INT PRIMARY KEY, " + "name VARCHAR(100), " + "count_val INT DEFAULT 1" + ")"); + } + + // After DDL is complete, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } + + // Start XA transaction after DDL is complete (must be called AFTER DDL to avoid MySQL/MariaDB XAER_RMFAIL) + connectionResult.startXATransactionIfNeeded(); - // Insert initial data + try (Statement stmt = conn.createStatement()) { stmt.execute("INSERT INTO mysql_upsert_test (id, name, count_val) VALUES (1, 'Test Item', 1)"); // Test ON DUPLICATE KEY UPDATE @@ -77,12 +90,12 @@ public void onDuplicateKeyUpdateTestSuccessful(String driverClass, String url, S rs.close(); } - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void selectForUpdateTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void selectForUpdateTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { // Skip MySQL tests if not enabled if (url.toLowerCase().contains("mysql") && !isMySQLTestEnabled) { assumeFalse(true, "Skipping MySQL tests"); @@ -93,31 +106,36 @@ public void selectForUpdateTestSuccessful(String driverClass, String url, String assumeFalse(true, "Skipping MariaDB tests"); } - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); System.out.println("Testing SELECT ... FOR UPDATE for url -> " + url); try (Statement stmt = conn.createStatement()) { - // Drop table if exists + // Drop table if exists (DDL with autocommit=true) try { stmt.execute("DROP TABLE mysql_lock_test"); } catch (SQLException e) { // Ignore - table might not exist } - // Create table + // Create table (DDL with autocommit=true) stmt.execute("CREATE TABLE mysql_lock_test (" + "id INT PRIMARY KEY, " + "balance DECIMAL(10,2)" + ")"); - // Insert test data + // Insert test data (still with autocommit=true) stmt.execute("INSERT INTO mysql_lock_test (id, balance) VALUES (1, 100.00)"); + } - // Disable autocommit to test locking - conn.setAutoCommit(false); + // After DDL is complete, set autocommit to false for transaction control + conn.setAutoCommit(false); + + // Start XA transaction after DDL is complete (must be called AFTER DDL to avoid MySQL/MariaDB XAER_RMFAIL) + connectionResult.startXATransactionIfNeeded(); - // Test SELECT ... FOR UPDATE + try (Statement stmt = conn.createStatement()) { ResultSet rs = stmt.executeQuery("SELECT id, balance FROM mysql_lock_test WHERE id = 1 FOR UPDATE"); Assert.assertTrue(rs.next()); Assert.assertEquals(1, rs.getInt("id")); @@ -137,12 +155,12 @@ public void selectForUpdateTestSuccessful(String driverClass, String url, String rs.close(); } - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void showTablesTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void showTablesTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { // Skip MySQL tests if not enabled if (url.toLowerCase().contains("mysql") && !isMySQLTestEnabled) { assumeFalse(true, "Skipping MySQL tests"); @@ -153,12 +171,13 @@ public void showTablesTestSuccessful(String driverClass, String url, String user assumeFalse(true, "Skipping MariaDB tests"); } - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); System.out.println("Testing SHOW TABLES for url -> " + url); try (Statement stmt = conn.createStatement()) { - // Create a test table + // Create a test table (DDL with autocommit=true) try { stmt.execute("DROP TABLE mysql_show_test"); } catch (SQLException e) { @@ -166,8 +185,17 @@ public void showTablesTestSuccessful(String driverClass, String url, String user } stmt.execute("CREATE TABLE mysql_show_test (id INT PRIMARY KEY)"); + } - // Test SHOW TABLES + // After DDL is complete, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } + + // Start XA transaction after DDL is complete (must be called AFTER DDL to avoid MySQL/MariaDB XAER_RMFAIL) + connectionResult.startXATransactionIfNeeded(); + + try (Statement stmt = conn.createStatement()) { ResultSet rs = stmt.executeQuery("SHOW TABLES"); boolean foundTable = false; while (rs.next()) { @@ -182,12 +210,12 @@ public void showTablesTestSuccessful(String driverClass, String url, String user rs.close(); } - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void autoIncrementAndLastInsertIdTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void autoIncrementAndLastInsertIdTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { // Skip MySQL tests if not enabled if (url.toLowerCase().contains("mysql") && !isMySQLTestEnabled) { assumeFalse(true, "Skipping MySQL tests"); @@ -198,24 +226,35 @@ public void autoIncrementAndLastInsertIdTestSuccessful(String driverClass, Strin assumeFalse(true, "Skipping MariaDB tests"); } - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); System.out.println("Testing AUTO_INCREMENT and LAST_INSERT_ID() for url -> " + url); try (Statement stmt = conn.createStatement()) { - // Drop table if exists + // Drop table if exists (DDL with autocommit=true) try { stmt.execute("DROP TABLE mysql_auto_increment_test"); } catch (SQLException e) { // Ignore - table might not exist } - // Create table with auto-increment + // Create table with auto-increment (DDL with autocommit=true) stmt.execute("CREATE TABLE mysql_auto_increment_test (" + "id INT AUTO_INCREMENT PRIMARY KEY, " + "name VARCHAR(100)" + ")"); + } + // After DDL is complete, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } + + // Start XA transaction after DDL is complete (must be called AFTER DDL to avoid MySQL/MariaDB XAER_RMFAIL) + connectionResult.startXATransactionIfNeeded(); + + try (Statement stmt = conn.createStatement()) { // Insert data and test LAST_INSERT_ID() stmt.execute("INSERT INTO mysql_auto_increment_test (name) VALUES ('First Item')"); ResultSet rs = stmt.executeQuery("SELECT LAST_INSERT_ID()"); @@ -243,12 +282,12 @@ public void autoIncrementAndLastInsertIdTestSuccessful(String driverClass, Strin rs.close(); } - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void mysqlInformationSchemaTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void mysqlInformationSchemaTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { // Skip MySQL tests if not enabled if (url.toLowerCase().contains("mysql") && !isMySQLTestEnabled) { assumeFalse(true, "Skipping MySQL tests"); @@ -259,10 +298,15 @@ public void mysqlInformationSchemaTestSuccessful(String driverClass, String url, assumeFalse(true, "Skipping MariaDB tests"); } - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); System.out.println("Testing MySQL INFORMATION_SCHEMA queries for url -> " + url); + // For non-XA connections, set autocommit to false for transaction control + // For this test, we can use autocommit=true as we're only doing SELECT queries + // No need to change autocommit + try (Statement stmt = conn.createStatement()) { // Test INFORMATION_SCHEMA.TABLES ResultSet rs = stmt.executeQuery( @@ -301,6 +345,6 @@ public void mysqlInformationSchemaTestSuccessful(String driverClass, String url, rs.close(); } - conn.close(); + connectionResult.close(); } } \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLStatementExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLStatementExtensiveTests.java index e3658b71b..07d836ae2 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLStatementExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/MySQLStatementExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; @@ -19,6 +20,8 @@ public class MySQLStatementExtensiveTests { private static boolean isMySQLTestEnabled; private static boolean isMariaDBTestEnabled; + private ConnectionResult connectionResult; + private Connection connection; private Statement statement; @@ -28,11 +31,17 @@ public static void checkTestConfiguration() { isMariaDBTestEnabled = Boolean.parseBoolean(System.getProperty("enableMariaDBTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(!isMySQLTestEnabled, "MySQL tests are not enabled"); assumeFalse(!isMariaDBTestEnabled, "MariaDB tests are not enabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } statement = connection.createStatement(); TestDBUtils.createBasicTestTable(connection, "mysql_statement_test", TestDBUtils.SqlSyntax.MYSQL, true); } @@ -44,8 +53,8 @@ public void tearDown() throws Exception { @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testExecuteQuery(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteQuery(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ResultSet rs = statement.executeQuery("SELECT * FROM mysql_statement_test"); Assert.assertNotNull(rs); Assert.assertTrue(rs.next()); @@ -54,8 +63,8 @@ public void testExecuteQuery(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testExecuteUpdate(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteUpdate(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int rows = statement.executeUpdate("UPDATE mysql_statement_test SET name = 'Updated Alice' WHERE id = 1"); Assert.assertEquals(1, rows); @@ -67,8 +76,8 @@ public void testExecuteUpdate(String driverClass, String url, String user, Strin @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testClose(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testClose(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); Assert.assertFalse(statement.isClosed()); statement.close(); Assert.assertTrue(statement.isClosed()); @@ -76,8 +85,8 @@ public void testClose(String driverClass, String url, String user, String passwo @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testMaxFieldSize(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testMaxFieldSize(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int orig = statement.getMaxFieldSize(); if (url.toLowerCase().contains("mysql")) Assert.assertTrue(orig > 0); @@ -92,8 +101,8 @@ public void testMaxFieldSize(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testMaxRows(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testMaxRows(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); Assert.assertEquals(0, statement.getMaxRows()); statement.setMaxRows(10); Assert.assertEquals(10, statement.getMaxRows()); @@ -103,8 +112,8 @@ public void testMaxRows(String driverClass, String url, String user, String pass @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testQueryTimeout(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testQueryTimeout(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); Assert.assertEquals(0, statement.getQueryTimeout()); statement.setQueryTimeout(30); Assert.assertEquals(30, statement.getQueryTimeout()); @@ -114,8 +123,8 @@ public void testQueryTimeout(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testWarnings(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testWarnings(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Initial warnings might be null statement.getWarnings(); statement.clearWarnings(); @@ -124,8 +133,8 @@ public void testWarnings(String driverClass, String url, String user, String pas @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testExecute(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecute(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); boolean hasResultSet = statement.execute("SELECT * FROM mysql_statement_test"); Assert.assertTrue(hasResultSet); @@ -141,8 +150,8 @@ public void testExecute(String driverClass, String url, String user, String pass @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetResultSet(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetResultSet(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.execute("SELECT * FROM mysql_statement_test"); ResultSet rs = statement.getResultSet(); Assert.assertNotNull(rs); @@ -151,8 +160,8 @@ public void testGetResultSet(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetUpdateCount(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetUpdateCount(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.execute("UPDATE mysql_statement_test SET name = 'Test Update' WHERE id = 1"); Assert.assertEquals(1, statement.getUpdateCount()); @@ -162,8 +171,8 @@ public void testGetUpdateCount(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetMoreResults(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetMoreResults(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.execute("SELECT * FROM mysql_statement_test"); if (url.toLowerCase().contains("mysql")) Assert.assertFalse(statement.getMoreResults()); @@ -173,8 +182,8 @@ public void testGetMoreResults(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testFetchDirection(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testFetchDirection(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); Assert.assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); statement.setFetchDirection(ResultSet.FETCH_FORWARD); Assert.assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); @@ -182,8 +191,8 @@ public void testFetchDirection(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testFetchSize(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testFetchSize(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int originalFetchSize = statement.getFetchSize(); statement.setFetchSize(100); Assert.assertEquals(100, statement.getFetchSize()); @@ -192,16 +201,16 @@ public void testFetchSize(String driverClass, String url, String user, String pa @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testResultSetConcurrency(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testResultSetConcurrency(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int concurrency = statement.getResultSetConcurrency(); Assert.assertTrue(concurrency == ResultSet.CONCUR_READ_ONLY || concurrency == ResultSet.CONCUR_UPDATABLE); } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testResultSetType(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testResultSetType(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int type = statement.getResultSetType(); Assert.assertTrue(type == ResultSet.TYPE_FORWARD_ONLY || type == ResultSet.TYPE_SCROLL_INSENSITIVE || @@ -210,8 +219,8 @@ public void testResultSetType(String driverClass, String url, String user, Strin @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testAddBatch(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testAddBatch(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.addBatch("INSERT INTO mysql_statement_test (id, name) VALUES (10, 'Batch1')"); statement.addBatch("INSERT INTO mysql_statement_test (id, name) VALUES (11, 'Batch2')"); statement.clearBatch(); @@ -224,15 +233,15 @@ public void testAddBatch(String driverClass, String url, String user, String pas @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetConnection(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetConnection(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); Assert.assertSame(connection, statement.getConnection()); } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testGetGeneratedKeys(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetGeneratedKeys(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Create table with auto-increment try { @@ -254,8 +263,8 @@ public void testGetGeneratedKeys(String driverClass, String url, String user, St @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testExecuteUpdateWithGeneratedKeys(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteUpdateWithGeneratedKeys(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Create table with auto-increment try{ @@ -279,8 +288,8 @@ public void testExecuteUpdateWithGeneratedKeys(String driverClass, String url, S @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testResultSetHoldability(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testResultSetHoldability(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int holdability = statement.getResultSetHoldability(); Assert.assertTrue(holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT || holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT); @@ -288,16 +297,16 @@ public void testResultSetHoldability(String driverClass, String url, String user @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testCancel(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testCancel(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Test that cancel doesn't throw an exception statement.cancel(); } @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testEscapeProcessing(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testEscapeProcessing(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.setEscapeProcessing(true); statement.setEscapeProcessing(false); // Just verify these calls don't throw exceptions @@ -305,8 +314,8 @@ public void testEscapeProcessing(String driverClass, String url, String user, St @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testCursorName(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testCursorName(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // MySQL may not support named cursors in all configurations if (url.toLowerCase().contains("mysql")) statement.setCursorName("test_cursor"); @@ -316,8 +325,8 @@ public void testCursorName(String driverClass, String url, String user, String p @ParameterizedTest @CsvFileSource(resources = "/mysql_mariadb_connection.csv") - public void testPoolable(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testPoolable(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); boolean poolable = statement.isPoolable(); statement.setPoolable(!poolable); if (url.toLowerCase().contains("mysql")) diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBinaryStreamIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBinaryStreamIntegrationTest.java index 015968e57..2106e2b7c 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBinaryStreamIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBinaryStreamIntegrationTest.java @@ -10,6 +10,8 @@ import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -24,6 +26,7 @@ public class OracleBinaryStreamIntegrationTest { private static boolean isTestDisabled; + private ConnectionResult connectionResult; @BeforeAll public static void setup() { @@ -32,10 +35,16 @@ public static void setup() { @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void createAndReadingBinaryStreamSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { + public void createAndReadingBinaryStreamSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing Oracle binary stream for url -> " + url); @@ -88,15 +97,21 @@ public void createAndReadingBinaryStreamSuccessful(String driverClass, String ur resultSet.close(); psSelect.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void createAndReadingLargeBinaryStreamSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { + public void createAndReadingLargeBinaryStreamSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing Oracle large binary stream for url -> " + url); @@ -138,15 +153,21 @@ public void createAndReadingLargeBinaryStreamSuccessful(String driverClass, Stri resultSet.close(); psSelect.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleSpecificBinaryHandling(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { + public void testOracleSpecificBinaryHandling(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing Oracle-specific binary handling for url -> " + url); @@ -198,6 +219,6 @@ public void testOracleSpecificBinaryHandling(String driverClass, String url, Str resultSet.close(); psSelect.close(); - conn.close(); + connectionResult.close(); } } \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBlobIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBlobIntegrationTest.java index f7692773c..9c45ba372 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBlobIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleBlobIntegrationTest.java @@ -11,6 +11,8 @@ import java.sql.Blob; import java.sql.Connection; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -26,6 +28,7 @@ public class OracleBlobIntegrationTest { private static boolean isTestDisabled; private String tableName; + private ConnectionResult connectionResult; private Connection conn; @BeforeAll @@ -33,11 +36,17 @@ public static void checkTestConfiguration() { isTestDisabled = !Boolean.parseBoolean(System.getProperty("enableOracleTests", "false")); } - public void setUp(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void setUp(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); this.tableName = "oracle_blob_test"; - conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } try { executeUpdate(conn, "DROP TABLE " + tableName); @@ -53,8 +62,8 @@ public void setUp(String driverClass, String url, String user, String pwd) throw @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleBlobCreationAndRetrieval(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + public void testOracleBlobCreationAndRetrieval(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { + setUp(driverClass, url, user, pwd, isXA); System.out.println("Testing Oracle BLOB creation and retrieval for url -> " + url); @@ -90,13 +99,13 @@ public void testOracleBlobCreationAndRetrieval(String driverClass, String url, S psInsert.close(); psSelect.close(); rs.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleLargeBlobHandling(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + public void testOracleLargeBlobHandling(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { + setUp(driverClass, url, user, pwd, isXA); System.out.println("Testing Oracle large BLOB handling for url -> " + url); @@ -138,13 +147,13 @@ public void testOracleLargeBlobHandling(String driverClass, String url, String u psInsert.close(); psSelect.close(); rs.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleBlobBinaryStream(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + public void testOracleBlobBinaryStream(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { + setUp(driverClass, url, user, pwd, isXA); System.out.println("Testing Oracle BLOB binary stream for url -> " + url); @@ -186,13 +195,13 @@ public void testOracleBlobBinaryStream(String driverClass, String url, String us psSelect.close(); rs.close(); binaryStream.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleBlobUpdate(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + public void testOracleBlobUpdate(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { + setUp(driverClass, url, user, pwd, isXA); System.out.println("Testing Oracle BLOB update for url -> " + url); @@ -233,13 +242,13 @@ public void testOracleBlobUpdate(String driverClass, String url, String user, St psUpdate.close(); psSelect.close(); rs.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleEmptyAndNullBlob(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, IOException { - setUp(driverClass, url, user, pwd); + public void testOracleEmptyAndNullBlob(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, IOException { + setUp(driverClass, url, user, pwd, isXA); System.out.println("Testing Oracle empty and null BLOB for url -> " + url); @@ -277,6 +286,6 @@ public void testOracleEmptyAndNullBlob(String driverClass, String url, String us psInsert.close(); psSelect.close(); rs.close(); - conn.close(); + connectionResult.close(); } } \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleConnectionExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleConnectionExtensiveTests.java index a699b7762..2aee305b9 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleConnectionExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleConnectionExtensiveTests.java @@ -6,6 +6,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvFileSource; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.Connection; import java.sql.DriverManager; @@ -32,7 +33,7 @@ public static void setup() { @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleBasicConnection(String driverClass, String url, String user, String pwd) throws SQLException { + public void testOracleBasicConnection(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { Assumptions.assumeFalse(!isOracleTestEnabled, "Skipping Oracle tests"); log.info("Testing Oracle connection with URL: {}", url); @@ -68,7 +69,7 @@ public void testOracleBasicConnection(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleDataTypes(String driverClass, String url, String user, String pwd) throws SQLException { + public void testOracleDataTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { Assumptions.assumeFalse(!isOracleTestEnabled, "Skipping Oracle tests"); log.info("Testing Oracle data types with URL: {}", url); @@ -105,7 +106,7 @@ public void testOracleDataTypes(String driverClass, String url, String user, Str @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleAutoIncrementSequence(String driverClass, String url, String user, String pwd) throws SQLException { + public void testOracleAutoIncrementSequence(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { Assumptions.assumeFalse(!isOracleTestEnabled, "Skipping Oracle tests"); log.info("Testing Oracle auto-increment (IDENTITY) with URL: {}", url); diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleDatabaseMetaDataExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleDatabaseMetaDataExtensiveTests.java index ecfaff7c9..8e4ffd3e2 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleDatabaseMetaDataExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleDatabaseMetaDataExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvFileSource; @@ -12,6 +13,7 @@ public class OracleDatabaseMetaDataExtensiveTests { private static boolean isTestDisabled; + private static ConnectionResult connectionResult; private static Connection connection; @BeforeAll @@ -19,22 +21,30 @@ public static void checkTestConfiguration() { isTestDisabled = !Boolean.parseBoolean(System.getProperty("enableOracleTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } TestDBUtils.createBasicTestTable(connection, "oracle_db_metadata_test", TestDBUtils.SqlSyntax.ORACLE, true); } @AfterAll public static void teardown() throws Exception { - TestDBUtils.closeQuietly(connection); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void allDatabaseMetaDataMethodsShouldWorkAndBeAsserted(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void allDatabaseMetaDataMethodsShouldWorkAndBeAsserted(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // 1–5: Basic database information (Oracle-specific values) diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleMultipleTypesIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleMultipleTypesIntegrationTest.java index 0f8938c3e..65f0d6625 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleMultipleTypesIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleMultipleTypesIntegrationTest.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.Assert; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -22,6 +23,7 @@ public class OracleMultipleTypesIntegrationTest { private static boolean isTestDisabled; + private ConnectionResult connectionResult; @BeforeAll public static void checkTestConfiguration() { @@ -30,10 +32,16 @@ public static void checkTestConfiguration() { @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void typesCoverageTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, ParseException { + public void typesCoverageTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, ParseException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing for url -> " + url); @@ -132,15 +140,21 @@ public void typesCoverageTestSuccessful(String driverClass, String url, String u resultSet.close(); psSelect.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleSpecificTypes(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void testOracleSpecificTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing Oracle-specific types for url -> " + url); @@ -187,15 +201,21 @@ public void testOracleSpecificTypes(String driverClass, String url, String user, resultSet.close(); psSelect.close(); psInsert.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleNumberTypes(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void testOracleNumberTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing Oracle NUMBER types for url -> " + url); @@ -241,7 +261,7 @@ public void testOracleNumberTypes(String driverClass, String url, String user, S resultSet.close(); psSelect.close(); psInsert.close(); - conn.close(); + connectionResult.close(); } /** diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OraclePreparedStatementExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OraclePreparedStatementExtensiveTests.java index 23798c05f..5b0f84c61 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OraclePreparedStatementExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OraclePreparedStatementExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -33,6 +34,9 @@ public class OraclePreparedStatementExtensiveTests { private static boolean isTestDisabled; + private ConnectionResult connectionResult; + + private Connection connection; private PreparedStatement ps; @@ -41,10 +45,16 @@ public static void checkTestConfiguration() { isTestDisabled = !Boolean.parseBoolean(System.getProperty("enableOracleTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } Statement stmt = connection.createStatement(); try { stmt.execute("DROP TABLE oracle_prepared_stmt_test"); @@ -67,8 +77,8 @@ public void tearDown() throws Exception { @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testBasicParameterSetting(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBasicParameterSetting(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO oracle_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); ps.setInt(1, 1); @@ -92,8 +102,8 @@ public void testBasicParameterSetting(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testNullParameterHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testNullParameterHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO oracle_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); ps.setInt(1, 2); @@ -120,8 +130,8 @@ public void testNullParameterHandling(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testNumericParameterTypes(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testNumericParameterTypes(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Test BigDecimal Statement stmt = connection.createStatement(); @@ -148,8 +158,8 @@ public void testNumericParameterTypes(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testDateTimeParameterTypes(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testDateTimeParameterTypes(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO oracle_prepared_stmt_test (id, name, dt) VALUES (?, ?, ?)"); java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis()); @@ -173,8 +183,8 @@ public void testDateTimeParameterTypes(String driverClass, String url, String us @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testLargeObjectHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testLargeObjectHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO oracle_prepared_stmt_test (id, name, data, info) VALUES (?, ?, ?, ?)"); byte[] testData = "This is test binary data".getBytes(); @@ -203,8 +213,8 @@ public void testLargeObjectHandling(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testStreamHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testStreamHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO oracle_prepared_stmt_test (id, name, data, info) VALUES (?, ?, ?, ?)"); byte[] testData = "Stream binary data".getBytes(); @@ -223,8 +233,8 @@ public void testStreamHandling(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testParameterMetaData(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testParameterMetaData(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO oracle_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); // Basic parameter metadata operations @@ -237,8 +247,8 @@ public void testParameterMetaData(String driverClass, String url, String user, S @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testBatchOperations(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBatchOperations(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO oracle_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); // Add multiple batches @@ -265,8 +275,8 @@ public void testBatchOperations(String driverClass, String url, String user, Str @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testResultSetHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testResultSetHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Insert test data first ps = connection.prepareStatement("INSERT INTO oracle_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); @@ -295,8 +305,8 @@ public void testResultSetHandling(String driverClass, String url, String user, S @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleSpecificTypes(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testOracleSpecificTypes(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Create table with Oracle-specific types Statement stmt = connection.createStatement(); @@ -339,8 +349,8 @@ public void testOracleSpecificTypes(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testErrorHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testErrorHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO oracle_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); // Test setting invalid parameter index - Oracle would throw an exception but as OJP delays the diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleReadMultipleBlocksOfDataIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleReadMultipleBlocksOfDataIntegrationTest.java index d3d515350..e12f06e4f 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleReadMultipleBlocksOfDataIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleReadMultipleBlocksOfDataIntegrationTest.java @@ -7,6 +7,8 @@ import java.sql.Connection; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.ResultSet; import java.sql.SQLException; @@ -20,6 +22,7 @@ public class OracleReadMultipleBlocksOfDataIntegrationTest { private static boolean isTestDisabled; + private ConnectionResult connectionResult; @BeforeAll public static void checkTestConfiguration() { @@ -28,10 +31,16 @@ public static void checkTestConfiguration() { @ParameterizedTest @CsvFileSource(resources = "/oracle_connections_with_record_counts.csv") - public void multiplePagesOfRowsResultSetSuccessful(int totalRecords, String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void multiplePagesOfRowsResultSetSuccessful(int totalRecords, String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing Oracle retrieving " + totalRecords + " records from url -> " + url); @@ -70,15 +79,21 @@ public void multiplePagesOfRowsResultSetSuccessful(int totalRecords, String driv resultSet.close(); psSelect.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleLargeDataSetPagination(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void testOracleLargeDataSetPagination(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing Oracle large dataset pagination for url -> " + url); @@ -135,15 +150,21 @@ public void testOracleLargeDataSetPagination(String driverClass, String url, Str page2.close(); psPage1.close(); psPage2.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleResultSetScrolling(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void testOracleResultSetScrolling(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing Oracle ResultSet scrolling for url -> " + url); @@ -198,15 +219,21 @@ public void testOracleResultSetScrolling(String driverClass, String url, String scrollableRs.close(); scrollableStmt.close(); - conn.close(); + connectionResult.close(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleMultipleDataTypes(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void testOracleMultipleDataTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); - Connection conn = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } System.out.println("Testing Oracle multiple data types in large result set for url -> " + url); @@ -261,6 +288,6 @@ public void testOracleMultipleDataTypes(String driverClass, String url, String u resultSet.close(); psSelect.close(); - conn.close(); + connectionResult.close(); } } \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleResultSetMetaDataExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleResultSetMetaDataExtensiveTests.java index c4669ef74..05aac5c2b 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleResultSetMetaDataExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleResultSetMetaDataExtensiveTests.java @@ -1,6 +1,8 @@ package openjproxy.jdbc; import lombok.SneakyThrows; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -14,6 +16,8 @@ public class OracleResultSetMetaDataExtensiveTests { private static boolean isTestDisabled; + private ConnectionResult connectionResult; + private Connection connection; private ResultSetMetaData metaData; @@ -23,10 +27,16 @@ public static void checkTestConfiguration() { } @SneakyThrows - public void setUp(String driverClass, String url, String user, String password) throws SQLException { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } Statement statement = connection.createStatement(); try { @@ -52,13 +62,15 @@ public void setUp(String driverClass, String url, String user, String password) @AfterEach public void tearDown() throws Exception { - if (connection != null) connection.close(); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testAllResultSetMetaDataMethods(String driverClass, String url, String user, String password) throws SQLException { - setUp(driverClass, url, user, password); + public void testAllResultSetMetaDataMethods(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + setUp(driverClass, url, user, password, isXA); // getColumnCount assertEquals(4, metaData.getColumnCount()); diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleResultSetTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleResultSetTest.java index cc8d59c25..7b805dd4e 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleResultSetTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleResultSetTest.java @@ -8,6 +8,8 @@ import java.sql.Connection; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; @@ -26,6 +28,9 @@ */ public class OracleResultSetTest { + private ConnectionResult connectionResult; + + private Connection connection; private Statement statement; private ResultSet resultSet; @@ -38,11 +43,17 @@ public static void checkTestConfiguration() { } @SneakyThrows - public void setUp(String driverClass, String url, String user, String pwd) throws SQLException { + public void setUp(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Skipping Oracle tests"); // Create Oracle database connection - connection = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } // Create a scrollable and updatable Statement statement = connection.createStatement( @@ -82,13 +93,15 @@ public void tearDown() throws SQLException { // Clean up resources if (resultSet != null) resultSet.close(); if (statement != null) statement.close(); - if (connection != null) connection.close(); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleNavigationMethods(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleNavigationMethods(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); assertTrue(resultSet.next()); // Row 1 assertTrue(resultSet.next()); // Row 2 assertTrue(resultSet.previous()); // Back to Row 1 @@ -102,8 +115,8 @@ public void testOracleNavigationMethods(String driverClass, String url, String u @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleDataRetrievalMethods(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleDataRetrievalMethods(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); resultSet.next(); assertEquals(1, resultSet.getInt("id")); assertEquals("Alice", resultSet.getString("name")); @@ -116,8 +129,8 @@ public void testOracleDataRetrievalMethods(String driverClass, String url, Strin @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleGetMethodsByColumnIndex(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleGetMethodsByColumnIndex(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); resultSet.next(); assertEquals(1, resultSet.getInt(1)); // id assertEquals("Alice", resultSet.getString(2)); // name @@ -129,8 +142,8 @@ public void testOracleGetMethodsByColumnIndex(String driverClass, String url, St @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleNullHandling(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleNullHandling(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); statement.execute("INSERT INTO oracle_resultset_test_table (id, name, age, salary, active, created_at) " + "VALUES (5, NULL, NULL, NULL, NULL, NULL)"); resultSet = statement.executeQuery("SELECT * FROM oracle_resultset_test_table WHERE id = 5"); @@ -143,8 +156,8 @@ public void testOracleNullHandling(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleCursorPositionMethods(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleCursorPositionMethods(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); assertTrue(resultSet.first()); assertFalse(resultSet.isBeforeFirst()); assertFalse(resultSet.isAfterLast()); @@ -157,8 +170,8 @@ public void testOracleCursorPositionMethods(String driverClass, String url, Stri @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleWarnings(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleWarnings(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); SQLWarning warning = resultSet.getWarnings(); // Oracle may or may not have warnings, just check it doesn't throw assertNotNull(resultSet); // Basic validation @@ -166,8 +179,8 @@ public void testOracleWarnings(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleAdvancedNavigation(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleAdvancedNavigation(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); resultSet.absolute(2); // Move to the second row assertEquals("Bob", resultSet.getString("name")); @@ -180,8 +193,8 @@ public void testOracleAdvancedNavigation(String driverClass, String url, String @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleSpecificDataTypes(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleSpecificDataTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); // Create table with Oracle-specific data types try { @@ -221,8 +234,8 @@ public void testOracleSpecificDataTypes(String driverClass, String url, String u @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleResultSetMetadata(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleResultSetMetadata(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); java.sql.ResultSetMetaData metadata = resultSet.getMetaData(); @@ -246,8 +259,8 @@ public void testOracleResultSetMetadata(String driverClass, String url, String u @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleRowCounting(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testOracleRowCounting(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); // Count rows by iterating int count = 0; diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleSavepointTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleSavepointTests.java index 3dab4f6c1..fe2906025 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleSavepointTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleSavepointTests.java @@ -8,6 +8,8 @@ import java.sql.Connection; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Savepoint; @@ -19,6 +21,8 @@ public class OracleSavepointTests { private static boolean isTestDisabled; + private ConnectionResult connectionResult; + private Connection connection; @BeforeAll @@ -27,10 +31,16 @@ public static void checkTestConfiguration() { } @SneakyThrows - public void setUp(String driverClass, String url, String user, String pwd) throws SQLException { + public void setUp(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - connection = DriverManager.getConnection(url, user, pwd); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } connection.setAutoCommit(false); Statement stmt = connection.createStatement(); @@ -49,13 +59,15 @@ public void setUp(String driverClass, String url, String user, String pwd) throw @AfterEach public void tearDown() throws Exception { - if (connection != null) connection.close(); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testUnnamedSavepoint(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testUnnamedSavepoint(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); connection.createStatement().execute("INSERT INTO savepoint_test_table (id, name) VALUES (1, 'Alice')"); Savepoint savepoint = connection.setSavepoint(); @@ -73,8 +85,8 @@ public void testUnnamedSavepoint(String driverClass, String url, String user, St @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testNamedSavepoint(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testNamedSavepoint(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); connection.createStatement().execute("INSERT INTO savepoint_test_table (id, name) VALUES (1, 'Alice')"); Savepoint savepoint = connection.setSavepoint("sp1"); @@ -94,8 +106,8 @@ public void testNamedSavepoint(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testMultipleSavepoints(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testMultipleSavepoints(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); connection.createStatement().execute("INSERT INTO savepoint_test_table (id, name) VALUES (1, 'Alice')"); Savepoint sp1 = connection.setSavepoint("sp1"); @@ -124,8 +136,8 @@ public void testMultipleSavepoints(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testReleaseSavepoint(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testReleaseSavepoint(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); connection.createStatement().execute("INSERT INTO savepoint_test_table (id, name) VALUES (1, 'Alice')"); Savepoint savepoint = connection.setSavepoint("sp1"); @@ -147,8 +159,8 @@ public void testReleaseSavepoint(String driverClass, String url, String user, St @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testSavepointAfterCommit(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testSavepointAfterCommit(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); connection.createStatement().execute("INSERT INTO savepoint_test_table (id, name) VALUES (1, 'Alice')"); Savepoint savepoint = connection.setSavepoint("sp1"); @@ -170,8 +182,8 @@ public void testSavepointAfterCommit(String driverClass, String url, String user @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testSavepointMetadata(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testSavepointMetadata(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); // Test that Oracle supports savepoints assertTrue(connection.getMetaData().supportsSavepoints()); diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleStatementExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleStatementExtensiveTests.java index f848302ec..84ec3cfde 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleStatementExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/OracleStatementExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; @@ -27,6 +28,9 @@ public class OracleStatementExtensiveTests { private static boolean isTestDisabled; + private ConnectionResult connectionResult; + + private Connection connection; private Statement statement; @@ -35,10 +39,16 @@ public static void checkTestConfiguration() { isTestDisabled = !Boolean.parseBoolean(System.getProperty("enableOracleTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(isTestDisabled, "Oracle tests are disabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } statement = connection.createStatement(); TestDBUtils.createBasicTestTable(connection, "oracle_statement_test", TestDBUtils.SqlSyntax.ORACLE, true); @@ -51,8 +61,8 @@ public void tearDown() throws Exception { @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testExecuteQuery(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteQuery(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ResultSet rs = statement.executeQuery("SELECT * FROM oracle_statement_test"); assertNotNull(rs); assertTrue(rs.next()); @@ -61,8 +71,8 @@ public void testExecuteQuery(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testExecuteUpdate(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteUpdate(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int rows = statement.executeUpdate("UPDATE oracle_statement_test SET name = 'Updated Alice' WHERE id = 1"); assertEquals(1, rows); @@ -74,8 +84,8 @@ public void testExecuteUpdate(String driverClass, String url, String user, Strin @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testClose(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testClose(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); assertFalse(statement.isClosed()); statement.close(); assertTrue(statement.isClosed()); @@ -83,8 +93,8 @@ public void testClose(String driverClass, String url, String user, String passwo @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testMaxFieldSize(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testMaxFieldSize(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int orig = statement.getMaxFieldSize(); statement.setMaxFieldSize(orig + 1); // Oracle behavior: typically returns 0 (unlimited) unless specifically set @@ -94,8 +104,8 @@ public void testMaxFieldSize(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testExecuteAfterCloseThrows(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteAfterCloseThrows(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.close(); assertThrows(SQLException.class, () -> statement.executeQuery("SELECT * FROM oracle_statement_test")); assertThrows(SQLException.class, () -> statement.executeUpdate("UPDATE oracle_statement_test SET name = 'fail' WHERE id = 1")); @@ -104,8 +114,8 @@ public void testExecuteAfterCloseThrows(String driverClass, String url, String u @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testMaxRows(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testMaxRows(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.setMaxRows(1); assertEquals(1, statement.getMaxRows()); ResultSet rs = statement.executeQuery("SELECT * FROM oracle_statement_test"); @@ -116,8 +126,8 @@ public void testMaxRows(String driverClass, String url, String user, String pass @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testEscapeProcessing(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testEscapeProcessing(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Should not throw statement.setEscapeProcessing(true); statement.setEscapeProcessing(false); @@ -125,40 +135,40 @@ public void testEscapeProcessing(String driverClass, String url, String user, St @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testQueryTimeout(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testQueryTimeout(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.setQueryTimeout(5); assertEquals(5, statement.getQueryTimeout()); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testCancel(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testCancel(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Should not throw statement.cancel(); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testWarnings(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testWarnings(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.clearWarnings(); assertNull(statement.getWarnings()); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testSetCursorName(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testSetCursorName(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Some Oracle versions supports named cursors; the one used for tests does not. Assert.assertThrows(SQLException.class, () -> statement.setCursorName("CURSOR_A")); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testExecute(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecute(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); boolean isResultSet = statement.execute("SELECT * FROM oracle_statement_test"); assertTrue(isResultSet); ResultSet rs = statement.getResultSet(); @@ -173,8 +183,8 @@ public void testExecute(String driverClass, String url, String user, String pass @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testGetMoreResults(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetMoreResults(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.execute("SELECT * FROM oracle_statement_test"); assertFalse(statement.getMoreResults()); assertEquals(-1, statement.getUpdateCount()); @@ -182,8 +192,8 @@ public void testGetMoreResults(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testFetchDirection(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testFetchDirection(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int orig = statement.getFetchDirection(); statement.setFetchDirection(ResultSet.FETCH_FORWARD); assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); @@ -192,8 +202,8 @@ public void testFetchDirection(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testFetchSize(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testFetchSize(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int orig = statement.getFetchSize(); statement.setFetchSize(orig + 1); assertEquals(orig + 1, statement.getFetchSize()); @@ -202,8 +212,8 @@ public void testFetchSize(String driverClass, String url, String user, String pa @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testResultSetConcurrencyAndType(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testResultSetConcurrencyAndType(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int concurrency = statement.getResultSetConcurrency(); int type = statement.getResultSetType(); assertTrue(concurrency == ResultSet.CONCUR_READ_ONLY || concurrency == ResultSet.CONCUR_UPDATABLE); @@ -212,8 +222,8 @@ public void testResultSetConcurrencyAndType(String driverClass, String url, Stri @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testBatchExecution(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBatchExecution(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.addBatch("INSERT INTO oracle_statement_test (id, name) VALUES (3, 'Charlie')"); statement.addBatch("INSERT INTO oracle_statement_test (id, name) VALUES (4, 'David')"); int[] results = statement.executeBatch(); @@ -227,8 +237,8 @@ public void testBatchExecution(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testClearBatch(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testClearBatch(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.addBatch("INSERT INTO oracle_statement_test (id, name) VALUES (5, 'Eve')"); statement.clearBatch(); int[] results = statement.executeBatch(); @@ -237,23 +247,23 @@ public void testClearBatch(String driverClass, String url, String user, String p @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testGetConnection(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetConnection(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); assertSame(connection, statement.getConnection()); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testGetMoreResultsWithCurrent(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetMoreResultsWithCurrent(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.execute("SELECT * FROM oracle_statement_test"); assertFalse(statement.getMoreResults(Statement.CLOSE_CURRENT_RESULT)); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testGeneratedKeys(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGeneratedKeys(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); TestDBUtils.createAutoIncrementTestTable(connection, "test_auto_keys", TestDBUtils.SqlSyntax.ORACLE); int affected = statement.executeUpdate("INSERT INTO test_auto_keys (name) VALUES ('foo')", @@ -267,8 +277,8 @@ public void testGeneratedKeys(String driverClass, String url, String user, Strin @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testExecuteUpdateVariants(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteUpdateVariants(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); TestDBUtils.createAutoIncrementTestTable(connection, "test_cols", TestDBUtils.SqlSyntax.ORACLE); @@ -287,8 +297,8 @@ public void testExecuteUpdateVariants(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testExecuteVariants(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteVariants(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); TestDBUtils.createAutoIncrementTestTable(connection, "test_exec", TestDBUtils.SqlSyntax.ORACLE); boolean b = statement.execute("INSERT INTO test_exec (name) VALUES ('v1')", Statement.RETURN_GENERATED_KEYS); @@ -306,16 +316,16 @@ public void testExecuteVariants(String driverClass, String url, String user, Str @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testGetResultSetHoldability(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetResultSetHoldability(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int holdability = statement.getResultSetHoldability(); assertTrue(holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT || holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testPoolable(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testPoolable(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.setPoolable(true); // Oracle behavior: supports statement pooling boolean isPoolable = statement.isPoolable(); @@ -327,16 +337,16 @@ public void testPoolable(String driverClass, String url, String user, String pas @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testCloseOnCompletion(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testCloseOnCompletion(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.closeOnCompletion(); assertTrue(statement.isCloseOnCompletion()); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testLargeMethodsDefault(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testLargeMethodsDefault(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.getFetchDirection(); statement.execute("INSERT INTO oracle_statement_test (id, name) VALUES (3, 'Juca Bala')"); // Oracle drivers support large methods @@ -354,16 +364,16 @@ public void testLargeMethodsDefault(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testEnquoteLiteral(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testEnquoteLiteral(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); String quoted = statement.enquoteLiteral("foo'bar"); assertEquals("'foo''bar'", quoted); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testEnquoteIdentifier(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testEnquoteIdentifier(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Oracle quotes identifiers to preserve case sensitivity String quoted = statement.enquoteIdentifier("abc", true); assertNotNull(quoted); @@ -373,8 +383,8 @@ public void testEnquoteIdentifier(String driverClass, String url, String user, S @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testIsSimpleIdentifier(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testIsSimpleIdentifier(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Oracle has specific rules for simple identifiers boolean result1 = statement.isSimpleIdentifier("abc123"); boolean result2 = statement.isSimpleIdentifier("ab-c"); // Contains hyphen - not simple @@ -387,16 +397,16 @@ public void testIsSimpleIdentifier(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testEnquoteNCharLiteral(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testEnquoteNCharLiteral(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); String quoted = statement.enquoteNCharLiteral("foo'bar"); assertEquals("N'foo''bar'", quoted); } @ParameterizedTest @CsvFileSource(resources = "/oracle_connections.csv") - public void testOracleSpecificFeatures(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testOracleSpecificFeatures(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Test Oracle-specific SQL features statement.execute("CREATE OR REPLACE VIEW oracle_test_view AS SELECT * FROM oracle_statement_test"); diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresCallableStatementTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresCallableStatementTests.java index b746394f4..69587c837 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresCallableStatementTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresCallableStatementTests.java @@ -10,6 +10,8 @@ import java.sql.Connection; import java.sql.Date; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -32,6 +34,9 @@ public class PostgresCallableStatementTests { private static boolean isTestEnabled; + private ConnectionResult connectionResult; + + private Connection connection; private CallableStatement callableStatement; @@ -40,11 +45,17 @@ public static void checkTestConfiguration() { isTestEnabled = Boolean.parseBoolean(System.getProperty("enablePostgresTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(!isTestEnabled, "Postgres tests are disabled"); // Connect to the PostgreSQL database - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } // Ensure the employee table and stored procedures exist try (Statement stmt = connection.createStatement()) { @@ -85,13 +96,15 @@ public void setUp(String driverClass, String url, String user, String password) @AfterEach public void tearDown() throws Exception { if (callableStatement != null) callableStatement.close(); - if (connection != null) connection.close(); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testExecuteProcedure(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteProcedure(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); callableStatement = connection.prepareCall("CALL update_salary(?, ?, ?)"); callableStatement.setInt(1, 1); callableStatement.setBigDecimal(2, new BigDecimal("60000")); @@ -120,8 +133,8 @@ public void testExecuteProcedure(String driverClass, String url, String user, St @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testDateTimeParameters(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testDateTimeParameters(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); callableStatement = connection.prepareCall("CALL update_employee_dates(?, ?, ?, ?, ?, ?, ?)"); int empId = 1; Date newDate = Date.valueOf(LocalDate.of(2024, 6, 27)); @@ -160,8 +173,8 @@ public void testDateTimeParameters(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testSetAndGetStringAndBoolean(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testSetAndGetStringAndBoolean(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Add an employee with a boolean flag using the name column as a boolean string try (Statement stmt = connection.createStatement()) { @@ -190,8 +203,8 @@ public void testSetAndGetStringAndBoolean(String driverClass, String url, String @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testSetObjectAndGetObject(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testSetObjectAndGetObject(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); callableStatement = connection.prepareCall("CALL update_salary(?, ?, ?)"); callableStatement.setObject(1, 1, Types.INTEGER); callableStatement.setObject(2, new BigDecimal("70000.00"), Types.NUMERIC); @@ -209,8 +222,8 @@ public void testSetObjectAndGetObject(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testInvalidParameterIndex(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testInvalidParameterIndex(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // This test will intentionally fail due to an invalid parameter index assertThrows(SQLException.class, () -> { callableStatement = connection.prepareCall("{ CALL update_salary(?, ?, ?) }"); diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests$1.class b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests$1.class new file mode 100644 index 000000000..e6bcd1425 Binary files /dev/null and b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests$1.class differ diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests.class b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests.class new file mode 100644 index 000000000..346d81804 Binary files /dev/null and b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests.class differ diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests.java index fd4030327..2b72a7f8a 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresConnectionExtensiveTests.java @@ -3,6 +3,7 @@ import io.grpc.StatusRuntimeException; import lombok.SneakyThrows; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -39,6 +40,8 @@ public class PostgresConnectionExtensiveTests { private static boolean isTestEnabled; + private ConnectionResult connectionResult; + private Connection connection; @BeforeAll @@ -47,20 +50,28 @@ public static void checkTestConfiguration() { } @SneakyThrows - public void setUp(String driverClass, String url, String user, String password) throws SQLException { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { assumeFalse(!isTestEnabled, "Postgres tests are disabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } } @AfterEach public void tearDown() throws SQLException { - TestDBUtils.closeQuietly(connection); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testConnectionProperties(String driverClass, String url, String user, String password) throws SQLException { - this.setUp(driverClass, url, user, password); + public void testConnectionProperties(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + this.setUp(driverClass, url, user, password, isXA); assertEquals(false, connection.isClosed()); assertEquals(true, connection.isValid(5)); assertNotNull(connection.getSchema()); // PostgreSQL should return current schema @@ -69,9 +80,15 @@ public void testConnectionProperties(String driverClass, String url, String user @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testAutoCommitAndTransactionIsolation(String driverClass, String url, String user, String password) throws SQLException { - this.setUp(driverClass, url, user, password); - assertEquals(true, connection.getAutoCommit()); + public void testAutoCommitAndTransactionIsolation(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + this.setUp(driverClass, url, user, password, isXA); + + // XA connections have autocommit set to false by createConnection() + // Non-XA connections have autocommit set to false by setUp() + // Both should have autocommit=false after setUp() + assertEquals(false, connection.getAutoCommit()); + + // Verify we can set it (even though it's already false) connection.setAutoCommit(false); assertEquals(false, connection.getAutoCommit()); @@ -84,38 +101,44 @@ public void testAutoCommitAndTransactionIsolation(String driverClass, String url @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testCommitAndRollback(String driverClass, String url, String user, String password) throws SQLException { - this.setUp(driverClass, url, user, password); + public void testCommitAndRollback(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + this.setUp(driverClass, url, user, password, isXA); // PostgreSQL DDL statements are transactional, so we need to create and commit the table first TestDBUtils.createBasicTestTable(connection, "postgres_connection_test", TestDBUtils.SqlSyntax.POSTGRES, true); - connection.commit(); // Ensure table creation is committed + connectionResult.commit(); // Ensure table creation is committed using ConnectionResult - connection.setAutoCommit(false); + // Start new transaction for DML + connectionResult.startXATransactionIfNeeded(); connection.createStatement().execute("INSERT INTO postgres_connection_test (id, name) VALUES (3, 'Charlie')"); - connection.rollback(); + connectionResult.rollback(); + // Start new transaction for query + connectionResult.startXATransactionIfNeeded(); ResultSet rs = connection.createStatement().executeQuery("SELECT * FROM postgres_connection_test WHERE id = 3"); assertEquals(false, rs.next()); connection.createStatement().execute("INSERT INTO postgres_connection_test (id, name) VALUES (3, 'Charlie')"); - connection.commit(); + connectionResult.commit(); + // Start new transaction for query + connectionResult.startXATransactionIfNeeded(); rs = connection.createStatement().executeQuery("SELECT * FROM postgres_connection_test WHERE id = 3"); assertEquals(true, rs.next()); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testSavepoints(String driverClass, String url, String user, String password) throws SQLException { - this.setUp(driverClass, url, user, password); + public void testSavepoints(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + this.setUp(driverClass, url, user, password, isXA); // PostgreSQL DDL statements are transactional, so we need to create and commit the table first TestDBUtils.createBasicTestTable(connection, "postgres_connection_test", TestDBUtils.SqlSyntax.POSTGRES, true); - connection.commit(); // Ensure table creation is committed + connectionResult.commit(); // Ensure table creation is committed using ConnectionResult - connection.setAutoCommit(false); + // Start new transaction for DML + connectionResult.startXATransactionIfNeeded(); Savepoint sp1 = connection.setSavepoint("Savepoint1"); connection.createStatement().execute("INSERT INTO postgres_connection_test (id, name) VALUES (3, 'Charlie')"); @@ -128,16 +151,18 @@ public void testSavepoints(String driverClass, String url, String user, String p // sp1 is no longer valid after rollback, so create a new savepoint to demonstrate release functionality Savepoint sp2 = connection.setSavepoint("Savepoint2"); connection.releaseSavepoint(sp2); - connection.commit(); + connectionResult.commit(); + // Start new transaction for query + connectionResult.startXATransactionIfNeeded(); rs = connection.createStatement().executeQuery("SELECT * FROM postgres_connection_test WHERE id = 3"); assertEquals(true, rs.next()); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testConnectionMetadata(String driverClass, String url, String user, String password) throws SQLException { - this.setUp(driverClass, url, user, password); + public void testConnectionMetadata(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData metaData = connection.getMetaData(); assertNotNull(metaData); assertEquals("PostgreSQL", metaData.getDatabaseProductName()); @@ -146,8 +171,8 @@ public void testConnectionMetadata(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testClientInfo(String driverClass, String url, String user, String password) throws SQLException { - this.setUp(driverClass, url, user, password); + public void testClientInfo(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + this.setUp(driverClass, url, user, password, isXA); // PostgreSQL supports client info try { connection.setClientInfo("ApplicationName", "TestApp"); @@ -159,8 +184,8 @@ public void testClientInfo(String driverClass, String url, String user, String p @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testClose(String driverClass, String url, String user, String password) throws SQLException { - this.setUp(driverClass, url, user, password); + public void testClose(String driverClass, String url, String user, String password, boolean isXA) throws SQLException { + this.setUp(driverClass, url, user, password, isXA); assertEquals(false, connection.isClosed()); connection.close(); assertEquals(true, connection.isClosed()); @@ -170,8 +195,8 @@ public void testClose(String driverClass, String url, String user, String passwo @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testAllConnectionMethods(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testAllConnectionMethods(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // createStatement Statement st1 = connection.createStatement(); diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresDatabaseMetaDataExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresDatabaseMetaDataExtensiveTests.java index 5fd50996d..68d54ed56 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresDatabaseMetaDataExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresDatabaseMetaDataExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvFileSource; @@ -12,6 +13,7 @@ public class PostgresDatabaseMetaDataExtensiveTests { private static boolean isTestEnabled; + private static ConnectionResult connectionResult; private static Connection connection; @BeforeAll @@ -19,22 +21,30 @@ public static void checkTestConfiguration() { isTestEnabled = Boolean.parseBoolean(System.getProperty("enablePostgresTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(!isTestEnabled, "Postgres tests are disabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } TestDBUtils.createBasicTestTable(connection, "postgres_db_metadata_test", TestDBUtils.SqlSyntax.POSTGRES, true); } @AfterAll public static void teardown() throws Exception { - TestDBUtils.closeQuietly(connection); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void allDatabaseMetaDataMethodsShouldWorkAndBeAsserted(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void allDatabaseMetaDataMethodsShouldWorkAndBeAsserted(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); DatabaseMetaData meta = connection.getMetaData(); // 1–5: Basic database information (PostgreSQL-specific values) diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresMiniStressTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresMiniStressTest.java index 98e518dda..f67073b6b 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresMiniStressTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresMiniStressTest.java @@ -10,6 +10,8 @@ import java.math.BigDecimal; import java.sql.Connection; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresMultipleTypesIntegrationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresMultipleTypesIntegrationTest.java index 268840599..7fe9f7857 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresMultipleTypesIntegrationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresMultipleTypesIntegrationTest.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.Assert; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -9,7 +10,6 @@ import java.math.BigDecimal; import java.sql.Connection; import java.sql.Date; -import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Time; @@ -30,159 +30,198 @@ public static void checkTestConfiguration() { @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void typesCoverageTestSuccessful(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException, ParseException { + public void typesCoverageTestSuccessful(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException, ParseException { assumeFalse(!isTestEnabled, "Postgres tests are disabled"); - Connection conn = DriverManager.getConnection(url, user, pwd); - - System.out.println("Testing for url -> " + url); - - TestDBUtils.createMultiTypeTestTable(conn, "postgres_multi_types_test", TestDBUtils.SqlSyntax.POSTGRES); - - java.sql.PreparedStatement psInsert = conn.prepareStatement( - "insert into postgres_multi_types_test (val_int, val_varchar, val_double_precision, val_bigint, val_tinyint, " + - "val_smallint, val_boolean, val_decimal, val_float, val_byte, val_binary, val_date, val_time, " + - "val_timestamp) " + - "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - ); - - psInsert.setInt(1, 1); - psInsert.setString(2, "TITLE_1"); - psInsert.setDouble(3, 2.2222d); - psInsert.setLong(4, 33333333333333l); - psInsert.setInt(5, 127); // PostgreSQL SMALLINT can handle this - psInsert.setInt(6, 32767); - psInsert.setBoolean(7, true); - psInsert.setBigDecimal(8, new BigDecimal(10)); - psInsert.setFloat(9, 20.20f); - psInsert.setBytes(10, new byte[]{(byte) 1}); // PostgreSQL BYTEA expects byte array - psInsert.setBytes(11, "AAAA".getBytes()); // PostgreSQL BYTEA - SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); - psInsert.setDate(12, new Date(sdf.parse("29/03/2025").getTime())); - SimpleDateFormat sdfTime = new SimpleDateFormat("hh:mm:ss"); - psInsert.setTime(13, new Time(sdfTime.parse("11:12:13").getTime())); - SimpleDateFormat sdfTimestamp = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); - psInsert.setTimestamp(14, new Timestamp(sdfTimestamp.parse("30/03/2025 21:22:23").getTime())); - psInsert.executeUpdate(); - - java.sql.PreparedStatement psSelect = conn.prepareStatement("select * from postgres_multi_types_test where val_int = ?"); - psSelect.setInt(1, 1); - ResultSet resultSet = psSelect.executeQuery(); - resultSet.next(); - Assert.assertEquals(1, resultSet.getInt(1)); - Assert.assertEquals("TITLE_1", resultSet.getString(2)); - Assert.assertEquals("2.2222", ""+resultSet.getDouble(3)); - Assert.assertEquals(33333333333333L, resultSet.getLong(4)); - Assert.assertEquals(127, resultSet.getInt(5)); // SMALLINT in PostgreSQL - Assert.assertEquals(32767, resultSet.getInt(6)); - Assert.assertEquals(true, resultSet.getBoolean(7)); - Assert.assertEquals(new BigDecimal(10), resultSet.getBigDecimal(8)); - Assert.assertEquals(20.20f+"", ""+resultSet.getFloat(9)); - // PostgreSQL BYTEA column may be returned as String by OJP driver - // For now, just verify we get a non-null value - Object byteValue = resultSet.getObject(10); - Assert.assertNotNull("BYTEA column should not be null", byteValue); - // PostgreSQL BYTEA column may be returned as String by OJP driver - Object binaryValue = resultSet.getObject(11); - if (binaryValue instanceof String) { - // If returned as string, check the content - String stringValue = (String) binaryValue; - Assert.assertTrue("Binary column should contain expected data", - stringValue.contains("AAAA") || stringValue.length() > 0); - } else { - // Handle as byte array - Assert.assertEquals("AAAA", new String(resultSet.getBytes(11))); - } - Assert.assertEquals("29/03/2025", sdf.format(resultSet.getDate(12))); - Assert.assertEquals("11:12:13", sdfTime.format(resultSet.getTime(13))); - Assert.assertEquals("30/03/2025 21:22:23", sdfTimestamp.format(resultSet.getTimestamp(14))); - - // Test column name access - Assert.assertEquals(1, resultSet.getInt("val_int")); - Assert.assertEquals("TITLE_1", resultSet.getString("val_varchar")); - Assert.assertEquals("2.2222", ""+resultSet.getDouble("val_double_precision")); - Assert.assertEquals(33333333333333L, resultSet.getLong("val_bigint")); - Assert.assertEquals(127, resultSet.getInt("val_tinyint")); - Assert.assertEquals(32767, resultSet.getInt("val_smallint")); - Assert.assertEquals(new BigDecimal(10), resultSet.getBigDecimal("val_decimal")); - Assert.assertEquals(20.20f+"", ""+resultSet.getFloat("val_float")); - Assert.assertEquals(true, resultSet.getBoolean("val_boolean")); - // PostgreSQL BYTEA column may be returned as String by OJP driver - Object byteValueByName = resultSet.getObject("val_byte"); - Assert.assertNotNull("BYTEA column val_byte should not be null", byteValueByName); - // PostgreSQL BYTEA column may be returned as String by OJP driver - Object binaryValueByName = resultSet.getObject("val_binary"); - if (binaryValueByName instanceof String) { - String stringValue = (String) binaryValueByName; - Assert.assertTrue("Binary column should contain expected data", - stringValue.contains("AAAA") || stringValue.length() > 0); - } else { - Assert.assertEquals("AAAA", new String(resultSet.getBytes("val_binary"))); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); } - Assert.assertEquals("29/03/2025", sdf.format(resultSet.getDate("val_date"))); - Assert.assertEquals("11:12:13", sdfTime.format(resultSet.getTime("val_time"))); - Assert.assertEquals("30/03/2025 21:22:23", sdfTimestamp.format(resultSet.getTimestamp("val_timestamp"))); - - TestDBUtils.executeUpdate(conn, "delete from postgres_multi_types_test where val_int=1"); - ResultSet resultSetAfterDeletion = psSelect.executeQuery(); - Assert.assertFalse(resultSetAfterDeletion.next()); - - resultSet.close(); - psSelect.close(); - conn.close(); + try { + System.out.println("Testing for url -> " + url + " (XA: " + isXA + ")"); + + connResult.startXATransactionIfNeeded(); + TestDBUtils.createMultiTypeTestTable(conn, "postgres_multi_types_test", TestDBUtils.SqlSyntax.POSTGRES); + connResult.commit(); + + connResult.startXATransactionIfNeeded(); + java.sql.PreparedStatement psInsert = conn.prepareStatement( + "insert into postgres_multi_types_test (val_int, val_varchar, val_double_precision, val_bigint, val_tinyint, " + + "val_smallint, val_boolean, val_decimal, val_float, val_byte, val_binary, val_date, val_time, " + + "val_timestamp) " + + "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + + psInsert.setInt(1, 1); + psInsert.setString(2, "TITLE_1"); + psInsert.setDouble(3, 2.2222d); + psInsert.setLong(4, 33333333333333l); + psInsert.setInt(5, 127); // PostgreSQL SMALLINT can handle this + psInsert.setInt(6, 32767); + psInsert.setBoolean(7, true); + psInsert.setBigDecimal(8, new BigDecimal(10)); + psInsert.setFloat(9, 20.20f); + psInsert.setBytes(10, new byte[]{(byte) 1}); // PostgreSQL BYTEA expects byte array + psInsert.setBytes(11, "AAAA".getBytes()); // PostgreSQL BYTEA + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); + psInsert.setDate(12, new Date(sdf.parse("29/03/2025").getTime())); + SimpleDateFormat sdfTime = new SimpleDateFormat("hh:mm:ss"); + psInsert.setTime(13, new Time(sdfTime.parse("11:12:13").getTime())); + SimpleDateFormat sdfTimestamp = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); + psInsert.setTimestamp(14, new Timestamp(sdfTimestamp.parse("30/03/2025 21:22:23").getTime())); + psInsert.executeUpdate(); + connResult.commit(); + + connResult.startXATransactionIfNeeded(); + java.sql.PreparedStatement psSelect = conn.prepareStatement("select * from postgres_multi_types_test where val_int = ?"); + psSelect.setInt(1, 1); + ResultSet resultSet = psSelect.executeQuery(); + resultSet.next(); + Assert.assertEquals(1, resultSet.getInt(1)); + Assert.assertEquals("TITLE_1", resultSet.getString(2)); + Assert.assertEquals("2.2222", ""+resultSet.getDouble(3)); + Assert.assertEquals(33333333333333L, resultSet.getLong(4)); + Assert.assertEquals(127, resultSet.getInt(5)); // SMALLINT in PostgreSQL + Assert.assertEquals(32767, resultSet.getInt(6)); + Assert.assertEquals(true, resultSet.getBoolean(7)); + Assert.assertEquals(new BigDecimal(10), resultSet.getBigDecimal(8)); + Assert.assertEquals(20.20f+"", ""+resultSet.getFloat(9)); + // PostgreSQL BYTEA column may be returned as String by OJP driver + // For now, just verify we get a non-null value + Object byteValue = resultSet.getObject(10); + Assert.assertNotNull("BYTEA column should not be null", byteValue); + // PostgreSQL BYTEA column may be returned as String by OJP driver + Object binaryValue = resultSet.getObject(11); + if (binaryValue instanceof String) { + // If returned as string, check the content + String stringValue = (String) binaryValue; + Assert.assertTrue("Binary column should contain expected data", + stringValue.contains("AAAA") || stringValue.length() > 0); + } else { + // Handle as byte array + Assert.assertEquals("AAAA", new String(resultSet.getBytes(11))); + } + Assert.assertEquals("29/03/2025", sdf.format(resultSet.getDate(12))); + Assert.assertEquals("11:12:13", sdfTime.format(resultSet.getTime(13))); + Assert.assertEquals("30/03/2025 21:22:23", sdfTimestamp.format(resultSet.getTimestamp(14))); + + // Test column name access + Assert.assertEquals(1, resultSet.getInt("val_int")); + Assert.assertEquals("TITLE_1", resultSet.getString("val_varchar")); + Assert.assertEquals("2.2222", ""+resultSet.getDouble("val_double_precision")); + Assert.assertEquals(33333333333333L, resultSet.getLong("val_bigint")); + Assert.assertEquals(127, resultSet.getInt("val_tinyint")); + Assert.assertEquals(32767, resultSet.getInt("val_smallint")); + Assert.assertEquals(new BigDecimal(10), resultSet.getBigDecimal("val_decimal")); + Assert.assertEquals(20.20f+"", ""+resultSet.getFloat("val_float")); + Assert.assertEquals(true, resultSet.getBoolean("val_boolean")); + // PostgreSQL BYTEA column may be returned as String by OJP driver + Object byteValueByName = resultSet.getObject("val_byte"); + Assert.assertNotNull("BYTEA column val_byte should not be null", byteValueByName); + // PostgreSQL BYTEA column may be returned as String by OJP driver + Object binaryValueByName = resultSet.getObject("val_binary"); + if (binaryValueByName instanceof String) { + String stringValue = (String) binaryValueByName; + Assert.assertTrue("Binary column should contain expected data", + stringValue.contains("AAAA") || stringValue.length() > 0); + } else { + Assert.assertEquals("AAAA", new String(resultSet.getBytes("val_binary"))); + } + Assert.assertEquals("29/03/2025", sdf.format(resultSet.getDate("val_date"))); + Assert.assertEquals("11:12:13", sdfTime.format(resultSet.getTime("val_time"))); + Assert.assertEquals("30/03/2025 21:22:23", sdfTimestamp.format(resultSet.getTimestamp("val_timestamp"))); + connResult.commit(); + + connResult.startXATransactionIfNeeded(); + TestDBUtils.executeUpdate(conn, "delete from postgres_multi_types_test where val_int=1"); + connResult.commit(); + + connResult.startXATransactionIfNeeded(); + ResultSet resultSetAfterDeletion = psSelect.executeQuery(); + Assert.assertFalse(resultSetAfterDeletion.next()); + + resultSet.close(); + psSelect.close(); + } finally { + connResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testPostgresSpecificTypes(String driverClass, String url, String user, String pwd) throws SQLException, ClassNotFoundException { + public void testPostgresSpecificTypes(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException, ClassNotFoundException { assumeFalse(!isTestEnabled, "Postgres tests are disabled"); - Connection conn = DriverManager.getConnection(url, user, pwd); - - System.out.println("Testing PostgreSQL-specific types for url -> " + url); + ConnectionResult connResult = TestDBUtils.createConnection(url, user, pwd, isXA); + Connection conn = connResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + conn.setAutoCommit(false); + } - // Test UUID, JSON, and array types (PostgreSQL-specific) try { - TestDBUtils.executeUpdate(conn, "DROP TABLE test_postgres_types"); - } catch (Exception e) { - // Ignore if table doesn't exist + System.out.println("Testing PostgreSQL-specific types for url -> " + url + " (XA: " + isXA + ")"); + + // Test UUID, JSON, and array types (PostgreSQL-specific) + try { + connResult.startXATransactionIfNeeded(); + TestDBUtils.executeUpdate(conn, "DROP TABLE test_postgres_types"); + connResult.commit(); + } catch (Exception e) { + // Ignore if table doesn't exist + try { + connResult.rollback(); + } catch (Exception ex) { + // Ignore + } + } + + connResult.startXATransactionIfNeeded(); + TestDBUtils.executeUpdate(conn, + "CREATE TABLE test_postgres_types (" + + "id SERIAL PRIMARY KEY, " + + "uuid_col UUID, " + + "json_col JSON, " + + "array_col INTEGER[], " + + "text_col TEXT)" + ); + connResult.commit(); + + connResult.startXATransactionIfNeeded(); + java.sql.PreparedStatement psInsert = conn.prepareStatement( + "INSERT INTO test_postgres_types (uuid_col, json_col, array_col, text_col) VALUES (?, ?::json, ?::integer[], ?)" + ); + + // Test UUID + psInsert.setObject(1, java.util.UUID.randomUUID()); + // Test JSON + psInsert.setString(2, "{\"key\": \"value\"}"); + // Test Array - OJP driver currently doesn't support Array serialization, so use string representation + psInsert.setString(3, "{1,2,3}"); // PostgreSQL array literal format + // Test TEXT + psInsert.setString(4, "PostgreSQL text type"); + + psInsert.executeUpdate(); + connResult.commit(); + + connResult.startXATransactionIfNeeded(); + java.sql.PreparedStatement psSelect = conn.prepareStatement("SELECT text_col FROM test_postgres_types WHERE id = 1"); + ResultSet resultSet = psSelect.executeQuery(); + + Assert.assertTrue(resultSet.next()); + Assert.assertEquals("PostgreSQL text type", resultSet.getString("text_col")); + + resultSet.close(); + psSelect.close(); + psInsert.close(); + } finally { + connResult.close(); } - - TestDBUtils.executeUpdate(conn, - "CREATE TABLE test_postgres_types (" + - "id SERIAL PRIMARY KEY, " + - "uuid_col UUID, " + - "json_col JSON, " + - "array_col INTEGER[], " + - "text_col TEXT)" - ); - - java.sql.PreparedStatement psInsert = conn.prepareStatement( - "INSERT INTO test_postgres_types (uuid_col, json_col, array_col, text_col) VALUES (?, ?::json, ?::integer[], ?)" - ); - - // Test UUID - psInsert.setObject(1, java.util.UUID.randomUUID()); - // Test JSON - psInsert.setString(2, "{\"key\": \"value\"}"); - // Test Array - OJP driver currently doesn't support Array serialization, so use string representation - psInsert.setString(3, "{1,2,3}"); // PostgreSQL array literal format - // Test TEXT - psInsert.setString(4, "PostgreSQL text type"); - - psInsert.executeUpdate(); - - java.sql.PreparedStatement psSelect = conn.prepareStatement("SELECT text_col FROM test_postgres_types WHERE id = 1"); - ResultSet resultSet = psSelect.executeQuery(); - - Assert.assertTrue(resultSet.next()); - Assert.assertEquals("PostgreSQL text type", resultSet.getString("text_col")); - - resultSet.close(); - psSelect.close(); - psInsert.close(); - conn.close(); } /** diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresPreparedStatementExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresPreparedStatementExtensiveTests.java index be8b3501b..4c2812d5e 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresPreparedStatementExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresPreparedStatementExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -33,6 +34,9 @@ public class PostgresPreparedStatementExtensiveTests { private static boolean isTestEnabled; + private ConnectionResult connectionResult; + + private Connection connection; private PreparedStatement ps; @@ -41,10 +45,16 @@ public static void checkTestConfiguration() { isTestEnabled = Boolean.parseBoolean(System.getProperty("enablePostgresTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(!isTestEnabled, "Postgres tests are disabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } Statement stmt = connection.createStatement(); try { stmt.execute("DROP TABLE postgres_prepared_stmt_test"); @@ -58,6 +68,10 @@ public void setUp(String driverClass, String url, String user, String password) "info TEXT, " + // PostgreSQL equivalent of CLOB "dt DATE)"); stmt.close(); + + // Commit DDL and start new transaction for DML + connectionResult.commit(); + connectionResult.startXATransactionIfNeeded(); } @AfterEach @@ -67,8 +81,8 @@ public void tearDown() throws Exception { @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testBasicParameterSetting(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBasicParameterSetting(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO postgres_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); ps.setInt(1, 1); @@ -92,8 +106,8 @@ public void testBasicParameterSetting(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testNullParameterHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testNullParameterHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO postgres_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); ps.setInt(1, 2); @@ -120,8 +134,8 @@ public void testNullParameterHandling(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testNumericParameterTypes(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testNumericParameterTypes(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Test BigDecimal Statement stmt = connection.createStatement(); @@ -148,8 +162,8 @@ public void testNumericParameterTypes(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testDateTimeParameterTypes(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testDateTimeParameterTypes(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO postgres_prepared_stmt_test (id, name, dt) VALUES (?, ?, ?)"); java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis()); @@ -173,8 +187,8 @@ public void testDateTimeParameterTypes(String driverClass, String url, String us @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testLargeObjectHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testLargeObjectHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO postgres_prepared_stmt_test (id, name, data, info) VALUES (?, ?, ?, ?)"); byte[] testData = "This is test binary data".getBytes(); @@ -203,8 +217,8 @@ public void testLargeObjectHandling(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testStreamHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testStreamHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO postgres_prepared_stmt_test (id, name, data, info) VALUES (?, ?, ?, ?)"); byte[] testData = "Stream binary data".getBytes(); @@ -223,8 +237,8 @@ public void testStreamHandling(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testParameterMetaData(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testParameterMetaData(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO postgres_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); // Basic parameter metadata operations @@ -236,8 +250,8 @@ public void testParameterMetaData(String driverClass, String url, String user, S @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testBatchOperations(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBatchOperations(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO postgres_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); // Add multiple batches @@ -264,8 +278,8 @@ public void testBatchOperations(String driverClass, String url, String user, Str @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testResultSetHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testResultSetHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Insert test data first ps = connection.prepareStatement("INSERT INTO postgres_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); @@ -294,8 +308,8 @@ public void testResultSetHandling(String driverClass, String url, String user, S @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testErrorHandling(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testErrorHandling(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ps = connection.prepareStatement("INSERT INTO postgres_prepared_stmt_test (id, name, age) VALUES (?, ?, ?)"); // Test setting invalid parameter index - PostgreSQL may allow this without immediate error diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresSavepointTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresSavepointTests.java index 716037d73..ab54a1b6e 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresSavepointTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresSavepointTests.java @@ -1,13 +1,14 @@ package openjproxy.jdbc; import lombok.SneakyThrows; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvFileSource; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Savepoint; @@ -19,6 +20,7 @@ public class PostgresSavepointTests { private static boolean isTestEnabled; + private ConnectionResult connectionResult; private Connection connection; @BeforeAll @@ -27,34 +29,56 @@ public static void checkTestConfiguration() { } @SneakyThrows - public void setUp(String driverClass, String url, String user, String pwd) throws SQLException { + public void setUp(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { assumeFalse(!isTestEnabled, "PostgreSQL tests are disabled"); - connection = DriverManager.getConnection(url, user, pwd); - connection.setAutoCommit(false); + connectionResult = TestDBUtils.createConnection(url, user, pwd, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false + if (!isXA) { + connection.setAutoCommit(false); + } + connection.createStatement().execute( "DROP TABLE IF EXISTS savepoint_test_table" ); + connectionResult.commit(); + + // Start new transaction for table creation + connectionResult.startXATransactionIfNeeded(); connection.createStatement().execute( "CREATE TABLE savepoint_test_table (id INT PRIMARY KEY, name VARCHAR(255))" ); + connectionResult.commit(); } @AfterEach public void tearDown() throws Exception { - if (connection != null) connection.close(); + if (connectionResult != null) { + connectionResult.close(); + } } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testSavepoint(String driverClass, String url, String user, String pwd) throws SQLException { - setUp(driverClass, url, user, pwd); + public void testSavepoint(String driverClass, String url, String user, String pwd, boolean isXA) throws SQLException { + setUp(driverClass, url, user, pwd, isXA); + + // Start transaction for test + connectionResult.startXATransactionIfNeeded(); + connection.createStatement().execute("INSERT INTO savepoint_test_table (id, name) VALUES (1, 'Alice')"); Savepoint savepoint = connection.setSavepoint(); connection.createStatement().execute("INSERT INTO savepoint_test_table (id, name) VALUES (2, 'Bob')"); connection.rollback(savepoint); + // Commit the transaction to finalize the first insert + connectionResult.commit(); + + // Start new transaction for query + connectionResult.startXATransactionIfNeeded(); ResultSet resultSet = connection.createStatement().executeQuery("SELECT * FROM savepoint_test_table order by id desc"); assertTrue(resultSet.next()); assertEquals(1, resultSet.getInt("id")); diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresSlowQuerySegregationTest.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresSlowQuerySegregationTest.java index 48bf0e631..9b16cb2c3 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresSlowQuerySegregationTest.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresSlowQuerySegregationTest.java @@ -12,6 +12,8 @@ import java.math.BigDecimal; import java.sql.Connection; import java.sql.DriverManager; +import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresStatementExtensiveTests.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresStatementExtensiveTests.java index 8225086ed..116a13500 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresStatementExtensiveTests.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/PostgresStatementExtensiveTests.java @@ -1,6 +1,7 @@ package openjproxy.jdbc; import openjproxy.jdbc.testutil.TestDBUtils; +import openjproxy.jdbc.testutil.TestDBUtils.ConnectionResult; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -26,6 +27,9 @@ public class PostgresStatementExtensiveTests { private static boolean isTestEnabled; + private ConnectionResult connectionResult; + + private Connection connection; private Statement statement; @@ -34,10 +38,16 @@ public static void checkTestConfiguration() { isTestEnabled = Boolean.parseBoolean(System.getProperty("enablePostgresTests", "false")); } - public void setUp(String driverClass, String url, String user, String password) throws Exception { + public void setUp(String driverClass, String url, String user, String password, boolean isXA) throws Exception { assumeFalse(!isTestEnabled, "Postgres tests are disabled"); - connection = DriverManager.getConnection(url, user, password); + connectionResult = TestDBUtils.createConnection(url, user, password, isXA); + connection = connectionResult.getConnection(); + + // For non-XA connections, set autocommit to false for transaction control + if (!isXA) { + connection.setAutoCommit(false); + } statement = connection.createStatement(); TestDBUtils.createBasicTestTable(connection, "postgres_statement_test", TestDBUtils.SqlSyntax.POSTGRES, true); @@ -50,8 +60,8 @@ public void tearDown() throws Exception { @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testExecuteQuery(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteQuery(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); ResultSet rs = statement.executeQuery("SELECT * FROM postgres_statement_test"); assertNotNull(rs); assertTrue(rs.next()); @@ -60,8 +70,8 @@ public void testExecuteQuery(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testExecuteUpdate(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteUpdate(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int rows = statement.executeUpdate("UPDATE postgres_statement_test SET name = 'Updated Alice' WHERE id = 1"); assertEquals(1, rows); @@ -73,8 +83,8 @@ public void testExecuteUpdate(String driverClass, String url, String user, Strin @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testClose(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testClose(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); assertFalse(statement.isClosed()); statement.close(); assertTrue(statement.isClosed()); @@ -82,8 +92,8 @@ public void testClose(String driverClass, String url, String user, String passwo @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testMaxFieldSize(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testMaxFieldSize(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int orig = statement.getMaxFieldSize(); statement.setMaxFieldSize(orig + 1); // PostgreSQL behavior: may return 1 instead of 0 (different from H2) @@ -93,8 +103,8 @@ public void testMaxFieldSize(String driverClass, String url, String user, String @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testExecuteAfterCloseThrows(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteAfterCloseThrows(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.close(); assertThrows(SQLException.class, () -> statement.executeQuery("SELECT * FROM postgres_statement_test")); assertThrows(SQLException.class, () -> statement.executeUpdate("UPDATE postgres_statement_test SET name = 'fail' WHERE id = 1")); @@ -103,8 +113,8 @@ public void testExecuteAfterCloseThrows(String driverClass, String url, String u @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testMaxRows(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testMaxRows(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.setMaxRows(1); assertEquals(1, statement.getMaxRows()); ResultSet rs = statement.executeQuery("SELECT * FROM postgres_statement_test"); @@ -115,8 +125,8 @@ public void testMaxRows(String driverClass, String url, String user, String pass @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testEscapeProcessing(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testEscapeProcessing(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Should not throw statement.setEscapeProcessing(true); statement.setEscapeProcessing(false); @@ -124,40 +134,40 @@ public void testEscapeProcessing(String driverClass, String url, String user, St @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testQueryTimeout(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testQueryTimeout(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.setQueryTimeout(5); assertEquals(5, statement.getQueryTimeout()); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testCancel(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testCancel(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // Should not throw statement.cancel(); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testWarnings(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testWarnings(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.clearWarnings(); assertNull(statement.getWarnings()); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testSetCursorName(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testSetCursorName(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // No-op in most drivers; should not throw statement.setCursorName("CURSOR_A"); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testExecute(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecute(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); boolean isResultSet = statement.execute("SELECT * FROM postgres_statement_test"); assertTrue(isResultSet); ResultSet rs = statement.getResultSet(); @@ -172,8 +182,8 @@ public void testExecute(String driverClass, String url, String user, String pass @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testGetMoreResults(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetMoreResults(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.execute("SELECT * FROM postgres_statement_test"); assertFalse(statement.getMoreResults()); assertEquals(-1, statement.getUpdateCount()); @@ -181,8 +191,8 @@ public void testGetMoreResults(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testFetchDirection(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testFetchDirection(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int orig = statement.getFetchDirection(); statement.setFetchDirection(ResultSet.FETCH_FORWARD); assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); @@ -191,8 +201,8 @@ public void testFetchDirection(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testFetchSize(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testFetchSize(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int orig = statement.getFetchSize(); statement.setFetchSize(orig + 1); assertEquals(orig + 1, statement.getFetchSize()); @@ -201,8 +211,8 @@ public void testFetchSize(String driverClass, String url, String user, String pa @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testResultSetConcurrencyAndType(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testResultSetConcurrencyAndType(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int concurrency = statement.getResultSetConcurrency(); int type = statement.getResultSetType(); assertTrue(concurrency == ResultSet.CONCUR_READ_ONLY || concurrency == ResultSet.CONCUR_UPDATABLE); @@ -211,8 +221,8 @@ public void testResultSetConcurrencyAndType(String driverClass, String url, Stri @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testBatchExecution(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testBatchExecution(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.addBatch("INSERT INTO postgres_statement_test (id, name) VALUES (3, 'Charlie')"); statement.addBatch("INSERT INTO postgres_statement_test (id, name) VALUES (4, 'David')"); int[] results = statement.executeBatch(); @@ -226,8 +236,8 @@ public void testBatchExecution(String driverClass, String url, String user, Stri @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testClearBatch(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testClearBatch(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.addBatch("INSERT INTO postgres_statement_test (id, name) VALUES (5, 'Eve')"); statement.clearBatch(); int[] results = statement.executeBatch(); @@ -236,23 +246,23 @@ public void testClearBatch(String driverClass, String url, String user, String p @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testGetConnection(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetConnection(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); assertSame(connection, statement.getConnection()); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testGetMoreResultsWithCurrent(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetMoreResultsWithCurrent(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.execute("SELECT * FROM postgres_statement_test"); assertFalse(statement.getMoreResults(Statement.CLOSE_CURRENT_RESULT)); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testGeneratedKeys(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGeneratedKeys(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); TestDBUtils.createAutoIncrementTestTable(connection, "test_auto_keys", TestDBUtils.SqlSyntax.POSTGRES); int affected = statement.executeUpdate("INSERT INTO test_auto_keys (name) VALUES ('foo')", Statement.RETURN_GENERATED_KEYS); @@ -265,8 +275,8 @@ public void testGeneratedKeys(String driverClass, String url, String user, Strin @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testExecuteUpdateVariants(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteUpdateVariants(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); TestDBUtils.createAutoIncrementTestTable(connection, "test_cols", TestDBUtils.SqlSyntax.POSTGRES); @@ -293,8 +303,8 @@ public void testExecuteUpdateVariants(String driverClass, String url, String use @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testExecuteVariants(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testExecuteVariants(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); TestDBUtils.createAutoIncrementTestTable(connection, "test_exec", TestDBUtils.SqlSyntax.POSTGRES); boolean b = statement.execute("INSERT INTO test_exec (name) VALUES ('v1')", Statement.RETURN_GENERATED_KEYS); @@ -313,16 +323,16 @@ public void testExecuteVariants(String driverClass, String url, String user, Str @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testGetResultSetHoldability(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testGetResultSetHoldability(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); int holdability = statement.getResultSetHoldability(); assertTrue(holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT || holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testPoolable(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testPoolable(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.setPoolable(true); // PostgreSQL behavior: may return true (different from H2) boolean isPoolable = statement.isPoolable(); @@ -334,16 +344,16 @@ public void testPoolable(String driverClass, String url, String user, String pas @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testCloseOnCompletion(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testCloseOnCompletion(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.closeOnCompletion(); assertTrue(statement.isCloseOnCompletion()); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testLargeMethodsDefault(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testLargeMethodsDefault(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); statement.getFetchDirection(); statement.execute("INSERT INTO postgres_statement_test (id, name) VALUES (3, 'Juca Bala')"); // Most drivers will throw or return default for these methods @@ -364,16 +374,16 @@ public void testLargeMethodsDefault(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testEnquoteLiteral(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testEnquoteLiteral(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); String quoted = statement.enquoteLiteral("foo'bar"); assertEquals("'foo''bar'", quoted); } @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testEnquoteIdentifier(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testEnquoteIdentifier(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // PostgreSQL may not quote identifiers the same way as H2 String quoted = statement.enquoteIdentifier("abc", false); assertNotNull(quoted); @@ -383,8 +393,8 @@ public void testEnquoteIdentifier(String driverClass, String url, String user, S @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testIsSimpleIdentifier(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testIsSimpleIdentifier(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); // PostgreSQL may have different rules for simple identifiers // Just verify the method doesn't throw an exception boolean result1 = statement.isSimpleIdentifier("abc123"); @@ -398,8 +408,8 @@ public void testIsSimpleIdentifier(String driverClass, String url, String user, @ParameterizedTest @CsvFileSource(resources = "/postgres_connection.csv") - public void testEnquoteNCharLiteral(String driverClass, String url, String user, String password) throws Exception { - this.setUp(driverClass, url, user, password); + public void testEnquoteNCharLiteral(String driverClass, String url, String user, String password, boolean isXA) throws Exception { + this.setUp(driverClass, url, user, password, isXA); String quoted = statement.enquoteNCharLiteral("foo'bar"); assertEquals("N'foo''bar'", quoted); } diff --git a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/testutil/TestDBUtils.java b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/testutil/TestDBUtils.java index bd637cdcb..ac59465a2 100644 --- a/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/testutil/TestDBUtils.java +++ b/ojp-jdbc-driver/src/test/java/openjproxy/jdbc/testutil/TestDBUtils.java @@ -212,9 +212,9 @@ public static ConnectionResult createConnection(String url, String user, String XAConnection xaConnection = xaDataSource.getXAConnection(user, password); Connection connection = xaConnection.getConnection(); ConnectionResult result = new ConnectionResult(connection, xaConnection); - // For XA connections, set autocommit to false and start transaction immediately + // For XA connections, set autocommit to false but DON'T start transaction yet + // Tests must call startXATransactionIfNeeded() AFTER DDL to avoid MySQL/MariaDB XAER_RMFAIL errors connection.setAutoCommit(false); - result.startXATransactionIfNeeded(); return result; } else { Connection connection = DriverManager.getConnection(url, user, password); diff --git a/ojp-jdbc-driver/src/test/resources/h2_mysql_mariadb_oracle_connections.csv b/ojp-jdbc-driver/src/test/resources/h2_mysql_mariadb_oracle_connections.csv index 009564e39..52e8cc5b8 100644 --- a/ojp-jdbc-driver/src/test/resources/h2_mysql_mariadb_oracle_connections.csv +++ b/ojp-jdbc-driver/src/test/resources/h2_mysql_mariadb_oracle_connections.csv @@ -1,4 +1,7 @@ -org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_h2:~/test,sa, -org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mysql://localhost:3306/defaultdb,testuser,testpassword -org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mariadb://localhost:3307/defaultdb,testuser,testpassword -org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword \ No newline at end of file +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_h2:~/test,sa,,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mysql://localhost:3306/defaultdb,testuser,testpassword,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mysql://localhost:3306/defaultdb,testuser,testpassword,true +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mariadb://localhost:3307/defaultdb,testuser,testpassword,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mariadb://localhost:3307/defaultdb,testuser,testpassword,true +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/resources/mysql_mariadb_connection.csv b/ojp-jdbc-driver/src/test/resources/mysql_mariadb_connection.csv index 8bda7086d..cb9b1e256 100644 --- a/ojp-jdbc-driver/src/test/resources/mysql_mariadb_connection.csv +++ b/ojp-jdbc-driver/src/test/resources/mysql_mariadb_connection.csv @@ -1,2 +1,4 @@ org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mysql://localhost:3306/defaultdb,testuser,testpassword,false -org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mariadb://localhost:3307/defaultdb,testuser,testpassword,false \ No newline at end of file +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mysql://localhost:3306/defaultdb,testuser,testpassword,true +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mariadb://localhost:3307/defaultdb,testuser,testpassword,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_mariadb://localhost:3307/defaultdb,testuser,testpassword,true \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/resources/oracle_connections.csv b/ojp-jdbc-driver/src/test/resources/oracle_connections.csv index d124daff7..668800e9a 100644 --- a/ojp-jdbc-driver/src/test/resources/oracle_connections.csv +++ b/ojp-jdbc-driver/src/test/resources/oracle_connections.csv @@ -1 +1,2 @@ -org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true diff --git a/ojp-jdbc-driver/src/test/resources/oracle_connections_with_record_counts.csv b/ojp-jdbc-driver/src/test/resources/oracle_connections_with_record_counts.csv index 9b5c886a8..111c235ac 100644 --- a/ojp-jdbc-driver/src/test/resources/oracle_connections_with_record_counts.csv +++ b/ojp-jdbc-driver/src/test/resources/oracle_connections_with_record_counts.csv @@ -1,6 +1,12 @@ -1,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -99,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -100,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -101,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -1000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword -10000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword \ No newline at end of file +1,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +99,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +100,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +101,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +1000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +10000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,false +1,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +99,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +100,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +101,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +1000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true +10000,org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword,true \ No newline at end of file diff --git a/ojp-jdbc-driver/src/test/resources/postgres_connection.csv b/ojp-jdbc-driver/src/test/resources/postgres_connection.csv index 43abe5cb7..6f0dd4b5b 100644 --- a/ojp-jdbc-driver/src/test/resources/postgres_connection.csv +++ b/ojp-jdbc-driver/src/test/resources/postgres_connection.csv @@ -1 +1,2 @@ -org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword,false \ No newline at end of file +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword,false +org.openjproxy.jdbc.Driver,jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword,true \ No newline at end of file