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

gianm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 1772ede6386 test: Rewrite some parameterized classes to tests. (#20108)
1772ede6386 is described below

commit 1772ede6386226ef0a6f5a4b75b55610853f397b
Author: Gian Merlino <[email protected]>
AuthorDate: Fri Aug 21 15:04:29 2026 -0700

    test: Rewrite some parameterized classes to tests. (#20108)
    
    With JUnit 5, ParameterizedClass leads to quadratic writes of Surefire
    reports, which causes significant overhead for certain of our
    highly-parameterized test suites. For more information see this Surefire
    issue: https://github.com/apache/maven-surefire/issues/3439.
    
    This didn't happen on JUnit 4, so it's a test performance regression
    connected to the migration to JUnit 5.
    
    This patch improves test runtime by ~8 minutes on my machine by switching
    four heavily-parameterized tests to use ParameterizedTest instead of
    ParameterizedTest. These four tests were originally migrated to JUnit 5
    in #19980 and #19982.
---
 .../org/apache/druid/frame/file/FrameFileTest.java | 237 +++++++++++---------
 .../druid/frame/processor/SuperSorterTest.java     | 243 ++++++++++-----------
 .../query/scan/MultiSegmentScanQueryTest.java      |  72 +++---
 .../query/scan/ScanQueryResultOrderingTest.java    |  95 ++++----
 4 files changed, 351 insertions(+), 296 deletions(-)

diff --git 
a/processing/src/test/java/org/apache/druid/frame/file/FrameFileTest.java 
b/processing/src/test/java/org/apache/druid/frame/file/FrameFileTest.java
index 7721e24f28d..536cce904ca 100644
--- a/processing/src/test/java/org/apache/druid/frame/file/FrameFileTest.java
+++ b/processing/src/test/java/org/apache/druid/frame/file/FrameFileTest.java
@@ -46,10 +46,8 @@ import org.apache.druid.testing.TemporaryFolderExtension;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Assumptions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
-import org.junit.jupiter.params.ParameterizedClass;
+import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 
 import javax.annotation.Nullable;
@@ -69,9 +67,6 @@ import java.util.Objects;
 import java.util.function.Function;
 import java.util.stream.IntStream;
 
-@ParameterizedClass
-
-@MethodSource("constructorFeeder")
 public class FrameFileTest extends InitializedNullHandlingTest
 {
   /**
@@ -148,37 +143,67 @@ public class FrameFileTest extends 
InitializedNullHandlingTest
   @RegisterExtension
   public final TemporaryFolderExtension temporaryFolder = new 
TemporaryFolderExtension();
 
-  private final FrameType frameType;
-  private final int maxRowsPerFrame;
-  private final boolean partitioned;
-  private final AdapterType adapterType;
-  private final int maxMmapSize;
-  private final boolean useLegacyFrameSerialization;
-
-  private CursorFactory cursorFactory;
-  private int rowCount;
-  private File file;
-
-  public FrameFileTest(
-      final FrameType frameType,
-      final int maxRowsPerFrame,
-      final boolean partitioned,
-      final AdapterType adapterType,
-      final int maxMmapSize,
-      final boolean useLegacyFrameSerialization
+  /**
+   * Writes the frame file for one case into the temporary folder, and returns 
it.
+   */
+  private File writeFrameFile(final FrameFileCase testCase) throws IOException
+  {
+    final File file = temporaryFolder.newFile();
+
+    try (final OutputStream out = Files.newOutputStream(file.toPath())) {
+      final FrameFileKey frameFileKey = new FrameFileKey(
+          testCase.adapterType(),
+          testCase.frameType(),
+          testCase.maxRowsPerFrame(),
+          testCase.partitioned(),
+          testCase.useLegacyFrameSerialization()
+      );
+      final byte[] frameFileBytes = FRAME_FILES.computeIfAbsent(frameFileKey, 
FrameFileTest::computeFrameFile);
+      out.write(frameFileBytes);
+    }
+
+    return file;
+  }
+
+  /**
+   * Writes the frame file for one case and opens it.
+   */
+  private FrameFile openFrameFile(final FrameFileCase testCase) throws 
IOException
+  {
+    return FrameFile.open(writeFrameFile(testCase), testCase.maxMmapSize(), 
null);
+  }
+
+  /**
+   * One case of the {@link #constructorFeeder()} matrix. Supplied as a single 
test-method parameter rather than
+   * as six positional ones, so the test signatures stay readable.
+   */
+  record FrameFileCase(
+      FrameType frameType,
+      int maxRowsPerFrame,
+      boolean partitioned,
+      AdapterType adapterType,
+      int maxMmapSize,
+      boolean useLegacyFrameSerialization
   )
   {
-    this.frameType = frameType;
-    this.maxRowsPerFrame = maxRowsPerFrame;
-    this.partitioned = partitioned;
-    this.adapterType = adapterType;
-    this.maxMmapSize = maxMmapSize;
-    this.useLegacyFrameSerialization = useLegacyFrameSerialization;
+    CursorFactory cursorFactory()
+    {
+      return adapterType.getCursorFactory();
+    }
+
+    int rowCount()
+    {
+      return adapterType.getRowCount();
+    }
   }
 
-  public static Iterable<Object[]> constructorFeeder()
+  /**
+   * Cases for the tests below. These are {@link ParameterizedTest} rather 
than a parameterized class
+   * for performance reasons: <a 
href="https://github.com/apache/maven-surefire/issues/3439";>maven-surefire#3439</a>.
+   */
+  public static Iterable<FrameFileCase> constructorFeeder()
   {
-    final List<Object[]> constructors = new ArrayList<>();
+    final List<FrameFileCase> constructors = new ArrayList<>();
 
     for (FrameType frameType : FrameType.values()) {
       for (int maxRowsPerFrame : new int[]{1, 17, 50, PARTITION_SIZE, 
Integer.MAX_VALUE}) {
@@ -194,7 +219,16 @@ public class FrameFileTest extends 
InitializedNullHandlingTest
 
             for (int maxMmapSize : maxMmapSizes) {
               for (boolean useLegacyFrameSerialization : new boolean[]{true, 
false}) {
-                constructors.add(new Object[]{frameType, maxRowsPerFrame, 
partitioned, adapterType, maxMmapSize, useLegacyFrameSerialization});
+                constructors.add(
+                    new FrameFileCase(
+                        frameType,
+                        maxRowsPerFrame,
+                        partitioned,
+                        adapterType,
+                        maxMmapSize,
+                        useLegacyFrameSerialization
+                    )
+                );
               }
             }
           }
@@ -206,9 +240,9 @@ public class FrameFileTest extends 
InitializedNullHandlingTest
   }
 
   @Nullable
-  private WireTransferable.ConcreteDeserializer makeConcreteDeserializer()
+  private WireTransferable.ConcreteDeserializer makeConcreteDeserializer(final 
FrameFileCase testCase)
   {
-    if (useLegacyFrameSerialization) {
+    if (testCase.useLegacyFrameSerialization()) {
       return null;
     } else {
       final ObjectMapper objectMapper = new ObjectMapper();
@@ -222,75 +256,66 @@ public class FrameFileTest extends 
InitializedNullHandlingTest
     }
   }
 
-  @BeforeEach
-  public void setUp() throws IOException
-  {
-    cursorFactory = adapterType.getCursorFactory();
-    rowCount = adapterType.getRowCount();
-    file = temporaryFolder.newFile();
-
-    try (final OutputStream out = Files.newOutputStream(file.toPath())) {
-      final FrameFileKey frameFileKey = new FrameFileKey(adapterType, 
frameType, maxRowsPerFrame, partitioned, useLegacyFrameSerialization);
-      final byte[] frameFileBytes = FRAME_FILES.computeIfAbsent(frameFileKey, 
FrameFileTest::computeFrameFile);
-      out.write(frameFileBytes);
-    }
-  }
-
   @AfterAll
   public static void afterClass()
   {
     FRAME_FILES.clear();
   }
 
-  @Test
-  public void test_numFrames() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_numFrames(final FrameFileCase testCase) throws IOException
   {
-    try (final FrameFile frameFile = FrameFile.open(file, maxMmapSize, null)) {
-      Assertions.assertEquals(computeExpectedNumFrames(), 
frameFile.numFrames());
+    try (final FrameFile frameFile = openFrameFile(testCase)) {
+      Assertions.assertEquals(computeExpectedNumFrames(testCase), 
frameFile.numFrames());
     }
   }
 
-  @Test
-  public void test_numPartitions() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_numPartitions(final FrameFileCase testCase) throws 
IOException
   {
-    try (final FrameFile frameFile = FrameFile.open(file, maxMmapSize, null)) {
-      Assertions.assertEquals(computeExpectedNumPartitions(), 
frameFile.numPartitions());
+    try (final FrameFile frameFile = openFrameFile(testCase)) {
+      Assertions.assertEquals(computeExpectedNumPartitions(testCase), 
frameFile.numPartitions());
     }
   }
 
-  @Test
-  public void test_rac_first() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_rac_first(final FrameFileCase testCase) throws IOException
   {
-    try (final FrameFile frameFile = FrameFile.open(file, maxMmapSize, null)) {
+    try (final FrameFile frameFile = openFrameFile(testCase)) {
       // Skip test for empty files.
       Assumptions.assumeTrue(frameFile.numFrames() > 0);
 
-      final Frame firstFrame = frameFile.rac(0, 
makeConcreteDeserializer()).as(Frame.class);
-      Assertions.assertEquals(Math.min(rowCount, maxRowsPerFrame), 
firstFrame.numRows());
+      final Frame firstFrame = frameFile.rac(0, 
makeConcreteDeserializer(testCase)).as(Frame.class);
+      Assertions.assertEquals(Math.min(testCase.rowCount(), 
testCase.maxRowsPerFrame()), firstFrame.numRows());
     }
   }
 
-  @Test
-  public void test_rac_last() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_rac_last(final FrameFileCase testCase) throws IOException
   {
-    try (final FrameFile frameFile = FrameFile.open(file, maxMmapSize, null)) {
+    try (final FrameFile frameFile = openFrameFile(testCase)) {
       // Skip test for empty files.
       Assumptions.assumeTrue(frameFile.numFrames() > 0);
 
-      final Frame lastFrame = frameFile.rac(frameFile.numFrames() - 1, 
makeConcreteDeserializer()).as(Frame.class);
+      final Frame lastFrame = frameFile.rac(frameFile.numFrames() - 1, 
makeConcreteDeserializer(testCase)).as(Frame.class);
       Assertions.assertEquals(
-          rowCount % maxRowsPerFrame != 0
-          ? rowCount % maxRowsPerFrame
-          : Math.min(rowCount, maxRowsPerFrame),
+          testCase.rowCount() % testCase.maxRowsPerFrame() != 0
+          ? testCase.rowCount() % testCase.maxRowsPerFrame()
+          : Math.min(testCase.rowCount(), testCase.maxRowsPerFrame()),
           lastFrame.numRows()
       );
     }
   }
 
-  @Test
-  public void test_rac_outOfBoundsNegative() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_rac_outOfBoundsNegative(final FrameFileCase testCase) 
throws IOException
   {
-    try (final FrameFile frameFile = FrameFile.open(file, maxMmapSize, null)) {
+    try (final FrameFile frameFile = openFrameFile(testCase)) {
       final IllegalArgumentException exception = Assertions.assertThrows(
           IllegalArgumentException.class,
           () -> frameFile.rac(-1, null)
@@ -299,10 +324,11 @@ public class FrameFileTest extends 
InitializedNullHandlingTest
     }
   }
 
-  @Test
-  public void test_rac_outOfBoundsTooLarge() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_rac_outOfBoundsTooLarge(final FrameFileCase testCase) 
throws IOException
   {
-    try (final FrameFile frameFile = FrameFile.open(file, maxMmapSize, null)) {
+    try (final FrameFile frameFile = openFrameFile(testCase)) {
       final IllegalArgumentException exception = Assertions.assertThrows(
           IllegalArgumentException.class,
           () -> frameFile.rac(frameFile.numFrames(), null)
@@ -314,36 +340,38 @@ public class FrameFileTest extends 
InitializedNullHandlingTest
     }
   }
 
-  @Test
-  public void test_rac_readAllDataViaCursorFactory() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_rac_readAllDataViaCursorFactory(final FrameFileCase 
testCase) throws IOException
   {
-    final FrameReader frameReader = 
FrameReader.create(cursorFactory.getRowSignature());
+    final FrameReader frameReader = 
FrameReader.create(testCase.cursorFactory().getRowSignature());
 
-    try (final FrameFile frameFile = FrameFile.open(file, maxMmapSize, null)) {
+    try (final FrameFile frameFile = openFrameFile(testCase)) {
       final Sequence<List<Object>> frameFileRows = Sequences.concat(
           () -> IntStream.range(0, frameFile.numFrames())
-                         .mapToObj(i -> frameFile.rac(i, 
makeConcreteDeserializer()).as(Frame.class))
+                         .mapToObj(i -> frameFile.rac(i, 
makeConcreteDeserializer(testCase)).as(Frame.class))
                          .map(frameReader::makeCursorFactory)
                          
.map(FrameTestUtil::readRowsFromCursorFactoryWithRowNumber)
                          .iterator()
       );
 
-      final Sequence<List<Object>> adapterRows = 
FrameTestUtil.readRowsFromCursorFactoryWithRowNumber(cursorFactory);
+      final Sequence<List<Object>> adapterRows = 
FrameTestUtil.readRowsFromCursorFactoryWithRowNumber(testCase.cursorFactory());
       FrameTestUtil.assertRowsEqual(adapterRows, frameFileRows);
     }
   }
 
-  @Test
-  public void test_getPartitionStartFrame() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_getPartitionStartFrame(final FrameFileCase testCase) throws 
IOException
   {
-    try (final FrameFile frameFile = FrameFile.open(file, maxMmapSize, null)) {
-      if (partitioned) {
+    try (final FrameFile frameFile = openFrameFile(testCase)) {
+      if (testCase.partitioned()) {
         for (int partitionNum = 0; partitionNum < frameFile.numPartitions(); 
partitionNum++) {
           Assertions.assertEquals(
               Math.min(
                   IntMath.divide(
                       (partitionNum >= SKIP_PARTITION ? partitionNum + 1 : 
partitionNum) * PARTITION_SIZE,
-                      maxRowsPerFrame,
+                      testCase.maxRowsPerFrame(),
                       RoundingMode.CEILING
                   ),
                   frameFile.numFrames()
@@ -358,27 +386,36 @@ public class FrameFileTest extends 
InitializedNullHandlingTest
     }
   }
 
-  @Test
-  public void test_file() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_file(final FrameFileCase testCase) throws IOException
   {
-    try (final FrameFile frameFile = FrameFile.open(file, maxMmapSize, null)) {
+    final File file = writeFrameFile(testCase);
+
+    try (final FrameFile frameFile = FrameFile.open(file, 
testCase.maxMmapSize(), null)) {
       Assertions.assertEquals(file, frameFile.file());
     }
   }
 
-  @Test
-  public void test_open_withDeleteOnClose() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_open_withDeleteOnClose(final FrameFileCase testCase) throws 
IOException
   {
-    FrameFile.open(file, maxMmapSize, null).close();
+    final File file = writeFrameFile(testCase);
+
+    FrameFile.open(file, testCase.maxMmapSize(), null).close();
     Assertions.assertTrue(file.exists());
 
     FrameFile.open(file, null, FrameFile.Flag.DELETE_ON_CLOSE).close();
     Assertions.assertFalse(file.exists());
   }
 
-  @Test
-  public void test_newReference() throws IOException
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void test_newReference(final FrameFileCase testCase) throws 
IOException
   {
+    final File file = writeFrameFile(testCase);
+
     final FrameFile frameFile1 = FrameFile.open(file, null, 
FrameFile.Flag.DELETE_ON_CLOSE);
     final FrameFile frameFile2 = frameFile1.newReference();
     final FrameFile frameFile3 = frameFile2.newReference();
@@ -411,17 +448,17 @@ public class FrameFileTest extends 
InitializedNullHandlingTest
     Assertions.assertEquals("Frame file is closed", exception.getMessage());
   }
 
-  private int computeExpectedNumFrames()
+  private int computeExpectedNumFrames(final FrameFileCase testCase)
   {
-    return IntMath.divide(countRows(cursorFactory), maxRowsPerFrame, 
RoundingMode.CEILING);
+    return IntMath.divide(countRows(testCase.cursorFactory()), 
testCase.maxRowsPerFrame(), RoundingMode.CEILING);
   }
 
-  private int computeExpectedNumPartitions()
+  private int computeExpectedNumPartitions(final FrameFileCase testCase)
   {
-    if (partitioned) {
+    if (testCase.partitioned()) {
       return Math.min(
-          computeExpectedNumFrames(),
-          IntMath.divide(countRows(cursorFactory), PARTITION_SIZE, 
RoundingMode.CEILING)
+          computeExpectedNumFrames(testCase),
+          IntMath.divide(countRows(testCase.cursorFactory()), PARTITION_SIZE, 
RoundingMode.CEILING)
       );
     } else {
       // 0 = not partitioned.
diff --git 
a/processing/src/test/java/org/apache/druid/frame/processor/SuperSorterTest.java
 
b/processing/src/test/java/org/apache/druid/frame/processor/SuperSorterTest.java
index 8689bb4664a..462855c419f 100644
--- 
a/processing/src/test/java/org/apache/druid/frame/processor/SuperSorterTest.java
+++ 
b/processing/src/test/java/org/apache/druid/frame/processor/SuperSorterTest.java
@@ -72,6 +72,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.params.ParameterizedClass;
+import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 
 import java.io.File;
@@ -236,8 +237,6 @@ public class SuperSorterTest
    * Parameterized test cases that use {@link 
TestIndex#getNoRollupIncrementalTestIndex} with various frame sizes,
    * numbers of channels, and worker configurations.
    */
-  @ParameterizedClass
-  @MethodSource("constructorFeeder")
   public static class ParameterizedCasesTest extends 
InitializedNullHandlingTest
   {
     private static CursorFactory CURSOR_FACTORY;
@@ -252,23 +251,16 @@ public class SuperSorterTest
     @RegisterExtension
     public final TemporaryFolderExtension temporaryFolder = new 
TemporaryFolderExtension();
 
-    private final FrameType outputFrameType;
-    private final int maxRowsPerFrame;
-    private final int maxBytesPerFrame;
-    private final int numChannels;
-    private final int maxActiveProcessors;
-    private final int maxChannelsPerProcessor;
-    private final int numThreads;
-    private final boolean isComposedStorage;
-    private final boolean partitionsDeferred;
-    private final long limitHint;
-
     private RowSignature signature;
     private FrameProcessorExecutor exec;
     private List<ReadableFrameChannel> inputChannels;
     private FrameReader frameReader;
 
-    public ParameterizedCasesTest(
+    /**
+     * One case of the {@link #constructorFeeder()} matrix. Supplied as a 
single test-method parameter rather than
+     * as ten positional ones, so the test signatures stay readable.
+     */
+    record SortCase(
         FrameType outputFrameType,
         int maxRowsPerFrame,
         int maxBytesPerFrame,
@@ -281,21 +273,15 @@ public class SuperSorterTest
         long limitHint
     )
     {
-      this.outputFrameType = outputFrameType;
-      this.maxRowsPerFrame = maxRowsPerFrame;
-      this.maxBytesPerFrame = maxBytesPerFrame;
-      this.numChannels = numChannels;
-      this.maxActiveProcessors = maxActiveProcessors;
-      this.maxChannelsPerProcessor = maxChannelsPerProcessor;
-      this.numThreads = numThreads;
-      this.isComposedStorage = isComposedStorage;
-      this.partitionsDeferred = partitionsDeferred;
-      this.limitHint = limitHint;
     }
 
-    public static Iterable<Object[]> constructorFeeder()
+    /**
+     * Cases for the tests below. These are {@link ParameterizedTest} rather 
than a parameterized class
+     * for performance reasons: <a 
href="https://github.com/apache/maven-surefire/issues/3439";>maven-surefire#3439</a>.
+     */
+    public static Iterable<SortCase> constructorFeeder()
     {
-      final List<Object[]> constructors = new ArrayList<>();
+      final List<SortCase> constructors = new ArrayList<>();
 
       final FrameType[] rowBasedFrameTypes =
           
Arrays.stream(FrameType.values()).filter(FrameType::isRowBased).toArray(FrameType[]::new);
@@ -312,7 +298,7 @@ public class SuperSorterTest
                       for (boolean partitionsDeferred : new boolean[]{true, 
false}) {
                         for (long limitHint : new 
long[]{SuperSorter.UNLIMITED, 3, 1_000}) {
                           constructors.add(
-                              new Object[]{
+                              new SortCase(
                                   outputFrameType,
                                   maxRowsPerFrame,
                                   maxBytesPerFrame,
@@ -323,7 +309,7 @@ public class SuperSorterTest
                                   isComposedStorage,
                                   partitionsDeferred,
                                   limitHint
-                              }
+                              )
                           );
                         }
                       }
@@ -341,7 +327,7 @@ public class SuperSorterTest
       for (boolean isComposedStorage : new boolean[]{true, false}) {
         for (long limitHint : new long[]{SuperSorter.UNLIMITED, 3, 1_000}) {
           constructors.add(
-              new Object[]{
+              new SortCase(
                   FrameType.latestRowBased(),
                   1 /* maxRowsPerFrame */,
                   20_000 /* maxBytesPerFrame */,
@@ -352,7 +338,7 @@ public class SuperSorterTest
                   isComposedStorage,
                   false /* partitionsDeferred */,
                   limitHint
-              }
+              )
           );
         }
       }
@@ -376,14 +362,6 @@ public class SuperSorterTest
       SORTED_TEST_ROWS.clear();
     }
 
-    @BeforeEach
-    public void setUp()
-    {
-      exec = new FrameProcessorExecutor(
-          MoreExecutors.listeningDecorator(Execs.multiThreaded(numThreads, 
getClass().getSimpleName() + "[%d]"))
-      );
-    }
-
     @AfterEach
     public void tearDown() throws Exception
     {
@@ -400,44 +378,53 @@ public class SuperSorterTest
      *
      * Sets {@link #inputChannels}, {@link #signature}, and {@link 
#frameReader}.
      */
-    private void setUpInputChannels(final ClusterBy clusterBy) throws Exception
+    private void setUpInputChannels(final SortCase sortCase, final ClusterBy 
clusterBy) throws Exception
     {
       if (signature != null || inputChannels != null) {
         throw new ISE("Channels already created for this case");
       }
 
+      exec = new FrameProcessorExecutor(
+          MoreExecutors.listeningDecorator(
+              Execs.multiThreaded(sortCase.numThreads(), 
getClass().getSimpleName() + "[%d]")
+          )
+      );
+
       final FrameSequenceBuilder frameSequenceBuilder =
           FrameSequenceBuilder.fromCursorFactory(CURSOR_FACTORY)
-                              .maxRowsPerFrame(maxRowsPerFrame)
+                              .maxRowsPerFrame(sortCase.maxRowsPerFrame())
                               .sortBy(clusterBy.getColumns())
-                              
.allocator(ArenaMemoryAllocator.create(ByteBuffer.allocate(maxBytesPerFrame)))
+                              .allocator(
+                                  
ArenaMemoryAllocator.create(ByteBuffer.allocate(sortCase.maxBytesPerFrame()))
+                              )
                               .frameType(FrameType.latestRowBased())
                               .populateRowNumber();
 
-      inputChannels = makeRoundRobinChannels(frameSequenceBuilder.frames(), 
numChannels);
+      inputChannels = makeRoundRobinChannels(frameSequenceBuilder.frames(), 
sortCase.numChannels());
       signature = 
FrameWriters.sortableSignature(CURSOR_FACTORY_SIGNATURE_WITH_ROW_NUMBER, 
clusterBy.getColumns());
       frameReader = FrameReader.create(signature);
     }
 
     private void verifySuperSorter(
+        final SortCase sortCase,
         final ClusterBy clusterBy,
         final ClusterByPartitions clusterByPartitions
     ) throws Exception
     {
       final File tempFolder = temporaryFolder.newFolder();
-      final OutputChannelFactory outputChannelFactory = isComposedStorage ? 
new ComposingOutputChannelFactory(
+      final OutputChannelFactory outputChannelFactory = 
sortCase.isComposedStorage() ? new ComposingOutputChannelFactory(
           ImmutableList.of(
-              new FileOutputChannelFactory(new File(tempFolder, "1"), 
maxBytesPerFrame, null, FrameTestUtil.WT_CONTEXT_LEGACY),
-              new FileOutputChannelFactory(new File(tempFolder, "2"), 
maxBytesPerFrame, null, FrameTestUtil.WT_CONTEXT_LEGACY)
+              new FileOutputChannelFactory(new File(tempFolder, "1"), 
sortCase.maxBytesPerFrame(), null, FrameTestUtil.WT_CONTEXT_LEGACY),
+              new FileOutputChannelFactory(new File(tempFolder, "2"), 
sortCase.maxBytesPerFrame(), null, FrameTestUtil.WT_CONTEXT_LEGACY)
           ),
-          maxBytesPerFrame
-      ) : new FileOutputChannelFactory(tempFolder, maxBytesPerFrame, null, 
FrameTestUtil.WT_CONTEXT_LEGACY);
-      final RowKeyReader keyReader = clusterBy.keyReader(signature, 
outputFrameType);
+          sortCase.maxBytesPerFrame()
+      ) : new FileOutputChannelFactory(tempFolder, 
sortCase.maxBytesPerFrame(), null, FrameTestUtil.WT_CONTEXT_LEGACY);
+      final RowKeyReader keyReader = clusterBy.keyReader(signature, 
sortCase.outputFrameType());
       final Comparator<RowKey> keyComparator = 
clusterBy.keyComparator(signature);
       final SettableFuture<ClusterByPartitions> clusterByPartitionsFuture = 
SettableFuture.create();
       final SuperSorterProgressTracker superSorterProgressTracker = new 
SuperSorterProgressTracker();
 
-      if (!partitionsDeferred) {
+      if (!sortCase.partitionsDeferred()) {
         clusterByPartitionsFuture.set(clusterByPartitions);
       }
 
@@ -448,19 +435,19 @@ public class SuperSorterTest
           clusterByPartitionsFuture,
           exec,
           FrameProcessorDecorator.NONE,
-          makeOutputChannelFactory(new FileOutputChannelFactory(tempFolder, 
maxBytesPerFrame, null, FrameTestUtil.WT_CONTEXT_LEGACY)),
+          makeOutputChannelFactory(new FileOutputChannelFactory(tempFolder, 
sortCase.maxBytesPerFrame(), null, FrameTestUtil.WT_CONTEXT_LEGACY)),
           makeOutputChannelFactory(outputChannelFactory),
-          outputFrameType,
-          maxActiveProcessors,
-          maxChannelsPerProcessor,
-          limitHint,
+          sortCase.outputFrameType(),
+          sortCase.maxActiveProcessors(),
+          sortCase.maxChannelsPerProcessor(),
+          sortCase.limitHint(),
           null,
           superSorterProgressTracker,
           false,
           null
       );
 
-      if (partitionsDeferred) {
+      if (sortCase.partitionsDeferred()) {
         superSorter.setNoWorkRunnable(() -> 
clusterByPartitionsFuture.set(clusterByPartitions));
       }
 
@@ -490,7 +477,7 @@ public class SuperSorterTest
                 array[i] = row.get(clusterByColumns[i]);
               }
 
-              final RowKey key = createKey(clusterBy, array);
+              final RowKey key = createKey(sortCase, clusterBy, array);
 
               if (!(partition.getStart() == null || keyComparator.compare(key, 
partition.getStart()) >= 0)) {
                 // Defer formatting of error message until it's actually needed
@@ -520,19 +507,20 @@ public class SuperSorterTest
         );
       }
 
-      if (limitHint != SuperSorter.UNLIMITED) {
-        MatcherAssert.assertThat(readRows.size(), 
Matchers.greaterThanOrEqualTo(Ints.checkedCast(limitHint)));
+      if (sortCase.limitHint() != SuperSorter.UNLIMITED) {
+        MatcherAssert.assertThat(readRows.size(), 
Matchers.greaterThanOrEqualTo(Ints.checkedCast(sortCase.limitHint())));
       }
 
       final Sequence<List<Object>> expectedRows =
           Sequences.simple(getOrComputeSortedTestRows(clusterBy))
-                   .limit(limitHint == SuperSorter.UNLIMITED ? Long.MAX_VALUE 
: readRows.size());
+                   .limit(sortCase.limitHint() == SuperSorter.UNLIMITED ? 
Long.MAX_VALUE : readRows.size());
 
       FrameTestUtil.assertRowsEqual(expectedRows, Sequences.simple(readRows));
     }
 
-    @Test
-    public void test_clusterByQualityLongAscRowNumberAsc_onePartition() throws 
Exception
+    @ParameterizedTest
+    @MethodSource("constructorFeeder")
+    public void test_clusterByQualityLongAscRowNumberAsc_onePartition(final 
SortCase sortCase) throws Exception
     {
       final ClusterBy clusterBy = new ClusterBy(
           ImmutableList.of(
@@ -542,12 +530,13 @@ public class SuperSorterTest
           0
       );
 
-      setUpInputChannels(clusterBy);
-      verifySuperSorter(clusterBy, 
ClusterByPartitions.oneUniversalPartition());
+      setUpInputChannels(sortCase, clusterBy);
+      verifySuperSorter(sortCase, clusterBy, 
ClusterByPartitions.oneUniversalPartition());
     }
 
-    @Test
-    public void 
test_clusterByQualityLongAscRowNumberAsc_twoPartitionsOneEmpty() throws 
Exception
+    @ParameterizedTest
+    @MethodSource("constructorFeeder")
+    public void 
test_clusterByQualityLongAscRowNumberAsc_twoPartitionsOneEmpty(final SortCase 
sortCase) throws Exception
     {
       final ClusterBy clusterBy = new ClusterBy(
           ImmutableList.of(
@@ -557,10 +546,11 @@ public class SuperSorterTest
           0
       );
 
-      setUpInputChannels(clusterBy);
+      setUpInputChannels(sortCase, clusterBy);
 
-      final RowKey zeroZero = createKey(clusterBy, 0L, 0L);
+      final RowKey zeroZero = createKey(sortCase, clusterBy, 0L, 0L);
       verifySuperSorter(
+          sortCase,
           clusterBy,
           new ClusterByPartitions(
               ImmutableList.of(
@@ -571,8 +561,9 @@ public class SuperSorterTest
       );
     }
 
-    @Test
-    public void test_clusterByQualityDescRowNumberAsc_fourPartitions() throws 
Exception
+    @ParameterizedTest
+    @MethodSource("constructorFeeder")
+    public void test_clusterByQualityDescRowNumberAsc_fourPartitions(final 
SortCase sortCase) throws Exception
     {
       final ClusterBy clusterBy = new ClusterBy(
           ImmutableList.of(
@@ -582,24 +573,24 @@ public class SuperSorterTest
           0
       );
 
-      setUpInputChannels(clusterBy);
+      setUpInputChannels(sortCase, clusterBy);
 
       final ClusterByPartitions partitions = new ClusterByPartitions(
           ImmutableList.of(
               new ClusterByPartition(
-                  createKey(clusterBy, "travel", 8L),
-                  createKey(clusterBy, "premium", 506L)
+                  createKey(sortCase, clusterBy, "travel", 8L),
+                  createKey(sortCase, clusterBy, "premium", 506L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, "premium", 506L),
-                  createKey(clusterBy, "mezzanine", 204L)
+                  createKey(sortCase, clusterBy, "premium", 506L),
+                  createKey(sortCase, clusterBy, "mezzanine", 204L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, "mezzanine", 204L),
-                  createKey(clusterBy, "health", 900L)
+                  createKey(sortCase, clusterBy, "mezzanine", 204L),
+                  createKey(sortCase, clusterBy, "health", 900L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, "health", 900L),
+                  createKey(sortCase, clusterBy, "health", 900L),
                   null
               )
           )
@@ -607,11 +598,12 @@ public class SuperSorterTest
 
       Assertions.assertEquals(4, partitions.size());
 
-      verifySuperSorter(clusterBy, partitions);
+      verifySuperSorter(sortCase, clusterBy, partitions);
     }
 
-    @Test
-    public void test_clusterByTimeAscMarketAscRowNumberAsc_fourPartitions() 
throws Exception
+    @ParameterizedTest
+    @MethodSource("constructorFeeder")
+    public void 
test_clusterByTimeAscMarketAscRowNumberAsc_fourPartitions(final SortCase 
sortCase) throws Exception
     {
       final ClusterBy clusterBy = new ClusterBy(
           ImmutableList.of(
@@ -622,24 +614,24 @@ public class SuperSorterTest
           0
       );
 
-      setUpInputChannels(clusterBy);
+      setUpInputChannels(sortCase, clusterBy);
 
       final ClusterByPartitions partitions = new ClusterByPartitions(
           ImmutableList.of(
               new ClusterByPartition(
-                  createKey(clusterBy, 1294790400000L, "spot", 0L),
-                  createKey(clusterBy, 1296864000000L, "spot", 302L)
+                  createKey(sortCase, clusterBy, 1294790400000L, "spot", 0L),
+                  createKey(sortCase, clusterBy, 1296864000000L, "spot", 302L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, 1296864000000L, "spot", 302L),
-                  createKey(clusterBy, 1298851200000L, "spot", 604L)
+                  createKey(sortCase, clusterBy, 1296864000000L, "spot", 302L),
+                  createKey(sortCase, clusterBy, 1298851200000L, "spot", 604L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, 1298851200000L, "spot", 604L),
-                  createKey(clusterBy, 1300838400000L, "total_market", 906L)
+                  createKey(sortCase, clusterBy, 1298851200000L, "spot", 604L),
+                  createKey(sortCase, clusterBy, 1300838400000L, 
"total_market", 906L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, 1300838400000L, "total_market", 906L),
+                  createKey(sortCase, clusterBy, 1300838400000L, 
"total_market", 906L),
                   null
               )
           )
@@ -647,11 +639,12 @@ public class SuperSorterTest
 
       Assertions.assertEquals(4, partitions.size());
 
-      verifySuperSorter(clusterBy, partitions);
+      verifySuperSorter(sortCase, clusterBy, partitions);
     }
 
-    @Test
-    public void test_clusterByPlacementishDescRowNumberAsc_fourPartitions() 
throws Exception
+    @ParameterizedTest
+    @MethodSource("constructorFeeder")
+    public void 
test_clusterByPlacementishDescRowNumberAsc_fourPartitions(final SortCase 
sortCase) throws Exception
     {
       final ClusterBy clusterBy = new ClusterBy(
           ImmutableList.of(
@@ -661,24 +654,24 @@ public class SuperSorterTest
           0
       );
 
-      setUpInputChannels(clusterBy);
+      setUpInputChannels(sortCase, clusterBy);
 
       final ClusterByPartitions partitions = new ClusterByPartitions(
           ImmutableList.of(
               new ClusterByPartition(
-                  createKey(clusterBy, ImmutableList.of("preferred", "t"), 7L),
-                  createKey(clusterBy, ImmutableList.of("p", "preferred"), 
506L)
+                  createKey(sortCase, clusterBy, ImmutableList.of("preferred", 
"t"), 7L),
+                  createKey(sortCase, clusterBy, ImmutableList.of("p", 
"preferred"), 506L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, ImmutableList.of("p", "preferred"), 
506L),
-                  createKey(clusterBy, ImmutableList.of("m", "preferred"), 
204L)
+                  createKey(sortCase, clusterBy, ImmutableList.of("p", 
"preferred"), 506L),
+                  createKey(sortCase, clusterBy, ImmutableList.of("m", 
"preferred"), 204L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, ImmutableList.of("m", "preferred"), 
204L),
-                  createKey(clusterBy, ImmutableList.of("h", "preferred"), 
900L)
+                  createKey(sortCase, clusterBy, ImmutableList.of("m", 
"preferred"), 204L),
+                  createKey(sortCase, clusterBy, ImmutableList.of("h", 
"preferred"), 900L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, ImmutableList.of("h", "preferred"), 
900L),
+                  createKey(sortCase, clusterBy, ImmutableList.of("h", 
"preferred"), 900L),
                   null
               )
           )
@@ -686,11 +679,12 @@ public class SuperSorterTest
 
       Assertions.assertEquals(4, partitions.size());
 
-      verifySuperSorter(clusterBy, partitions);
+      verifySuperSorter(sortCase, clusterBy, partitions);
     }
 
-    @Test
-    public void test_clusterByQualityLongDescRowNumberAsc_fourPartitions() 
throws Exception
+    @ParameterizedTest
+    @MethodSource("constructorFeeder")
+    public void test_clusterByQualityLongDescRowNumberAsc_fourPartitions(final 
SortCase sortCase) throws Exception
     {
       final ClusterBy clusterBy = new ClusterBy(
           ImmutableList.of(
@@ -700,24 +694,24 @@ public class SuperSorterTest
           0
       );
 
-      setUpInputChannels(clusterBy);
+      setUpInputChannels(sortCase, clusterBy);
 
       final ClusterByPartitions partitions = new ClusterByPartitions(
           ImmutableList.of(
               new ClusterByPartition(
-                  createKey(clusterBy, 1800L, 8L),
-                  createKey(clusterBy, 1600L, 506L)
+                  createKey(sortCase, clusterBy, 1800L, 8L),
+                  createKey(sortCase, clusterBy, 1600L, 506L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, 1600L, 506L),
-                  createKey(clusterBy, 1400L, 204L)
+                  createKey(sortCase, clusterBy, 1600L, 506L),
+                  createKey(sortCase, clusterBy, 1400L, 204L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, 1400L, 204L),
-                  createKey(clusterBy, 1300L, 900L)
+                  createKey(sortCase, clusterBy, 1400L, 204L),
+                  createKey(sortCase, clusterBy, 1300L, 900L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, 1300L, 900L),
+                  createKey(sortCase, clusterBy, 1300L, 900L),
                   null
               )
           )
@@ -725,11 +719,12 @@ public class SuperSorterTest
 
       Assertions.assertEquals(4, partitions.size());
 
-      verifySuperSorter(clusterBy, partitions);
+      verifySuperSorter(sortCase, clusterBy, partitions);
     }
 
-    @Test
-    public void 
test_clusterByQualityLongDescRowNumberAsc_fourPartitions_durableStorage() 
throws Exception
+    @ParameterizedTest
+    @MethodSource("constructorFeeder")
+    public void 
test_clusterByQualityLongDescRowNumberAsc_fourPartitions_durableStorage(final 
SortCase sortCase) throws Exception
     {
       final ClusterBy clusterBy = new ClusterBy(
           ImmutableList.of(
@@ -739,24 +734,24 @@ public class SuperSorterTest
           0
       );
 
-      setUpInputChannels(clusterBy);
+      setUpInputChannels(sortCase, clusterBy);
 
       final ClusterByPartitions partitions = new ClusterByPartitions(
           ImmutableList.of(
               new ClusterByPartition(
-                  createKey(clusterBy, 1800L, 8L),
-                  createKey(clusterBy, 1600L, 506L)
+                  createKey(sortCase, clusterBy, 1800L, 8L),
+                  createKey(sortCase, clusterBy, 1600L, 506L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, 1600L, 506L),
-                  createKey(clusterBy, 1400L, 204L)
+                  createKey(sortCase, clusterBy, 1600L, 506L),
+                  createKey(sortCase, clusterBy, 1400L, 204L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, 1400L, 204L),
-                  createKey(clusterBy, 1300L, 900L)
+                  createKey(sortCase, clusterBy, 1400L, 204L),
+                  createKey(sortCase, clusterBy, 1300L, 900L)
               ),
               new ClusterByPartition(
-                  createKey(clusterBy, 1300L, 900L),
+                  createKey(sortCase, clusterBy, 1300L, 900L),
                   null
               )
           )
@@ -764,13 +759,13 @@ public class SuperSorterTest
 
       Assertions.assertEquals(4, partitions.size());
 
-      verifySuperSorter(clusterBy, partitions);
+      verifySuperSorter(sortCase, clusterBy, partitions);
     }
 
-    private RowKey createKey(final ClusterBy clusterBy, final Object... 
objects)
+    private RowKey createKey(final SortCase sortCase, final ClusterBy 
clusterBy, final Object... objects)
     {
       final RowSignature keySignature = 
KeyTestUtils.createKeySignature(clusterBy.getColumns(), signature);
-      return KeyTestUtils.createKey(keySignature, outputFrameType, objects);
+      return KeyTestUtils.createKey(keySignature, sortCase.outputFrameType(), 
objects);
     }
 
     /**
diff --git 
a/processing/src/test/java/org/apache/druid/query/scan/MultiSegmentScanQueryTest.java
 
b/processing/src/test/java/org/apache/druid/query/scan/MultiSegmentScanQueryTest.java
index 005f478a484..395031fe555 100644
--- 
a/processing/src/test/java/org/apache/druid/query/scan/MultiSegmentScanQueryTest.java
+++ 
b/processing/src/test/java/org/apache/druid/query/scan/MultiSegmentScanQueryTest.java
@@ -53,20 +53,17 @@ import org.joda.time.Interval;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedClass;
+import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 
 import java.io.IOException;
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 /**
  *
  */
-@ParameterizedClass
-@MethodSource("constructorFeeder")
 public class MultiSegmentScanQueryTest extends InitializedNullHandlingTest
 {
   private static final ScanQueryQueryToolChest TOOL_CHEST = new 
ScanQueryQueryToolChest(
@@ -164,41 +161,49 @@ public class MultiSegmentScanQueryTest extends 
InitializedNullHandlingTest
     IOUtils.closeQuietly(segment0);
     IOUtils.closeQuietly(segment1);
   }
-  public static Iterable<Object[]> constructorFeeder()
+
+  /**
+   * Cases for the tests below. These are {@link ParameterizedTest} rather 
than a parameterized class
+   * for performance reasons: <a 
href="https://github.com/apache/maven-surefire/issues/3439";>maven-surefire#3439</a>.
+   */
+  public static Iterable<ScanCase> constructorFeeder()
   {
-    return QueryRunnerTestHelper.cartesian(
-        Arrays.asList(0, 1, 3, 7, 10, 20, 1000),
-        Arrays.asList(0, 1, 3, 5, 7, 10, 20, 200, 1000),
-        Arrays.asList(0, 1, 3, 6, 7, 10, 123, 2000)
-    );
-  }
+    final List<ScanCase> constructors = new ArrayList<>();
 
-  private final int limit;
-  private final int offset;
-  private final int batchSize;
+    for (int limit : new int[]{0, 1, 3, 7, 10, 20, 1000}) {
+      for (int offset : new int[]{0, 1, 3, 5, 7, 10, 20, 200, 1000}) {
+        for (int batchSize : new int[]{0, 1, 3, 6, 7, 10, 123, 2000}) {
+          constructors.add(new ScanCase(limit, offset, batchSize));
+        }
+      }
+    }
+
+    return constructors;
+  }
 
-  public MultiSegmentScanQueryTest(int limit, int offset, int batchSize)
+  /**
+   * One case of the {@link #constructorFeeder()} matrix, supplied as a single 
test-method parameter.
+   */
+  record ScanCase(int limit, int offset, int batchSize)
   {
-    this.limit = limit;
-    this.offset = offset;
-    this.batchSize = batchSize;
   }
 
-  private Druids.ScanQueryBuilder newBuilder()
+  private static Druids.ScanQueryBuilder newBuilder(final ScanCase testCase)
   {
     return Druids.newScanQueryBuilder()
                  .dataSource(new 
TableDataSource(QueryRunnerTestHelper.DATA_SOURCE))
                  .intervals(I_0112_0114_SPEC)
-                 .batchSize(batchSize)
+                 .batchSize(testCase.batchSize())
                  .columns(Collections.emptyList())
-                 .limit(limit)
-                 .offset(offset);
+                 .limit(testCase.limit())
+                 .offset(testCase.offset());
   }
 
-  @Test
-  public void testMergeRunnersWithLimitAndOffset()
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void testMergeRunnersWithLimitAndOffset(final ScanCase testCase)
   {
-    ScanQuery query = newBuilder().build();
+    ScanQuery query = newBuilder(testCase).build();
     List<ScanResultValue> results = FACTORY
         .mergeRunners(
             Execs.directExecutor(),
@@ -212,12 +217,13 @@ public class MultiSegmentScanQueryTest extends 
InitializedNullHandlingTest
     }
     Assertions.assertEquals(
         totalCount,
-        limit != 0 ? Math.min(limit, V_0112.length + V_0113.length) : 
V_0112.length + V_0113.length
+        testCase.limit() != 0 ? Math.min(testCase.limit(), V_0112.length + 
V_0113.length) : V_0112.length + V_0113.length
     );
   }
 
-  @Test
-  public void testMergeResultsWithLimitAndOffset()
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void testMergeResultsWithLimitAndOffset(final ScanCase testCase)
   {
     QueryRunner<ScanResultValue> runner = TOOL_CHEST.mergeResults(
         (queryPlus, responseContext) -> {
@@ -231,7 +237,7 @@ public class MultiSegmentScanQueryTest extends 
InitializedNullHandlingTest
           );
         }
     );
-    ScanQuery query = newBuilder().build();
+    ScanQuery query = newBuilder(testCase).build();
     List<ScanResultValue> results = runner.run(QueryPlus.wrap(query)).toList();
     int totalCount = 0;
     for (ScanResultValue result : results) {
@@ -241,9 +247,9 @@ public class MultiSegmentScanQueryTest extends 
InitializedNullHandlingTest
         totalCount,
         Math.max(
             0,
-            limit != 0
-            ? Math.min(limit, V_0112.length + V_0113.length - offset)
-            : V_0112.length + V_0113.length - offset
+            testCase.limit() != 0
+            ? Math.min(testCase.limit(), V_0112.length + V_0113.length - 
testCase.offset())
+            : V_0112.length + V_0113.length - testCase.offset()
         )
     );
   }
diff --git 
a/processing/src/test/java/org/apache/druid/query/scan/ScanQueryResultOrderingTest.java
 
b/processing/src/test/java/org/apache/druid/query/scan/ScanQueryResultOrderingTest.java
index 03c1a623e67..50574375929 100644
--- 
a/processing/src/test/java/org/apache/druid/query/scan/ScanQueryResultOrderingTest.java
+++ 
b/processing/src/test/java/org/apache/druid/query/scan/ScanQueryResultOrderingTest.java
@@ -48,8 +48,7 @@ import org.apache.druid.timeline.SegmentId;
 import org.joda.time.DateTime;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedClass;
+import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 
 import java.util.ArrayList;
@@ -66,8 +65,6 @@ import java.util.stream.IntStream;
  * <p>
  * Ensures that we have run-to-run stability of result order, which is 
important for offset-based pagination.
  */
-@ParameterizedClass
-@MethodSource("constructorFeeder")
 public class ScanQueryResultOrderingTest extends InitializedNullHandlingTest
 {
   private static final String DATASOURCE = "datasource";
@@ -137,15 +134,26 @@ public class ScanQueryResultOrderingTest extends 
InitializedNullHandlingTest
       )
   );
 
-  private final List<Integer> segmentToServerMap;
-  private final int limit;
-  private final int batchSize;
-  private final int maxRowsQueuedForOrdering;
-
   private ScanQueryRunnerFactory queryRunnerFactory;
   private List<QueryRunner<ScanResultValue>> segmentRunners;
 
-  public static Iterable<Object[]> constructorFeeder()
+  /**
+   * One case of the {@link #constructorFeeder()} matrix, supplied as a single 
test-method parameter.
+   */
+  record ResultOrderingCase(
+      List<Integer> segmentToServerMap,
+      int limit,
+      int batchSize,
+      int maxRowsQueuedForOrdering
+  )
+  {
+  }
+
+  /**
+   * Cases for the tests below. These are {@link ParameterizedTest} rather 
than a parameterized class
+   * for performance reasons: <a 
href="https://github.com/apache/maven-surefire/issues/3439";>maven-surefire#3439</a>.
+   */
+  public static Iterable<ResultOrderingCase> constructorFeeder()
   {
     // Set number of server equal to number of segments, then try all possible 
distributions of segments to servers.
     final int numServers = SEGMENTS.size();
@@ -167,25 +175,21 @@ public class ScanQueryResultOrderingTest extends 
InitializedNullHandlingTest
     final Set<Integer> batchSizes = ImmutableSortedSet.of(1, 2, 100);
     final Set<Integer> maxRowsQueuedForOrderings = ImmutableSortedSet.of(1, 7, 
100000);
 
-    return Sets.cartesianProduct(
-        segmentToServerMaps,
-        limits,
-        batchSizes,
-        maxRowsQueuedForOrderings
-    ).stream().map(args -> args.toArray(new 
Object[0])).collect(Collectors.toList());
-  }
+    final List<ResultOrderingCase> constructors = new ArrayList<>();
 
-  public ScanQueryResultOrderingTest(
-      final List<Integer> segmentToServerMap,
-      final int limit,
-      final int batchSize,
-      final int maxRowsQueuedForOrdering
-  )
-  {
-    this.segmentToServerMap = segmentToServerMap;
-    this.limit = limit;
-    this.batchSize = batchSize;
-    this.maxRowsQueuedForOrdering = maxRowsQueuedForOrdering;
+    for (final List<Integer> segmentToServerMap : segmentToServerMaps) {
+      for (final int limit : limits) {
+        for (final int batchSize : batchSizes) {
+          for (final int maxRowsQueuedForOrdering : maxRowsQueuedForOrderings) 
{
+            constructors.add(
+                new ResultOrderingCase(segmentToServerMap, limit, batchSize, 
maxRowsQueuedForOrdering)
+            );
+          }
+        }
+      }
+    }
+
+    return constructors;
   }
 
   @BeforeEach
@@ -200,10 +204,12 @@ public class ScanQueryResultOrderingTest extends 
InitializedNullHandlingTest
     segmentRunners = 
SEGMENTS.stream().map(queryRunnerFactory::createRunner).collect(Collectors.toList());
   }
 
-  @Test
-  public void testOrderNone()
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void testOrderNone(final ResultOrderingCase testCase)
   {
     assertResultsEquals(
+        testCase,
         Druids.newScanQueryBuilder()
               .dataSource("ds")
               .intervals(new 
MultipleIntervalSegmentSpec(Collections.singletonList(Intervals.of("2000/P1D"))))
@@ -234,10 +240,12 @@ public class ScanQueryResultOrderingTest extends 
InitializedNullHandlingTest
     );
   }
 
-  @Test
-  public void testOrderTimeAscending()
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void testOrderTimeAscending(final ResultOrderingCase testCase)
   {
     assertResultsEquals(
+        testCase,
         Druids.newScanQueryBuilder()
               .dataSource("ds")
               .intervals(new 
MultipleIntervalSegmentSpec(Collections.singletonList(Intervals.of("2000/P1D"))))
@@ -268,10 +276,12 @@ public class ScanQueryResultOrderingTest extends 
InitializedNullHandlingTest
     );
   }
 
-  @Test
-  public void testOrderTimeDescending()
+  @ParameterizedTest
+  @MethodSource("constructorFeeder")
+  public void testOrderTimeDescending(final ResultOrderingCase testCase)
   {
     assertResultsEquals(
+        testCase,
         Druids.newScanQueryBuilder()
               .dataSource("ds")
               .intervals(new 
MultipleIntervalSegmentSpec(Collections.singletonList(Intervals.of("2000/P1D"))))
@@ -302,9 +312,14 @@ public class ScanQueryResultOrderingTest extends 
InitializedNullHandlingTest
     );
   }
 
-  private void assertResultsEquals(final ScanQuery query, final List<Integer> 
expectedResults)
+  private void assertResultsEquals(
+      final ResultOrderingCase testCase,
+      final ScanQuery query,
+      final List<Integer> expectedResults
+  )
   {
     final List<List<Pair<SegmentId, QueryRunner<ScanResultValue>>>> 
serverRunners = new ArrayList<>();
+    final List<Integer> segmentToServerMap = testCase.segmentToServerMap();
     for (int i = 0; i <= 
segmentToServerMap.stream().max(Comparator.naturalOrder()).orElse(0); i++) {
       serverRunners.add(new ArrayList<>());
     }
@@ -371,20 +386,22 @@ public class ScanQueryResultOrderingTest extends 
InitializedNullHandlingTest
     // Finally: run the query.
     final List<Integer> results = runQuery(
         (ScanQuery) Druids.ScanQueryBuilder.copy(query)
-                                           .limit(limit)
-                                           .batchSize(batchSize)
+                                           .limit(testCase.limit())
+                                           .batchSize(testCase.batchSize())
                                            .build()
                                            .withOverriddenContext(
                                                ImmutableMap.of(
                                                    
ScanQueryConfig.CTX_KEY_MAX_ROWS_QUEUED_FOR_ORDERING,
-                                                   maxRowsQueuedForOrdering
+                                                   
testCase.maxRowsQueuedForOrdering()
                                                )
                                            ),
         brokerRunner
     );
 
     Assertions.assertEquals(
-        expectedResults.stream().limit(limit == 0 ? Long.MAX_VALUE : 
limit).collect(Collectors.toList()),
+        expectedResults.stream()
+                       .limit(testCase.limit() == 0 ? Long.MAX_VALUE : 
testCase.limit())
+                       .collect(Collectors.toList()),
         results
     );
   }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to