diff --git a/jdo/identity/pom.xml b/jdo/identity/pom.xml index e6e8ec4c..8dd7fc88 100644 --- a/jdo/identity/pom.xml +++ b/jdo/identity/pom.xml @@ -26,6 +26,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs datanucleus-api-jdo [${api.jdo.min.version}, ${api.jdo.max.version}) + + com.github.zabetak + jdbc-faulty + 2.0 + diff --git a/jdo/identity/src/test/org/datanucleus/tests/ValueGeneratorRandomFailureTest.java b/jdo/identity/src/test/org/datanucleus/tests/ValueGeneratorRandomFailureTest.java new file mode 100644 index 00000000..b59748f7 --- /dev/null +++ b/jdo/identity/src/test/org/datanucleus/tests/ValueGeneratorRandomFailureTest.java @@ -0,0 +1,101 @@ +/********************************************************************** +Copyright (c) 2004 Andy Jefferson and others. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Contributors : + 2025 Stamatis Zampetakis - Test reproducing a connection leak when failures occur during value generation +***********************************************************************/ +package org.datanucleus.tests; + +import com.github.zabetak.jdbc.faulty.ExceptionFault; +import com.github.zabetak.jdbc.faulty.FaultyJDBCDriver; +import org.datanucleus.samples.valuegeneration.TableGeneratorItem; + +import javax.jdo.PersistenceManager; +import javax.jdo.Transaction; +import java.util.Properties; + +/** + * Test value generators in the presence of random failures when calling {@link java.sql.Connection} methods. + */ +public class ValueGeneratorRandomFailureTest extends JDOPersistenceTestCase +{ + private static Properties userProperties() { + Properties factoryProperties = TestHelper.getFactoryProperties(1, null); + String url = factoryProperties.getProperty("datanucleus.ConnectionURL"); + // Add the faulty proxy in front of the regular JDBC driver + String faultyURL = url.replace("jdbc", "jdbc:faulty"); + Properties userProps = new Properties(); + userProps.put("datanucleus.connectionURL", faultyURL); + return userProps; + } + + public ValueGeneratorRandomFailureTest(String name) { + super(name, userProperties()); + } + + /** + * In normal circumstances, the test should finish normally even though there are some occasional errors during + * commit. Due to the connection leak, the test currently fails (most often with lock timeout exceptions). + */ + public void testTableGeneratorWithFailureOnCommitFinishesWithoutErrors() + { + try { + for (int i = 0; i < 100; i++) { + PersistenceManager pm = pmf.getPersistenceManager(); + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + // Generate a random exception on 10% of the calls to Connection#commit + FaultyJDBCDriver.addFault("ex-fault-1", new ExceptionFault(0.1, "commit")); + pm.makePersistent(new TableGeneratorItem("Item_" + i)); + FaultyJDBCDriver.clearFaults(); + tx.commit(); + } + catch(Exception e) + { + // If it is the artificially generated faulty exception ignore it and continue + // otherwise stop and propagate it + if (!isFaultyException(e)) { + throw e; + } + } + finally + { + if (tx.isActive()) { + tx.rollback(); + } + pm.close(); + } + } + } + finally + { + // Remove all registered faults + FaultyJDBCDriver.clearFaults(); + // Clean out any created data + clean(TableGeneratorItem.class); + } + } + + private static boolean isFaultyException(Throwable e) { + if (e == null) { + return false; + } + if (e.getMessage() != null && "Random exception generated by jdbc-faulty".equals(e.getMessage())) { + return true; + } + return isFaultyException(e.getCause()); + } + +} \ No newline at end of file