test: update integration tests for env-scoped URL shape
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m49s
CI / docker (push) Successful in 2m5s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 1m37s

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) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-16 23:53:55 +02:00
parent 51d7bda5b8
commit b7a107d33f
5 changed files with 39 additions and 36 deletions

View File

@@ -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<String> 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<String> 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<String> 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<String> 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<String> 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);

View File

@@ -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<String> 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<String> 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<String> 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<String> 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<String> 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);

View File

@@ -375,7 +375,7 @@ class SearchControllerIT extends AbstractPostgresIT {
private ResponseEntity<String> 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<String> 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);

View File

@@ -160,7 +160,7 @@ class JwtRefreshIT extends AbstractPostgresIT {
authHeaders.set("X-Cameleer-Protocol-Version", "1");
ResponseEntity<String> response = restTemplate.exchange(
"/api/v1/search/executions",
"/api/v1/environments/default/executions",
HttpMethod.GET,
new HttpEntity<>(authHeaders),
String.class);

View File

@@ -86,7 +86,7 @@ class RegistrationSecurityIT extends AbstractPostgresIT {
headers.set("X-Cameleer-Protocol-Version", "1");
ResponseEntity<String> response = restTemplate.exchange(
"/api/v1/search/executions",
"/api/v1/environments/default/executions",
HttpMethod.GET,
new HttpEntity<>(headers),
String.class);