// GraphQL API 실행 플랫폼 verification lanes. // // The GraphQL platform design package ships a 16-module Stable map and a 12-module Advanced map. // This repository's registry (`src/config/architecture/modules.json`) owns exactly 19 leaf // identities, so those maps are realised as bounded PACKAGES inside the single registered // `adapter-inbound-graphql` leaf — the same mapping the httpclient capability already uses. The // module identities, their allowed internal dependency edges and the Stable→Advanced isolation rule // stay machine-checked through `GraphQlBuildModel` and `GraphQlModuleBoundaryTest`. // // Lanes (design §24, Stable plan Task 1 / Task 48): // graphqlStableTest Stable platform unit + boundary tests (default lane) // graphqlContractTest cross-module contract suites (@Tag("graphql-contract")) // graphqlAdvancedTest Advanced/Experimental capability tests (@Tag("graphql-advanced")) // graphqlPerformanceTest load/soak/fault scenarios (@Tag("graphql-performance")) // // `graphql-performance` is excluded from the default `test` task so external load and soak work can // never run inside the unit lane. ext.registerGraphQlPlatformTestLanes = { -> String platformPackage = 'dev.caskeleton.adapter.inbound.graphql' tasks.named('test') { useJUnitPlatform { excludeTags 'quarantine', 'graphql-performance' } } Closure configureLane = { org.gradle.api.tasks.testing.Test lane -> lane.group = 'verification' lane.testClassesDirs = sourceSets.test.output.classesDirs lane.classpath = sourceSets.test.runtimeClasspath lane.jvmArgs '-Duser.timezone=UTC' lane.outputs.upToDateWhen { false } } tasks.register('graphqlStableTest', Test) { description = 'Runs the Stable GraphQL platform test lane (Stable plan Task 1-48).' configureLane(it) useJUnitPlatform { excludeTags 'quarantine', 'graphql-performance', 'graphql-advanced' } filter { includeTestsMatching "${platformPackage}.*" failOnNoMatchingTests = true } failOnNoDiscoveredTests = true } tasks.register('graphqlContractTest', Test) { description = 'Runs the GraphQL cross-module contract lane (Stable plan Task 47).' configureLane(it) useJUnitPlatform { includeTags 'graphql-contract' excludeTags 'quarantine' } failOnNoDiscoveredTests = true } tasks.register('graphqlAdvancedTest', Test) { description = 'Runs the Advanced/Experimental GraphQL capability lane (Advanced plan Task 1-19).' configureLane(it) useJUnitPlatform { includeTags 'graphql-advanced' excludeTags 'quarantine' } failOnNoDiscoveredTests = true } tasks.register('graphqlPerformanceTest', Test) { description = 'Runs the GraphQL load, soak and fault scenario lane (design §24.3, §24.4).' configureLane(it) useJUnitPlatform { includeTags 'graphql-performance' excludeTags 'quarantine' } // The Stable gate requires real load/fault evidence before a Stable release claim, so an // empty run here is a missing-evidence condition rather than a pass. // // `failOnNoDiscoveredTests` alone does NOT cover this: it reacts to an empty candidate class // scan, and this lane always scans a non-empty test tree that JUnit then tag-filters down to // zero. Without the explicit result check below the lane reports BUILD SUCCESSFUL while // proving nothing. Verified empirically on Gradle 9.0.0. failOnNoDiscoveredTests = true doLast { File resultsDir = reports.junitXml.outputLocation.get().asFile File[] executed = resultsDir.listFiles({ File file -> file.name.endsWith('.xml') } as FileFilter) if (executed == null || executed.length == 0) { throw new GradleException( 'graphqlPerformanceTest ran no scenario: the Stable release gate requires real ' + 'load, soak and fault evidence, so an empty performance lane is a missing-evidence ' + 'failure, not a pass. Register @Tag("graphql-performance") scenarios or run the ' + 'lane against the external load environment that owns them.') } } } }