This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 8cdda2385199f9d81c4fa144ff34a618dea1ee54
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Mon Feb 19 17:17:52 2024 +0100

    Enable JUnit parallel tests in `endorsed` modules.
    This requires the addition of a few resource locks.
---
 endorsed/build.gradle.kts                          |  3 ++
 .../sis/metadata/sql/MetadataFallbackVerifier.java |  2 +-
 .../sis/metadata/sql/MetadataSourceTest.java       |  2 ++
 .../sis/metadata/sql/MetadataWriterTest.java       |  2 ++
 .../org/apache/sis/metadata/sql/TestDatabase.java  | 33 +++++++++++++++--
 .../factory/ConcurrentAuthorityFactoryTest.java    |  8 +++--
 .../referencing/factory/sql/EPSGInstallerTest.java |  4 ++-
 .../sis/storage/netcdf/base/FeatureSetTest.java    | 13 +++++++
 .../apache/sis/storage/netcdf/base/GridTest.java   |  4 +++
 .../apache/sis/storage/netcdf/base/TestCase.java   | 42 +++++++++++++++-------
 .../apache/sis/storage/sql/TestOnAllDatabases.java |  6 ++++
 .../sql/feature/SelectionClauseWriterTest.java     |  2 +-
 .../sis/storage/sql/postgis/PostgresTest.java      |  2 ++
 .../org/apache/sis/util/collection/CacheTest.java  |  2 ++
 14 files changed, 105 insertions(+), 20 deletions(-)

diff --git a/endorsed/build.gradle.kts b/endorsed/build.gradle.kts
index e9903b3fad..d3198451b9 100644
--- a/endorsed/build.gradle.kts
+++ b/endorsed/build.gradle.kts
@@ -201,6 +201,9 @@ tasks.test {
         events("FAILED", "STANDARD_OUT", "STANDARD_ERROR")
         setExceptionFormat("FULL")
     }
