Skip to content

Commit 5a62cee

Browse files
committed
Add sample for M7
1 parent 83a0d22 commit 5a62cee

37 files changed

+314
-784
lines changed

.github/workflows/gradle.yml

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,26 +35,3 @@ jobs:
3535

3636
- name: Build with Gradle Wrapper
3737
run: ./gradlew build
38-
39-
execute-tests-in-sample-consumer:
40-
41-
runs-on: ubuntu-latest
42-
permissions:
43-
contents: read
44-
45-
steps:
46-
- uses: actions/checkout@v4
47-
- name: Set up JDK 17
48-
uses: actions/setup-java@v4
49-
with:
50-
java-version: '17'
51-
distribution: 'temurin'
52-
53-
# Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies.
54-
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
55-
- name: Setup Gradle
56-
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0
57-
58-
- name: executeTests with Gradle Wrapper
59-
working-directory: sample-consumer
60-
run: ./gradlew executeTests

README.md

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,60 @@
1-
# Resource-Based Testing in JUnit 5
1+
# Milestone 7 Demo
22

3-
This project provides a sample [JUnit Test Engine](https://docs.junit.org/current/user-guide/#test-engines) that uses resource files to
4-
define tests that can be run with JUnit 5.
3+
This project demonstrates running non-class-based tests via the Tooling API. The demo consists of the following projects:
4+
- `engine`: contains a JUnit Test engine demonstrating resource-based test execution.
5+
- `demo-m7`: a test project that defines tests in the `tests.xml` using the test engine.
6+
- `demo-m7-client`: a sample Tooling API client that invokes the `customTest` task on the `demo-m7` project and renders the progress events on the console.
57

6-
This project contains an included build in `/sample-consumer`.
8+
Run the demo project using `./gradlew :demo-m7-client:run -q` from the root of this repository.
79

8-
Run that project to demo using the plugin in a Gradle build with: `executeTests`.
10+
## Details
11+
12+
The test engine defined in `engine` project is slightly modified to exhibit the following behavior. For each test definition it:
13+
- provides some output on stdout for each test,
14+
- will fail tests with names containing the 'fail' substring,
15+
- will skip tests with names containing the 'skip' substring,
16+
- will publish metadata for tests with names containing the 'publishMetadata' substring,
17+
- will publish a file entry for tests with names containing the 'publishFile' substring, and
18+
- succeeds the remaining tests.
19+
20+
The `demo-m7` project defines a `customtest` task that uses the test engine and exercise all the above behaviors.
21+
22+
Tooling API client is defined in the `M7ToolingClient` class. It connects to the `demo-m7` project and invokes the `customTest` task.
23+
The client listens to the following progress event operation types: TEST, TEST_OUTPUT and TEST_METADATA.
24+
25+
The rendered output should look similar to the following:
26+
27+
```
28+
------------------------------------------------
29+
Running resource-based tests via the Tooling API
30+
------------------------------------------------
31+
START Gradle Test Run :demo-m7:customTest
32+
START Gradle Test Executor 27
33+
START Test tests.xml : failingTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml)
34+
OUTPUT StdOut: Test engine fails tests with names containing the 'fail' substring Test [file=tests.xml, name=failingTest]
35+
FAILURE Test tests.xml : failingTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml) (reason: Test failed because its name contains the 'fail' substring)
36+
START Test tests.xml : skippedTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml)
37+
OUTPUT StdOut: Test engine skips tests with names containing the 'skip' substring Test [file=tests.xml, name=skippedTest]
38+
SKIPPED Test tests.xml : skippedTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml)
39+
START Test tests.xml : publishMetadataTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml)
40+
OUTPUT StdOut: Test engine publishes some metadata for tests with names containing the 'publishMetadata' substring Test [file=tests.xml, name=publishMetadataTest]
41+
METADATA Entry:{non-class-based-testing=check}
42+
SUCCESS Test tests.xml : publishMetadataTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml)
43+
START Test tests.xml : publishFileTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml)
44+
OUTPUT StdOut: Test engine publishes a file entry for tests with names containing the 'publishFile' substring Test [file=tests.xml, name=publishFileTest]
45+
METADATA File: /var/folders/6v/j9zhh5fs00b_bbr2f35_7s7m0000gq/T/tests.txt type: text/plain
46+
SUCCESS Test tests.xml : publishFileTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml)
47+
START Test tests.xml : passingTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml)
48+
SUCCESS Test tests.xml : passingTest (file=/Users/donat/Development/git/gradle/sample-rbt-engine/demo-m7/src/customTest/definitions/tests.xml)
49+
FAILURE Gradle Test Executor 27
50+
FAILURE Gradle Test Run :demo-m7:customTest
51+
```
52+
53+
The indentations represent the event hierarchy. It demonstrates that the Tooling API client can successfully execute non-class-based tests, and it emits the same events and data for
54+
- Test started/finished
55+
- The test results: successful, failed, skipped
56+
- The test metadata (including ReportEntry and FileEntry), and
57+
- Test output
58+
59+
NOTE: this demo uses a snapshot version of Gradle 9.4.0 that includes the non-class-based testing feature.
60+
We'll update the demo once a milestone or a release version is available with the feature.

build-logic/conventions/build.gradle.kts

Lines changed: 0 additions & 9 deletions
This file was deleted.

build-logic/conventions/src/main/kotlin/java-lib-conventions.gradle.kts

Lines changed: 0 additions & 13 deletions
This file was deleted.

build-logic/settings.gradle.kts

Lines changed: 0 additions & 17 deletions
This file was deleted.

demo-m7-client/build.gradle.kts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
plugins {
2+
`application`
3+
kotlin("jvm") version "2.2.21"
4+
}
5+
6+
dependencies {
7+
implementation("org.gradle:gradle-tooling-api:9.4.0-milestone-3")
8+
implementation(libs.slf4j.simple)
9+
}
10+
11+
java {
12+
sourceCompatibility = JavaVersion.VERSION_17
13+
targetCompatibility = JavaVersion.VERSION_17
14+
15+
toolchain {
16+
languageVersion = JavaLanguageVersion.of(17)
17+
}
18+
}
19+
20+
application {
21+
mainClass.set("sample.M7ToolingClient")
22+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package sample
2+
3+
import org.gradle.tooling.GradleConnectionException
4+
import org.gradle.tooling.GradleConnector
5+
import org.gradle.tooling.ResultHandler
6+
import org.gradle.tooling.events.*
7+
import org.gradle.tooling.events.test.*
8+
import org.gradle.tooling.events.test.source.FilesystemSource
9+
import java.io.File
10+
11+
class M7ToolingClient {
12+
companion object {
13+
@JvmStatic
14+
fun main(args: Array<String>) {
15+
// Non-class-based tests will be reported to Tooling API (TAPI) clients like class-based tests.
16+
// Gradle will emit the same events/data:
17+
// Test started/finished
18+
// Test results (successful, failed, skipped)
19+
// Test metadata (includes ReportEntry and FileEntry data)
20+
// Test output
21+
22+
println("------------------------------------------------")
23+
println("Running resource-based tests via the Tooling API")
24+
println("------------------------------------------------")
25+
val projectDir = File("..")
26+
GradleConnector.newConnector()
27+
.forProjectDirectory(projectDir)
28+
.useBuildDistribution()
29+
.connect()
30+
.use {
31+
it.newTestLauncher()
32+
.addProgressListener(ProgressEventListener(), OperationType.TEST, OperationType.TEST_OUTPUT, OperationType.TEST_METADATA)
33+
.withTestsFor { s -> s.forTaskPath(":demo-m7:customTest")}
34+
.run(SuppressingResultHandler)
35+
}
36+
}
37+
}
38+
39+
class ProgressEventListener : ProgressListener {
40+
var descriptorParents = mutableMapOf<OperationDescriptor, Int>()
41+
override fun statusChanged(event: ProgressEvent) {
42+
val parents: Int
43+
if (event.descriptor.parent == null) {
44+
parents = 0
45+
descriptorParents[event.descriptor] = parents
46+
} else {
47+
val grandParents = descriptorParents[event.descriptor.parent]!!
48+
parents = grandParents + 1
49+
descriptorParents[event.descriptor] = parents
50+
}
51+
println("${" ".repeat(parents)}${renderEvent(event)}")
52+
}
53+
54+
private fun renderEvent(event: ProgressEvent): String {
55+
val prefix = when (event) {
56+
is StartEvent -> "START "
57+
is FinishEvent -> {
58+
when(event.result) {
59+
is SuccessResult -> "SUCCESS "
60+
is SkippedResult-> "SKIPPED "
61+
is FailureResult -> "FAILURE "
62+
else -> "FINISH "
63+
}
64+
}
65+
is TestOutputEvent -> "OUTPUT "
66+
is TestMetadataEvent -> "METADATA "
67+
else -> "UNKNOWN "
68+
}
69+
70+
val content = when (val descriptor = event.descriptor) {
71+
is JvmTestOperationDescriptor -> {
72+
val source = descriptor.source
73+
val sourceInfo = if (source is FilesystemSource) {
74+
" (file=${(descriptor.source as? FilesystemSource)?.file?.absolutePath})"
75+
} else {
76+
""
77+
}
78+
"$descriptor $sourceInfo"
79+
}
80+
is TestOutputDescriptor -> {
81+
"${descriptor.destination}: ${descriptor.message.trim()}"
82+
}
83+
else -> {
84+
if (event is TestKeyValueMetadataEvent) {
85+
if (event.values.size == 1) "Entry:" + event.values.toString() else "Entries:" + event.values.toString()
86+
} else if (event is TestFileAttachmentMetadataEvent) {
87+
"File: ${event.file.absolutePath} type: ${event.mediaType}"
88+
} else {
89+
"$descriptor"
90+
}
91+
}
92+
}
93+
94+
val postfix = if (event is FinishEvent && event.result is FailureResult && (event.result as FailureResult).failures.isNotEmpty()) {
95+
"(reason: ${(event.result as FailureResult).failures[0].message})"
96+
} else {
97+
""
98+
}
99+
100+
return "$prefix $content $postfix"
101+
}
102+
103+
}
104+
105+
object SuppressingResultHandler : ResultHandler<Void> {
106+
override fun onComplete(result: Void?) {
107+
}
108+
109+
override fun onFailure(failure: GradleConnectionException?) {
110+
// suppress build failure
111+
}
112+
}
113+
}

demo-m7/build.gradle.kts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
plugins {
2+
`java-library`
3+
}
4+
5+
java {
6+
sourceCompatibility = JavaVersion.VERSION_17
7+
targetCompatibility = JavaVersion.VERSION_17
8+
9+
toolchain {
10+
languageVersion = JavaLanguageVersion.of(17)
11+
}
12+
}
13+
14+
testing {
15+
suites {
16+
register<JvmTestSuite>("customTest") {
17+
useJUnitJupiter()
18+
19+
dependencies {
20+
implementation(project(":engine"))
21+
}
22+
23+
targets.all {
24+
testTask.configure {
25+
testDefinitionDirs.from("src/customTest/definitions")
26+
}
27+
}
28+
}
29+
30+
named("test", JvmTestSuite::class) {
31+
useJUnitJupiter()
32+
33+
dependencies {
34+
implementation(project(":engine"))
35+
}
36+
37+
targets.all {
38+
testTask.configure {
39+
testDefinitionDirs.from("src/test/definitions")
40+
}
41+
}
42+
}
43+
}
44+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<tests>
3+
<test name="failingTest" />
4+
<test name="skippedTest" />
5+
<test name="publishMetadataTest" />
6+
<test name="publishFileTest" />
7+
<test name="passingTest" />
8+
</tests>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<tests>
3+
<test name="skippedTest" />
4+
<test name="publishMetadataTest" />
5+
<test name="publishFileTest" />
6+
<test name="passingTest" />
7+
</tests>

0 commit comments

Comments
 (0)