From 3b3063eb2bba973b78ef0d7ed9748c0a3733efba Mon Sep 17 00:00:00 2001 From: Dai Ha Date: Thu, 3 Sep 2026 15:59:35 +0700 Subject: [PATCH] #252: the route scrape counted commented-out registrations as live MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #259, found by verifying the guard rather than trusting it. The scrape read FleetApp's raw source, so a registration disabled with `//` still matched. Measured: commenting out `app.get("/tasks/{ticket}", ...)` left the test GREEN, while deleting the same line was caught. Only the commented-out shape was blind, and it is the silent direction — the inventory would keep claiming a route the server no longer serves. Drop whole-line comments before scraping. Only lines starting with //, * or /* are dropped, deliberately not every // on a line: that would also cut a string literal containing // (a URL) and could silently delete a real registration sharing the line. The remaining gap is a trailing comment beside real code; no registration here has that shape, and the vacuity test catches a scrape that loses registrations wholesale. Proof: with the fix, the comment-out mutation fails naming "Removed ... [GET /tasks/{ticket}]"; reverted, FleetApp.java confirmed clean. mvn clean install: 0 compile errors, 1257 tests, BUILD SUCCESS. --- .../fleet/rest/RestRouteInventoryTest.java | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/fleetd/src/test/java/dev/ltms/fleet/rest/RestRouteInventoryTest.java b/fleetd/src/test/java/dev/ltms/fleet/rest/RestRouteInventoryTest.java index 2b2f552..dd1ef7a 100644 --- a/fleetd/src/test/java/dev/ltms/fleet/rest/RestRouteInventoryTest.java +++ b/fleetd/src/test/java/dev/ltms/fleet/rest/RestRouteInventoryTest.java @@ -7,6 +7,7 @@ import java.util.Locale; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -68,6 +69,32 @@ class RestRouteInventoryTest { "GET /tasks/{ticket}" ); + private static final Pattern ROUTE_CALL = + Pattern.compile("app\\.(get|post|delete|put|patch)\\(\\s*\"([^\"]+)\""); + + /** + * Drop whole-line comments before scraping. Without this the scrape reads commented-out code as + * live: a registration disabled with {@code //} still matched, so the route stayed in the + * inventory while the server no longer served it — a silent false PASS, measured on 2026-09-03 + * by commenting out {@code app.get("/tasks/{ticket}", ...)} and watching this test stay green. + * Deleting the same line was caught correctly, so only the commented-out shape was blind. + * + *

Only lines whose first non-blank characters are {@code //}, {@code *} or {@code /*} are + * dropped — deliberately NOT every {@code //} anywhere on a line, because that would also cut a + * string literal containing {@code //} (a URL) and could silently delete a real registration + * sharing that line. The remaining gap is a trailing comment on the same line as real code; no + * registration in this file has that shape, and the vacuity test below would catch a scrape that + * lost registrations wholesale. + */ + private static String withoutCommentLines(String source) { + return source.lines() + .filter(line -> { + String t = line.stripLeading(); + return !(t.startsWith("//") || t.startsWith("*") || t.startsWith("/*")); + }) + .collect(Collectors.joining("\n")); + } + /** * Every {@code app.("")} call in {@link FleetApp}'s source, as {@code "VERB path"}. * This matches inside an {@code if (...) { ... }} block just as well as a top-level statement — @@ -75,8 +102,7 @@ class RestRouteInventoryTest { * catches {@code GET /metrics} (registered conditionally on {@code metrics != null}). */ private static Set routesTheServerRegisters() throws Exception { - String source = Files.readString(REST_SOURCE); - Matcher m = Pattern.compile("app\\.(get|post|delete|put|patch)\\(\\s*\"([^\"]+)\"").matcher(source); + Matcher m = ROUTE_CALL.matcher(withoutCommentLines(Files.readString(REST_SOURCE))); Set found = new LinkedHashSet<>(); while (m.find()) { found.add(m.group(1).toUpperCase(Locale.ROOT) + " " + m.group(2));