|
21 | 21 | import org.firebirdsql.common.FBTestProperties; |
22 | 22 | import org.firebirdsql.common.extension.UsesDatabaseExtension; |
23 | 23 | import org.firebirdsql.gds.impl.GDSServerVersion; |
| 24 | +import org.firebirdsql.gds.ng.AbstractFbAttachment; |
| 25 | +import org.firebirdsql.gds.ng.listeners.ExceptionListenerDispatcher; |
24 | 26 | import org.firebirdsql.jaybird.xca.XidImpl; |
25 | 27 | import org.firebirdsql.jdbc.FirebirdConnection; |
26 | 28 | import org.firebirdsql.jdbc.SQLStateConstants; |
| 29 | +import org.jspecify.annotations.Nullable; |
27 | 30 | import org.junit.jupiter.api.AfterEach; |
28 | 31 | import org.junit.jupiter.api.Test; |
29 | 32 | import org.junit.jupiter.api.extension.RegisterExtension; |
| 33 | +import org.junit.jupiter.params.ParameterizedTest; |
| 34 | +import org.junit.jupiter.params.provider.CsvSource; |
30 | 35 |
|
31 | 36 | import javax.sql.XAConnection; |
32 | 37 | import javax.transaction.xa.XAResource; |
33 | 38 | import javax.transaction.xa.Xid; |
| 39 | +import java.lang.invoke.MethodHandles; |
34 | 40 | import java.sql.*; |
35 | 41 | import java.util.ArrayList; |
36 | 42 | import java.util.List; |
37 | 43 |
|
38 | 44 | import static org.firebirdsql.common.FBTestProperties.*; |
39 | 45 | import static org.firebirdsql.common.JdbcResourceHelper.closeQuietly; |
| 46 | +import static org.firebirdsql.common.SystemPropertyHelper.withTemporarySystemProperty; |
40 | 47 | import static org.firebirdsql.common.matchers.GdsTypeMatchers.isPureJavaType; |
41 | 48 | import static org.firebirdsql.common.matchers.MatcherAssume.assumeThat; |
42 | 49 | import static org.firebirdsql.common.matchers.SQLExceptionMatchers.sqlStateEquals; |
| 50 | +import static org.firebirdsql.gds.JaybirdSystemProperties.XA_CONNECTION_FORCE_CLOSE_FATAL; |
43 | 51 | import static org.hamcrest.MatcherAssert.assertThat; |
44 | 52 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; |
45 | 53 | import static org.junit.jupiter.api.Assertions.assertEquals; |
@@ -282,4 +290,34 @@ void enableWireCompression() throws Exception { |
282 | 290 | } |
283 | 291 | } |
284 | 292 |
|
| 293 | + @ParameterizedTest |
| 294 | + @CsvSource(useHeadersInDisplayName = true, nullValues = { "NIL" }, textBlock = """ |
| 295 | + propertyValue, expectForceClose |
| 296 | + NIL, true |
| 297 | + true, true |
| 298 | + '', true |
| 299 | + false, false |
| 300 | + garbage, false |
| 301 | + """) |
| 302 | + void systemPropertyXaConnectionForceCloseOnFatal(@Nullable String propertyValue, boolean expectForceClose) |
| 303 | + throws Exception { |
| 304 | + var lookup = MethodHandles.privateLookupIn(AbstractFbAttachment.class, MethodHandles.lookup()) |
| 305 | + .findVarHandle(AbstractFbAttachment.class, "exceptionListenerDispatcher", ExceptionListenerDispatcher.class); |
| 306 | + XAConnection xaConnection = getXAConnection(); |
| 307 | + try (var ignored = withTemporarySystemProperty(XA_CONNECTION_FORCE_CLOSE_FATAL, propertyValue); |
| 308 | + var connection = xaConnection.getConnection().unwrap(FirebirdConnection.class)) { |
| 309 | + AbstractFbAttachment<?> db = (AbstractFbAttachment<?>) connection.getFbDatabase(); |
| 310 | + ExceptionListenerDispatcher eld = (ExceptionListenerDispatcher) lookup.get(db); |
| 311 | + |
| 312 | + assertFalse(connection.isClosed(), "Expected open connection before sending fatal exception"); |
| 313 | + |
| 314 | + eld.errorOccurred(new SQLException("Test fatal exception", SQLStateConstants.SQL_STATE_CONNECTION_FAILURE)); |
| 315 | + |
| 316 | + assertEquals(expectForceClose, connection.isClosed(), |
| 317 | + "Unexpected Connection#isClosed() value after sending fatal exception"); |
| 318 | + assertEquals(!expectForceClose, db.isAttached(), |
| 319 | + "Unexpected FbDatabase#isAttached() value after sending fatal exception"); |
| 320 | + } |
| 321 | + } |
| 322 | + |
285 | 323 | } |
0 commit comments