Skip to content
Merged
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 @@ -3,10 +3,12 @@
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
* Resolves configured CDC source type ids to {@link CdcSourceConnector} instances.
Expand All @@ -32,15 +34,23 @@ public Optional<CdcSourceConnector> resolve(String type) {
}

/**
* Validate a multi-source config list. Does not start engines — live capture
* remains single-source in {@code CdcService}.
* Validates and describes a multi-source configuration list without starting engines.
* Live capture remains single-source in {@code CdcService}.
*
* @param specs configured source entries; {@code null} is treated as an empty list
* @return one descriptive row for each configured source
* @throws IllegalArgumentException when two entries declare the same source id
*/
public List<Map<String, Object>> describeConfigured(List<SourceSpec> specs) {
List<Map<String, Object>> out = new ArrayList<>();
if (specs == null) {
return out;
}
Set<String> sourceIds = new HashSet<>();
for (SourceSpec spec : specs) {
if (!sourceIds.add(spec.id())) {
throw new IllegalArgumentException("duplicate source id: " + spec.id());
}
Map<String, Object> row = new java.util.LinkedHashMap<>();
row.put("id", spec.id());
row.put("type", spec.type());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.xtrmetl.cdc.spi;

import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* Protects configured CDC source identity from ambiguous duplicate declarations.
*/
class CdcSourceFactoryIdentityContractTest {

@Test
void duplicateConfiguredSourceIdsFailClosed() {
CdcSourceFactory factory = factory();

IllegalArgumentException failure = assertThrows(
IllegalArgumentException.class,
() -> factory.describeConfigured(List.of(
new CdcSourceFactory.SourceSpec("pg-main", "postgres-debezium", true),
new CdcSourceFactory.SourceSpec("pg-main", "postgres-debezium", false)
))
);

assertTrue(failure.getMessage().contains("pg-main"));
}

@Test
void repeatedSourceTypeWithDistinctIdsRemainsValid() {
CdcSourceFactory factory = factory();

assertDoesNotThrow(() -> factory.describeConfigured(List.of(
new CdcSourceFactory.SourceSpec("pg-primary", "postgres-debezium", true),
new CdcSourceFactory.SourceSpec("pg-secondary", "postgres-debezium", false)
)));
}

private static CdcSourceFactory factory() {
return new CdcSourceFactory(new CdcSourceRegistry(List.of(new PostgresDebeziumCdcSource())));
}
}
Loading