From 8a526965181ef75d27d3167560c69da8155bb584 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Tue, 5 May 2026 10:37:46 +0200 Subject: [PATCH 1/3] Store already logged seeds to avoid logging them multiple times Signed-off-by: Christian Stein --- .../junit/jupiter/api/RandomOrdererUtils.java | 11 +++++++++-- .../jupiter/api/RandomlyOrderedTests.java | 19 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java index 22ae43b73ec6..9e43a40ee24a 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java @@ -11,6 +11,8 @@ package org.junit.jupiter.api; import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; import java.util.function.Function; import org.junit.platform.commons.logging.Logger; @@ -28,6 +30,8 @@ class RandomOrdererUtils { static final long DEFAULT_SEED = System.nanoTime(); + static final Set CUSTOM_SEEDS_ALREADY_LOGGED = new CopyOnWriteArraySet<>(); + static Long getSeed(Function> configurationParameterLookup, Logger logger) { return getCustomSeed(configurationParameterLookup, logger).orElse(DEFAULT_SEED); } @@ -36,8 +40,11 @@ private static Optional getCustomSeed(Function> c Logger logger) { return configurationParameterLookup.apply(RANDOM_SEED_PROPERTY_NAME).map(configurationParameter -> { try { - logger.config(() -> "Using custom seed for configuration parameter [%s] with value [%s].".formatted( - RANDOM_SEED_PROPERTY_NAME, configurationParameter)); + if (!CUSTOM_SEEDS_ALREADY_LOGGED.contains(configurationParameter)) { + CUSTOM_SEEDS_ALREADY_LOGGED.add(configurationParameter); + logger.config(() -> "Using custom seed for configuration parameter [%s] with value [%s].".formatted( + RANDOM_SEED_PROPERTY_NAME, configurationParameter)); + } return Long.valueOf(configurationParameter); } catch (NumberFormatException ex) { diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java index 5f4e2185dbbd..a4bef4d5c3be 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java @@ -18,8 +18,11 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import java.util.logging.LogRecord; import java.util.stream.IntStream; +import org.junit.jupiter.api.fixtures.TrackLogRecords; +import org.junit.platform.commons.logging.LogRecordListener; import org.junit.platform.testkit.engine.EngineTestKit; import org.junit.platform.testkit.engine.Events; @@ -31,24 +34,30 @@ class RandomlyOrderedTests { private static final Set callSequence = Collections.synchronizedSet(new LinkedHashSet<>()); @Test - void randomSeedForClassAndMethodOrderingIsDeterministic() { - IntStream.range(0, 20).forEach(i -> { + void randomSeedForClassAndMethodOrderingIsDeterministic(@TrackLogRecords LogRecordListener listener) { + var seed = "1618034"; + IntStream.range(0, 20).forEach(_ -> { callSequence.clear(); - var tests = executeTests(1618034); + var tests = executeTests(seed); tests.assertStatistics(stats -> stats.succeeded(callSequence.size())); assertThat(callSequence).containsExactlyInAnyOrder("B_TestCase#b", "B_TestCase#c", "B_TestCase#a", "C_TestCase#b", "C_TestCase#c", "C_TestCase#a", "A_TestCase#b", "A_TestCase#c", "A_TestCase#a"); }); + + assertThat(listener.stream() + .map(LogRecord::getMessage) + .filter(message -> message.contains(seed))) + .hasSize(1); // was logged 80 times before #4647 } - private Events executeTests(@SuppressWarnings("SameParameterValue") long randomSeed) { + private Events executeTests(@SuppressWarnings("SameParameterValue") String randomSeed) { // @formatter:off return EngineTestKit .engine("junit-jupiter") .configurationParameter(DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME, ClassOrderer.Random.class.getName()) .configurationParameter(DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME, MethodOrderer.Random.class.getName()) - .configurationParameter(MethodOrderer.Random.RANDOM_SEED_PROPERTY_NAME, String.valueOf(randomSeed)) + .configurationParameter(MethodOrderer.Random.RANDOM_SEED_PROPERTY_NAME, randomSeed) .selectors(selectClasses(A_TestCase.class, B_TestCase.class, C_TestCase.class)) .execute() .testEvents(); From 36414fcf948545f8db95dc24b796bb1553604519 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Tue, 5 May 2026 10:45:38 +0200 Subject: [PATCH 2/3] Spotless... Signed-off-by: Christian Stein --- .../main/java/org/junit/jupiter/api/RandomOrdererUtils.java | 2 +- .../java/org/junit/jupiter/api/RandomlyOrderedTests.java | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java index 9e43a40ee24a..a9b51d934cdc 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java @@ -43,7 +43,7 @@ private static Optional getCustomSeed(Function> c if (!CUSTOM_SEEDS_ALREADY_LOGGED.contains(configurationParameter)) { CUSTOM_SEEDS_ALREADY_LOGGED.add(configurationParameter); logger.config(() -> "Using custom seed for configuration parameter [%s] with value [%s].".formatted( - RANDOM_SEED_PROPERTY_NAME, configurationParameter)); + RANDOM_SEED_PROPERTY_NAME, configurationParameter)); } return Long.valueOf(configurationParameter); } diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java index a4bef4d5c3be..4f59ee53dd01 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/RandomlyOrderedTests.java @@ -45,10 +45,7 @@ void randomSeedForClassAndMethodOrderingIsDeterministic(@TrackLogRecords LogReco "C_TestCase#b", "C_TestCase#c", "C_TestCase#a", "A_TestCase#b", "A_TestCase#c", "A_TestCase#a"); }); - assertThat(listener.stream() - .map(LogRecord::getMessage) - .filter(message -> message.contains(seed))) - .hasSize(1); // was logged 80 times before #4647 + assertThat(listener.stream().map(LogRecord::getMessage).filter(message -> message.contains(seed))).hasSize(1); // was logged 80 times before #4647 } private Events executeTests(@SuppressWarnings("SameParameterValue") String randomSeed) { From 4ad0ff7355ef38f717b4b1e5997ea85ee5675e57 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Tue, 5 May 2026 16:07:18 +0200 Subject: [PATCH 3/3] Launcher session store is soo far away... Signed-off-by: Christian Stein --- .../java/org/junit/jupiter/api/RandomOrdererUtils.java | 9 ++++++++- .../jupiter/engine/extension/OrderedMethodTests.java | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java index a9b51d934cdc..f5bf57ff208a 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/RandomOrdererUtils.java @@ -28,6 +28,8 @@ class RandomOrdererUtils { static final String RANDOM_SEED_PROPERTY_NAME = "junit.jupiter.execution.order.random.seed"; + static final String RANDOM_SEED_LOG_FREQUENCY_PROPERTY_NAME = "junit.jupiter.execution.order.random.seed.log.frequency"; + static final long DEFAULT_SEED = System.nanoTime(); static final Set CUSTOM_SEEDS_ALREADY_LOGGED = new CopyOnWriteArraySet<>(); @@ -40,8 +42,13 @@ private static Optional getCustomSeed(Function> c Logger logger) { return configurationParameterLookup.apply(RANDOM_SEED_PROPERTY_NAME).map(configurationParameter -> { try { + // TODO Replace seed logging memory with launcher session store backed logic + var frequency = configurationParameterLookup.apply(RANDOM_SEED_LOG_FREQUENCY_PROPERTY_NAME).orElse( + "once_per_runtime"); if (!CUSTOM_SEEDS_ALREADY_LOGGED.contains(configurationParameter)) { - CUSTOM_SEEDS_ALREADY_LOGGED.add(configurationParameter); + if ("once_per_runtime".equalsIgnoreCase(frequency)) { + CUSTOM_SEEDS_ALREADY_LOGGED.add(configurationParameter); + } logger.config(() -> "Using custom seed for configuration parameter [%s] with value [%s].".formatted( RANDOM_SEED_PROPERTY_NAME, configurationParameter)); } diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java index 5751c03494eb..5f98a1fad865 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java @@ -386,7 +386,8 @@ private Events executeRandomTestCaseInParallelWithRandomSeed(String seed) { var configurationParameters = Map.of(// PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME, "true", // DEFAULT_EXECUTION_MODE_PROPERTY_NAME, "concurrent", // - RANDOM_SEED_PROPERTY_NAME, seed // + RANDOM_SEED_PROPERTY_NAME, seed, // + "junit.jupiter.execution.order.random.seed.log.frequency", "always" // ); // @formatter:off