Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,35 @@ private Map<String, Object> sourceEntry(com.xtrmetl.cdc.spi.CdcSourceConnector s
return entry;
}

/**
* Requests CDC engine startup and exposes only a stable public failure contract.
*
* @return {@code 200} when startup is accepted, or {@code 500} without internal startup diagnostics
*/
@PostMapping("/start")
@Observed(name = "cdc.start", contextualName = "cdc-start")
public ResponseEntity<String> startCdc() {
cdcService.start();
return ResponseEntity.ok("CDC process started");
try {
cdcService.start();
return ResponseEntity.ok("CDC process started");
} catch (RuntimeException e) {
return ResponseEntity.internalServerError().body("CDC process could not be started");
}
}

/**
* Requests CDC engine shutdown and exposes only a stable public failure contract.
*
* @return {@code 200} when shutdown succeeds, or {@code 500} without internal shutdown diagnostics
*/
@PostMapping("/stop")
@Observed(name = "cdc.stop", contextualName = "cdc-stop")
public ResponseEntity<String> stopCdc() {
try {
cdcService.stop();
return ResponseEntity.ok("CDC process stopped");
} catch (IOException e) {
return ResponseEntity.internalServerError().body("Error stopping CDC process: " + e.getMessage());
return ResponseEntity.internalServerError().body("CDC process could not be stopped");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ void testStartCdc() {
verify(cdcService, times(1)).start();
}

@Test
void testStartCdcWithExceptionDoesNotExposeInternalDiagnostics() {
String sensitiveDiagnostic =
"Failed to initialize jdbc:postgresql://db.internal/prod?user=cdc&password=driver-secret";
doThrow(new IllegalStateException(sensitiveDiagnostic)).when(cdcService).start();

ResponseEntity<String> response = cdcController.startCdc();

assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
assertEquals("CDC process could not be started", response.getBody());
assertFalse(response.getBody().contains("driver-secret"));
assertFalse(response.getBody().contains("jdbc:postgresql://"));
verify(cdcService, times(1)).start();
}

@Test
void testStopCdc() throws IOException {
ResponseEntity<String> response = cdcController.stopCdc();
Expand All @@ -79,13 +94,17 @@ void testStopCdc() throws IOException {
}

@Test
void testStopCdcWithException() throws IOException {
doThrow(new IOException("Error stopping CDC")).when(cdcService).stop();
void testStopCdcWithExceptionDoesNotExposeInternalDiagnostics() throws IOException {
String sensitiveDiagnostic =
"Error closing offset store at jdbc:postgresql://db.internal/prod?password=driver-secret";
doThrow(new IOException(sensitiveDiagnostic)).when(cdcService).stop();

ResponseEntity<String> response = cdcController.stopCdc();

assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
assertEquals("Error stopping CDC process: Error stopping CDC", response.getBody());
assertEquals("CDC process could not be stopped", response.getBody());
assertFalse(response.getBody().contains("driver-secret"));
assertFalse(response.getBody().contains("jdbc:postgresql://"));
verify(cdcService, times(1)).stop();
}

Expand Down
Loading