+    systemProperty("junit.jupiter.execution.parallel.enabled", "true")
+    systemProperty("junit.jupiter.execution.parallel.mode.default", 
"concurrent")
+    systemProperty("junit.jupiter.execution.parallel.mode.classes.default", 
"concurrent")
 }
 
 /*
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataFallbackVerifier.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataFallbackVerifier.java
index 02c77cd1b5..99c0ebfbb0 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataFallbackVerifier.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataFallbackVerifier.java
@@ -63,7 +63,7 @@ public final class MetadataFallbackVerifier {
      */
     @Test
     public void compare() throws Exception {
-        try (TestDatabase db = TestDatabase.create("MetadataSource");
+        try (TestDatabase db = TestDatabase.create("MetadataFallback");
              MetadataSource source = new 
MetadataSource(MetadataStandard.ISO_19115, db.source, "metadata", null))
         {
             source.install();
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataSourceTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataSourceTest.java
index 3018a480ba..70f25d2cca 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataSourceTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataSourceTest.java
@@ -30,6 +30,7 @@ import org.apache.sis.metadata.iso.distribution.DefaultFormat;
 // Test dependencies
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.parallel.ResourceLock;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.TestStep;
 
@@ -68,6 +69,7 @@ public final class MetadataSourceTest extends TestCase {
      * @throws Exception if an error occurred while executing the script 
runner.
      */
     @Test
+    @ResourceLock(TestDatabase.POSTGRESQL)
     public void testOnPostgreSQL() throws Exception {
         try (TestDatabase db = TestDatabase.createOnPostgreSQL("metadata", 
false)) {
             testAll(db);
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataWriterTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataWriterTest.java
index 3705b52ba8..14c7a25c6f 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataWriterTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataWriterTest.java
@@ -29,6 +29,7 @@ import org.apache.sis.metadata.iso.citation.DefaultTelephone;
 // Test dependencies
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.parallel.ResourceLock;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.metadata.iso.citation.HardCodedCitations;
@@ -84,6 +85,7 @@ public final class MetadataWriterTest extends TestCase {
      * @throws Exception if an error occurred while writing or reading the 
database.
      */
     @Test
+    @ResourceLock(TestDatabase.POSTGRESQL)
     public void testPostgreSQL() throws Exception {
         try (final TestDatabase db = 
TestDatabase.createOnPostgreSQL("MetadataWriter", true)) {
             source = new MetadataWriter(MetadataStandard.ISO_19115, db.source, 
"MetadataWriter", null);
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/TestDatabase.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/TestDatabase.java
index bbef9fd59b..b945c42983 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/TestDatabase.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/TestDatabase.java
@@ -68,6 +68,23 @@ import org.apache.sis.test.TestCase;
  * @author  Alexis Manin (Geomatys)
  */
 public class TestDatabase implements AutoCloseable {
+    /**
+     * The lock to use for ensuring that there is no collision between tests 
using the PostgreSQL database.
+     * Example:
+     *
+     * {@snippet lang="java" :
+     *     @Test
+     *     @ResourceLock(TestDatabase.POSTGRESQL)
+     *     public void testFoo() throws SQLException {
+     *         try (TestDatabase db = TestDatabase.createOnPostgreSQL("Foo", 
true)) {
+     *         }
+     *     }
+     *     }
+     *
+     * @see #createOnPostgreSQL(String, boolean)
+     */
+    public static final String POSTGRESQL = "PostgreSQL";
+
     /**
      * Data source for connection to an alternative database for testing 
purpose.
      * If {@code null}, an in-memory Derby database will be used.
@@ -107,8 +124,10 @@ public class TestDatabase implements AutoCloseable {
     /**
      * Creates a temporary database. This method creates a Derby in-memory 
database by default,
      * but this default can be changed by setting the {@link #TEST_DATABASE} 
hard-coded value.
+     * See class javadoc if there is a need to inspect content of that 
in-memory database.
      *
-     * <p>See class javadoc if there is a need to inspect content of that 
in-memory database.</p>
+     * <p>The given database name shall be unique, for allowing parallel 
execution of tests.
+     * This is often the name of the test class without the {@code Test} 
suffix.</p>
      *
      * @param  name  the database name (without {@code "memory:"} prefix).
      * @return connection to the test database (usually on Apache Derby).
@@ -139,10 +158,13 @@ public class TestDatabase implements AutoCloseable {
     }
 
     /**
-     * Creates a in-memory database on HSQLDB. The database can optionally use 
a connection pool.
+     * Creates an in-memory database on HSQLDB. The database can optionally 
use a connection pool.
      * The test method can set {@code pooled} to {@code true} if it needs the 
data to survive when
      * the connection is closed and re-opened.
      *
+     * <p>The given database name shall be unique, for allowing parallel 
execution of tests.
+     * This is often the name of the test class without the {@code Test} 
suffix.</p>
+     *
      * @param  name    the database name (without {@code "jdbc:hsqldb:mem:"} 
prefix).
      * @param  pooled  whether the database should use a connection pool.
      * @return connection to the test database.
@@ -179,6 +201,9 @@ public class TestDatabase implements AutoCloseable {
     /**
      * Creates a in-memory database on H2. The database can optionally use a 
connection pool.
      *
+     * <p>The given database name shall be unique, for allowing parallel 
execution of tests.
+     * This is often the name of the test class without the {@code Test} 
suffix.</p>
+     *
      * @param  name  the database name (without {@code "jdbc:h2:mem:"} prefix).
      * @return connection to the test database.
      * @throws SQLException if an error occurred while creating the database.
@@ -215,6 +240,10 @@ public class TestDatabase implements AutoCloseable {
      * If the {@code create} argument is {@code false}, then the callers is 
responsible for creating the schema
      * soon after this method call. That schema will be deleted by {@link 
#close()}.
      *
+     * <h4>Thread safety</h4>
+     * Because all tests on PostgreSQL use the same database and some tests 
require the same schema,
+     * there is a risk of conflict. See {@link #POSTGRESQL} for indication 
about how to synchronize.
+     *
      * @param  schema  temporary schema to create. Shall not contain {@code 
'_'} or {@code '%'} characters.
      * @param  create  whether the schema should be created by this method.
      * @return connection to a PostgreSQL database
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/ConcurrentAuthorityFactoryTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/ConcurrentAuthorityFactoryTest.java
index 7addb79515..884c82c107 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/ConcurrentAuthorityFactoryTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/ConcurrentAuthorityFactoryTest.java
@@ -23,6 +23,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.TimeUnit;
 import java.lang.reflect.Field;
 import org.opengis.util.FactoryException;
+import static 
org.apache.sis.util.internal.StandardDateFormat.NANOS_PER_MILLISECOND;
 
 // Test dependencies
 import org.junit.jupiter.api.Test;
@@ -38,7 +39,7 @@ import org.apache.sis.test.TestCase;
  */
 public final class ConcurrentAuthorityFactoryTest extends TestCase {
     /**
-     * The timeout used for this test.
+     * The timeout used for this test, in nanoseconds.
      */
     private static final long TIMEOUT = 
ConcurrentAuthorityFactory.TIMEOUT_RESOLUTION * 4;
 
@@ -165,6 +166,7 @@ public final class ConcurrentAuthorityFactoryTest extends 
TestCase {
     /**
      * Sleeps and ensures that the sleep time did not exceeded the timeout. 
The sleep time could be greater if the test
      * machine is under heavy load (for example a Jenkins server), in which 
case we will cancel the test without failure.
+     * All times are in nanoseconds.
      */
     private static void sleepWithoutExceedingTimeout(final long previousTime, 
final long waitTime) throws InterruptedException {
         Thread.sleep(TimeUnit.NANOSECONDS.toMillis(waitTime));
@@ -178,6 +180,8 @@ public final class ConcurrentAuthorityFactoryTest extends 
TestCase {
      * <p>The workers should be disposed right after the sleep time. However, 
the workers disposal is performed
      * by a shared (SIS-library wide) daemon thread. Because the latter is 
invoked in a background thread,
      * it is subject to the hazard of thread scheduling.</p>
+     *
+     * @param  waitTime  the time to wait, in nanoseconds.
      */
     private static void sleepUntilAfterTimeout(final long waitTime, final 
ConcurrentAuthorityFactory<?> factory)
             throws InterruptedException
@@ -186,7 +190,7 @@ public final class ConcurrentAuthorityFactoryTest extends 
TestCase {
         int n = 3;
         while (factory.isCleanScheduled()) {
             ConcurrentAuthorityFactory.LOGGER.warning("Execution of 
ConcurrentAuthorityFactory.disposeExpired() has been delayed.");
-            Thread.sleep(TIMEOUT);
+            Thread.sleep(TIMEOUT / NANOS_PER_MILLISECOND);
             System.gc();
             if (--n == 0) {
                 break;
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
index ba97805368..d1357580ac 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
@@ -39,8 +39,9 @@ import org.apache.sis.metadata.sql.util.Reflection;
 
 // Test dependencies
 import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
 import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+import org.junit.jupiter.api.parallel.ResourceLock;
 import org.apache.sis.test.TestCaseWithLogs;
 import org.apache.sis.metadata.sql.TestDatabase;
 
@@ -169,6 +170,7 @@ public final class EPSGInstallerTest extends 
TestCaseWithLogs {
      * @throws Exception if an error occurred while creating the database.
      */
     @Test
+    @ResourceLock(TestDatabase.POSTGRESQL)
     public void testCreationOnPostgreSQL() throws Exception {
         final InstallationScriptProvider scripts = getScripts();            // 
Needs to be invoked first.
         try (TestDatabase db = TestDatabase.createOnPostgreSQL("EPSG", false)) 
{
diff --git 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/FeatureSetTest.java
 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/FeatureSetTest.java
index 1dae1d3456..4912f6da67 100644
--- 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/FeatureSetTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/FeatureSetTest.java
@@ -37,6 +37,7 @@ import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
 
 // Test dependencies
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.*;
 import org.opengis.test.dataset.TestData;
@@ -72,6 +73,18 @@ public class FeatureSetTest extends TestCase {
         timeOrigin = Instant.parse("2014-11-29T00:00:00Z");
     }
 
+    /**
+     * Forgets the data used by the current test. This method makes {@code 
this} instance
+     * ready for another test method reusing the decoders that are already 
opened.
+     */
+    @Override
+    @AfterEach
+    public void reset() {
+        super.reset();
+        type = null;
+        featureIndex = 0;
+    }
+
     /**
      * Returns a dummy data store implementation for the sole purpose of 
providing a non-null lock.
      */
diff --git 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/GridTest.java
 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/GridTest.java
index b1b24b749e..6d7a28d010 100644
--- 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/GridTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/GridTest.java
@@ -43,6 +43,8 @@ public class GridTest extends TestCase {
      * Whether the {@code "runtime"} variable in {@link 
TestData#NETCDF_4D_PROJECTED} is used as a target dimension
      * for the {@code gridToCRS} transform. The UCAR library and Apache SIS 
implementation have different behavior
      * regarding this dimension.
+     *
+     * <p>This field can be set in subclasses constructor and shall not be 
modified afterward.</p>
      */
     protected boolean includeRuntimeDimension;
 
@@ -52,6 +54,8 @@ public class GridTest extends TestCase {
     public GridTest() {
     }
 
+    // Do not override `reset()` because `includeRuntimeDimension` should be 
constant.
+
     /**
      * Optionally filters out some grid geometries that shall be ignored by 
the tests.
      * The default implementation returns the given array unmodified. This 
method is overridden by
diff --git 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
index 5d68cee166..b231a151bd 100644
--- 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
+++ 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
@@ -17,7 +17,6 @@
 package org.apache.sis.storage.netcdf.base;
 
 import java.util.Date;
-import java.util.Map;
 import java.util.EnumMap;
 import java.util.Iterator;
 import java.io.IOException;
@@ -35,6 +34,8 @@ import org.apache.sis.storage.event.StoreListeners;
 
 // Test dependencies
 import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.TestInstance;
 import static org.junit.jupiter.api.Assertions.*;
 
 // Specific to the geoapi-3.1 and geoapi-4.0 branches:
@@ -45,10 +46,11 @@ import org.opengis.test.dataset.TestData;
  * Base class of netCDF tests. The base class uses the UCAR decoder, which is 
taken as a reference implementation.
  * Subclasses testing Apache SIS implementation needs to override the {@link 
#createDecoder(TestData)}.
  *
- * <p>This class is <strong>not</strong> thread safe - do not run subclasses 
in parallel.</p>
+ * <p>Subclasses must ensure that they do not hold any state, or that they 
clear the state after each test.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public abstract class TestCase extends org.apache.sis.test.TestCase {
     /**
      * The {@code searchPath} argument value to be given to the {@link 
Decoder#setSearchPath(String[])}
@@ -58,15 +60,17 @@ public abstract class TestCase extends 
org.apache.sis.test.TestCase {
 
     /**
      * The decoders cached by {@link #selectDataset(TestData)}.
-     * The map is non-empty only during the execution of a single test class.
      *
      * @see #closeAllDecoders()
      */
-    private static final Map<TestData,Decoder> DECODERS = new 
EnumMap<>(TestData.class);
+    private final EnumMap<TestData,Decoder> decoders;
 
     /**
      * The decoder to test, which is set by {@link #selectDataset(TestData)}.
      * This field must be set before any {@code assert} method is invoked.
+     *
+     * @see #decoder()
+     * @see #reset()
      */
     private Decoder decoder;
 
@@ -74,6 +78,7 @@ public abstract class TestCase extends 
org.apache.sis.test.TestCase {
      * Creates a new test case.
      */
     protected TestCase() {
+        decoders = new EnumMap<>(TestData.class);
     }
 
     /**
@@ -153,12 +158,12 @@ public abstract class TestCase extends 
org.apache.sis.test.TestCase {
      * @throws DataStoreException if a logical error occurred.
      */
     protected final Decoder selectDataset(final TestData name) throws 
IOException, DataStoreException {
-        synchronized (DECODERS) {               // Paranoiac safety, but 
should not be used in multi-threads environment.
-            decoder = DECODERS.get(name);
+        synchronized (decoders) {               // Paranoiac safety, but 
should not be used in multi-threads environment.
+            decoder = decoders.get(name);
             if (decoder == null) {
                 decoder = createDecoder(name);
                 assertNotNull(decoder);
-                assertNull(DECODERS.put(name, decoder));
+                assertNull(decoders.put(name, decoder));
             }
             decoder.setSearchPath(GLOBAL);
             return decoder;                     // Reminder: Decoder instances 
are not thread-safe.
@@ -169,9 +174,20 @@ public abstract class TestCase extends 
org.apache.sis.test.TestCase {
      * Returns the decoder being tested.
      */
     final Decoder decoder() {
+        assertNotNull(decoder);
         return decoder;
     }
 
+    /**
+     * Forgets (but do not close) the decoder used by the current test.
+     * This method makes {@code this} instance ready for another test
+     * method reusing the decoders that are already opened.
+     */
+    @AfterEach
+    public void reset() {
+        decoder = null;
+    }
+
     /**
      * Invoked after all tests in a class have been executed.
      * This method closes all netCDF files.
@@ -179,15 +195,15 @@ public abstract class TestCase extends 
org.apache.sis.test.TestCase {
      * @throws IOException if an error occurred while closing a file.
      */
     @AfterAll
-    public static void closeAllDecoders() throws IOException {
+    public void closeAllDecoders() throws IOException {
         final var ds = new DataStoreMock("lock");
         Throwable failure = null;
-        synchronized (DECODERS) {               // Paranoiac safety.
-            final Iterator<Decoder> it = DECODERS.values().iterator();
+        synchronized (decoders) {               // Paranoiac safety.
+            final Iterator<Decoder> it = decoders.values().iterator();
             while (it.hasNext()) {
-                final Decoder decoder = it.next();
+                final Decoder d = it.next();
                 try {
-                    decoder.close(ds);
+                    d.close(ds);
                 } catch (Throwable e) {
                     if (failure == null) {
                         failure = e;
@@ -197,7 +213,7 @@ public abstract class TestCase extends 
org.apache.sis.test.TestCase {
                 }
                 it.remove();
             }
-            assertTrue(DECODERS.isEmpty());
+            assertTrue(decoders.isEmpty());
         }
         /*
          * If we failed to close a file, propagates the error
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/TestOnAllDatabases.java
 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/TestOnAllDatabases.java
index e66715eb38..88457e760a 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/TestOnAllDatabases.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/TestOnAllDatabases.java
@@ -18,6 +18,7 @@ package org.apache.sis.storage.sql;
 
 // Test dependencies
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.ResourceLock;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.metadata.sql.TestDatabase;
 
@@ -45,6 +46,7 @@ public abstract class TestOnAllDatabases extends TestCase {
      * @throws Exception if an error occurred while testing the database.
      */
     @Test
+    @ResourceLock("SQLStore-Derby")
     public void testOnDerby() throws Exception {
         try (TestDatabase database = TestDatabase.create("SQLStore")) {
             test(database, true);
@@ -57,6 +59,7 @@ public abstract class TestOnAllDatabases extends TestCase {
      * @throws Exception if an error occurred while testing the database.
      */
     @Test
+    @ResourceLock("SQLStore-HSQLDB")
     public void testOnHSQLDB() throws Exception {
         try (TestDatabase database = TestDatabase.createOnHSQLDB("SQLStore", 
true)) {
             test(database, true);
@@ -69,6 +72,7 @@ public abstract class TestOnAllDatabases extends TestCase {
      * @throws Exception if an error occurred while testing the database.
      */
     @Test
+    @ResourceLock("SQLStore-H2")
     public void testOnH2() throws Exception {
         try (TestDatabase database = TestDatabase.createOnH2("SQLStore")) {
             test(database, true);
@@ -81,6 +85,8 @@ public abstract class TestOnAllDatabases extends TestCase {
      * @throws Exception if an error occurred while testing the database.
      */
     @Test
+    @ResourceLock("SQLStore-PostgreSQL")
+    @ResourceLock(TestDatabase.POSTGRESQL)
     public void testOnPostgreSQL() throws Exception {
         try (TestDatabase database = TestDatabase.createOnPostgreSQL(SCHEMA, 
true)) {
             test(database, false);
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/SelectionClauseWriterTest.java
 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/SelectionClauseWriterTest.java
index 18989d98f5..457f7d0ff2 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/SelectionClauseWriterTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/SelectionClauseWriterTest.java
@@ -72,7 +72,7 @@ public final class SelectionClauseWriterTest extends TestCase 
implements SchemaM
      */
     @Test
     public void testOnDerby() throws Exception {
-        try (TestDatabase db = TestDatabase.create("SQLStore")) {
+        try (TestDatabase db = TestDatabase.create("SelectionClause")) {
             db.executeSQL(List.of("CREATE TABLE TEST (ALPHA INTEGER, BETA 
INTEGER, GAMMA INTEGER, PI FLOAT);"));
             final StorageConnector connector = new StorageConnector(db.source);
             connector.setOption(SchemaModifier.OPTION, this);
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/postgis/PostgresTest.java
 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/postgis/PostgresTest.java
index 16a40b53d6..75437a403f 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/postgis/PostgresTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/postgis/PostgresTest.java
@@ -50,6 +50,7 @@ import org.apache.sis.util.Version;
 // Test dependencies
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.parallel.ResourceLock;
 import org.apache.sis.storage.sql.SQLStoreTest;
 import org.apache.sis.storage.sql.feature.GeometryGetterTest;
 import org.apache.sis.test.TestCase;
@@ -103,6 +104,7 @@ public final class PostgresTest extends TestCase {
      * @throws Exception if an error occurred while testing the database.
      */
     @Test
+    @ResourceLock(TestDatabase.POSTGRESQL)
     public void testSpatialFeatures() throws Exception {
         try (TestDatabase database = 
TestDatabase.createOnPostgreSQL(SQLStoreTest.SCHEMA, true)) {
             database.executeSQL(List.of(resource("SpatialFeatures.sql")));
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/CacheTest.java
 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/CacheTest.java
index 2ea0f66d2d..a2e120f7fd 100644
--- 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/CacheTest.java
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/CacheTest.java
@@ -34,6 +34,7 @@ import org.apache.sis.util.internal.StandardDateFormat;
 // Test dependencies
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.parallel.Isolated;
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.Performance;
@@ -45,6 +46,7 @@ import static org.apache.sis.test.Assertions.assertMapEquals;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
+@Isolated("Depends on garbage collector activity")
 public final class CacheTest extends TestCase {
     /**
      * Creates a new test case.

Reply via email to