From 22ea205ae73a3035b0a91b3913a591fe2f63cd88 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 15 Jul 2026 11:13:46 +0300 Subject: [PATCH 1/3] Run integration tests in CI and fix the openig-war IT suite Switch the CI build from `mvn package` to `mvn verify` so the failsafe integration tests actually execute. `package` stops before the integration-test/verify phases, so IT_MockRoute/IT_SwaggerRoute (openig-war) and the openig-doc Sample tests never ran in CI. Make openig-war enforce IT results: its failsafe execution only bound `integration-test`, so failures were silently swallowed - add the `verify` goal. Mirror surefire's `--add-opens` argLine onto the failsafe plugin so RestAssured assertion failures report cleanly on JDK 17+ instead of a GroovyRuntimeException. Fix the war IT fixtures: the shared petstore spec declares base path `/v2.1` but the mock/custom routes used `/v2`, so the mock handler never matched an operation (404). Align the request paths and route conditions to `/v2.1`, using an unescaped dot in the route JSON conditions (an escaped `\.` fails to compile in the EL string literal and the route is silently rejected). --- .github/workflows/build.yml | 2 +- openig-war/pom.xml | 2 +- .../openig/test/integration/IT_MockRoute.java | 12 ++++++------ .../src/test/resources/routes/01-find-pet.json | 4 ++-- .../src/test/resources/routes/petstore-mock.json | 2 +- pom.xml | 3 +++ 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c92dcd7..d2b54e91 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ jobs: - name: Build with Maven env: MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10 - run: mvn --batch-mode --errors --update-snapshots package --file pom.xml + run: mvn --batch-mode --errors --update-snapshots verify --file pom.xml - name: Upload artifacts uses: actions/upload-artifact@v7 with: diff --git a/openig-war/pom.xml b/openig-war/pom.xml index ae9c0bb0..36f8ce7f 100644 --- a/openig-war/pom.xml +++ b/openig-war/pom.xml @@ -205,8 +205,8 @@ integration-test + verify - integration-test integration-test diff --git a/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_MockRoute.java b/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_MockRoute.java index 6bb16368..fc6cc715 100644 --- a/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_MockRoute.java +++ b/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_MockRoute.java @@ -83,11 +83,11 @@ public void testMockRoute_petCollection() throws IOException { .atMost(30, SECONDS) .until(() -> routeAvailable(ROUTE_ID)); - // GET /v2/pet/findByStatus?status=available → 200 JSON array + // GET /v2.1/pet/findByStatus?status=available → 200 JSON array final String body = RestAssured .given() .when() - .get("/v2/pet/findByStatus?status=available") + .get("/v2.1/pet/findByStatus?status=available") .then() .statusCode(200) .contentType("application/json") @@ -99,7 +99,7 @@ public void testMockRoute_petCollection() throws IOException { // Parse and assert array contents @SuppressWarnings("unchecked") final List> pets = - RestAssured.given().when().get("/v2/pet/findByStatus?status=available") + RestAssured.given().when().get("/v2.1/pet/findByStatus?status=available") .jsonPath().getList("$"); assertThat(pets).isNotEmpty(); @@ -131,7 +131,7 @@ public void testMockRoute_petCollection() throws IOException { .until(() -> !routeAvailable(ROUTE_ID)); RestAssured.given().when() - .get("/v2/pet/findByStatus?status=available") + .get("/v2.1/pet/findByStatus?status=available") .then() .statusCode(404); } @@ -161,10 +161,10 @@ public void testMockRoute_singlePet() throws IOException { .atMost(30, SECONDS) .until(() -> routeAvailable("petstore-mock-single")); - // GET /v2/pet/{petId} → single object + // GET /v2.1/pet/{petId} → single object @SuppressWarnings("unchecked") final Map pet = - RestAssured.given().when().get("/v2/pet/42") + RestAssured.given().when().get("/v2.1/pet/42") .then() .statusCode(200) .contentType("application/json") diff --git a/openig-war/src/test/resources/routes/01-find-pet.json b/openig-war/src/test/resources/routes/01-find-pet.json index 5c89b4bb..5d6cd768 100644 --- a/openig-war/src/test/resources/routes/01-find-pet.json +++ b/openig-war/src/test/resources/routes/01-find-pet.json @@ -1,7 +1,7 @@ { "name": "swagger-petstore-test", - "condition": "${(matches(request.uri.path, '^/v2/pet/findByStatus$') && matches(request.method, '^GET$'))}", - "baseURI": "http://localhost:8090/v2", + "condition": "${(matches(request.uri.path, '^/v2.1/pet/findByStatus$') && matches(request.method, '^GET$'))}", + "baseURI": "http://localhost:8090/v2.1", "heap": [ { "name": "OpenApiValidator", diff --git a/openig-war/src/test/resources/routes/petstore-mock.json b/openig-war/src/test/resources/routes/petstore-mock.json index 60dac964..b41b5276 100644 --- a/openig-war/src/test/resources/routes/petstore-mock.json +++ b/openig-war/src/test/resources/routes/petstore-mock.json @@ -1,6 +1,6 @@ { "name": "petstore-mock", - "condition": "${matches(request.uri.path, '^/v2/')}", + "condition": "${matches(request.uri.path, '^/v2.1/')}", "heap": [ { "name": "PetstoreMock", diff --git a/pom.xml b/pom.xml index 6033c767..794b603d 100644 --- a/pom.xml +++ b/pom.xml @@ -939,6 +939,9 @@ org.apache.maven.plugins maven-failsafe-plugin 3.0.0-M4 + + ${java.surefire.options} + From d326bcd4060da43b49a4def2c599a64884a8d0f0 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 15 Jul 2026 12:01:14 +0300 Subject: [PATCH 2/3] Make the war integration tests work on Windows IT_MockRoute and IT_SwaggerRoute substitute an absolute spec-file path into the route JSON and an EL `read('...')` expression. On Windows the path uses backslashes (C:\..., D:\...), which are invalid JSON/EL escapes, so the route JSON fails to parse and the route never loads (routeAvailable times out). Normalise the injected paths to forward slashes, which OpenIG's read()/File accepts on every OS (no-op on Linux/macOS). --- .../openig/test/integration/IT_MockRoute.java | 4 +++- .../openig/test/integration/IT_SwaggerRoute.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_MockRoute.java b/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_MockRoute.java index fc6cc715..a6aee558 100644 --- a/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_MockRoute.java +++ b/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_MockRoute.java @@ -216,6 +216,8 @@ private static String getSpecFilePath() throws IOException { Files.copy(in, tmp, StandardCopyOption.REPLACE_EXISTING); } tmp.toFile().deleteOnExit(); - return tmp.toAbsolutePath().toString(); + // Use forward slashes: the path is substituted into the route JSON and an EL read('...') + // expression, where a Windows backslash path (C:\...) is an invalid JSON/EL escape. + return tmp.toAbsolutePath().toString().replace('\\', '/'); } } diff --git a/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_SwaggerRoute.java b/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_SwaggerRoute.java index fa263922..ae233287 100644 --- a/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_SwaggerRoute.java +++ b/openig-war/src/test/java/org/openidentityplatrform/openig/test/integration/IT_SwaggerRoute.java @@ -87,7 +87,9 @@ public void testSwaggerRoute() throws IOException { @Test public void testCustomRoute() throws IOException { String testConfigPath = getTestConfigPath(); - String openApiSpec = this.getClass().getClassLoader().getResource("routes/petstore.yaml").getPath(); + // Use forward slashes: the path is substituted into the route JSON and an EL read('...') + // expression, where a Windows backslash path (D:\...) is an invalid JSON/EL escape. + String openApiSpec = this.getClass().getClassLoader().getResource("routes/petstore.yaml").getPath().replace('\\', '/'); String routeContents = IOUtils.resourceToString("routes/01-find-pet.json", StandardCharsets.UTF_8, this.getClass().getClassLoader()) .replace("$$SWAGGER_FILE$$", openApiSpec); Path destination = Path.of(testConfigPath, "config", "routes", "01-find-pet.json"); From 63791d620b970b11ccf1b9815a025e20b45d55cd Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 15 Jul 2026 12:17:13 +0300 Subject: [PATCH 3/3] Make OpenApiRouteBuilder spec path cross-platform The auto-built OpenAPI route embeds specFile.getAbsolutePath() into an EL `${read('...')}` string literal for the validator and mock-handler config. On Windows the absolute path uses the '\' separator, which the EL parser treats as an (invalid) escape sequence, so the generated route fails to parse and never loads. Normalise the platform separator to '/', which read()/File accept on every OS (no-op on Linux/macOS). --- .../openig/handler/router/OpenApiRouteBuilder.java | 10 ++++++++-- .../openig/handler/router/OpenApiRouteBuilderTest.java | 6 ++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/openig-core/src/main/java/org/forgerock/openig/handler/router/OpenApiRouteBuilder.java b/openig-core/src/main/java/org/forgerock/openig/handler/router/OpenApiRouteBuilder.java index 31e9d3ff..706ccd0f 100644 --- a/openig-core/src/main/java/org/forgerock/openig/handler/router/OpenApiRouteBuilder.java +++ b/openig-core/src/main/java/org/forgerock/openig/handler/router/OpenApiRouteBuilder.java @@ -108,9 +108,15 @@ public JsonValue buildRouteJson(final OpenAPI spec, final File specFile, routeName, specFile.getName(), condition, baseUri != null ? baseUri : "", failOnResponseViolation, mockMode); + // Normalise the platform path separator to '/': this path is embedded in an EL + // read('...') string literal, where a Windows backslash (D:\...) is parsed as an + // (invalid) escape sequence. Forward slashes are accepted by read()/File on every OS. + final String absolutePath = specFile.getAbsolutePath(); + final String specPath = absolutePath == null ? null : absolutePath.replace(File.separatorChar, '/'); + // ----- heap: OpenApiValidationFilter entry ----- final Map validatorConfig = new LinkedHashMap<>(); - validatorConfig.put("spec", "${read('" + specFile.getAbsolutePath() + "')}"); + validatorConfig.put("spec", "${read('" + specPath + "')}"); validatorConfig.put("failOnResponseViolation", failOnResponseViolation); final Map validatorHeapObject = new LinkedHashMap<>(); @@ -125,7 +131,7 @@ public JsonValue buildRouteJson(final OpenAPI spec, final File specFile, if (mockMode) { // ----- heap: OpenApiMockResponseHandler entry ----- final Map mockConfig = new LinkedHashMap<>(); - mockConfig.put("spec", "${read('" + specFile.getAbsolutePath() + "')}"); + mockConfig.put("spec", "${read('" + specPath + "')}"); final Map mockHeapObject = new LinkedHashMap<>(); mockHeapObject.put("name", MOCK_HANDLER_HEAP_NAME); diff --git a/openig-core/src/test/java/org/forgerock/openig/handler/router/OpenApiRouteBuilderTest.java b/openig-core/src/test/java/org/forgerock/openig/handler/router/OpenApiRouteBuilderTest.java index 7b4d40cb..9a75fbee 100644 --- a/openig-core/src/test/java/org/forgerock/openig/handler/router/OpenApiRouteBuilderTest.java +++ b/openig-core/src/test/java/org/forgerock/openig/handler/router/OpenApiRouteBuilderTest.java @@ -239,7 +239,8 @@ public void buildRouteJson_validatorHeapObjectHasAbsoluteSpecFilePath() throws I .orElseThrow(() -> new AssertionError("No OpenApiValidationFilter in heap")); final java.util.Map config = (java.util.Map) validatorEntry.get("config"); - assertThat(config.get("spec").toString()).contains(spec.getAbsolutePath()); + // OpenApiRouteBuilder normalises the platform separator to '/' for the read() literal. + assertThat(config.get("spec").toString()).contains(spec.getAbsolutePath().replace(File.separatorChar, '/')); } @Test @@ -342,7 +343,8 @@ public void buildRouteJson_mockMode_mockHandlerConfigContainsSpecPath() throws I .orElseThrow(() -> new AssertionError("No OpenApiMockResponseHandler in heap")); final java.util.Map config = (java.util.Map) mockEntry.get("config"); - assertThat(config.get("spec").toString()).contains(spec.getAbsolutePath()); + // OpenApiRouteBuilder normalises the platform separator to '/' for the read() literal. + assertThat(config.get("spec").toString()).contains(spec.getAbsolutePath().replace(File.separatorChar, '/')); }