Skip to content

Commit b32a1ef

Browse files
committed
Add continuous testing getResults MCP variant to use with MCP tools
1 parent 9f1f9ca commit b32a1ef

File tree

3 files changed

+155
-1
lines changed

3 files changed

+155
-1
lines changed

extensions/devui/deployment/src/main/java/io/quarkus/devui/deployment/jsonrpc/DevUIDatabindCodec.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import java.util.Map;
99
import java.util.function.Function;
1010

11+
import org.junit.platform.engine.UniqueId;
12+
13+
import com.fasterxml.jackson.annotation.JsonIgnore;
1114
import com.fasterxml.jackson.annotation.JsonInclude;
1215
import com.fasterxml.jackson.core.JsonGenerator;
1316
import com.fasterxml.jackson.core.JsonParser;
@@ -21,6 +24,7 @@
2124
import com.fasterxml.jackson.databind.module.SimpleModule;
2225
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
2326

27+
import io.quarkus.deployment.dev.testing.TestResult;
2428
import io.quarkus.devui.runtime.jsonrpc.json.JsonMapper;
2529
import io.quarkus.devui.runtime.jsonrpc.json.JsonTypeAdapter;
2630
import io.quarkus.vertx.runtime.jackson.ByteArrayDeserializer;
@@ -134,6 +138,7 @@ public JsonMapper create(JsonTypeAdapter<?, Map<String, Object>> jsonObjectAdapt
134138
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
135139
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
136140

141+
mapper.addMixIn(TestResult.class, TestResultMixIn.class);
137142
SimpleModule module = new SimpleModule("vertx-module-common");
138143
module.addSerializer(Instant.class, new InstantSerializer());
139144
module.addDeserializer(Instant.class, new InstantDeserializer());
@@ -178,4 +183,8 @@ public T deserialize(JsonParser parser, DeserializationContext ctxt) throws IOEx
178183
}
179184
}
180185

186+
private interface TestResultMixIn {
187+
@JsonIgnore
188+
UniqueId getUniqueId();
189+
}
181190
}

