diff --git a/core/src/test/java/ai/timefold/solver/core/testutil/AbstractMeterTest.java b/core/src/test/java/ai/timefold/solver/core/testutil/AbstractMeterTest.java index 9633537bf43..fde20f05f3f 100644 --- a/core/src/test/java/ai/timefold/solver/core/testutil/AbstractMeterTest.java +++ b/core/src/test/java/ai/timefold/solver/core/testutil/AbstractMeterTest.java @@ -8,7 +8,8 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.MockClock; @@ -16,7 +17,8 @@ import io.micrometer.core.instrument.simple.SimpleConfig; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -@ResourceLock(value = "metrics") // Mutual exclusion to prevent flaky tests. +// We also want to ensure that tests of the same suite do not update the registry concurrently +@Execution(ExecutionMode.SAME_THREAD) public abstract class AbstractMeterTest { @BeforeEach // To guard against nasty tests which do not do this. diff --git a/core/src/test/java/ai/timefold/solver/core/testutil/PlannerTestUtils.java b/core/src/test/java/ai/timefold/solver/core/testutil/PlannerTestUtils.java index 3390a62e0de..a6ca194a416 100644 --- a/core/src/test/java/ai/timefold/solver/core/testutil/PlannerTestUtils.java +++ b/core/src/test/java/ai/timefold/solver/core/testutil/PlannerTestUtils.java @@ -70,11 +70,16 @@ public static SolverConfig buildSolverConfig(Class soluti new TerminationConfig().withStepCountLimit(TERMINATION_STEP_COUNT_LIMIT))); } - public static Solution_ solve(SolverConfig solverConfig, Solution_ problem) { + public static synchronized Solution_ solve(SolverConfig solverConfig, Solution_ problem) { return solve(solverConfig, problem, true); } - public static Solution_ solve(SolverConfig solverConfig, Solution_ problem, boolean bestSolutionEventExists) { + /** + * We need to synchronize the solving process because there are some shared resources, such as the Meter registry, + * which could be updated concurrently. + */ + public static synchronized Solution_ solve(SolverConfig solverConfig, Solution_ problem, + boolean bestSolutionEventExists) { SolverFactory solverFactory = SolverFactory.create(solverConfig); var solver = solverFactory.buildSolver(); var eventBestSolutionRef = new AtomicReference();