Skip to content

Commit fda8483

Browse files
k-wallclaude
andauthored
refactor(systemtest): Share KMS facades across RecordEncryptionST tests (kroxylicious#3703)
* perf(systemtest): Share KMS facades across RecordEncryptionST tests Apply the shared KMS facade pattern from PR kroxylicious#3681 and kroxylicious#3700 to RecordEncryptionST. This starts each KMS facade once and shares it across all tests in the class, rather than starting/stopping for each test method. Changes: - Replace @testtemplate + TestKubeKmsFacadeInvocationContextProvider with @ParameterizedClass and @MethodSource - Add facadesSource() method using lazy stream evaluation with .peek() - Use autoCloseArguments = true for automatic facade cleanup - Replace @testtemplate + CompressionTypeInvocationContextProvider with @ParameterizedTest + @EnumSource(CompressionType.class) for compression testing This approach allows three different parameter injection mechanisms to work together: - testKmsFacade from @parameter field (via @ParameterizedClass) - namespace from KroxyliciousExtension (via AbstractSystemTests) - compressionType from @EnumSource (via @ParameterizedTest) Expected performance improvement: ~60% faster overall execution based on similar changes to KmsIT (kroxylicious#3700) which showed 60% overall improvement and 96.4% faster test execution for container-based KMS providers. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Keith Wall <kwall@apache.org> * reorder to allow parameter resolution to work. Signed-off-by: Keith Wall <kwall@apache.org> --------- Signed-off-by: Keith Wall <kwall@apache.org> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 8013e90 commit fda8483

4 files changed

Lines changed: 37 additions & 195 deletions

File tree

kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/installation/kms/aws/LocalStack.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.net.http.HttpRequest;
1212
import java.net.http.HttpResponse;
1313
import java.nio.file.Path;
14+
import java.time.Duration;
1415
import java.util.Map;
1516
import java.util.Optional;
1617
import java.util.concurrent.TimeUnit;
@@ -78,7 +79,9 @@ public void deploy() {
7879
// Experimental workaround for https://github.com/kroxylicious/kroxylicious/issues/3362
7980
@SuppressWarnings("java:S2095") // try-with-resources for "HttpClient" is not available until we adopt JDK21
8081
private void pingLocalStackEndpoint() {
81-
var client = HttpClient.newHttpClient();
82+
var client = HttpClient.newBuilder()
83+
.connectTimeout(Duration.ofSeconds(5))
84+
.build();
8285
Awaitility.await()
8386
.atMost(30, TimeUnit.SECONDS)
8487
.ignoreExceptions()

kroxylicious-systemtests/src/test/java/io/kroxylicious/systemtests/extensions/CompressionTypeInvocationContextProvider.java

Lines changed: 0 additions & 90 deletions
This file was deleted.

kroxylicious-systemtests/src/test/java/io/kroxylicious/systemtests/extensions/TestKubeKmsFacadeInvocationContextProvider.java

Lines changed: 0 additions & 82 deletions
This file was deleted.

kroxylicious-systemtests/src/test/java/io/kroxylicious/systemtests/filters/RecordEncryptionST.java

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,31 @@
99
import java.time.Duration;
1010
import java.util.ArrayList;
1111
import java.util.List;
12+
import java.util.stream.Stream;
1213

1314
import org.apache.kafka.common.record.CompressionType;
1415
import org.junit.jupiter.api.AfterAll;
1516
import org.junit.jupiter.api.AfterEach;
1617
import org.junit.jupiter.api.BeforeAll;
1718
import org.junit.jupiter.api.BeforeEach;
18-
import org.junit.jupiter.api.TestTemplate;
19-
import org.junit.jupiter.api.extension.ExtendWith;
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.params.Parameter;
21+
import org.junit.jupiter.params.ParameterizedClass;
22+
import org.junit.jupiter.params.ParameterizedTest;
23+
import org.junit.jupiter.params.provider.EnumSource;
24+
import org.junit.jupiter.params.provider.MethodSource;
2025
import org.slf4j.Logger;
2126
import org.slf4j.LoggerFactory;
2227

2328
import io.fabric8.kubernetes.api.model.Pod;
2429

2530
import io.kroxylicious.kms.service.TestKekManager;
2631
import io.kroxylicious.kms.service.TestKmsFacade;
32+
import io.kroxylicious.kms.service.TestKmsFacadeFactory;
2733
import io.kroxylicious.systemtests.AbstractSystemTests;
2834
import io.kroxylicious.systemtests.Constants;
2935
import io.kroxylicious.systemtests.clients.KafkaClients;
3036
import io.kroxylicious.systemtests.clients.records.ConsumerRecord;
31-
import io.kroxylicious.systemtests.extensions.CompressionTypeInvocationContextProvider;
32-
import io.kroxylicious.systemtests.extensions.TestKubeKmsFacadeInvocationContextProvider;
3337
import io.kroxylicious.systemtests.installation.kroxylicious.Kroxylicious;
3438
import io.kroxylicious.systemtests.installation.kroxylicious.KroxyliciousOperator;
3539
import io.kroxylicious.systemtests.k8s.exception.KubeClusterException;
@@ -44,6 +48,8 @@
4448
import static org.assertj.core.api.Assumptions.assumeThat;
4549
import static org.junit.jupiter.api.Assertions.assertAll;
4650

51+
@ParameterizedClass(autoCloseArguments = true)
52+
@MethodSource("facadesSource")
4753
class RecordEncryptionST extends AbstractSystemTests {
4854
private static final Logger LOGGER = LoggerFactory.getLogger(RecordEncryptionST.class);
4955
private static final String MESSAGE = "Hello-world";
@@ -53,6 +59,19 @@ class RecordEncryptionST extends AbstractSystemTests {
5359
private TestKekManager testKekManager;
5460
private KroxyliciousOperator kroxyliciousOperator;
5561

62+
static Stream<? extends TestKmsFacade<?, ?, ?>> facadesSource() {
63+
// We rely on the fact that streams are lazy so the facade isn't built
64+
// or started until the first test needs it.
65+
return TestKmsFacadeFactory.getTestKmsFacadeFactories()
66+
.filter(f -> f.getClass().getName().contains("systemtests"))
67+
.map(TestKmsFacadeFactory::build)
68+
.filter(TestKmsFacade::isAvailable)
69+
.peek(TestKmsFacade::start);
70+
}
71+
72+
@Parameter
73+
TestKmsFacade<?, ?, ?> testKmsFacade;
74+
5675
@BeforeAll
5776
void setUp() {
5877
KafkaClients.getKafkaClient().preloadImage();
@@ -103,9 +122,8 @@ void afterEach(String namespace) {
103122
}
104123
}
105124

106-
@TestTemplate
107-
@ExtendWith(TestKubeKmsFacadeInvocationContextProvider.class)
108-
void ensureClusterHasEncryptedMessage(String namespace, TestKmsFacade<?, ?, ?> testKmsFacade) {
125+
@Test
126+
void ensureClusterHasEncryptedMessage(String namespace) {
109127
testKekManager = testKmsFacade.getTestKekManager();
110128
testKekManager.generateKek(KEK_PREFIX + topicName);
111129
int numberOfMessages = 1;
@@ -139,17 +157,12 @@ void ensureClusterHasEncryptedMessage(String namespace, TestKmsFacade<?, ?, ?> t
139157
/**
140158
* Produce and consume compressed message.
141159
*
142-
* @param namespace the namespace
143-
* @param testKmsFacade the test kms facade
144160
* @param compressionType the compression type
161+
* @param namespace the namespace
145162
*/
146-
@TestTemplate
147-
@ExtendWith(CompressionTypeInvocationContextProvider.class)
148-
void produceAndConsumeCompressedMessages(String namespace, TestKmsFacade<?, ?, ?> testKmsFacade, CompressionType compressionType) {
149-
produceAndConsumeMessage(namespace, compressionType, testKmsFacade);
150-
}
151-
152-
private void produceAndConsumeMessage(String namespace, CompressionType compressionType, TestKmsFacade<?, ?, ?> testKmsFacade) {
163+
@ParameterizedTest
164+
@EnumSource(CompressionType.class)
165+
void produceAndConsumeMessage(CompressionType compressionType, String namespace) {
153166
testKekManager = testKmsFacade.getTestKekManager();
154167
testKekManager.generateKek(KEK_PREFIX + topicName);
155168
int numberOfMessages = 1;
@@ -177,9 +190,8 @@ private void produceAndConsumeMessage(String namespace, CompressionType compress
177190
}
178191

179192
@SuppressWarnings("java:S2925")
180-
@TestTemplate
181-
@ExtendWith(TestKubeKmsFacadeInvocationContextProvider.class)
182-
void ensureClusterHasEncryptedMessageWithRotatedKEK(String namespace, TestKmsFacade<?, ?, ?> testKmsFacade) {
193+
@Test
194+
void ensureClusterHasEncryptedMessageWithRotatedKEK(String namespace) {
183195
// Skip AWS test execution because the ciphertext blob metadata to read the version of the KEK is not available anywhere
184196
assumeThat(isVaultKms(testKmsFacade)).isTrue();
185197
String kekAlias = KEK_PREFIX + topicName;
@@ -244,9 +256,8 @@ private void assertKekVersionWithinParcel(List<ConsumerRecord> consumerRecords,
244256
}
245257

246258
@SuppressWarnings("java:S2925")
247-
@TestTemplate
248-
@ExtendWith(TestKubeKmsFacadeInvocationContextProvider.class)
249-
void produceAndConsumeMessageWithRotatedKEK(String namespace, TestKmsFacade<?, ?, ?> testKmsFacade) {
259+
@Test
260+
void produceAndConsumeMessageWithRotatedKEK(String namespace) {
250261
String kekAlias = KEK_PREFIX + topicName;
251262
testKekManager = testKmsFacade.getTestKekManager();
252263
testKekManager.generateKek(kekAlias);

0 commit comments

Comments
 (0)