extensions/devui/deployment/src/main/java/io/quarkus/devui/deployment/menu/ContinuousTestingProcessor.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ void registerBuildTimeActions(LaunchModeBuildItem launchModeBuildItem,
7777
registerToggleBrokenOnlyMethod(launchModeBuildItem, actions);
7878
registerToggleInstrumentationMethod(launchModeBuildItem, actions);
7979
registerGetResultsMethod(launchModeBuildItem, actions);
80+
registerGetResultsMCPMethod(launchModeBuildItem, actions);
8081
registerGetStatusMethod(launchModeBuildItem, actions);
8182
buildTimeActionProducer.produce(actions);
8283
}
@@ -268,7 +269,7 @@ private void registerGetStatusMethod(LaunchModeBuildItem launchModeBuildItem, Bu
268269
private void registerGetResultsMethod(LaunchModeBuildItem launchModeBuildItem, BuildTimeActionBuildItem actions) {
269270
actions.actionBuilder()
270271
.methodName("getResults")
271-
.description("Get the results of a Continuous testing test run")
272+
.description("Get the full results of a Continuous testing test run")
272273
.function(ignored -> {
273274
try {
274275
Optional<TestSupport> ts = TestSupport.instance();
@@ -291,5 +292,36 @@ private void registerGetResultsMethod(LaunchModeBuildItem launchModeBuildItem, B
291292
.build();
292293
}
293294

295+
/**
296+
* Duplicate of getResults but using a MCP friendly version of TestRunResults.
297+
* TODO to consolidate with getResults after we evaluate other usage
298+
*/
299+
private void registerGetResultsMCPMethod(LaunchModeBuildItem launchModeBuildItem, BuildTimeActionBuildItem actions) {
300+
actions.actionBuilder()
301+
.methodName("getResultsMCP")
302+
.description("Get the results of a Continuous testing test run")
303+
.enableMcpFuctionByDefault()
304+
.function(ignored -> {
305+
try {
306+
Optional<TestSupport> ts = TestSupport.instance();
307+
if (testsDisabled(launchModeBuildItem, ts)) {
308+
return null;
309+
}
310+
TestSupport testSupport = ts.get();
311+
TestRunResults testRunResults = testSupport.getResults();
312+
313+
if (testRunResults == null) {
314+
return null;
315+
}
316+
317+
return new TrimmedTestRunResult(testRunResults);
318+
319+
} catch (Exception e) {
320+
throw new RuntimeException(e);
321+
}
322+
})
323+
.build();
324+
}
325+
294326
private static final String NAMESPACE = "devui-continuous-testing";
295327
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package io.quarkus.devui.deployment.menu;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
import io.quarkus.deployment.dev.testing.TestClassResult;
7+
import io.quarkus.deployment.dev.testing.TestRunResults;
8+
9+
public class TrimmedTestRunResult {
10+
11+
/**
12+
* The run id
13+
*/
14+
private final long id;
15+
16+
/**
17+
* If this ran all tests, or just the modified ones
18+
*/
19+
private final boolean full;
20+
21+
private final long started;
22+
private final long completed;
23+
24+
private final Map<String, TestClassResult> currentFailing = new HashMap<>();
25+
private final Map<String, TestClassResult> historicFailing = new HashMap<>();
26+
private final Map<String, TestClassResult> currentPassing = new HashMap<>();
27+
private final Map<String, TestClassResult> historicPassing = new HashMap<>();
28+
29+
private final long passedCount;
30+
private final long failedCount;
31+
private final long skippedCount;
32+
private final long currentPassedCount;
33+
private final long currentFailedCount;
34+
private final long currentSkippedCount;
35+
36+
public TrimmedTestRunResult(TestRunResults testRunResults) {
37+
this.id = testRunResults.getId();
38+
this.full = testRunResults.isFull();
39+
this.started = testRunResults.getStartedTime();
40+
this.completed = testRunResults.getCompletedTime();
41+
this.currentFailing.putAll(testRunResults.getCurrentFailing());
42+
this.historicFailing.putAll(testRunResults.getHistoricFailing());
43+
this.currentPassing.putAll(testRunResults.getCurrentPassing());
44+
this.historicPassing.putAll(testRunResults.getHistoricPassing());
45+
this.passedCount = testRunResults.getPassedCount();
46+
this.failedCount = testRunResults.getFailedCount();
47+
this.skippedCount = testRunResults.getSkippedCount();
48+
this.currentPassedCount = testRunResults.getCurrentPassedCount();
49+
this.currentFailedCount = testRunResults.getCurrentFailedCount();
50+
this.currentSkippedCount = testRunResults.getCurrentSkippedCount();
51+
}
52+
53+
public long getId() {
54+
return id;
55+
}
56+
57+
public boolean isFull() {
58+
return full;
59+
}
60+
61+
public Map<String, TestClassResult> getCurrentFailing() {
62+
return currentFailing;
63+
}
64+
65+
public Map<String, TestClassResult> getHistoricFailing() {
66+
return historicFailing;
67+
}
68+
69+
public Map<String, TestClassResult> getCurrentPassing() {
70+
return currentPassing;
71+
}
72+
73+
public Map<String, TestClassResult> getHistoricPassing() {
74+
return historicPassing;
75+
}
76+
77+
public long getStartedTime() {
78+
return started;
79+
}
80+
81+
public long getCompletedTime() {
82+
return completed;
83+
}
84+
85+
public long getTotalTime() {
86+
return completed - started;
87+
}
88+
89+
public long getPassedCount() {
90+
return passedCount;
91+
}
92+
93+
public long getFailedCount() {
94+
return failedCount;
95+
}
96+
97+
public long getSkippedCount() {
98+
return skippedCount;
99+
}
100+
101+
public long getCurrentPassedCount() {
102+
return currentPassedCount;
103+
}
104+
105+
public long getCurrentFailedCount() {
106+
return currentFailedCount;
107+
}
108+
109+
public long getCurrentSkippedCount() {
110+
return currentSkippedCount;
111+
}
112+
113+
}

0 commit comments

Comments
 (0)