This is an automated email from the ASF dual-hosted git repository.
karan 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 a04e2080ce4 Split QTest runs into multiple splits (#18173)
a04e2080ce4 is described below
commit a04e2080ce411f59e0a018c9d09dfd3ca9952f5c
Author: Zoltan Haindrich <[email protected]>
AuthorDate: Fri Jun 27 15:01:58 2025 +0200
Split QTest runs into multiple splits (#18173)
* disable jacoco on pushes
* wondering
* Revert "wondering"
This reverts commit 22a82e335460795ecec947a55d38b5d67b51dbd1.
* add properties
* Reapply "wondering"
This reverts commit 1febbf4c085a079003a76e86b7c5d1fb044d0149.
* add quidem.split
---
.github/workflows/ci.yml | 10 +-
.../apache/druid/quidem/DruidQuidemTestBase.java | 106 +++++++++++++++++----
2 files changed, 95 insertions(+), 21 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ca5229780c9..b8bdd7ba157 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -59,7 +59,7 @@ jobs:
name: "coverage-jacoco"
needs: run-unit-tests
uses: ./.github/workflows/worker.yml
- if: ${{ !contains( github.event.pull_request.labels.*.name, 'jacoco:skip')
}}
+ if: ${{ !cancelled() && !contains(
github.event.pull_request.labels.*.name, 'jacoco:skip') && github.event_name !=
'push' }}
with:
script: .github/scripts/create-jacoco-coverage-report.sh
artifacts_to_download: "unit-test-reports-*"
@@ -82,8 +82,12 @@ jobs:
# this will be running in parallel with the ITs later; but until that
migration happens - run them in parallel with normal tests
run-qtest:
+ strategy:
+ fail-fast: false
+ matrix:
+ split: [ "0/4", "1/4", "2/4", "3/4" ]
uses: ./.github/workflows/worker.yml
with:
- script: .github/scripts/run_unit-tests -Dtest=QTest -fae
- key: quidem-QTest
+ script: .github/scripts/run_unit-tests -Dtest=QTest -Dquidem.split=${{
matrix.split }} -fae
+ key: QTest-${{ matrix.split }}
jdk: 17
diff --git a/sql/src/test/java/org/apache/druid/quidem/DruidQuidemTestBase.java
b/sql/src/test/java/org/apache/druid/quidem/DruidQuidemTestBase.java
index f2e9c515e23..2215c7670e7 100644
--- a/sql/src/test/java/org/apache/druid/quidem/DruidQuidemTestBase.java
+++ b/sql/src/test/java/org/apache/druid/quidem/DruidQuidemTestBase.java
@@ -19,6 +19,7 @@
package org.apache.druid.quidem;
+import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.io.Files;
@@ -29,6 +30,7 @@ import net.hydromatic.quidem.Quidem.ConfigBuilder;
import org.apache.calcite.test.DiffTestCase;
import org.apache.calcite.util.Closer;
import org.apache.calcite.util.Util;
+import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.druid.concurrent.Threads;
import org.apache.druid.error.DruidException;
import org.apache.druid.java.util.common.FileUtils;
@@ -44,7 +46,6 @@ import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
-import javax.annotation.Nullable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -61,6 +62,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import static org.junit.jupiter.api.Assertions.fail;
@@ -100,7 +103,12 @@ public abstract class DruidQuidemTestBase
private static final String PROPERTY_FILTER = "quidem.filter";
- private final String filterStr;
+ /**
+ * This property enables the test system to split up huge cases into desired
+ * number of smaller testcases.
+ */
+ private static final String PROPERTY_SPLIT = "quidem.split";
+
private final PathMatcher filterMatcher;
private DruidQuidemRunner druidQuidemRunner;
@@ -112,30 +120,92 @@ public abstract class DruidQuidemTestBase
public DruidQuidemTestBase(DruidQuidemRunner druidQuidemRunner)
{
- this.filterStr = System.getProperty(PROPERTY_FILTER, null);
- this.filterMatcher = buildFilterMatcher(filterStr);
+ String filterStr = Strings.emptyToNull(System.getProperty(PROPERTY_FILTER,
null));
+ String splitStr = Strings.emptyToNull(System.getProperty(PROPERTY_SPLIT,
null));
+ this.filterMatcher = buildFilterMatcher(filterStr, splitStr);
this.druidQuidemRunner = druidQuidemRunner;
}
- private static PathMatcher buildFilterMatcher(@Nullable String filterStr)
+ private PathMatcher buildFilterMatcher(String filterStr, String splitStr)
+ {
+ if (filterStr != null && splitStr != null) {
+ throw new IAE(
+ "Cannot configure multiple filter methods with properties: %s and
%s.", PROPERTY_FILTER, PROPERTY_SPLIT
+ );
+ }
+ if (filterStr != null) {
+ return new IQPathMatcher(filterStr);
+ }
+ if (splitStr != null) {
+ return new QuidemSplitPathMatcher(splitStr);
+ }
+ return TrueFileFilter.INSTANCE;
+ }
+
+ static class QuidemSplitPathMatcher implements PathMatcher
+ {
+ private final int splitIndex;
+ private final int splitCount;
+
+ public QuidemSplitPathMatcher(String splitStr)
+ {
+ Pattern pattern = Pattern.compile("^([0-9]+)/([0-9]+)$");
+ Matcher m = pattern.matcher(splitStr);
+ if (!m.matches()) {
+ throw DruidException.defensive("Invalid split pattern; must match
pattern [%s]", pattern);
+ }
+ splitIndex = Integer.parseInt(m.group(1));
+ splitCount = Integer.parseInt(m.group(2));
+ if (splitCount < 1 || splitIndex < 0 || splitIndex >= splitCount) {
+ throw DruidException.defensive("invalid splitStr [%s]", splitStr);
+ }
+ }
+
+ @Override
+ public boolean matches(Path path)
+ {
+ return Math.floorMod(path.toString().hashCode(), splitCount) ==
splitIndex;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "split:" + splitIndex + "/" + splitCount;
+ }
+ }
+
+ static class IQPathMatcher implements PathMatcher
{
- if (null == filterStr) {
- return f -> true;
+ private final List<PathMatcher> filterMatchers = new ArrayList<>();
+ private final String filterStr;
+
+ public IQPathMatcher(String filterStr)
+ {
+ this.filterStr = filterStr;
+ final FileSystem fileSystem = FileSystems.getDefault();
+ for (String filterGlob : filterStr.split(",")) {
+ if (!filterGlob.endsWith("*") && !filterGlob.endsWith(IQ_SUFFIX)) {
+ filterGlob = filterStr + IQ_SUFFIX;
+ }
+ filterMatchers.add(fileSystem.getPathMatcher("glob:" + filterGlob));
+ }
}
- final FileSystem fileSystem = FileSystems.getDefault();
- final List<PathMatcher> filterMatchers = new ArrayList<>();
- for (String filterGlob : filterStr.split(",")) {
- if (!filterGlob.endsWith("*") && !filterGlob.endsWith(IQ_SUFFIX)) {
- filterGlob = filterStr + IQ_SUFFIX;
+ @Override
+ public boolean matches(Path path)
+ {
+ for (PathMatcher m : filterMatchers) {
+ if (m.matches(path)) {
+ return true;
+ }
}
- filterMatchers.add(fileSystem.getPathMatcher("glob:" + filterGlob));
+ return false;
}
- if (filterMatchers.isEmpty()) {
- return f -> true;
- } else {
- return f -> filterMatchers.stream().anyMatch(m -> m.matches(f));
+ @Override
+ public String toString()
+ {
+ return filterStr;
}
}
@@ -372,7 +442,7 @@ public abstract class DruidQuidemTestBase
throw new IAE(
"There are no test cases in directory[%s] or there are no matches to
filter[%s]",
testRoot,
- filterStr
+ filterMatcher
);
}
Collections.sort(ret);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]