Skip to content
Closed
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 @@ -11,6 +11,10 @@
/**
* Adapter for the live Debezium PostgreSQL capture path owned by {@link CdcService}.
*
* <p>The live service reads connection and Debezium settings from deployment configuration. Per-call
* SPI configuration is therefore intentionally unsupported: callers must pass an empty map so values
* such as credentials are never accepted and then silently ignored.</p>
*
* <p>{@link #start(Map)} / {@link #stop()} delegate to the service when available so the SPI
* is a real control surface for the supported source type.</p>
*/
Expand Down Expand Up @@ -67,13 +71,34 @@ public SourceCapabilities capabilities() {
return new SourceCapabilities("debezium-embedded", Set.of("postgresql"), false);
}

/**
* Validates the per-call configuration accepted by this adapter.
*
* <p>The live PostgreSQL capture service is configured by the deployment, not by this SPI call.
* An empty map is therefore the only valid value.</p>
*
* @param config per-call settings; must be non-null and empty
* @throws IllegalArgumentException when {@code config} is null or contains any entry
*/
@Override
public void validate(Map<String, String> config) {
if (config == null) {
throw new IllegalArgumentException("config must not be null");
}
if (!config.isEmpty()) {
throw new IllegalArgumentException(
"postgres-debezium uses deployment-owned configuration; per-call config must be empty"
);
}
}

/**
* Starts the deployment-configured PostgreSQL CDC service.
*
* @param config per-call settings; must be non-null and empty
* @throws IllegalArgumentException when {@code config} is null or contains any entry
* @throws IllegalStateException when the live {@link CdcService} is unavailable
*/
@Override
public void start(Map<String, String> config) {
validate(config);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.xtrmetl.cdc.spi;

import com.xtrmetl.cdc.service.CdcService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.ObjectProvider;

import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;

/**
* Guards the PostgreSQL source SPI against silently ignored per-call configuration.
*/
class PostgresDebeziumCdcSourceConfigurationTest {

@Test
void rejectsCallerConfigurationBeforeStartingDeploymentConfiguredService() {
CdcService service = mock(CdcService.class);
@SuppressWarnings("unchecked")
ObjectProvider<CdcService> provider = mock(ObjectProvider.class);
when(provider.getIfAvailable()).thenReturn(service);
PostgresDebeziumCdcSource source = new PostgresDebeziumCdcSource(provider);
String rejectedSecret = "buyer-secret-password-8472";

IllegalArgumentException failure = assertThrows(
IllegalArgumentException.class,
() -> source.start(Map.of("database.password", rejectedSecret))
);

assertEquals(
"postgres-debezium uses deployment-owned configuration; per-call config must be empty",
failure.getMessage()
);
assertFalse(failure.getMessage().contains(rejectedSecret));
assertFalse(failure.getMessage().contains("database.password"));
verifyNoInteractions(service);
}
}
Loading