From d628f7227d75ef70f8830b8780a4169b24a0e6c1 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 3 Aug 2025 07:54:41 +1000 Subject: [PATCH 1/6] Group together archunit tests --- .../{ => archunit}/NullabilityAnnotationUsageTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/groovy/graphql/{ => archunit}/NullabilityAnnotationUsageTest.groovy (98%) diff --git a/src/test/groovy/graphql/NullabilityAnnotationUsageTest.groovy b/src/test/groovy/graphql/archunit/NullabilityAnnotationUsageTest.groovy similarity index 98% rename from src/test/groovy/graphql/NullabilityAnnotationUsageTest.groovy rename to src/test/groovy/graphql/archunit/NullabilityAnnotationUsageTest.groovy index 10b6b5458..ed0b93197 100644 --- a/src/test/groovy/graphql/NullabilityAnnotationUsageTest.groovy +++ b/src/test/groovy/graphql/archunit/NullabilityAnnotationUsageTest.groovy @@ -1,4 +1,4 @@ -package graphql +package graphql.archunit import com.tngtech.archunit.core.domain.JavaClasses import com.tngtech.archunit.core.importer.ClassFileImporter From 5a8daaacd430c6aa172c77d2233fe60a2e4f1c42 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 3 Aug 2025 08:10:02 +1000 Subject: [PATCH 2/6] Consolidate common test config --- build.gradle | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/build.gradle b/build.gradle index 718aafea5..fc5f21612 100644 --- a/build.gradle +++ b/build.gradle @@ -309,7 +309,8 @@ artifacts { List failedTests = [] -test { +tasks.withType(Test) { + useJUnitPlatform() testLogging { events "FAILED", "SKIPPED" @@ -327,34 +328,11 @@ tasks.register('testWithJava17', Test) { javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(17) } - useJUnitPlatform() - testLogging { - events "FAILED", "SKIPPED" - exceptionFormat = "FULL" - } - - afterTest { TestDescriptor descriptor, TestResult result -> - if (result.getFailedTestCount() > 0) { - failedTests.add(descriptor) - } - } - } tasks.register('testWithJava11', Test) { javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(11) } - useJUnitPlatform() - testLogging { - events "FAILED", "SKIPPED" - exceptionFormat = "FULL" - } - - afterTest { TestDescriptor descriptor, TestResult result -> - if (result.getFailedTestCount() > 0) { - failedTests.add(descriptor) - } - } } test.dependsOn testWithJava17 test.dependsOn testWithJava11 From 780c92ce199ddb8f9962a68bb7cefc729e969769 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 3 Aug 2025 08:10:51 +1000 Subject: [PATCH 3/6] Update test to compile JMH as well --- build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fc5f21612..f1225e3df 100644 --- a/build.gradle +++ b/build.gradle @@ -144,6 +144,7 @@ dependencies { testImplementation 'org.testng:testng:7.11.0' // use for reactive streams test inheritance testImplementation "com.tngtech.archunit:archunit-junit5:1.4.1" + testImplementation 'org.openjdk.jmh:jmh-core:1.37' // for ArchUnit tests that check JMH annotations antlr 'org.antlr:antlr4:' + antlrVersion @@ -310,13 +311,16 @@ artifacts { List failedTests = [] tasks.withType(Test) { - useJUnitPlatform() testLogging { events "FAILED", "SKIPPED" exceptionFormat = "FULL" } + // Required for JMH ArchUnit tests + classpath += sourceSets.jmh.output + dependsOn "jmhClasses" + afterTest { TestDescriptor descriptor, TestResult result -> if (result.getFailedTestCount() > 0) { failedTests.add(descriptor) From 8b2d05e9eabe8185ec3870798dcf2ca89a1feda1 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 3 Aug 2025 08:11:25 +1000 Subject: [PATCH 4/6] Add JMH archunit test to enforce no more than 2 forks --- .../archunit/JMHForkArchRuleTest.groovy | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/test/groovy/graphql/archunit/JMHForkArchRuleTest.groovy diff --git a/src/test/groovy/graphql/archunit/JMHForkArchRuleTest.groovy b/src/test/groovy/graphql/archunit/JMHForkArchRuleTest.groovy new file mode 100644 index 000000000..c3128daab --- /dev/null +++ b/src/test/groovy/graphql/archunit/JMHForkArchRuleTest.groovy @@ -0,0 +1,50 @@ +package graphql.archunit + +import com.tngtech.archunit.core.domain.JavaClass +import com.tngtech.archunit.core.importer.ClassFileImporter +import com.tngtech.archunit.lang.ArchCondition +import com.tngtech.archunit.lang.ConditionEvents +import com.tngtech.archunit.lang.EvaluationResult +import com.tngtech.archunit.lang.SimpleConditionEvent +import org.openjdk.jmh.annotations.Fork +import spock.lang.Specification + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes + +class JMHForkArchRuleTest extends Specification { + + def "JMH benchmarks on classes should not have a fork value greater than 2"() { + given: + def importedClasses = new ClassFileImporter() + .importPackages("benchmark", "performance", "graphql.execution") + + def rule = classes() + .that().areAnnotatedWith(Fork.class) + .and().areTopLevelClasses() + .should(haveForkValueNotGreaterThan(2)) + + when: + EvaluationResult result = rule.evaluate(importedClasses) + + then: + !result.hasViolation() + + cleanup: + if (result.hasViolation()) { + println result.getFailureReport().toString() + } + } + + private static ArchCondition haveForkValueNotGreaterThan(int maxFork) { + return new ArchCondition("have a @Fork value of at most $maxFork") { + @Override + void check(JavaClass javaClass, ConditionEvents events) { + def forkAnnotation = javaClass.getAnnotationOfType(Fork.class) + if (forkAnnotation.value() > maxFork) { + def message = "Class ${javaClass.name} has a @Fork value of ${forkAnnotation.value()} which is > $maxFork" + events.add(SimpleConditionEvent.violated(javaClass, message)) + } + } + } + } +} \ No newline at end of file From de5ade505084df3e96b252dce9d74a449f0dc208 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 3 Aug 2025 08:18:59 +1000 Subject: [PATCH 5/6] Set all JMH tests to no more than 2 forks --- src/jmh/java/benchmark/AssertBenchmark.java | 2 +- src/jmh/java/benchmark/AstPrinterBenchmark.java | 2 +- src/jmh/java/benchmark/ChainedInstrumentationBenchmark.java | 2 +- src/jmh/java/benchmark/CompletableFuturesBenchmark.java | 2 +- src/jmh/java/benchmark/CreateExtendedSchemaBenchmark.java | 2 +- src/jmh/java/benchmark/CreateSchemaBenchmark.java | 2 +- src/jmh/java/benchmark/GetterAccessBenchmark.java | 2 +- src/jmh/java/benchmark/IntMapBenchmark.java | 2 +- src/jmh/java/benchmark/IntrospectionBenchmark.java | 2 +- src/jmh/java/benchmark/MapBenchmark.java | 2 +- src/jmh/java/benchmark/OverlappingFieldValidationBenchmark.java | 2 +- src/jmh/java/benchmark/PropertyFetcherBenchMark.java | 2 +- src/jmh/java/benchmark/SchemaTransformerBenchmark.java | 2 +- src/jmh/java/benchmark/SimpleQueryBenchmark.java | 2 +- src/jmh/java/benchmark/TwitterBenchmark.java | 2 +- .../benchmark/TypeDefinitionParserVersusSerializeBenchmark.java | 2 +- src/jmh/java/benchmark/ValidatorBenchmark.java | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/jmh/java/benchmark/AssertBenchmark.java b/src/jmh/java/benchmark/AssertBenchmark.java index 04a11c03b..d3ecc838a 100644 --- a/src/jmh/java/benchmark/AssertBenchmark.java +++ b/src/jmh/java/benchmark/AssertBenchmark.java @@ -18,7 +18,7 @@ @Warmup(iterations = 2, time = 5, batchSize = 50) @Measurement(iterations = 3, batchSize = 50) -@Fork(3) +@Fork(2) public class AssertBenchmark { private static final int LOOPS = 100; diff --git a/src/jmh/java/benchmark/AstPrinterBenchmark.java b/src/jmh/java/benchmark/AstPrinterBenchmark.java index fd7f26452..f3eb10d06 100644 --- a/src/jmh/java/benchmark/AstPrinterBenchmark.java +++ b/src/jmh/java/benchmark/AstPrinterBenchmark.java @@ -16,7 +16,7 @@ @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3, time = 10) -@Fork(3) +@Fork(2) public class AstPrinterBenchmark { /** * Note: this query is a redacted version of a real query diff --git a/src/jmh/java/benchmark/ChainedInstrumentationBenchmark.java b/src/jmh/java/benchmark/ChainedInstrumentationBenchmark.java index 674f42403..da28bdbad 100644 --- a/src/jmh/java/benchmark/ChainedInstrumentationBenchmark.java +++ b/src/jmh/java/benchmark/ChainedInstrumentationBenchmark.java @@ -35,7 +35,7 @@ @State(Scope.Benchmark) @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) public class ChainedInstrumentationBenchmark { @Param({"0", "1", "10"}) diff --git a/src/jmh/java/benchmark/CompletableFuturesBenchmark.java b/src/jmh/java/benchmark/CompletableFuturesBenchmark.java index e22bb1eb7..746a1fb19 100644 --- a/src/jmh/java/benchmark/CompletableFuturesBenchmark.java +++ b/src/jmh/java/benchmark/CompletableFuturesBenchmark.java @@ -23,7 +23,7 @@ @State(Scope.Benchmark) @Warmup(iterations = 2, time = 1) @Measurement(iterations = 3, time = 10, batchSize = 10) -@Fork(3) +@Fork(2) public class CompletableFuturesBenchmark { diff --git a/src/jmh/java/benchmark/CreateExtendedSchemaBenchmark.java b/src/jmh/java/benchmark/CreateExtendedSchemaBenchmark.java index 92c624967..54ade0d76 100644 --- a/src/jmh/java/benchmark/CreateExtendedSchemaBenchmark.java +++ b/src/jmh/java/benchmark/CreateExtendedSchemaBenchmark.java @@ -27,7 +27,7 @@ */ @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) public class CreateExtendedSchemaBenchmark { private static final String SDL = mkSDL(); diff --git a/src/jmh/java/benchmark/CreateSchemaBenchmark.java b/src/jmh/java/benchmark/CreateSchemaBenchmark.java index 0b5e67b41..6d2099041 100644 --- a/src/jmh/java/benchmark/CreateSchemaBenchmark.java +++ b/src/jmh/java/benchmark/CreateSchemaBenchmark.java @@ -18,7 +18,7 @@ @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) public class CreateSchemaBenchmark { static String largeSDL = BenchmarkUtils.loadResource("large-schema-3.graphqls"); diff --git a/src/jmh/java/benchmark/GetterAccessBenchmark.java b/src/jmh/java/benchmark/GetterAccessBenchmark.java index d7ff9b752..5bf881160 100644 --- a/src/jmh/java/benchmark/GetterAccessBenchmark.java +++ b/src/jmh/java/benchmark/GetterAccessBenchmark.java @@ -13,7 +13,7 @@ @Warmup(iterations = 2, time = 5, batchSize = 500) @Measurement(iterations = 3, batchSize = 500) -@Fork(3) +@Fork(2) public class GetterAccessBenchmark { public static class Pojo { diff --git a/src/jmh/java/benchmark/IntMapBenchmark.java b/src/jmh/java/benchmark/IntMapBenchmark.java index 2dd74732c..b5b5272e4 100644 --- a/src/jmh/java/benchmark/IntMapBenchmark.java +++ b/src/jmh/java/benchmark/IntMapBenchmark.java @@ -15,7 +15,7 @@ @State(Scope.Benchmark) @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) public class IntMapBenchmark { @Benchmark diff --git a/src/jmh/java/benchmark/IntrospectionBenchmark.java b/src/jmh/java/benchmark/IntrospectionBenchmark.java index d226d232d..261a64047 100644 --- a/src/jmh/java/benchmark/IntrospectionBenchmark.java +++ b/src/jmh/java/benchmark/IntrospectionBenchmark.java @@ -21,7 +21,7 @@ @State(Scope.Benchmark) @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) public class IntrospectionBenchmark { @Benchmark diff --git a/src/jmh/java/benchmark/MapBenchmark.java b/src/jmh/java/benchmark/MapBenchmark.java index 04f05f73f..50cbe576f 100644 --- a/src/jmh/java/benchmark/MapBenchmark.java +++ b/src/jmh/java/benchmark/MapBenchmark.java @@ -25,7 +25,7 @@ @State(Scope.Benchmark) @Warmup(iterations = 2, time = 1) @Measurement(iterations = 3, time = 1, batchSize = 1000) -@Fork(3) +@Fork(2) public class MapBenchmark { @Param({"10", "50", "300"}) diff --git a/src/jmh/java/benchmark/OverlappingFieldValidationBenchmark.java b/src/jmh/java/benchmark/OverlappingFieldValidationBenchmark.java index 7340f9342..837a0f639 100644 --- a/src/jmh/java/benchmark/OverlappingFieldValidationBenchmark.java +++ b/src/jmh/java/benchmark/OverlappingFieldValidationBenchmark.java @@ -35,7 +35,7 @@ @State(Scope.Benchmark) @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) public class OverlappingFieldValidationBenchmark { @State(Scope.Benchmark) diff --git a/src/jmh/java/benchmark/PropertyFetcherBenchMark.java b/src/jmh/java/benchmark/PropertyFetcherBenchMark.java index 00146f8ca..7bb85410e 100644 --- a/src/jmh/java/benchmark/PropertyFetcherBenchMark.java +++ b/src/jmh/java/benchmark/PropertyFetcherBenchMark.java @@ -16,7 +16,7 @@ @Warmup(iterations = 2, time = 5, batchSize = 50) @Measurement(iterations = 3, batchSize = 50) -@Fork(3) +@Fork(2) public class PropertyFetcherBenchMark { @Benchmark diff --git a/src/jmh/java/benchmark/SchemaTransformerBenchmark.java b/src/jmh/java/benchmark/SchemaTransformerBenchmark.java index 669bda3f5..353dd0253 100644 --- a/src/jmh/java/benchmark/SchemaTransformerBenchmark.java +++ b/src/jmh/java/benchmark/SchemaTransformerBenchmark.java @@ -30,7 +30,7 @@ @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3, time = 10) -@Fork(3) +@Fork(2) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class SchemaTransformerBenchmark { diff --git a/src/jmh/java/benchmark/SimpleQueryBenchmark.java b/src/jmh/java/benchmark/SimpleQueryBenchmark.java index 0cce5c0fb..fe95a7b83 100644 --- a/src/jmh/java/benchmark/SimpleQueryBenchmark.java +++ b/src/jmh/java/benchmark/SimpleQueryBenchmark.java @@ -28,7 +28,7 @@ @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) public class SimpleQueryBenchmark { private static final int NUMBER_OF_FRIENDS = 10 * 100; diff --git a/src/jmh/java/benchmark/TwitterBenchmark.java b/src/jmh/java/benchmark/TwitterBenchmark.java index 9136fff7c..8fe58b082 100644 --- a/src/jmh/java/benchmark/TwitterBenchmark.java +++ b/src/jmh/java/benchmark/TwitterBenchmark.java @@ -35,7 +35,7 @@ @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) public class TwitterBenchmark { private static final int BREADTH = 150; private static final int DEPTH = 150; diff --git a/src/jmh/java/benchmark/TypeDefinitionParserVersusSerializeBenchmark.java b/src/jmh/java/benchmark/TypeDefinitionParserVersusSerializeBenchmark.java index 995700d07..a27444b55 100644 --- a/src/jmh/java/benchmark/TypeDefinitionParserVersusSerializeBenchmark.java +++ b/src/jmh/java/benchmark/TypeDefinitionParserVersusSerializeBenchmark.java @@ -21,7 +21,7 @@ @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) public class TypeDefinitionParserVersusSerializeBenchmark { static SchemaParser schemaParser = new SchemaParser(); diff --git a/src/jmh/java/benchmark/ValidatorBenchmark.java b/src/jmh/java/benchmark/ValidatorBenchmark.java index 71dc0aa33..f9dd34a0c 100644 --- a/src/jmh/java/benchmark/ValidatorBenchmark.java +++ b/src/jmh/java/benchmark/ValidatorBenchmark.java @@ -28,7 +28,7 @@ @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 2, time = 5) @Measurement(iterations = 3) -@Fork(3) +@Fork(2) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class ValidatorBenchmark { From 697b4634cf870b9d7204f8a9f237da8831476113 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 3 Aug 2025 08:50:08 +1000 Subject: [PATCH 6/6] Tidy up --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f1225e3df..9b1581648 100644 --- a/build.gradle +++ b/build.gradle @@ -144,7 +144,7 @@ dependencies { testImplementation 'org.testng:testng:7.11.0' // use for reactive streams test inheritance testImplementation "com.tngtech.archunit:archunit-junit5:1.4.1" - testImplementation 'org.openjdk.jmh:jmh-core:1.37' // for ArchUnit tests that check JMH annotations + testImplementation 'org.openjdk.jmh:jmh-core:1.37' // required for ArchUnit to check JMH tests antlr 'org.antlr:antlr4:' + antlrVersion