Skip to content

Commit c1dbfbf

Browse files
CASSSIDECAR-308 CDC: Add end-to-end CDC integration tests (#317)
Patch by Jyothsna Konisa; Reviewed by Bernardo Botella and Josh McKenzie for CASSSIDECAR-308
1 parent 431a3fd commit c1dbfbf

13 files changed

Lines changed: 780 additions & 105 deletions

File tree

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
0.3.0
22
-----
3+
* CDC: Add end-to-end CDC integration tests (CASSSIDECAR-308)
34
* SchemaStorePublisherFactory should be Injectable in CachingSchemaStore (CASSSIDECAR-408)
45
* Fix StorageClientTest Docker API compatibility and improve CI test reporting (CASSSIDECAR-410)
56
* Incorrect SSL Configuration Keys in CdcPublisher.secretsProvider() (CASSSIDECAR-401)

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,5 @@ swaggerVersion=2.2.21
4646
kryoVersion=4.0.2
4747
# OSHI dependencies
4848
oshiVersion=6.9.0
49-
analyticsVersion=0.2.0
49+
analyticsVersion=0.3.0
5050
kafkaClientVersion=3.7.0

integration-framework/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,16 @@ dependencies {
6565
api("io.vertx:vertx-junit5:${project.vertxVersion}")
6666
// The server itself
6767
api(project(path: ":server"))
68+
api(testFixtures(project(path: ":server")))
6869
api(project(path: ":server-common"))
70+
71+
// CDC dependencies
72+
api(group: "org.apache.cassandra", name: "cassandra-analytics-cdc_spark3_2.12", version: "${project.analyticsVersion}")
73+
api(group: "org.apache.cassandra", name: "cassandra-analytics-cdc-sidecar_spark3_2.12", version: "${project.analyticsVersion}")
74+
api "org.apache.kafka:kafka-clients:${project.kafkaClientVersion}"
6975
}
7076

7177
compileJava.onlyIf { !skipIntegrationTest }
7278
compileTestJava.onlyIf { !skipIntegrationTest }
7379
javadoc.onlyIf { !skipIntegrationTest }
80+

integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/MtlsTestHelper.java

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@
2222
import java.util.Objects;
2323
import java.util.function.Consumer;
2424

25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
27+
28+
import org.apache.cassandra.sidecar.common.server.utils.SecondBoundConfiguration;
29+
import org.apache.cassandra.sidecar.config.KeyStoreConfiguration;
30+
import org.apache.cassandra.sidecar.config.SidecarClientConfiguration;
31+
import org.apache.cassandra.sidecar.config.SslConfiguration;
32+
import org.apache.cassandra.sidecar.config.yaml.KeyStoreConfigurationImpl;
33+
import org.apache.cassandra.sidecar.config.yaml.SidecarClientConfigurationImpl;
34+
import org.apache.cassandra.sidecar.config.yaml.SslConfigurationImpl;
2535
import org.apache.cassandra.testing.utils.tls.CertificateBuilder;
2636
import org.apache.cassandra.testing.utils.tls.CertificateBundle;
2737

@@ -30,6 +40,7 @@
3040
*/
3141
public class MtlsTestHelper
3242
{
43+
private static final Logger LOGGER = LoggerFactory.getLogger(MtlsTestHelper.class);
3344
public static final String PASSWORD_STRING = "cassandra";
3445
public static final char[] PASSWORD = PASSWORD_STRING.toCharArray();
3546
/**
@@ -142,4 +153,78 @@ public String serverKeyStoreType()
142153
{
143154
return "PKCS12";
144155
}
156+
157+
/**
158+
* Creates SSL configuration with the specified keystore and shared truststore.
159+
*
160+
* @param keyStorePath the path to the keystore
161+
* @param keyStorePassword the keystore password
162+
* @param keyStoreType the keystore type
163+
* @return SslConfiguration with the provided keystore and shared truststore
164+
*/
165+
private SslConfiguration createSslConfiguration(String keyStorePath,
166+
String keyStorePassword,
167+
String keyStoreType)
168+
{
169+
KeyStoreConfiguration truststoreConfiguration =
170+
new KeyStoreConfigurationImpl(trustStorePath(),
171+
trustStorePassword(),
172+
trustStoreType(),
173+
SecondBoundConfiguration.parse("60s"));
174+
175+
KeyStoreConfiguration keyStoreConfiguration =
176+
new KeyStoreConfigurationImpl(keyStorePath,
177+
keyStorePassword,
178+
keyStoreType,
179+
SecondBoundConfiguration.parse("60s"));
180+
181+
return SslConfigurationImpl.builder()
182+
.enabled(true)
183+
.keystore(keyStoreConfiguration)
184+
.truststore(truststoreConfiguration)
185+
.build();
186+
}
187+
188+
/**
189+
* Creates SSL configuration for the Sidecar server with mTLS settings if enabled.
190+
*
191+
* @return SslConfiguration with server keystore/truststore, or null if mTLS is not enabled
192+
*/
193+
public SslConfiguration createServerSslConfiguration()
194+
{
195+
if (!isEnabled())
196+
{
197+
LOGGER.info("Not enabling mTLS for testing. Set '{}' to 'true' if you would like mTLS enabled.",
198+
CASSANDRA_INTEGRATION_TEST_ENABLE_MTLS);
199+
return null;
200+
}
201+
202+
LOGGER.info("Enabling test mTLS certificate/keystore for server.");
203+
return createSslConfiguration(serverKeyStorePath(),
204+
serverKeyStorePassword(),
205+
serverKeyStoreType());
206+
}
207+
208+
/**
209+
* Creates a SidecarClientConfiguration with mTLS settings if mTLS is enabled.
210+
*
211+
* @return a SidecarClientConfiguration with mTLS settings, or null if mTLS is not enabled
212+
*/
213+
public SidecarClientConfiguration createSidecarClientConfiguration()
214+
{
215+
if (!isEnabled())
216+
{
217+
LOGGER.info("Not enabling mTLS for testing. Set '{}' to 'true' if you would like mTLS enabled.",
218+
CASSANDRA_INTEGRATION_TEST_ENABLE_MTLS);
219+
return new SidecarClientConfigurationImpl(null);
220+
}
221+
222+
LOGGER.info("Enabling test mTLS certificate/keystore for client.");
223+
SslConfiguration clientSslConfiguration =
224+
createSslConfiguration(clientKeyStorePath(),
225+
clientKeyStorePassword(),
226+
serverKeyStoreType());
227+
228+
return new SidecarClientConfigurationImpl(clientSslConfiguration);
229+
}
145230
}

integration-framework/src/main/java/org/apache/cassandra/sidecar/testing/SharedClusterIntegrationTestBase.java

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.concurrent.ConcurrentHashMap;
3737
import java.util.concurrent.CountDownLatch;
3838
import java.util.concurrent.TimeUnit;
39+
import java.util.function.BooleanSupplier;
3940
import java.util.function.Consumer;
4041
import java.util.function.Function;
4142
import java.util.stream.Collectors;
@@ -88,18 +89,15 @@
8889
import org.apache.cassandra.sidecar.common.server.utils.SidecarVersionProvider;
8990
import org.apache.cassandra.sidecar.common.server.utils.ThrowableUtils;
9091
import org.apache.cassandra.sidecar.config.JmxConfiguration;
91-
import org.apache.cassandra.sidecar.config.KeyStoreConfiguration;
9292
import org.apache.cassandra.sidecar.config.S3ClientConfiguration;
9393
import org.apache.cassandra.sidecar.config.S3ProxyConfiguration;
9494
import org.apache.cassandra.sidecar.config.ServiceConfiguration;
9595
import org.apache.cassandra.sidecar.config.SidecarConfiguration;
9696
import org.apache.cassandra.sidecar.config.SslConfiguration;
97-
import org.apache.cassandra.sidecar.config.yaml.KeyStoreConfigurationImpl;
9897
import org.apache.cassandra.sidecar.config.yaml.S3ClientConfigurationImpl;
9998
import org.apache.cassandra.sidecar.config.yaml.SchemaKeyspaceConfigurationImpl;
100-
import org.apache.cassandra.sidecar.config.yaml.ServiceConfigurationImpl;
10199
import org.apache.cassandra.sidecar.config.yaml.SidecarConfigurationImpl;
102-
import org.apache.cassandra.sidecar.config.yaml.SslConfigurationImpl;
100+
import org.apache.cassandra.sidecar.config.yaml.TestServiceConfiguration;
103101
import org.apache.cassandra.sidecar.coordination.ClusterLease;
104102
import org.apache.cassandra.sidecar.lifecycle.InJvmDTestLifecycleProvider;
105103
import org.apache.cassandra.sidecar.lifecycle.LifecycleProvider;
@@ -116,7 +114,6 @@
116114
import org.apache.cassandra.testing.TestVersionSupplier;
117115

118116
import static org.apache.cassandra.sidecar.config.yaml.S3ClientConfigurationImpl.DEFAULT_API_CALL_TIMEOUT;
119-
import static org.apache.cassandra.sidecar.testing.MtlsTestHelper.CASSANDRA_INTEGRATION_TEST_ENABLE_MTLS;
120117
import static org.apache.cassandra.testing.DriverTestUtils.buildContactPoints;
121118
import static org.apache.cassandra.testing.utils.IInstanceUtils.tryGetIntConfig;
122119
import static org.assertj.core.api.Assertions.assertThat;
@@ -440,6 +437,30 @@ protected void waitForSchemaReady(ServerWrapper serverWrapper, long timeout, Tim
440437
.isTrue();
441438
}
442439

440+
/**
441+
* Polls a condition until it returns true or timeout is reached.
442+
* Uses System.nanoTime() for accurate timing and Uninterruptibles for consistent sleep behavior.
443+
*
444+
* @param condition the condition to check
445+
* @param timeoutSeconds maximum time to wait in seconds
446+
* @param pollIntervalMillis interval between checks in milliseconds
447+
* @throws AssertionError if timeout is reached before condition is met
448+
*/
449+
protected void waitUntil(BooleanSupplier condition, long timeoutSeconds, long pollIntervalMillis)
450+
{
451+
long startTime = System.nanoTime();
452+
long timeoutNanos = TimeUnit.SECONDS.toNanos(timeoutSeconds);
453+
454+
while (!condition.getAsBoolean())
455+
{
456+
if (System.nanoTime() - startTime > timeoutNanos)
457+
{
458+
throw new AssertionError("Condition not met within " + timeoutSeconds + " seconds");
459+
}
460+
Uninterruptibles.sleepUninterruptibly(pollIntervalMillis, TimeUnit.MILLISECONDS);
461+
}
462+
}
463+
443464
/**
444465
* Stops the Sidecar service
445466
*
@@ -775,48 +796,23 @@ public LifecycleProvider lifecycleProvider()
775796
}
776797

777798
public static SidecarConfigurationImpl.Builder defaultConfigurationBuilder(
778-
MtlsTestHelper mtlsTestHelper, Function<SidecarConfigurationImpl.Builder, SidecarConfigurationImpl.Builder> configurationOverrides)
799+
MtlsTestHelper mtlsTestHelper,
800+
Function<SidecarConfigurationImpl.Builder, SidecarConfigurationImpl.Builder> configurationOverrides)
779801
{
780-
ServiceConfiguration conf = ServiceConfigurationImpl.builder()
781-
.host("0.0.0.0") // binds to all interfaces, potential security issue if left running for long
782-
.port(0) // let the test find an available port
802+
ServiceConfiguration conf = TestServiceConfiguration.builder()
783803
.schemaKeyspaceConfiguration(SchemaKeyspaceConfigurationImpl.builder()
784804
.isEnabled(true)
785805
.build())
786806
.build();
787807

788-
789-
SslConfiguration sslConfiguration = null;
790-
if (mtlsTestHelper.isEnabled())
791-
{
792-
LOGGER.info("Enabling test mTLS certificate/keystore.");
793-
794-
KeyStoreConfiguration truststoreConfiguration =
795-
new KeyStoreConfigurationImpl(mtlsTestHelper.trustStorePath(),
796-
mtlsTestHelper.trustStorePassword(),
797-
mtlsTestHelper.trustStoreType(),
798-
SecondBoundConfiguration.parse("60s"));
799-
800-
KeyStoreConfiguration keyStoreConfiguration =
801-
new KeyStoreConfigurationImpl(mtlsTestHelper.serverKeyStorePath(),
802-
mtlsTestHelper.serverKeyStorePassword(),
803-
mtlsTestHelper.serverKeyStoreType(),
804-
SecondBoundConfiguration.parse("60s"));
805-
806-
sslConfiguration = SslConfigurationImpl.builder()
807-
.enabled(true)
808-
.keystore(keyStoreConfiguration)
809-
.truststore(truststoreConfiguration)
810-
.build();
811-
}
812-
else
813-
{
814-
LOGGER.info("Not enabling mTLS for testing purposes. Set '{}' to 'true' if you would " +
815-
"like mTLS enabled.", CASSANDRA_INTEGRATION_TEST_ENABLE_MTLS);
816-
}
817-
S3ClientConfiguration s3ClientConfig = new S3ClientConfigurationImpl("s3-client", 4, SecondBoundConfiguration.parse("60s"),
818-
5242880, DEFAULT_API_CALL_TIMEOUT,
819-
buildTestS3ProxyConfig());
808+
SslConfiguration sslConfiguration = mtlsTestHelper.createServerSslConfiguration();
809+
S3ClientConfiguration s3ClientConfig =
810+
new S3ClientConfigurationImpl("s3-client",
811+
4,
812+
SecondBoundConfiguration.parse("60s"),
813+
5242880,
814+
DEFAULT_API_CALL_TIMEOUT,
815+
buildTestS3ProxyConfig());
820816

821817
SidecarConfigurationImpl.Builder builder = SidecarConfigurationImpl.builder()
822818
.serviceConfiguration(conf)

0 commit comments

Comments
 (0)