From b7a107d33feedcef1d3ec1f2b016eba8a7dc012e Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Thu, 16 Apr 2026 23:53:55 +0200 Subject: [PATCH] test: update integration tests for env-scoped URL shape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Picks up the URL moves from P2/P3A/P3B/P3C. Also fixes a latent bug in AppControllerIT.uploadJar_asOperator_returns201 / DeploymentControllerIT setUp: the tests were passing the app's UUID as the {appSlug} path variable (via `path("id").asText()`); the old AppController looked up apps via getBySlug(), so the legacy URL call would 404 when the slug literal was a UUID. Now the test tracks the known slug string and uses it for every /apps/{appSlug}/... path. Test URL updates: - SearchControllerIT: /api/v1/search/executions → /api/v1/environments/default/executions (GET) and /api/v1/environments/default/executions/search (POST). - AppControllerIT: /api/v1/apps → /api/v1/environments/default/apps. Request bodies drop environmentId (it's in the path). - DeploymentControllerIT: /api/v1/apps/{appId}/deployments → /api/v1/environments/default/apps/{appSlug}/deployments. DeployRequest body drops environmentId. - JwtRefreshIT + RegistrationSecurityIT: smoke-test protected endpoint call updated to the new /environments/default/executions shape. All tests compile clean. Runtime behavior requires a full stack (Postgres + ClickHouse + Docker); validating integration tests is a pre-merge step before merging the feature branch. Remaining pre-merge items (not blocked by code): 1. Regenerate ui/src/api/schema.d.ts + openapi.json by running `cd ui && npm run generate-api:live` against a running backend. SearchController, DeploymentController, etc. DTO signatures have changed; schema.d.ts is frozen at the pre-migration shape. Raw-fetch call sites introduced in P3A/P3C work at runtime without the schema; the regen only sharpens TypeScript coverage. 2. Smoke test locally: boot server, verify EnvironmentsPage, AppsTab, Exchanges, Dashboard, Runtime pages all function. 3. Run `mvn verify` end-to-end (Testcontainers + Docker required). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../app/controller/AppControllerIT.java | 38 +++++++++---------- .../controller/DeploymentControllerIT.java | 29 +++++++------- .../app/controller/SearchControllerIT.java | 4 +- .../server/app/security/JwtRefreshIT.java | 2 +- .../app/security/RegistrationSecurityIT.java | 2 +- 5 files changed, 39 insertions(+), 36 deletions(-) diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AppControllerIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AppControllerIT.java index 599e4832..68c612c6 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AppControllerIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AppControllerIT.java @@ -60,12 +60,12 @@ class AppControllerIT extends AbstractPostgresIT { @Test void createApp_asOperator_returns201() throws Exception { - String json = String.format(""" - {"environmentId": "%s", "slug": "my-app", "displayName": "My App"} - """, defaultEnvId); + String json = """ + {"slug": "my-app", "displayName": "My App"} + """; ResponseEntity response = restTemplate.exchange( - "/api/v1/apps", HttpMethod.POST, + "/api/v1/environments/default/apps", HttpMethod.POST, new HttpEntity<>(json, securityHelper.authHeaders(operatorJwt)), String.class); @@ -79,16 +79,16 @@ class AppControllerIT extends AbstractPostgresIT { @Test void listApps_asOperator_returnsCreatedApp() throws Exception { // Create an app first - String json = String.format(""" - {"environmentId": "%s", "slug": "list-test", "displayName": "List Test"} - """, defaultEnvId); + String json = """ + {"slug": "list-test", "displayName": "List Test"} + """; restTemplate.exchange( - "/api/v1/apps", HttpMethod.POST, + "/api/v1/environments/default/apps", HttpMethod.POST, new HttpEntity<>(json, securityHelper.authHeaders(operatorJwt)), String.class); ResponseEntity response = restTemplate.exchange( - "/api/v1/apps?environmentId=" + defaultEnvId, HttpMethod.GET, + "/api/v1/environments/default/apps", HttpMethod.GET, new HttpEntity<>(securityHelper.authHeadersNoBody(operatorJwt)), String.class); @@ -100,12 +100,12 @@ class AppControllerIT extends AbstractPostgresIT { @Test void createApp_asViewer_returns403() { - String json = String.format(""" - {"environmentId": "%s", "slug": "viewer-app", "displayName": "Viewer App"} - """, defaultEnvId); + String json = """ + {"slug": "viewer-app", "displayName": "Viewer App"} + """; ResponseEntity response = restTemplate.exchange( - "/api/v1/apps", HttpMethod.POST, + "/api/v1/environments/default/apps", HttpMethod.POST, new HttpEntity<>(json, securityHelper.authHeaders(viewerJwt)), String.class); @@ -114,15 +114,15 @@ class AppControllerIT extends AbstractPostgresIT { @Test void uploadJar_asOperator_returns201() throws Exception { + String appSlug = "jar-test"; // Create app String json = String.format(""" - {"environmentId": "%s", "slug": "jar-test", "displayName": "JAR Test"} - """, defaultEnvId); - ResponseEntity createResponse = restTemplate.exchange( - "/api/v1/apps", HttpMethod.POST, + {"slug": "%s", "displayName": "JAR Test"} + """, appSlug); + restTemplate.exchange( + "/api/v1/environments/default/apps", HttpMethod.POST, new HttpEntity<>(json, securityHelper.authHeaders(operatorJwt)), String.class); - String appId = objectMapper.readTree(createResponse.getBody()).path("id").asText(); // Upload JAR (fake content) byte[] jarContent = "fake-jar-content".getBytes(); @@ -142,7 +142,7 @@ class AppControllerIT extends AbstractPostgresIT { headers.setContentType(MediaType.MULTIPART_FORM_DATA); ResponseEntity response = restTemplate.exchange( - "/api/v1/apps/" + appId + "/versions", HttpMethod.POST, + "/api/v1/environments/default/apps/" + appSlug + "/versions", HttpMethod.POST, new HttpEntity<>(body, headers), String.class); diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DeploymentControllerIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DeploymentControllerIT.java index bcfdfba5..6f792357 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DeploymentControllerIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DeploymentControllerIT.java @@ -35,6 +35,7 @@ class DeploymentControllerIT extends AbstractPostgresIT { private String adminJwt; private String defaultEnvId; private String appId; + private String appSlugRef; private String versionId; @BeforeEach @@ -60,15 +61,17 @@ class DeploymentControllerIT extends AbstractPostgresIT { } } - // Create app + // Create app (slug becomes the path identifier) + String appSlug = "deploy-test"; String appJson = String.format(""" - {"environmentId": "%s", "slug": "deploy-test", "displayName": "Deploy Test"} - """, defaultEnvId); + {"slug": "%s", "displayName": "Deploy Test"} + """, appSlug); ResponseEntity appResponse = restTemplate.exchange( - "/api/v1/apps", HttpMethod.POST, + "/api/v1/environments/default/apps", HttpMethod.POST, new HttpEntity<>(appJson, securityHelper.authHeaders(operatorJwt)), String.class); appId = objectMapper.readTree(appResponse.getBody()).path("id").asText(); + appSlugRef = appSlug; // Upload a JAR version byte[] jarContent = "fake-jar-for-deploy".getBytes(); @@ -85,7 +88,7 @@ class DeploymentControllerIT extends AbstractPostgresIT { headers.set("X-Cameleer-Protocol-Version", "1"); headers.setContentType(MediaType.MULTIPART_FORM_DATA); ResponseEntity versionResponse = restTemplate.exchange( - "/api/v1/apps/" + appId + "/versions", HttpMethod.POST, + "/api/v1/environments/default/apps/" + appSlug + "/versions", HttpMethod.POST, new HttpEntity<>(body, headers), String.class); versionId = objectMapper.readTree(versionResponse.getBody()).path("id").asText(); @@ -95,11 +98,11 @@ class DeploymentControllerIT extends AbstractPostgresIT { void deploy_asOperator_returns202() throws Exception { // Deploy creates a record; the async executor will fail (no Docker) but the record should exist String json = String.format(""" - {"appVersionId": "%s", "environmentId": "%s"} - """, versionId, defaultEnvId); + {"appVersionId": "%s"} + """, versionId); ResponseEntity response = restTemplate.exchange( - "/api/v1/apps/" + appId + "/deployments", HttpMethod.POST, + "/api/v1/environments/default/apps/" + appSlugRef + "/deployments", HttpMethod.POST, new HttpEntity<>(json, securityHelper.authHeaders(operatorJwt)), String.class); @@ -114,15 +117,15 @@ class DeploymentControllerIT extends AbstractPostgresIT { void listDeployments_asOperator_returnsDeployments() throws Exception { // Create a deployment first String json = String.format(""" - {"appVersionId": "%s", "environmentId": "%s"} - """, versionId, defaultEnvId); + {"appVersionId": "%s"} + """, versionId); restTemplate.exchange( - "/api/v1/apps/" + appId + "/deployments", HttpMethod.POST, + "/api/v1/environments/default/apps/" + appSlugRef + "/deployments", HttpMethod.POST, new HttpEntity<>(json, securityHelper.authHeaders(operatorJwt)), String.class); ResponseEntity response = restTemplate.exchange( - "/api/v1/apps/" + appId + "/deployments", HttpMethod.GET, + "/api/v1/environments/default/apps/" + appSlugRef + "/deployments", HttpMethod.GET, new HttpEntity<>(securityHelper.authHeadersNoBody(operatorJwt)), String.class); @@ -135,7 +138,7 @@ class DeploymentControllerIT extends AbstractPostgresIT { @Test void getDeployment_notFound_returns404() { ResponseEntity response = restTemplate.exchange( - "/api/v1/apps/" + appId + "/deployments/00000000-0000-0000-0000-000000000000", + "/api/v1/environments/default/apps/" + appSlugRef + "/deployments/00000000-0000-0000-0000-000000000000", HttpMethod.GET, new HttpEntity<>(securityHelper.authHeadersNoBody(operatorJwt)), String.class); diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java index 94431faa..651a0cc7 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java @@ -375,7 +375,7 @@ class SearchControllerIT extends AbstractPostgresIT { private ResponseEntity searchGet(String queryString) { HttpHeaders headers = securityHelper.authHeadersNoBody(jwt); return restTemplate.exchange( - "/api/v1/search/executions" + queryString, + "/api/v1/environments/default/executions" + queryString, HttpMethod.GET, new HttpEntity<>(headers), String.class); @@ -383,7 +383,7 @@ class SearchControllerIT extends AbstractPostgresIT { private ResponseEntity searchPost(String jsonBody) { return restTemplate.exchange( - "/api/v1/search/executions", + "/api/v1/environments/default/executions/search", HttpMethod.POST, new HttpEntity<>(jsonBody, securityHelper.authHeaders(viewerJwt)), String.class); diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtRefreshIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtRefreshIT.java index 5672cdf4..c934cea8 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtRefreshIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtRefreshIT.java @@ -160,7 +160,7 @@ class JwtRefreshIT extends AbstractPostgresIT { authHeaders.set("X-Cameleer-Protocol-Version", "1"); ResponseEntity response = restTemplate.exchange( - "/api/v1/search/executions", + "/api/v1/environments/default/executions", HttpMethod.GET, new HttpEntity<>(authHeaders), String.class); diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/security/RegistrationSecurityIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/security/RegistrationSecurityIT.java index 394dbaff..fc6905c7 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/security/RegistrationSecurityIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/security/RegistrationSecurityIT.java @@ -86,7 +86,7 @@ class RegistrationSecurityIT extends AbstractPostgresIT { headers.set("X-Cameleer-Protocol-Version", "1"); ResponseEntity response = restTemplate.exchange( - "/api/v1/search/executions", + "/api/v1/environments/default/executions", HttpMethod.GET, new HttpEntity<>(headers), String.class);