KAFKA-16921 [5/N] Migrate test of connect module to Junit5 (Runtime subpackage) (#16350)

Reviewers: Chia-Ping Tsai <chia7712@gmail.com>
This commit is contained in:
TingIāu "Ting" Kì 2024-06-18 18:20:14 +08:00 committed by GitHub
parent 3a3f9ce48e
commit d5592d8fe6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 1325 additions and 1236 deletions

View File

@ -17,7 +17,7 @@
package org.apache.kafka.connect.runtime.distributed; package org.apache.kafka.connect.runtime.distributed;
import org.apache.kafka.connect.util.ConnectorTaskId; import org.apache.kafka.connect.util.ConnectorTaskId;
import org.junit.Test; import org.junit.jupiter.api.Test;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
@ -25,8 +25,8 @@ import java.util.Collections;
import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V1; import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V1;
import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V2; import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V2;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
public class ConnectProtocolCompatibilityTest { public class ConnectProtocolCompatibilityTest {
private static final String LEADER = "leader"; private static final String LEADER = "leader";

View File

@ -20,9 +20,11 @@ package org.apache.kafka.connect.runtime.distributed;
import org.apache.kafka.clients.CommonClientConfigs; import org.apache.kafka.clients.CommonClientConfigs;
import org.apache.kafka.common.config.ConfigException; import org.apache.kafka.common.config.ConfigException;
import org.apache.kafka.common.security.auth.SecurityProtocol; import org.apache.kafka.common.security.auth.SecurityProtocol;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import javax.crypto.KeyGenerator; import javax.crypto.KeyGenerator;
import javax.crypto.Mac; import javax.crypto.Mac;
@ -43,18 +45,19 @@ import static org.apache.kafka.connect.runtime.distributed.DistributedConfig.GRO
import static org.apache.kafka.connect.runtime.distributed.DistributedConfig.INTER_WORKER_KEY_GENERATION_ALGORITHM_CONFIG; import static org.apache.kafka.connect.runtime.distributed.DistributedConfig.INTER_WORKER_KEY_GENERATION_ALGORITHM_CONFIG;
import static org.apache.kafka.connect.runtime.distributed.DistributedConfig.INTER_WORKER_SIGNATURE_ALGORITHM_CONFIG; import static org.apache.kafka.connect.runtime.distributed.DistributedConfig.INTER_WORKER_SIGNATURE_ALGORITHM_CONFIG;
import static org.apache.kafka.connect.runtime.distributed.DistributedConfig.INTER_WORKER_VERIFICATION_ALGORITHMS_CONFIG; import static org.apache.kafka.connect.runtime.distributed.DistributedConfig.INTER_WORKER_VERIFICATION_ALGORITHMS_CONFIG;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class DistributedConfigTest { public class DistributedConfigTest {
public Map<String, String> configs() { public Map<String, String> configs() {
@ -148,7 +151,7 @@ public class DistributedConfigTest {
Set<String> supportedAlgorithms = DistributedConfig.supportedAlgorithms(type); Set<String> supportedAlgorithms = DistributedConfig.supportedAlgorithms(type);
Set<String> unsupportedAlgorithms = new HashSet<>(Arrays.asList(expectedAlgorithms)); Set<String> unsupportedAlgorithms = new HashSet<>(Arrays.asList(expectedAlgorithms));
unsupportedAlgorithms.removeAll(supportedAlgorithms); unsupportedAlgorithms.removeAll(supportedAlgorithms);
assertEquals(type + " algorithms were found that should be supported by this JVM but are not", Collections.emptySet(), unsupportedAlgorithms); assertEquals(Collections.emptySet(), unsupportedAlgorithms, type + " algorithms were found that should be supported by this JVM but are not");
} }
@Test @Test

View File

@ -72,13 +72,15 @@ import org.apache.kafka.connect.util.Callback;
import org.apache.kafka.connect.util.ConnectorTaskId; import org.apache.kafka.connect.util.ConnectorTaskId;
import org.apache.kafka.connect.util.FutureCallback; import org.apache.kafka.connect.util.FutureCallback;
import org.apache.kafka.connect.util.Stage; import org.apache.kafka.connect.util.Stage;
import org.junit.After; import org.junit.jupiter.api.AfterEach;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
@ -122,11 +124,11 @@ import static org.apache.kafka.connect.runtime.distributed.DistributedConfig.INT
import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V1; import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V1;
import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V2; import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V2;
import static org.apache.kafka.connect.source.SourceTask.TransactionBoundary.CONNECTOR; import static org.apache.kafka.connect.source.SourceTask.TransactionBoundary.CONNECTOR;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.mockito.AdditionalMatchers.leq; import static org.mockito.AdditionalMatchers.leq;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@ -147,7 +149,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings; import static org.mockito.Mockito.withSettings;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class DistributedHerderTest { public class DistributedHerderTest {
private static final Map<String, String> HERDER_CONFIG = new HashMap<>(); private static final Map<String, String> HERDER_CONFIG = new HashMap<>();
@ -301,12 +304,11 @@ public class DistributedHerderTest {
private final SampleConnectorClientConfigOverridePolicy private final SampleConnectorClientConfigOverridePolicy
noneConnectorClientConfigOverridePolicy = new SampleConnectorClientConfigOverridePolicy(); noneConnectorClientConfigOverridePolicy = new SampleConnectorClientConfigOverridePolicy();
@Before @BeforeEach
public void setUp() throws Exception { public void setUp() throws Exception {
time = new MockTime(); time = new MockTime();
metrics = new MockConnectMetrics(time); metrics = new MockConnectMetrics(time);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE); AutoCloseable uponShutdown = shutdownCalled::countDown;
AutoCloseable uponShutdown = () -> shutdownCalled.countDown();
// Default to the old protocol unless specified otherwise // Default to the old protocol unless specified otherwise
connectProtocolVersion = CONNECT_PROTOCOL_V0; connectProtocolVersion = CONNECT_PROTOCOL_V0;
@ -319,11 +321,9 @@ public class DistributedHerderTest {
rebalanceListener = herder.new RebalanceListener(time); rebalanceListener = herder.new RebalanceListener(time);
conn1SinkConfig = new SinkConnectorConfig(plugins, CONN1_CONFIG); conn1SinkConfig = new SinkConnectorConfig(plugins, CONN1_CONFIG);
conn1SinkConfigUpdated = new SinkConnectorConfig(plugins, CONN1_CONFIG_UPDATED); conn1SinkConfigUpdated = new SinkConnectorConfig(plugins, CONN1_CONFIG_UPDATED);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
} }
@After @AfterEach
public void tearDown() { public void tearDown() {
if (metrics != null) metrics.stop(); if (metrics != null) metrics.stop();
if (herderExecutor != null) { if (herderExecutor != null) {
@ -333,10 +333,12 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testJoinAssignment() throws Exception { public void testJoinAssignment() {
// Join group and get assignment // Join group and get assignment
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, singletonList(CONN1), singletonList(TASK1)); expectRebalance(1, singletonList(CONN1), singletonList(TASK1));
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -357,10 +359,12 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRebalance() throws Exception { public void testRebalance() {
// Join group and get assignment // Join group and get assignment
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, singletonList(CONN1), singletonList(TASK1)); expectRebalance(1, singletonList(CONN1), singletonList(TASK1));
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -401,12 +405,14 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testIncrementalCooperativeRebalanceForNewMember() throws Exception { public void testIncrementalCooperativeRebalanceForNewMember() {
connectProtocolVersion = CONNECT_PROTOCOL_V1; connectProtocolVersion = CONNECT_PROTOCOL_V1;
// Join group. First rebalance contains revocations from other members. For the new // Join group. First rebalance contains revocations from other members. For the new
// member the assignment should be empty // member the assignment should be empty
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V1); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V1);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList()); expectRebalance(1, Collections.emptyList(), Collections.emptyList());
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -478,7 +484,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testIncrementalCooperativeRebalanceWithDelay() throws Exception { public void testIncrementalCooperativeRebalanceWithDelay() {
connectProtocolVersion = CONNECT_PROTOCOL_V1; connectProtocolVersion = CONNECT_PROTOCOL_V1;
// Join group. First rebalance contains some assignments but also a delay, because a // Join group. First rebalance contains some assignments but also a delay, because a
// member was detected missing // member was detected missing
@ -486,6 +492,8 @@ public class DistributedHerderTest {
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V1); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V1);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(Collections.emptyList(), Collections.emptyList(), expectRebalance(Collections.emptyList(), Collections.emptyList(),
ConnectProtocol.Assignment.NO_ERROR, 1, ConnectProtocol.Assignment.NO_ERROR, 1,
Collections.emptyList(), singletonList(TASK2), Collections.emptyList(), singletonList(TASK2),
@ -530,10 +538,12 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRebalanceFailedConnector() throws Exception { public void testRebalanceFailedConnector() {
// Join group and get assignment // Join group and get assignment
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, singletonList(CONN1), singletonList(TASK1)); expectRebalance(1, singletonList(CONN1), singletonList(TASK1));
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -574,16 +584,20 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRevoke() throws TimeoutException { public void testRevoke() {
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
revokeAndReassign(false); revokeAndReassign(false);
} }
@Test @Test
public void testIncompleteRebalanceBeforeRevoke() throws TimeoutException { public void testIncompleteRebalanceBeforeRevoke() {
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
revokeAndReassign(true); revokeAndReassign(true);
} }
public void revokeAndReassign(boolean incompleteRebalance) throws TimeoutException { public void revokeAndReassign(boolean incompleteRebalance) {
connectProtocolVersion = CONNECT_PROTOCOL_V1; connectProtocolVersion = CONNECT_PROTOCOL_V1;
int configOffset = 1; int configOffset = 1;
@ -681,9 +695,10 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testCreateConnector() throws Exception { public void testCreateConnector() {
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -736,9 +751,10 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testCreateConnectorWithInitialState() throws Exception { public void testCreateConnectorWithInitialState() {
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -843,7 +859,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testCreateConnectorFailedValidation() throws Exception { public void testCreateConnectorFailedValidation() {
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
@ -933,7 +949,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testCreateConnectorAlreadyExists() throws Exception { public void testCreateConnectorAlreadyExists() {
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
@ -976,7 +992,8 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testDestroyConnector() throws Exception { public void testDestroyConnector() {
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
// Start with one connector // Start with one connector
@ -1045,6 +1062,7 @@ public class DistributedHerderTest {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
expectRebalance(1, singletonList(CONN1), Collections.emptyList(), true); expectRebalance(1, singletonList(CONN1), Collections.emptyList(), true);
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -1077,7 +1095,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRestartUnknownConnector() throws Exception { public void testRestartUnknownConnector() {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1101,7 +1119,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRestartConnectorRedirectToLeader() throws Exception { public void testRestartConnectorRedirectToLeader() {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1125,7 +1143,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRestartConnectorRedirectToOwner() throws Exception { public void testRestartConnectorRedirectToOwner() {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1160,7 +1178,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRestartConnectorAndTasksUnknownConnector() throws Exception { public void testRestartConnectorAndTasksUnknownConnector() {
String connectorName = "UnknownConnector"; String connectorName = "UnknownConnector";
RestartRequest restartRequest = new RestartRequest(connectorName, false, true); RestartRequest restartRequest = new RestartRequest(connectorName, false, true);
@ -1189,7 +1207,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRestartConnectorAndTasksNotLeader() throws Exception { public void testRestartConnectorAndTasksNotLeader() {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1214,7 +1232,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRestartConnectorAndTasksUnknownStatus() throws Exception { public void testRestartConnectorAndTasksUnknownStatus() {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1345,6 +1363,7 @@ public class DistributedHerderTest {
when(herder.assignment.connectors()).thenReturn(Collections.emptyList()); when(herder.assignment.connectors()).thenReturn(Collections.emptyList());
// But only one task is assigned to this worker // But only one task is assigned to this worker
when(herder.assignment.tasks()).thenReturn(Collections.singletonList(TASK0)); when(herder.assignment.tasks()).thenReturn(Collections.singletonList(TASK0));
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
herder.configState = SNAPSHOT; herder.configState = SNAPSHOT;
@ -1368,6 +1387,7 @@ public class DistributedHerderTest {
when(restartPlan.shouldRestartConnector()).thenReturn(true); when(restartPlan.shouldRestartConnector()).thenReturn(true);
when(restartPlan.taskIdsToRestart()).thenReturn(Collections.singletonList(taskId)); when(restartPlan.taskIdsToRestart()).thenReturn(Collections.singletonList(taskId));
when(restartPlan.totalTaskCount()).thenReturn(1); when(restartPlan.totalTaskCount()).thenReturn(1);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
doReturn(Optional.of(restartPlan)).when(herder).buildRestartPlan(restartRequest); doReturn(Optional.of(restartPlan)).when(herder).buildRestartPlan(restartRequest);
herder.assignment = mock(ExtendedAssignment.class); herder.assignment = mock(ExtendedAssignment.class);
@ -1405,6 +1425,7 @@ public class DistributedHerderTest {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), singletonList(TASK0), true); expectRebalance(1, Collections.emptyList(), singletonList(TASK0), true);
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -1429,7 +1450,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRestartUnknownTask() throws Exception { public void testRestartUnknownTask() {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1451,7 +1472,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRestartTaskRedirectToLeader() throws Exception { public void testRestartTaskRedirectToLeader() {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1474,7 +1495,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testRestartTaskRedirectToOwner() throws Exception { public void testRestartTaskRedirectToOwner() {
// get the initial assignment // get the initial assignment
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1519,8 +1540,9 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testConnectorConfigAdded() throws Exception { public void testConnectorConfigAdded() {
// If a connector was added, we need to rebalance // If a connector was added, we need to rebalance
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1531,7 +1553,7 @@ public class DistributedHerderTest {
herder.tick(); // join herder.tick(); // join
// Checks for config updates and starts rebalance // Checks for config updates and starts rebalance
expectConfigRefreshAndSnapshot(SNAPSHOT); when(configBackingStore.snapshot()).thenReturn(SNAPSHOT);
// Rebalance will be triggered when the new config is detected // Rebalance will be triggered when the new config is detected
doNothing().when(member).requestRejoin(); doNothing().when(member).requestRejoin();
@ -1556,11 +1578,12 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testConnectorConfigUpdate() throws Exception { public void testConnectorConfigUpdate() {
// Connector config can be applied without any rebalance // Connector config can be applied without any rebalance
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
// join // join
expectRebalance(1, singletonList(CONN1), Collections.emptyList()); expectRebalance(1, singletonList(CONN1), Collections.emptyList());
@ -1590,11 +1613,12 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testConnectorConfigUpdateFailedTransformation() throws Exception { public void testConnectorConfigUpdateFailedTransformation() {
// Connector config can be applied without any rebalance // Connector config can be applied without any rebalance
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
WorkerConfigTransformer configTransformer = mock(WorkerConfigTransformer.class); WorkerConfigTransformer configTransformer = mock(WorkerConfigTransformer.class);
// join // join
@ -1647,11 +1671,12 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testConnectorPaused() throws Exception { public void testConnectorPaused() {
// ensure that target state changes are propagated to the worker // ensure that target state changes are propagated to the worker
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
// join // join
expectRebalance(1, singletonList(CONN1), Collections.emptyList()); expectRebalance(1, singletonList(CONN1), Collections.emptyList());
@ -1686,9 +1711,10 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testConnectorResumed() throws Exception { public void testConnectorResumed() {
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
// start with the connector paused // start with the connector paused
expectRebalance(1, singletonList(CONN1), Collections.emptyList()); expectRebalance(1, singletonList(CONN1), Collections.emptyList());
@ -1724,11 +1750,12 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testConnectorStopped() throws Exception { public void testConnectorStopped() {
// ensure that target state changes are propagated to the worker // ensure that target state changes are propagated to the worker
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
// join // join
expectRebalance(1, singletonList(CONN1), Collections.emptyList()); expectRebalance(1, singletonList(CONN1), Collections.emptyList());
@ -1763,9 +1790,10 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testUnknownConnectorPaused() throws Exception { public void testUnknownConnectorPaused() {
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
// join // join
expectRebalance(1, Collections.emptyList(), singletonList(TASK0)); expectRebalance(1, Collections.emptyList(), singletonList(TASK0));
@ -1788,6 +1816,7 @@ public class DistributedHerderTest {
@Test @Test
public void testStopConnector() throws Exception { public void testStopConnector() throws Exception {
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1813,16 +1842,17 @@ public class DistributedHerderTest {
herder.stopConnector(CONN1, cb); // external request herder.stopConnector(CONN1, cb); // external request
herder.tick(); // continue herder.tick(); // continue
assertTrue("Callback should already have been invoked by herder", cb.isDone()); assertTrue(cb.isDone(), "Callback should already have been invoked by herder");
cb.get(0, TimeUnit.MILLISECONDS); cb.get(0, TimeUnit.MILLISECONDS);
verifyNoMoreInteractions(worker, member, configBackingStore, statusBackingStore); verifyNoMoreInteractions(worker, member, configBackingStore, statusBackingStore);
} }
@Test @Test
public void testStopConnectorNotLeader() throws Exception { public void testStopConnectorNotLeader() {
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
// join as member (non-leader) // join as member (non-leader)
expectRebalance(1, Collections.emptyList(), singletonList(TASK0)); expectRebalance(1, Collections.emptyList(), singletonList(TASK0));
@ -1840,11 +1870,11 @@ public class DistributedHerderTest {
herder.stopConnector(CONN1, cb); // external request herder.stopConnector(CONN1, cb); // external request
herder.tick(); // continue herder.tick(); // continue
assertTrue("Callback should already have been invoked by herder", cb.isDone()); assertTrue(cb.isDone(), "Callback should already have been invoked by herder");
ExecutionException e = assertThrows( ExecutionException e = assertThrows(
"Should not be able to handle request to stop connector when not leader",
ExecutionException.class, ExecutionException.class,
() -> cb.get(0, TimeUnit.SECONDS) () -> cb.get(0, TimeUnit.SECONDS),
"Should not be able to handle request to stop connector when not leader"
); );
assertInstanceOf(NotLeaderException.class, e.getCause()); assertInstanceOf(NotLeaderException.class, e.getCause());
@ -1852,9 +1882,10 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testStopConnectorFailToWriteTaskConfigs() throws Exception { public void testStopConnectorFailToWriteTaskConfigs() {
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
// join as leader // join as leader
expectRebalance(1, Collections.emptyList(), singletonList(TASK0), true); expectRebalance(1, Collections.emptyList(), singletonList(TASK0), true);
@ -1880,11 +1911,11 @@ public class DistributedHerderTest {
herder.stopConnector(CONN1, cb); // external request herder.stopConnector(CONN1, cb); // external request
herder.tick(); // continue herder.tick(); // continue
assertTrue("Callback should already have been invoked by herder", cb.isDone()); assertTrue(cb.isDone(), "Callback should already have been invoked by herder");
ExecutionException e = assertThrows( ExecutionException e = assertThrows(
"Should not be able to handle request to stop connector when not leader",
ExecutionException.class, ExecutionException.class,
() -> cb.get(0, TimeUnit.SECONDS) () -> cb.get(0, TimeUnit.SECONDS),
"Should not be able to handle request to stop connector when not leader"
); );
assertEquals(e.getCause(), taskConfigsWriteException); assertEquals(e.getCause(), taskConfigsWriteException);
@ -1892,10 +1923,11 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testConnectorPausedRunningTaskOnly() throws Exception { public void testConnectorPausedRunningTaskOnly() {
// even if we don't own the connector, we should still propagate target state // even if we don't own the connector, we should still propagate target state
// changes to the worker so that tasks will transition correctly // changes to the worker so that tasks will transition correctly
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1926,10 +1958,11 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testConnectorResumedRunningTaskOnly() throws Exception { public void testConnectorResumedRunningTaskOnly() {
// even if we don't own the connector, we should still propagate target state // even if we don't own the connector, we should still propagate target state
// changes to the worker so that tasks will transition correctly // changes to the worker so that tasks will transition correctly
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -1951,7 +1984,6 @@ public class DistributedHerderTest {
onStart.getValue().onCompletion(null, TargetState.PAUSED); onStart.getValue().onCompletion(null, TargetState.PAUSED);
return null; return null;
}).when(worker).setTargetState(eq(CONN1), eq(TargetState.STARTED), onStart.capture()); }).when(worker).setTargetState(eq(CONN1), eq(TargetState.STARTED), onStart.capture());
expectExecuteTaskReconfiguration(false, null, null);
configUpdateListener.onConnectorTargetStateChange(CONN1); // state changes to paused configUpdateListener.onConnectorTargetStateChange(CONN1); // state changes to paused
herder.tick(); // apply state change herder.tick(); // apply state change
@ -1966,6 +1998,7 @@ public class DistributedHerderTest {
// Task config always requires rebalance // Task config always requires rebalance
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
// join // join
expectRebalance(-1, Collections.emptyList(), Collections.emptyList()); expectRebalance(-1, Collections.emptyList(), Collections.emptyList());
@ -1985,7 +2018,6 @@ public class DistributedHerderTest {
expectRebalance(Collections.emptyList(), Collections.emptyList(), expectRebalance(Collections.emptyList(), Collections.emptyList(),
ConnectProtocol.Assignment.NO_ERROR, 1, Collections.emptyList(), ConnectProtocol.Assignment.NO_ERROR, 1, Collections.emptyList(),
singletonList(TASK0)); singletonList(TASK0));
expectConfigRefreshAndSnapshot(SNAPSHOT);
when(worker.startSourceTask(eq(TASK0), any(), any(), any(), eq(herder), eq(TargetState.STARTED))).thenReturn(true); when(worker.startSourceTask(eq(TASK0), any(), any(), any(), eq(herder), eq(TargetState.STARTED))).thenReturn(true);
herder.tick(); // do rebalance herder.tick(); // do rebalance
@ -2000,6 +2032,8 @@ public class DistributedHerderTest {
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(configBackingStore.snapshot()).thenReturn(SNAPSHOT); when(configBackingStore.snapshot()).thenReturn(SNAPSHOT);
when(statusBackingStore.connectors()).thenReturn(Collections.emptySet()); when(statusBackingStore.connectors()).thenReturn(Collections.emptySet());
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(Collections.emptyList(), Collections.emptyList(), expectRebalance(Collections.emptyList(), Collections.emptyList(),
ConnectProtocol.Assignment.CONFIG_MISMATCH, 1, "leader", "leaderUrl", Collections.emptyList(), ConnectProtocol.Assignment.CONFIG_MISMATCH, 1, "leader", "leaderUrl", Collections.emptyList(),
@ -2059,6 +2093,8 @@ public class DistributedHerderTest {
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V1); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V1);
when(statusBackingStore.connectors()).thenReturn(Collections.emptySet()); when(statusBackingStore.connectors()).thenReturn(Collections.emptySet());
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, singletonList(CONN1), singletonList(TASK1), true); expectRebalance(1, singletonList(CONN1), singletonList(TASK1), true);
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -2133,6 +2169,8 @@ public class DistributedHerderTest {
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V1); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V1);
when(statusBackingStore.connectors()).thenReturn(Collections.emptySet()); when(statusBackingStore.connectors()).thenReturn(Collections.emptySet());
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, singletonList(CONN1), singletonList(TASK1), true); expectRebalance(1, singletonList(CONN1), singletonList(TASK1), true);
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -2212,6 +2250,7 @@ public class DistributedHerderTest {
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(statusBackingStore.connectors()).thenReturn(Collections.emptySet()); when(statusBackingStore.connectors()).thenReturn(Collections.emptySet());
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
@ -2275,6 +2314,8 @@ public class DistributedHerderTest {
@Test @Test
public void testPutConnectorConfig() throws Exception { public void testPutConnectorConfig() throws Exception {
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
expectRebalance(1, singletonList(CONN1), Collections.emptyList(), true); expectRebalance(1, singletonList(CONN1), Collections.emptyList(), true);
when(statusBackingStore.connectors()).thenReturn(Collections.emptySet()); when(statusBackingStore.connectors()).thenReturn(Collections.emptySet());
@ -2398,7 +2439,6 @@ public class DistributedHerderTest {
// Patch the connector config. // Patch the connector config.
expectMemberEnsureActive();
expectRebalance(1, singletonList(CONN1), Collections.emptyList(), false); expectRebalance(1, singletonList(CONN1), Collections.emptyList(), false);
FutureCallback<Herder.Created<ConnectorInfo>> patchCallback = new FutureCallback<>(); FutureCallback<Herder.Created<ConnectorInfo>> patchCallback = new FutureCallback<>();
@ -2411,8 +2451,8 @@ public class DistributedHerderTest {
@Test @Test
public void testPatchConnectorConfig() throws Exception { public void testPatchConnectorConfig() throws Exception {
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
expectRebalance(1, singletonList(CONN1), Collections.emptyList(), true);
when(statusBackingStore.connectors()).thenReturn(Collections.emptySet()); when(statusBackingStore.connectors()).thenReturn(Collections.emptySet());
Map<String, String> originalConnConfig = new HashMap<>(CONN1_CONFIG); Map<String, String> originalConnConfig = new HashMap<>(CONN1_CONFIG);
@ -2451,7 +2491,6 @@ public class DistributedHerderTest {
patchedConnConfig.remove("foo2"); patchedConnConfig.remove("foo2");
patchedConnConfig.put("foo3", "added"); patchedConnConfig.put("foo3", "added");
expectMemberEnsureActive();
expectRebalance(1, singletonList(CONN1), Collections.emptyList(), true); expectRebalance(1, singletonList(CONN1), Collections.emptyList(), true);
ArgumentCaptor<Callback<ConfigInfos>> validateCallback = ArgumentCaptor.forClass(Callback.class); ArgumentCaptor<Callback<ConfigInfos>> validateCallback = ArgumentCaptor.forClass(Callback.class);
@ -2476,7 +2515,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testKeyRotationWhenWorkerBecomesLeader() throws Exception { public void testKeyRotationWhenWorkerBecomesLeader() {
long rotationTtlDelay = DistributedConfig.INTER_WORKER_KEY_TTL_MS_MS_DEFAULT; long rotationTtlDelay = DistributedConfig.INTER_WORKER_KEY_TTL_MS_MS_DEFAULT;
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2);
@ -2529,7 +2568,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testKeyRotationDisabledWhenWorkerBecomesFollower() throws Exception { public void testKeyRotationDisabledWhenWorkerBecomesFollower() {
long rotationTtlDelay = DistributedConfig.INTER_WORKER_KEY_TTL_MS_MS_DEFAULT; long rotationTtlDelay = DistributedConfig.INTER_WORKER_KEY_TTL_MS_MS_DEFAULT;
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2);
@ -2710,7 +2749,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testFailedToWriteSessionKey() throws Exception { public void testFailedToWriteSessionKey() {
// First tick -- after joining the group, we try to write a new // First tick -- after joining the group, we try to write a new
// session key to the config topic, and fail // session key to the config topic, and fail
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
@ -2878,6 +2917,7 @@ public class DistributedHerderTest {
@Test @Test
public void testExternalZombieFencingRequestForAlreadyFencedConnector() throws Exception { public void testExternalZombieFencingRequestForAlreadyFencedConnector() throws Exception {
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
ClusterConfigState configState = exactlyOnceSnapshot( ClusterConfigState configState = exactlyOnceSnapshot(
expectNewSessionKey(), expectNewSessionKey(),
TASK_CONFIGS_MAP, TASK_CONFIGS_MAP,
@ -2890,6 +2930,7 @@ public class DistributedHerderTest {
@Test @Test
public void testExternalZombieFencingRequestForSingleTaskConnector() throws Exception { public void testExternalZombieFencingRequestForSingleTaskConnector() throws Exception {
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
ClusterConfigState configState = exactlyOnceSnapshot( ClusterConfigState configState = exactlyOnceSnapshot(
expectNewSessionKey(), expectNewSessionKey(),
Collections.singletonMap(TASK1, TASK_CONFIG), Collections.singletonMap(TASK1, TASK_CONFIG),
@ -2902,6 +2943,7 @@ public class DistributedHerderTest {
@Test @Test
public void testExternalZombieFencingRequestForFreshConnector() throws Exception { public void testExternalZombieFencingRequestForFreshConnector() throws Exception {
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
ClusterConfigState configState = exactlyOnceSnapshot( ClusterConfigState configState = exactlyOnceSnapshot(
expectNewSessionKey(), expectNewSessionKey(),
TASK_CONFIGS_MAP, TASK_CONFIGS_MAP,
@ -2954,6 +2996,7 @@ public class DistributedHerderTest {
expectHerderStartup(); expectHerderStartup();
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
SessionKey sessionKey = expectNewSessionKey(); SessionKey sessionKey = expectNewSessionKey();
@ -3013,6 +3056,7 @@ public class DistributedHerderTest {
expectHerderStartup(); expectHerderStartup();
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
SessionKey sessionKey = expectNewSessionKey(); SessionKey sessionKey = expectNewSessionKey();
@ -3056,6 +3100,7 @@ public class DistributedHerderTest {
expectHerderStartup(); expectHerderStartup();
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
SessionKey sessionKey = expectNewSessionKey(); SessionKey sessionKey = expectNewSessionKey();
@ -3125,6 +3170,7 @@ public class DistributedHerderTest {
expectHerderStartup(); expectHerderStartup();
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V2);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
SessionKey sessionKey = expectNewSessionKey(); SessionKey sessionKey = expectNewSessionKey();
@ -3335,6 +3381,7 @@ public class DistributedHerderTest {
final long maxPollWaitMs = rebalanceDelayMs - operationDelayMs; final long maxPollWaitMs = rebalanceDelayMs - operationDelayMs;
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(connectProtocolVersion); when(member.currentProtocolVersion()).thenReturn(connectProtocolVersion);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
// Assign the connector to this worker, and have it start // Assign the connector to this worker, and have it start
expectRebalance(Collections.emptyList(), Collections.emptyList(), ConnectProtocol.Assignment.NO_ERROR, 1, singletonList(CONN1), Collections.emptyList(), rebalanceDelayMs); expectRebalance(Collections.emptyList(), Collections.emptyList(), ConnectProtocol.Assignment.NO_ERROR, 1, singletonList(CONN1), Collections.emptyList(), rebalanceDelayMs);
@ -3396,6 +3443,7 @@ public class DistributedHerderTest {
public void testTaskReconfigurationRetriesWithConnectorTaskConfigsException() { public void testTaskReconfigurationRetriesWithConnectorTaskConfigsException() {
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -3417,6 +3465,7 @@ public class DistributedHerderTest {
// initial tick // initial tick
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -3463,6 +3512,7 @@ public class DistributedHerderTest {
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(worker.isSinkConnector(CONN1)).thenReturn(Boolean.TRUE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), false); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), false);
expectConfigRefreshAndSnapshot(SNAPSHOT); expectConfigRefreshAndSnapshot(SNAPSHOT);
@ -3615,8 +3665,8 @@ public class DistributedHerderTest {
List<String> errors = validatedConfigs.get(SourceConnectorConfig.EXACTLY_ONCE_SUPPORT_CONFIG).errorMessages(); List<String> errors = validatedConfigs.get(SourceConnectorConfig.EXACTLY_ONCE_SUPPORT_CONFIG).errorMessages();
assertFalse(errors.isEmpty()); assertFalse(errors.isEmpty());
assertTrue( assertTrue(
"Error message did not contain expected text: " + errors.get(0), errors.get(0).contains("The connector does not implement the API required for preflight validation of exactly-once source support."),
errors.get(0).contains("The connector does not implement the API required for preflight validation of exactly-once source support.")); "Error message did not contain expected text: " + errors.get(0));
assertEquals(1, errors.size()); assertEquals(1, errors.size());
} }
@ -3636,8 +3686,8 @@ public class DistributedHerderTest {
List<String> errors = validatedConfigs.get(SourceConnectorConfig.EXACTLY_ONCE_SUPPORT_CONFIG).errorMessages(); List<String> errors = validatedConfigs.get(SourceConnectorConfig.EXACTLY_ONCE_SUPPORT_CONFIG).errorMessages();
assertFalse(errors.isEmpty()); assertFalse(errors.isEmpty());
assertTrue( assertTrue(
"Error message did not contain expected text: " + errors.get(0), errors.get(0).contains(errorMessage),
errors.get(0).contains(errorMessage)); "Error message did not contain expected text: " + errors.get(0));
assertEquals(1, errors.size()); assertEquals(1, errors.size());
} }
@ -3672,8 +3722,8 @@ public class DistributedHerderTest {
List<String> errors = validatedConfigs.get(SourceConnectorConfig.EXACTLY_ONCE_SUPPORT_CONFIG).errorMessages(); List<String> errors = validatedConfigs.get(SourceConnectorConfig.EXACTLY_ONCE_SUPPORT_CONFIG).errorMessages();
assertFalse(errors.isEmpty()); assertFalse(errors.isEmpty());
assertTrue( assertTrue(
"Error message did not contain expected text: " + errors.get(0), errors.get(0).contains("String must be one of (case insensitive): "),
errors.get(0).contains("String must be one of (case insensitive): ")); "Error message did not contain expected text: " + errors.get(0));
assertEquals(1, errors.size()); assertEquals(1, errors.size());
} }
@ -3710,8 +3760,8 @@ public class DistributedHerderTest {
List<String> errors = validatedConfigs.get(SourceConnectorConfig.TRANSACTION_BOUNDARY_CONFIG).errorMessages(); List<String> errors = validatedConfigs.get(SourceConnectorConfig.TRANSACTION_BOUNDARY_CONFIG).errorMessages();
assertFalse(errors.isEmpty()); assertFalse(errors.isEmpty());
assertTrue( assertTrue(
"Error message did not contain expected text: " + errors.get(0), errors.get(0).contains("The connector does not support connector-defined transaction boundaries with the given configuration."),
errors.get(0).contains("The connector does not support connector-defined transaction boundaries with the given configuration.")); "Error message did not contain expected text: " + errors.get(0));
assertEquals(1, errors.size()); assertEquals(1, errors.size());
} }
@ -3731,8 +3781,8 @@ public class DistributedHerderTest {
List<String> errors = validatedConfigs.get(SourceConnectorConfig.TRANSACTION_BOUNDARY_CONFIG).errorMessages(); List<String> errors = validatedConfigs.get(SourceConnectorConfig.TRANSACTION_BOUNDARY_CONFIG).errorMessages();
assertFalse(errors.isEmpty()); assertFalse(errors.isEmpty());
assertTrue( assertTrue(
"Error message did not contain expected text: " + errors.get(0), errors.get(0).contains(errorMessage),
errors.get(0).contains(errorMessage)); "Error message did not contain expected text: " + errors.get(0));
assertEquals(1, errors.size()); assertEquals(1, errors.size());
} }
@ -3750,8 +3800,8 @@ public class DistributedHerderTest {
List<String> errors = validatedConfigs.get(SourceConnectorConfig.TRANSACTION_BOUNDARY_CONFIG).errorMessages(); List<String> errors = validatedConfigs.get(SourceConnectorConfig.TRANSACTION_BOUNDARY_CONFIG).errorMessages();
assertFalse(errors.isEmpty()); assertFalse(errors.isEmpty());
assertTrue( assertTrue(
"Error message did not contain expected text: " + errors.get(0), errors.get(0).contains("String must be one of (case insensitive): "),
errors.get(0).contains("String must be one of (case insensitive): ")); "Error message did not contain expected text: " + errors.get(0));
assertEquals(1, errors.size()); assertEquals(1, errors.size());
} }
@ -3787,7 +3837,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testModifyConnectorOffsetsUnknownConnector() throws Exception { public void testModifyConnectorOffsetsUnknownConnector() {
// Get the initial assignment // Get the initial assignment
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -3805,7 +3855,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testModifyOffsetsConnectorNotInStoppedState() throws Exception { public void testModifyOffsetsConnectorNotInStoppedState() {
// Get the initial assignment // Get the initial assignment
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -3823,7 +3873,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testModifyOffsetsNotLeader() throws Exception { public void testModifyOffsetsNotLeader() {
// Get the initial assignment // Get the initial assignment
when(member.memberId()).thenReturn("member"); when(member.memberId()).thenReturn("member");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
@ -3875,6 +3925,7 @@ public class DistributedHerderTest {
// Get the initial assignment // Get the initial assignment
when(member.memberId()).thenReturn("leader"); when(member.memberId()).thenReturn("leader");
when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0); when(member.currentProtocolVersion()).thenReturn(CONNECT_PROTOCOL_V0);
when(herder.connectorType(anyMap())).thenReturn(ConnectorType.SOURCE);
expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true); expectRebalance(1, Collections.emptyList(), Collections.emptyList(), true);
expectConfigRefreshAndSnapshot(SNAPSHOT_STOPPED_CONN1); expectConfigRefreshAndSnapshot(SNAPSHOT_STOPPED_CONN1);
herder.tick(); herder.tick();
@ -3960,7 +4011,7 @@ public class DistributedHerderTest {
} }
@Test @Test
public void testModifyOffsetsSourceConnectorExactlyOnceEnabledZombieFencingFailure() throws Exception { public void testModifyOffsetsSourceConnectorExactlyOnceEnabledZombieFencingFailure() {
// Setup herder with exactly-once support for source connectors enabled // Setup herder with exactly-once support for source connectors enabled
herder = exactlyOnceHerder(); herder = exactlyOnceHerder();
rebalanceListener = herder.new RebalanceListener(time); rebalanceListener = herder.new RebalanceListener(time);
@ -4209,7 +4260,7 @@ public class DistributedHerderTest {
private void stopBackgroundHerder() throws Exception { private void stopBackgroundHerder() throws Exception {
herder.stop(); herder.stop();
herderExecutor.shutdown(); herderExecutor.shutdown();
assertTrue("herder thread did not finish in time", herderExecutor.awaitTermination(10, TimeUnit.SECONDS)); assertTrue(herderExecutor.awaitTermination(10, TimeUnit.SECONDS), "herder thread did not finish in time");
herderFuture.get(); herderFuture.get();
assertTrue(noneConnectorClientConfigOverridePolicy.isClosed()); assertTrue(noneConnectorClientConfigOverridePolicy.isClosed());
} }
@ -4313,7 +4364,7 @@ public class DistributedHerderTest {
} }
@Override @Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { public boolean awaitTermination(long timeout, TimeUnit unit) {
return false; return false;
} }
} }

View File

@ -27,10 +27,12 @@ import org.apache.kafka.connect.storage.AppliedConnectorConfig;
import org.apache.kafka.connect.util.ConnectUtils; import org.apache.kafka.connect.util.ConnectUtils;
import org.apache.kafka.connect.storage.ClusterConfigState; import org.apache.kafka.connect.storage.ClusterConfigState;
import org.apache.kafka.connect.util.ConnectorTaskId; import org.apache.kafka.connect.util.ConnectorTaskId;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -49,16 +51,17 @@ import java.util.stream.IntStream;
import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeAssignor.ClusterAssignment; import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeAssignor.ClusterAssignment;
import static org.apache.kafka.connect.runtime.distributed.WorkerCoordinator.WorkerLoad; import static org.apache.kafka.connect.runtime.distributed.WorkerCoordinator.WorkerLoad;
import static org.apache.kafka.connect.util.ConnectUtils.transformValues; import static org.apache.kafka.connect.util.ConnectUtils.transformValues;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class IncrementalCooperativeAssignorTest { public class IncrementalCooperativeAssignorTest {
// Offset isn't used in most tests but is required for creating a config snapshot object, // Offset isn't used in most tests but is required for creating a config snapshot object,
@ -73,7 +76,7 @@ public class IncrementalCooperativeAssignorTest {
private ClusterAssignment returnedAssignments; private ClusterAssignment returnedAssignments;
private Map<String, ConnectorsAndTasks> memberAssignments; private Map<String, ConnectorsAndTasks> memberAssignments;
@Before @BeforeEach
public void setup() { public void setup() {
generationId = 1000; generationId = 1000;
time = Time.SYSTEM; time = Time.SYSTEM;
@ -730,9 +733,9 @@ public class IncrementalCooperativeAssignorTest {
new ConnectorsAndTasks.Builder(), new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
@ -747,9 +750,9 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(), assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance); assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance);
assertEquals(rebalanceDelay, assignor.delay); assertEquals(rebalanceDelay, assignor.delay);
@ -762,9 +765,9 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(), assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.singleton(flakyWorker),
Collections.singleton(flakyWorker), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance); assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance);
assertEquals(rebalanceDelay, assignor.delay); assertEquals(rebalanceDelay, assignor.delay);
@ -775,17 +778,17 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(), assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertTrue("Wrong assignment of lost connectors", assertTrue(configuredAssignment.getOrDefault(flakyWorker, new WorkerLoad.Builder(flakyWorker).build())
configuredAssignment.getOrDefault(flakyWorker, new WorkerLoad.Builder(flakyWorker).build())
.connectors() .connectors()
.containsAll(lostAssignments.connectors())); .containsAll(lostAssignments.connectors()),
assertTrue("Wrong assignment of lost tasks", "Wrong assignment of lost connectors");
configuredAssignment.getOrDefault(flakyWorker, new WorkerLoad.Builder(flakyWorker).build()) assertTrue(configuredAssignment.getOrDefault(flakyWorker, new WorkerLoad.Builder(flakyWorker).build())
.tasks() .tasks()
.containsAll(lostAssignments.tasks())); .containsAll(lostAssignments.tasks()),
assertEquals("Wrong set of workers for reassignments", "Wrong assignment of lost tasks");
Collections.emptySet(), assertEquals(Collections.emptySet(),
assignor.candidateWorkersForReassignment); assignor.candidateWorkersForReassignment,
"Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
} }
@ -810,9 +813,9 @@ public class IncrementalCooperativeAssignorTest {
new ConnectorsAndTasks.Builder(), new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
@ -827,9 +830,9 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(), assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance); assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance);
assertEquals(rebalanceDelay, assignor.delay); assertEquals(rebalanceDelay, assignor.delay);
@ -841,9 +844,9 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(), assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance); assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance);
assertEquals(rebalanceDelay, assignor.delay); assertEquals(rebalanceDelay, assignor.delay);
@ -853,13 +856,13 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, lostAssignmentsToReassign, assignor.handleLostAssignments(lostAssignments, lostAssignmentsToReassign,
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertTrue("Wrong assignment of lost connectors", assertTrue(lostAssignmentsToReassign.build().connectors().containsAll(lostAssignments.connectors()),
lostAssignmentsToReassign.build().connectors().containsAll(lostAssignments.connectors())); "Wrong assignment of lost connectors");
assertTrue("Wrong assignment of lost tasks", assertTrue(lostAssignmentsToReassign.build().tasks().containsAll(lostAssignments.tasks()),
lostAssignmentsToReassign.build().tasks().containsAll(lostAssignments.tasks())); "Wrong assignment of lost tasks");
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
} }
@ -884,9 +887,9 @@ public class IncrementalCooperativeAssignorTest {
new ConnectorsAndTasks.Builder(), new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
@ -904,9 +907,9 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(), assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.singleton(newWorker),
Collections.singleton(newWorker), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance); assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance);
assertEquals(rebalanceDelay, assignor.delay); assertEquals(rebalanceDelay, assignor.delay);
@ -921,9 +924,9 @@ public class IncrementalCooperativeAssignorTest {
Set<String> expectedWorkers = new HashSet<>(); Set<String> expectedWorkers = new HashSet<>();
expectedWorkers.addAll(Arrays.asList(newWorker, flakyWorker)); expectedWorkers.addAll(Arrays.asList(newWorker, flakyWorker));
assertEquals("Wrong set of workers for reassignments", assertEquals(expectedWorkers,
expectedWorkers, assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance); assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance);
assertEquals(rebalanceDelay, assignor.delay); assertEquals(rebalanceDelay, assignor.delay);
@ -949,13 +952,13 @@ public class IncrementalCooperativeAssignorTest {
.tasks()); .tasks());
listOfTasksInLast2Workers.addAll(configuredAssignment.getOrDefault(flakyWorker, new WorkerLoad.Builder(flakyWorker).build()) listOfTasksInLast2Workers.addAll(configuredAssignment.getOrDefault(flakyWorker, new WorkerLoad.Builder(flakyWorker).build())
.tasks()); .tasks());
assertTrue("Wrong assignment of lost connectors", assertTrue(listOfConnectorsInLast2Workers.containsAll(lostAssignments.connectors()),
listOfConnectorsInLast2Workers.containsAll(lostAssignments.connectors())); "Wrong assignment of lost connectors");
assertTrue("Wrong assignment of lost tasks", assertTrue(listOfTasksInLast2Workers.containsAll(lostAssignments.tasks()),
listOfTasksInLast2Workers.containsAll(lostAssignments.tasks())); "Wrong assignment of lost tasks");
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
} }
@ -980,9 +983,9 @@ public class IncrementalCooperativeAssignorTest {
new ConnectorsAndTasks.Builder(), new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
@ -997,9 +1000,9 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(), assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance); assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance);
assertEquals(rebalanceDelay, assignor.delay); assertEquals(rebalanceDelay, assignor.delay);
@ -1012,9 +1015,9 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(), assignor.handleLostAssignments(lostAssignments, new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.singleton(veryFlakyWorker),
Collections.singleton(veryFlakyWorker), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance); assertEquals(time.milliseconds() + rebalanceDelay, assignor.scheduledRebalance);
assertEquals(rebalanceDelay, assignor.delay); assertEquals(rebalanceDelay, assignor.delay);
@ -1027,13 +1030,13 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, lostAssignmentsToReassign, assignor.handleLostAssignments(lostAssignments, lostAssignmentsToReassign,
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertTrue("Wrong assignment of lost connectors", assertTrue(lostAssignmentsToReassign.build().connectors().containsAll(lostAssignments.connectors()),
lostAssignmentsToReassign.build().connectors().containsAll(lostAssignments.connectors())); "Wrong assignment of lost connectors");
assertTrue("Wrong assignment of lost tasks", assertTrue(lostAssignmentsToReassign.build().tasks().containsAll(lostAssignments.tasks()),
lostAssignmentsToReassign.build().tasks().containsAll(lostAssignments.tasks())); "Wrong assignment of lost tasks");
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
} }
@ -1059,9 +1062,9 @@ public class IncrementalCooperativeAssignorTest {
new ConnectorsAndTasks.Builder(), new ConnectorsAndTasks.Builder(),
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
@ -1077,15 +1080,15 @@ public class IncrementalCooperativeAssignorTest {
assignor.handleLostAssignments(lostAssignments, lostAssignmentsToReassign, assignor.handleLostAssignments(lostAssignments, lostAssignmentsToReassign,
new ArrayList<>(configuredAssignment.values())); new ArrayList<>(configuredAssignment.values()));
assertEquals("Wrong set of workers for reassignments", assertEquals(Collections.emptySet(),
Collections.emptySet(), assignor.candidateWorkersForReassignment,
assignor.candidateWorkersForReassignment); "Wrong set of workers for reassignments");
assertEquals(0, assignor.scheduledRebalance); assertEquals(0, assignor.scheduledRebalance);
assertEquals(0, assignor.delay); assertEquals(0, assignor.delay);
assertEquals("Wrong assignment of lost connectors", assertEquals(lostAssignments.connectors(),
lostAssignments.connectors(), lostAssignmentsToReassign.build().connectors()); lostAssignmentsToReassign.build().connectors(), "Wrong assignment of lost connectors");
assertEquals("Wrong assignment of lost tasks", assertEquals(lostAssignments.tasks(),
lostAssignments.tasks(), lostAssignmentsToReassign.build().tasks()); lostAssignmentsToReassign.build().tasks(), "Wrong assignment of lost tasks");
} }
@Test @Test
@ -1240,9 +1243,9 @@ public class IncrementalCooperativeAssignorTest {
serializedAssignments.forEach((worker, serializedAssignment) -> { serializedAssignments.forEach((worker, serializedAssignment) -> {
ExtendedAssignment assignment = IncrementalCooperativeConnectProtocol.deserializeAssignment(serializedAssignment); ExtendedAssignment assignment = IncrementalCooperativeConnectProtocol.deserializeAssignment(serializedAssignment);
assertEquals( assertEquals(
"Incorrect protocol version in assignment for worker " + worker,
IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V1, IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V1,
assignment.version() assignment.version(),
"Incorrect protocol version in assignment for worker " + worker
); );
}); });
} }
@ -1281,9 +1284,9 @@ public class IncrementalCooperativeAssignorTest {
serializedAssignments.forEach((worker, serializedAssignment) -> { serializedAssignments.forEach((worker, serializedAssignment) -> {
ExtendedAssignment assignment = IncrementalCooperativeConnectProtocol.deserializeAssignment(serializedAssignment); ExtendedAssignment assignment = IncrementalCooperativeConnectProtocol.deserializeAssignment(serializedAssignment);
assertEquals( assertEquals(
"Incorrect protocol version in assignment for worker " + worker,
IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V2, IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V2,
assignment.version() assignment.version(),
"Incorrect protocol version in assignment for worker " + worker
); );
}); });
} }
@ -1332,16 +1335,16 @@ public class IncrementalCooperativeAssignorTest {
private void addNewWorker(String worker, List<String> connectors, List<ConnectorTaskId> tasks) { private void addNewWorker(String worker, List<String> connectors, List<ConnectorTaskId> tasks) {
ConnectorsAndTasks assignment = new ConnectorsAndTasks.Builder().with(connectors, tasks).build(); ConnectorsAndTasks assignment = new ConnectorsAndTasks.Builder().with(connectors, tasks).build();
assertNull( assertNull(
"Worker " + worker + " already exists", memberAssignments.put(worker, assignment),
memberAssignments.put(worker, assignment) "Worker " + worker + " already exists"
); );
} }
private void removeWorkers(String... workers) { private void removeWorkers(String... workers) {
for (String worker : workers) { for (String worker : workers) {
assertNotNull( assertNotNull(
"Worker " + worker + " does not exist", memberAssignments.remove(worker),
memberAssignments.remove(worker) "Worker " + worker + " does not exist"
); );
} }
} }
@ -1375,15 +1378,15 @@ public class IncrementalCooperativeAssignorTest {
private void addNewConnector(String connector, int taskCount) { private void addNewConnector(String connector, int taskCount) {
assertNull( assertNull(
"Connector " + connector + " already exists", connectors.put(connector, taskCount),
connectors.put(connector, taskCount) "Connector " + connector + " already exists"
); );
} }
private void removeConnector(String connector) { private void removeConnector(String connector) {
assertNotNull( assertNotNull(
"Connector " + connector + " does not exist", connectors.remove(connector),
connectors.remove(connector) "Connector " + connector + " does not exist"
); );
} }
@ -1425,50 +1428,34 @@ public class IncrementalCooperativeAssignorTest {
workerAssignment.tasks().removeAll(returnedAssignments.newlyRevokedTasks(worker)); workerAssignment.tasks().removeAll(returnedAssignments.newlyRevokedTasks(worker));
workerAssignment.tasks().addAll(returnedAssignments.newlyAssignedTasks(worker)); workerAssignment.tasks().addAll(returnedAssignments.newlyAssignedTasks(worker));
assertEquals( assertEquals(new HashSet<>(workerAssignment.connectors()),
new HashSet<>(returnedAssignments.allAssignedConnectors().get(worker)),
"Complete connector assignment for worker " + worker + " does not match expectations " + "Complete connector assignment for worker " + worker + " does not match expectations " +
"based on prior assignment and new revocations and assignments", "based on prior assignment and new revocations and assignments");
new HashSet<>(workerAssignment.connectors()), assertEquals(new HashSet<>(workerAssignment.tasks()),
new HashSet<>(returnedAssignments.allAssignedConnectors().get(worker)) new HashSet<>(returnedAssignments.allAssignedTasks().get(worker)),
);
assertEquals(
"Complete task assignment for worker " + worker + " does not match expectations " + "Complete task assignment for worker " + worker + " does not match expectations " +
"based on prior assignment and new revocations and assignments", "based on prior assignment and new revocations and assignments");
new HashSet<>(workerAssignment.tasks()),
new HashSet<>(returnedAssignments.allAssignedTasks().get(worker))
);
}); });
} }
private void assertEmptyAssignment() { private void assertEmptyAssignment() {
assertEquals( assertEquals(Collections.emptyList(),
"No connectors should have been newly assigned during this round", ConnectUtils.combineCollections(returnedAssignments.newlyAssignedConnectors().values()),
Collections.emptyList(), "No connectors should have been newly assigned during this round");
ConnectUtils.combineCollections(returnedAssignments.newlyAssignedConnectors().values()) assertEquals(Collections.emptyList(),
); ConnectUtils.combineCollections(returnedAssignments.newlyAssignedTasks().values()),
assertEquals( "No tasks should have been newly assigned during this round");
"No tasks should have been newly assigned during this round", assertEquals(Collections.emptyList(),
Collections.emptyList(), ConnectUtils.combineCollections(returnedAssignments.newlyRevokedConnectors().values()),
ConnectUtils.combineCollections(returnedAssignments.newlyAssignedTasks().values()) "No connectors should have been revoked during this round");
); assertEquals(Collections.emptyList(),
assertEquals( ConnectUtils.combineCollections(returnedAssignments.newlyRevokedTasks().values()),
"No connectors should have been revoked during this round", "No tasks should have been revoked during this round");
Collections.emptyList(),
ConnectUtils.combineCollections(returnedAssignments.newlyRevokedConnectors().values())
);
assertEquals(
"No tasks should have been revoked during this round",
Collections.emptyList(),
ConnectUtils.combineCollections(returnedAssignments.newlyRevokedTasks().values())
);
} }
private void assertWorkers(String... workers) { private void assertWorkers(String... workers) {
assertEquals( assertEquals(new HashSet<>(Arrays.asList(workers)), returnedAssignments.allWorkers(), "Wrong set of workers");
"Wrong set of workers",
new HashSet<>(Arrays.asList(workers)),
returnedAssignments.allWorkers()
);
} }
/** /**
@ -1497,11 +1484,9 @@ public class IncrementalCooperativeAssignorTest {
.sorted() .sorted()
.collect(Collectors.toList()); .collect(Collectors.toList());
List<Integer> actualAllocations = allocations(allocation); List<Integer> actualAllocations = allocations(allocation);
assertEquals( assertEquals(expectedAllocations,
"Allocation of assigned " + allocated + " across cluster does not match expected counts", actualAllocations,
expectedAllocations, "Allocation of assigned " + allocated + " across cluster does not match expected counts");
actualAllocations
);
} }
private List<Integer> allocations(Function<ConnectorsAndTasks, ? extends Collection<?>> allocation) { private List<Integer> allocations(Function<ConnectorsAndTasks, ? extends Collection<?>> allocation) {
@ -1515,25 +1500,25 @@ public class IncrementalCooperativeAssignorTest {
private void assertNoRevocations() { private void assertNoRevocations() {
returnedAssignments.newlyRevokedConnectors().forEach((worker, revocations) -> returnedAssignments.newlyRevokedConnectors().forEach((worker, revocations) ->
assertEquals( assertEquals(
"Expected no revocations to take place during this round, but connector revocations were issued for worker " + worker,
Collections.emptySet(), Collections.emptySet(),
new HashSet<>(revocations) new HashSet<>(revocations),
"Expected no revocations to take place during this round, but connector revocations were issued for worker " + worker
) )
); );
returnedAssignments.newlyRevokedTasks().forEach((worker, revocations) -> returnedAssignments.newlyRevokedTasks().forEach((worker, revocations) ->
assertEquals( assertEquals(
"Expected no revocations to take place during this round, but task revocations were issued for worker " + worker,
Collections.emptySet(), Collections.emptySet(),
new HashSet<>(revocations) new HashSet<>(revocations),
"Expected no revocations to take place during this round, but task revocations were issued for worker " + worker
) )
); );
} }
private void assertDelay(int expectedDelay) { private void assertDelay(int expectedDelay) {
assertEquals( assertEquals(
"Wrong rebalance delay",
expectedDelay, expectedDelay,
assignor.delay assignor.delay,
"Wrong rebalance delay"
); );
} }
@ -1557,13 +1542,13 @@ public class IncrementalCooperativeAssignorTest {
); );
existingConnectors.retainAll(newConnectors); existingConnectors.retainAll(newConnectors);
assertEquals("Found connectors in new assignment that already exist in current assignment", assertEquals(Collections.emptyList(),
Collections.emptyList(), existingConnectors,
existingConnectors); "Found connectors in new assignment that already exist in current assignment");
existingTasks.retainAll(newTasks); existingTasks.retainAll(newTasks);
assertEquals("Found tasks in new assignment that already exist in current assignment", assertEquals(Collections.emptyList(),
Collections.emptyList(), existingConnectors,
existingConnectors); "Found tasks in new assignment that already exist in current assignment");
} }
private void assertBalancedAndCompleteAllocation() { private void assertBalancedAndCompleteAllocation() {
@ -1581,23 +1566,17 @@ public class IncrementalCooperativeAssignorTest {
int minTasks = taskCounts.get(0); int minTasks = taskCounts.get(0);
int maxTasks = taskCounts.get(taskCounts.size() - 1); int maxTasks = taskCounts.get(taskCounts.size() - 1);
assertTrue( assertTrue(maxConnectors - minConnectors <= 1,
"Assignments are imbalanced. The spread of connectors across each worker is: " + connectorCounts, "Assignments are imbalanced. The spread of connectors across each worker is: " + connectorCounts);
maxConnectors - minConnectors <= 1 assertTrue(maxTasks - minTasks <= 1,
); "Assignments are imbalanced. The spread of tasks across each worker is: " + taskCounts);
assertTrue(
"Assignments are imbalanced. The spread of tasks across each worker is: " + taskCounts,
maxTasks - minTasks <= 1
);
} }
private void assertCompleteAllocation() { private void assertCompleteAllocation() {
List<String> allAssignedConnectors = ConnectUtils.combineCollections(memberAssignments.values(), ConnectorsAndTasks::connectors); List<String> allAssignedConnectors = ConnectUtils.combineCollections(memberAssignments.values(), ConnectorsAndTasks::connectors);
assertEquals( assertEquals(connectors.keySet(),
"The set of connectors assigned across the cluster does not match the set of connectors in the config topic", new HashSet<>(allAssignedConnectors),
connectors.keySet(), "The set of connectors assigned across the cluster does not match the set of connectors in the config topic");
new HashSet<>(allAssignedConnectors)
);
Map<String, List<ConnectorTaskId>> allAssignedTasks = ConnectUtils.combineCollections(memberAssignments.values(), ConnectorsAndTasks::tasks) Map<String, List<ConnectorTaskId>> allAssignedTasks = ConnectUtils.combineCollections(memberAssignments.values(), ConnectorsAndTasks::tasks)
.stream() .stream()
@ -1607,20 +1586,14 @@ public class IncrementalCooperativeAssignorTest {
Set<ConnectorTaskId> expectedTasks = IntStream.range(0, taskCount) Set<ConnectorTaskId> expectedTasks = IntStream.range(0, taskCount)
.mapToObj(i -> new ConnectorTaskId(connector, i)) .mapToObj(i -> new ConnectorTaskId(connector, i))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
assertEquals( assertEquals(expectedTasks,
"The set of tasks assigned across the cluster for connector " + connector + " does not match the set of tasks in the config topic", new HashSet<>(allAssignedTasks.get(connector)),
expectedTasks, "The set of tasks assigned across the cluster for connector " + connector + " does not match the set of tasks in the config topic");
new HashSet<>(allAssignedTasks.get(connector))
);
}); });
} }
private static <T> void assertNoDuplicates(List<T> collection, String assertionMessage) { private static <T> void assertNoDuplicates(List<T> collection, String assertionMessage) {
assertEquals( assertEquals(new HashSet<>(collection).size(), collection.size(), assertionMessage);
assertionMessage,
new HashSet<>(collection).size(),
collection.size()
);
} }
} }

View File

@ -29,15 +29,14 @@ import org.apache.kafka.common.utils.MockTime;
import org.apache.kafka.connect.storage.ClusterConfigState; import org.apache.kafka.connect.storage.ClusterConfigState;
import org.apache.kafka.connect.storage.KafkaConfigBackingStore; import org.apache.kafka.connect.storage.KafkaConfigBackingStore;
import org.apache.kafka.connect.util.ConnectorTaskId; import org.apache.kafka.connect.util.ConnectorTaskId;
import org.junit.After; import org.junit.jupiter.api.AfterEach;
import org.junit.Before; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.Rule; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.Test; import org.junit.jupiter.params.provider.Arguments;
import org.junit.runner.RunWith; import org.junit.jupiter.params.provider.MethodSource;
import org.junit.runners.Parameterized;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.MockitoRule; import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness; import org.mockito.quality.Strictness;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -49,6 +48,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream;
import static org.apache.kafka.common.message.JoinGroupRequestData.JoinGroupRequestProtocol; import static org.apache.kafka.common.message.JoinGroupRequestData.JoinGroupRequestProtocol;
import static org.apache.kafka.common.message.JoinGroupRequestData.JoinGroupRequestProtocolCollection; import static org.apache.kafka.common.message.JoinGroupRequestData.JoinGroupRequestProtocolCollection;
@ -58,22 +58,18 @@ import static org.apache.kafka.connect.runtime.WorkerTestUtils.clusterConfigStat
import static org.apache.kafka.connect.runtime.distributed.ConnectProtocol.WorkerState; import static org.apache.kafka.connect.runtime.distributed.ConnectProtocol.WorkerState;
import static org.apache.kafka.connect.runtime.distributed.ConnectProtocolCompatibility.COMPATIBLE; import static org.apache.kafka.connect.runtime.distributed.ConnectProtocolCompatibility.COMPATIBLE;
import static org.apache.kafka.connect.runtime.distributed.ConnectProtocolCompatibility.EAGER; import static org.apache.kafka.connect.runtime.distributed.ConnectProtocolCompatibility.EAGER;
import static org.apache.kafka.connect.runtime.distributed.ConnectProtocolCompatibility.SESSIONED;
import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V1; import static org.apache.kafka.connect.runtime.distributed.IncrementalCooperativeConnectProtocol.CONNECT_PROTOCOL_V1;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.runners.Parameterized.Parameter;
import static org.junit.runners.Parameterized.Parameters;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(value = Parameterized.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class WorkerCoordinatorIncrementalTest { public class WorkerCoordinatorIncrementalTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
private final String connectorId1 = "connector1"; private final String connectorId1 = "connector1";
private final String connectorId2 = "connector2"; private final String connectorId2 = "connector2";
@ -116,19 +112,14 @@ public class WorkerCoordinatorIncrementalTest {
// Arguments are: // Arguments are:
// - Protocol type // - Protocol type
// - Expected metadata size // - Expected metadata size
@Parameters static Stream<Arguments> mode() {
public static Iterable<?> mode() { return Stream.of(
return Arrays.asList(new Object[][]{{COMPATIBLE, 2}, {SESSIONED, 3}}); Arguments.of(ConnectProtocolCompatibility.COMPATIBLE, 2),
Arguments.of(ConnectProtocolCompatibility.SESSIONED, 3)
);
} }
@Parameter public void init(ConnectProtocolCompatibility compatibility) {
public ConnectProtocolCompatibility compatibility;
@Parameter(1)
public int expectedMetadataSize;
@Before
public void setup() {
LogContext loggerFactory = new LogContext(); LogContext loggerFactory = new LogContext();
this.time = new MockTime(); this.time = new MockTime();
@ -175,7 +166,7 @@ public class WorkerCoordinatorIncrementalTest {
configState1 = clusterConfigState(offset, 2, 4); configState1 = clusterConfigState(offset, 2, 4);
} }
@After @AfterEach
public void teardown() { public void teardown() {
this.metrics.close(); this.metrics.close();
verifyNoMoreInteractions(configStorage); verifyNoMoreInteractions(configStorage);
@ -188,8 +179,11 @@ public class WorkerCoordinatorIncrementalTest {
// We only test functionality unique to WorkerCoordinator. Other functionality is already // We only test functionality unique to WorkerCoordinator. Other functionality is already
// well tested via the tests that cover AbstractCoordinator & ConsumerCoordinator. // well tested via the tests that cover AbstractCoordinator & ConsumerCoordinator.
@Test @ParameterizedTest
public void testMetadata() { @MethodSource("mode")
public void testMetadata(ConnectProtocolCompatibility compatibility, int expectedMetadataSize) {
init(compatibility);
System.err.println(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
JoinGroupRequestProtocolCollection serialized = coordinator.metadata(); JoinGroupRequestProtocolCollection serialized = coordinator.metadata();
@ -206,8 +200,10 @@ public class WorkerCoordinatorIncrementalTest {
verify(configStorage, times(1)).snapshot(); verify(configStorage, times(1)).snapshot();
} }
@Test @ParameterizedTest
public void testMetadataWithExistingAssignment() { @MethodSource("mode")
public void testMetadataWithExistingAssignment(ConnectProtocolCompatibility compatibility, int expectedMetadataSize) {
init(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
ExtendedAssignment assignment = new ExtendedAssignment( ExtendedAssignment assignment = new ExtendedAssignment(
@ -237,8 +233,10 @@ public class WorkerCoordinatorIncrementalTest {
verify(configStorage, times(1)).snapshot(); verify(configStorage, times(1)).snapshot();
} }
@Test @ParameterizedTest
public void testMetadataWithExistingAssignmentButOlderProtocolSelection() { @MethodSource("mode")
public void testMetadataWithExistingAssignmentButOlderProtocolSelection(ConnectProtocolCompatibility compatibility, int expectedMetadataSize) {
init(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
ExtendedAssignment assignment = new ExtendedAssignment( ExtendedAssignment assignment = new ExtendedAssignment(
@ -266,16 +264,18 @@ public class WorkerCoordinatorIncrementalTest {
verify(configStorage, times(1)).snapshot(); verify(configStorage, times(1)).snapshot();
} }
@Test @ParameterizedTest
public void testTaskAssignmentWhenWorkerJoins() { @MethodSource("mode")
public void testTaskAssignmentWhenWorkerJoins(ConnectProtocolCompatibility compatibility) {
init(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
coordinator.metadata(); coordinator.metadata();
++configStorageCalls; ++configStorageCalls;
List<JoinGroupResponseMember> responseMembers = new ArrayList<>(); List<JoinGroupResponseMember> responseMembers = new ArrayList<>();
addJoinGroupResponseMember(responseMembers, leaderId, offset, null); addJoinGroupResponseMember(responseMembers, leaderId, offset, null, compatibility);
addJoinGroupResponseMember(responseMembers, memberId, offset, null); addJoinGroupResponseMember(responseMembers, memberId, offset, null, compatibility);
Map<String, ByteBuffer> result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false); Map<String, ByteBuffer> result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false);
@ -295,9 +295,9 @@ public class WorkerCoordinatorIncrementalTest {
++configStorageCalls; ++configStorageCalls;
responseMembers = new ArrayList<>(); responseMembers = new ArrayList<>();
addJoinGroupResponseMember(responseMembers, leaderId, offset, leaderAssignment); addJoinGroupResponseMember(responseMembers, leaderId, offset, leaderAssignment, compatibility);
addJoinGroupResponseMember(responseMembers, memberId, offset, memberAssignment); addJoinGroupResponseMember(responseMembers, memberId, offset, memberAssignment, compatibility);
addJoinGroupResponseMember(responseMembers, anotherMemberId, offset, null); addJoinGroupResponseMember(responseMembers, anotherMemberId, offset, null, compatibility);
result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false); result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false);
@ -323,8 +323,10 @@ public class WorkerCoordinatorIncrementalTest {
verify(configStorage, times(configStorageCalls)).snapshot(); verify(configStorage, times(configStorageCalls)).snapshot();
} }
@Test @ParameterizedTest
public void testTaskAssignmentWhenWorkerLeavesPermanently() { @MethodSource("mode")
public void testTaskAssignmentWhenWorkerLeavesPermanently(ConnectProtocolCompatibility compatibility) {
init(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
// First assignment distributes configured connectors and tasks // First assignment distributes configured connectors and tasks
@ -332,9 +334,9 @@ public class WorkerCoordinatorIncrementalTest {
++configStorageCalls; ++configStorageCalls;
List<JoinGroupResponseMember> responseMembers = new ArrayList<>(); List<JoinGroupResponseMember> responseMembers = new ArrayList<>();
addJoinGroupResponseMember(responseMembers, leaderId, offset, null); addJoinGroupResponseMember(responseMembers, leaderId, offset, null, compatibility);
addJoinGroupResponseMember(responseMembers, memberId, offset, null); addJoinGroupResponseMember(responseMembers, memberId, offset, null, compatibility);
addJoinGroupResponseMember(responseMembers, anotherMemberId, offset, null); addJoinGroupResponseMember(responseMembers, anotherMemberId, offset, null, compatibility);
Map<String, ByteBuffer> result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false); Map<String, ByteBuffer> result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false);
@ -362,8 +364,8 @@ public class WorkerCoordinatorIncrementalTest {
// Mark everyone as in sync with configState1 // Mark everyone as in sync with configState1
responseMembers = new ArrayList<>(); responseMembers = new ArrayList<>();
addJoinGroupResponseMember(responseMembers, leaderId, offset, leaderAssignment); addJoinGroupResponseMember(responseMembers, leaderId, offset, leaderAssignment, compatibility);
addJoinGroupResponseMember(responseMembers, memberId, offset, memberAssignment); addJoinGroupResponseMember(responseMembers, memberId, offset, memberAssignment, compatibility);
result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false); result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false);
@ -421,8 +423,10 @@ public class WorkerCoordinatorIncrementalTest {
verify(configStorage, times(configStorageCalls)).snapshot(); verify(configStorage, times(configStorageCalls)).snapshot();
} }
@Test @ParameterizedTest
public void testTaskAssignmentWhenWorkerBounces() { @MethodSource("mode")
public void testTaskAssignmentWhenWorkerBounces(ConnectProtocolCompatibility compatibility) {
init(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
// First assignment distributes configured connectors and tasks // First assignment distributes configured connectors and tasks
@ -430,9 +434,9 @@ public class WorkerCoordinatorIncrementalTest {
++configStorageCalls; ++configStorageCalls;
List<JoinGroupResponseMember> responseMembers = new ArrayList<>(); List<JoinGroupResponseMember> responseMembers = new ArrayList<>();
addJoinGroupResponseMember(responseMembers, leaderId, offset, null); addJoinGroupResponseMember(responseMembers, leaderId, offset, null, compatibility);
addJoinGroupResponseMember(responseMembers, memberId, offset, null); addJoinGroupResponseMember(responseMembers, memberId, offset, null, compatibility);
addJoinGroupResponseMember(responseMembers, anotherMemberId, offset, null); addJoinGroupResponseMember(responseMembers, anotherMemberId, offset, null, compatibility);
Map<String, ByteBuffer> result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false); Map<String, ByteBuffer> result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false);
@ -459,8 +463,8 @@ public class WorkerCoordinatorIncrementalTest {
++configStorageCalls; ++configStorageCalls;
responseMembers = new ArrayList<>(); responseMembers = new ArrayList<>();
addJoinGroupResponseMember(responseMembers, leaderId, offset, leaderAssignment); addJoinGroupResponseMember(responseMembers, leaderId, offset, leaderAssignment, compatibility);
addJoinGroupResponseMember(responseMembers, memberId, offset, memberAssignment); addJoinGroupResponseMember(responseMembers, memberId, offset, memberAssignment, compatibility);
result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false); result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false);
@ -483,7 +487,7 @@ public class WorkerCoordinatorIncrementalTest {
// A third rebalance before the delay expires won't change the assignments even if the // A third rebalance before the delay expires won't change the assignments even if the
// member returns in the meantime // member returns in the meantime
addJoinGroupResponseMember(responseMembers, anotherMemberId, offset, null); addJoinGroupResponseMember(responseMembers, anotherMemberId, offset, null, compatibility);
result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false); result = coordinator.onLeaderElected(leaderId, compatibility.protocol(), responseMembers, false);
leaderAssignment = deserializeAssignment(result, leaderId); leaderAssignment = deserializeAssignment(result, leaderId);
@ -569,10 +573,12 @@ public class WorkerCoordinatorIncrementalTest {
return IncrementalCooperativeConnectProtocol.deserializeAssignment(assignment.get(member)); return IncrementalCooperativeConnectProtocol.deserializeAssignment(assignment.get(member));
} }
private void addJoinGroupResponseMember(List<JoinGroupResponseMember> responseMembers, private void addJoinGroupResponseMember(List<JoinGroupResponseMember> responseMembers,
String member, String member,
long offset, long offset,
ExtendedAssignment assignment) { ExtendedAssignment assignment,
ConnectProtocolCompatibility compatibility) {
responseMembers.add(new JoinGroupResponseMember() responseMembers.add(new JoinGroupResponseMember()
.setMemberId(member) .setMemberId(member)
.setMetadata( .setMetadata(

View File

@ -41,15 +41,14 @@ import org.apache.kafka.connect.storage.AppliedConnectorConfig;
import org.apache.kafka.connect.storage.ClusterConfigState; import org.apache.kafka.connect.storage.ClusterConfigState;
import org.apache.kafka.connect.storage.KafkaConfigBackingStore; import org.apache.kafka.connect.storage.KafkaConfigBackingStore;
import org.apache.kafka.connect.util.ConnectorTaskId; import org.apache.kafka.connect.util.ConnectorTaskId;
import org.junit.After; import org.junit.jupiter.api.AfterEach;
import org.junit.Before; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.Rule; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.Test; import org.junit.jupiter.params.provider.Arguments;
import org.junit.runner.RunWith; import org.junit.jupiter.params.provider.MethodSource;
import org.junit.runners.Parameterized;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.MockitoRule; import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness; import org.mockito.quality.Strictness;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -63,26 +62,23 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.apache.kafka.connect.runtime.distributed.ConnectProtocolCompatibility.COMPATIBLE; import static org.apache.kafka.connect.runtime.distributed.ConnectProtocolCompatibility.COMPATIBLE;
import static org.apache.kafka.connect.runtime.distributed.ConnectProtocolCompatibility.EAGER; import static org.apache.kafka.connect.runtime.distributed.ConnectProtocolCompatibility.EAGER;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.runners.Parameterized.Parameter;
import static org.junit.runners.Parameterized.Parameters;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(value = Parameterized.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class WorkerCoordinatorTest { public class WorkerCoordinatorTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
private static final String LEADER_URL = "leaderUrl:8083"; private static final String LEADER_URL = "leaderUrl:8083";
private static final String MEMBER_URL = "memberUrl:8083"; private static final String MEMBER_URL = "memberUrl:8083";
@ -118,21 +114,14 @@ public class WorkerCoordinatorTest {
// Arguments are: // Arguments are:
// - Protocol type // - Protocol type
// - Expected metadata size // - Expected metadata size
@Parameters static Stream<Arguments> mode() {
public static Iterable<?> mode() { return Stream.of(
return Arrays.asList(new Object[][]{ Arguments.of(EAGER, 1),
{EAGER, 1}, Arguments.of(COMPATIBLE, 2)
{COMPATIBLE, 2}}); );
} }
@Parameter public void setup(ConnectProtocolCompatibility compatibility) {
public ConnectProtocolCompatibility compatibility;
@Parameter(1)
public int expectedMetadataSize;
@Before
public void setup() {
LogContext logContext = new LogContext(); LogContext logContext = new LogContext();
this.time = new MockTime(); this.time = new MockTime();
@ -241,7 +230,7 @@ public class WorkerCoordinatorTest {
); );
} }
@After @AfterEach
public void teardown() { public void teardown() {
this.metrics.close(); this.metrics.close();
} }
@ -249,8 +238,10 @@ public class WorkerCoordinatorTest {
// We only test functionality unique to WorkerCoordinator. Most functionality is already well tested via the tests // We only test functionality unique to WorkerCoordinator. Most functionality is already well tested via the tests
// that cover AbstractCoordinator & ConsumerCoordinator. // that cover AbstractCoordinator & ConsumerCoordinator.
@Test @ParameterizedTest
public void testMetadata() { @MethodSource("mode")
public void testMetadata(ConnectProtocolCompatibility compatibility, int expectedMetadataSize) {
setup(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
JoinGroupRequestData.JoinGroupRequestProtocolCollection serialized = coordinator.metadata(); JoinGroupRequestData.JoinGroupRequestProtocolCollection serialized = coordinator.metadata();
@ -267,8 +258,10 @@ public class WorkerCoordinatorTest {
verify(configStorage).snapshot(); verify(configStorage).snapshot();
} }
@Test @ParameterizedTest
public void testNormalJoinGroupLeader() { @MethodSource("mode")
public void testNormalJoinGroupLeader(ConnectProtocolCompatibility compatibility) {
setup(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
final String memberId = "leader"; final String memberId = "leader";
@ -302,8 +295,10 @@ public class WorkerCoordinatorTest {
verify(configStorage).snapshot(); verify(configStorage).snapshot();
} }
@Test @ParameterizedTest
public void testNormalJoinGroupFollower() { @MethodSource("mode")
public void testNormalJoinGroupFollower(ConnectProtocolCompatibility compatibility) {
setup(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
final String memberId = "member"; final String memberId = "member";
@ -333,8 +328,10 @@ public class WorkerCoordinatorTest {
verify(configStorage).snapshot(); verify(configStorage).snapshot();
} }
@Test @ParameterizedTest
public void testJoinLeaderCannotAssign() { @MethodSource("mode")
public void testJoinLeaderCannotAssign(ConnectProtocolCompatibility compatibility) {
setup(compatibility);
// If the selected leader can't get up to the maximum offset, it will fail to assign and we should immediately // If the selected leader can't get up to the maximum offset, it will fail to assign and we should immediately
// need to retry the join. // need to retry the join.
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
@ -366,8 +363,10 @@ public class WorkerCoordinatorTest {
verify(configStorage, times(2)).snapshot(); verify(configStorage, times(2)).snapshot();
} }
@Test @ParameterizedTest
public void testRejoinGroup() { @MethodSource("mode")
public void testRejoinGroup(ConnectProtocolCompatibility compatibility) {
setup(compatibility);
when(configStorage.snapshot()).thenReturn(configState1); when(configStorage.snapshot()).thenReturn(configState1);
client.prepareResponse(FindCoordinatorResponse.prepareResponse(Errors.NONE, groupId, node)); client.prepareResponse(FindCoordinatorResponse.prepareResponse(Errors.NONE, groupId, node));
@ -405,8 +404,10 @@ public class WorkerCoordinatorTest {
verify(configStorage, times(2)).snapshot(); verify(configStorage, times(2)).snapshot();
} }
@Test @ParameterizedTest
public void testLeaderPerformAssignment1() { @MethodSource("mode")
public void testLeaderPerformAssignment1(ConnectProtocolCompatibility compatibility) {
setup(compatibility);
// Since all the protocol responses are mocked, the other tests validate doSync runs, but don't validate its // Since all the protocol responses are mocked, the other tests validate doSync runs, but don't validate its
// output. So we test it directly here. // output. So we test it directly here.
@ -445,8 +446,10 @@ public class WorkerCoordinatorTest {
verify(configStorage).snapshot(); verify(configStorage).snapshot();
} }
@Test @ParameterizedTest
public void testLeaderPerformAssignment2() { @MethodSource("mode")
public void testLeaderPerformAssignment2(ConnectProtocolCompatibility compatibility) {
setup(compatibility);
// Since all the protocol responses are mocked, the other tests validate doSync runs, but don't validate its // Since all the protocol responses are mocked, the other tests validate doSync runs, but don't validate its
// output. So we test it directly here. // output. So we test it directly here.
@ -486,8 +489,10 @@ public class WorkerCoordinatorTest {
verify(configStorage).snapshot(); verify(configStorage).snapshot();
} }
@Test @ParameterizedTest
public void testLeaderPerformAssignmentSingleTaskConnectors() { @MethodSource("mode")
public void testLeaderPerformAssignmentSingleTaskConnectors(ConnectProtocolCompatibility compatibility) {
setup(compatibility);
// Since all the protocol responses are mocked, the other tests validate doSync runs, but don't validate its // Since all the protocol responses are mocked, the other tests validate doSync runs, but don't validate its
// output. So we test it directly here. // output. So we test it directly here.
@ -528,8 +533,10 @@ public class WorkerCoordinatorTest {
verify(configStorage).snapshot(); verify(configStorage).snapshot();
} }
@Test @ParameterizedTest
public void testSkippingAssignmentFails() { @MethodSource("mode")
public void testSkippingAssignmentFails(ConnectProtocolCompatibility compatibility) {
setup(compatibility);
// Connect does not support static membership so skipping assignment should // Connect does not support static membership so skipping assignment should
// never be set to true by the group coordinator. It is treated as an // never be set to true by the group coordinator. It is treated as an
// illegal state if it would. // illegal state if it would.

View File

@ -26,10 +26,12 @@ import org.apache.kafka.common.utils.Time;
import org.apache.kafka.connect.runtime.MockConnectMetrics; import org.apache.kafka.connect.runtime.MockConnectMetrics;
import org.apache.kafka.connect.runtime.WorkerConfig; import org.apache.kafka.connect.runtime.WorkerConfig;
import org.apache.kafka.connect.storage.ConfigBackingStore; import org.apache.kafka.connect.storage.ConfigBackingStore;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import javax.management.MBeanServer; import javax.management.MBeanServer;
import javax.management.ObjectName; import javax.management.ObjectName;
@ -37,15 +39,16 @@ import java.lang.management.ManagementFactory;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class WorkerGroupMemberTest { public class WorkerGroupMemberTest {
@Mock @Mock
private ConfigBackingStore configBackingStore; private ConfigBackingStore configBackingStore;
@ -83,8 +86,8 @@ public class WorkerGroupMemberTest {
foundJmxReporter = true; foundJmxReporter = true;
} }
} }
assertTrue("Failed to find MockMetricsReporter", foundMockReporter); assertTrue(foundMockReporter, "Failed to find MockMetricsReporter");
assertTrue("Failed to find JmxReporter", foundJmxReporter); assertTrue(foundJmxReporter, "Failed to find JmxReporter");
MetricName name = member.metrics().metricName("test.avg", "grp1"); MetricName name = member.metrics().metricName("test.avg", "grp1");
member.metrics().addMetric(name, new Avg()); member.metrics().addMetric(name, new Avg());

View File

@ -31,12 +31,14 @@ import org.apache.kafka.connect.runtime.isolation.Plugins;
import org.apache.kafka.connect.sink.SinkTask; import org.apache.kafka.connect.sink.SinkTask;
import org.apache.kafka.connect.transforms.Transformation; import org.apache.kafka.connect.transforms.Transformation;
import org.apache.kafka.connect.util.ConnectorTaskId; import org.apache.kafka.connect.util.ConnectorTaskId;
import org.junit.After; import org.junit.jupiter.api.Test;
import org.junit.Before; import org.junit.jupiter.api.AfterEach;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -55,11 +57,11 @@ import static org.apache.kafka.connect.runtime.errors.DeadLetterQueueReporter.ER
import static org.apache.kafka.connect.runtime.errors.DeadLetterQueueReporter.ERROR_HEADER_ORIG_TOPIC; import static org.apache.kafka.connect.runtime.errors.DeadLetterQueueReporter.ERROR_HEADER_ORIG_TOPIC;
import static org.apache.kafka.connect.runtime.errors.DeadLetterQueueReporter.ERROR_HEADER_STAGE; import static org.apache.kafka.connect.runtime.errors.DeadLetterQueueReporter.ERROR_HEADER_STAGE;
import static org.apache.kafka.connect.runtime.errors.DeadLetterQueueReporter.ERROR_HEADER_TASK_ID; import static org.apache.kafka.connect.runtime.errors.DeadLetterQueueReporter.ERROR_HEADER_TASK_ID;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
@ -67,7 +69,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class ErrorReporterTest { public class ErrorReporterTest {
private static final String TOPIC = "test-topic"; private static final String TOPIC = "test-topic";
@ -86,13 +89,13 @@ public class ErrorReporterTest {
private ErrorHandlingMetrics errorHandlingMetrics; private ErrorHandlingMetrics errorHandlingMetrics;
private MockConnectMetrics metrics; private MockConnectMetrics metrics;
@Before @BeforeEach
public void setup() { public void setup() {
metrics = new MockConnectMetrics(); metrics = new MockConnectMetrics();
errorHandlingMetrics = new ErrorHandlingMetrics(new ConnectorTaskId("connector-", 1), metrics); errorHandlingMetrics = new ErrorHandlingMetrics(new ConnectorTaskId("connector-", 1), metrics);
} }
@After @AfterEach
public void tearDown() { public void tearDown() {
if (metrics != null) { if (metrics != null) {
metrics.stop(); metrics.stop();

View File

@ -35,10 +35,12 @@ import org.apache.kafka.connect.sink.SinkConnector;
import org.apache.kafka.connect.sink.SinkTask; import org.apache.kafka.connect.sink.SinkTask;
import org.apache.kafka.connect.source.SourceRecord; import org.apache.kafka.connect.source.SourceRecord;
import org.apache.kafka.connect.util.ConnectorTaskId; import org.apache.kafka.connect.util.ConnectorTaskId;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.OngoingStubbing; import org.mockito.stubbing.OngoingStubbing;
import java.util.Arrays; import java.util.Arrays;
@ -65,11 +67,11 @@ import static org.apache.kafka.connect.runtime.ConnectorConfig.ERRORS_TOLERANCE_
import static org.apache.kafka.connect.runtime.ConnectorConfig.ERRORS_TOLERANCE_DEFAULT; import static org.apache.kafka.connect.runtime.ConnectorConfig.ERRORS_TOLERANCE_DEFAULT;
import static org.apache.kafka.connect.runtime.errors.ToleranceType.ALL; import static org.apache.kafka.connect.runtime.errors.ToleranceType.ALL;
import static org.apache.kafka.connect.runtime.errors.ToleranceType.NONE; import static org.apache.kafka.connect.runtime.errors.ToleranceType.NONE;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
@ -80,7 +82,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class RetryWithToleranceOperatorTest { public class RetryWithToleranceOperatorTest {
private static final Map<String, String> PROPERTIES = new HashMap<String, String>() {{ private static final Map<String, String> PROPERTIES = new HashMap<String, String>() {{
@ -358,15 +361,15 @@ public class RetryWithToleranceOperatorTest {
public void testToleranceLimit() { public void testToleranceLimit() {
RetryWithToleranceOperator<ConsumerRecord<byte[], byte[]>> retryWithToleranceOperator = genericOperator(ERRORS_RETRY_TIMEOUT_DEFAULT, NONE, errorHandlingMetrics); RetryWithToleranceOperator<ConsumerRecord<byte[], byte[]>> retryWithToleranceOperator = genericOperator(ERRORS_RETRY_TIMEOUT_DEFAULT, NONE, errorHandlingMetrics);
retryWithToleranceOperator.markAsFailed(); retryWithToleranceOperator.markAsFailed();
assertFalse("should not tolerate any errors", retryWithToleranceOperator.withinToleranceLimits()); assertFalse(retryWithToleranceOperator.withinToleranceLimits(), "should not tolerate any errors");
retryWithToleranceOperator = genericOperator(ERRORS_RETRY_TIMEOUT_DEFAULT, ALL, errorHandlingMetrics); retryWithToleranceOperator = genericOperator(ERRORS_RETRY_TIMEOUT_DEFAULT, ALL, errorHandlingMetrics);
retryWithToleranceOperator.markAsFailed(); retryWithToleranceOperator.markAsFailed();
retryWithToleranceOperator.markAsFailed(); retryWithToleranceOperator.markAsFailed();
assertTrue("should tolerate all errors", retryWithToleranceOperator.withinToleranceLimits()); assertTrue(retryWithToleranceOperator.withinToleranceLimits(), "should tolerate all errors");
retryWithToleranceOperator = genericOperator(ERRORS_RETRY_TIMEOUT_DEFAULT, NONE, errorHandlingMetrics); retryWithToleranceOperator = genericOperator(ERRORS_RETRY_TIMEOUT_DEFAULT, NONE, errorHandlingMetrics);
assertTrue("no tolerance is within limits if no failures", retryWithToleranceOperator.withinToleranceLimits()); assertTrue(retryWithToleranceOperator.withinToleranceLimits(), "no tolerance is within limits if no failures");
} }
@Test @Test

View File

@ -25,24 +25,27 @@ import org.apache.kafka.connect.runtime.ConnectorConfig;
import org.apache.kafka.connect.runtime.InternalSinkRecord; import org.apache.kafka.connect.runtime.InternalSinkRecord;
import org.apache.kafka.connect.storage.Converter; import org.apache.kafka.connect.storage.Converter;
import org.apache.kafka.connect.storage.HeaderConverter; import org.apache.kafka.connect.storage.HeaderConverter;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class WorkerErrantRecordReporterTest { public class WorkerErrantRecordReporterTest {
private WorkerErrantRecordReporter reporter; private WorkerErrantRecordReporter reporter;

View File

@ -19,12 +19,14 @@ package org.apache.kafka.connect.runtime.health;
import org.apache.kafka.connect.errors.ConnectException; import org.apache.kafka.connect.errors.ConnectException;
import org.apache.kafka.connect.runtime.Herder; import org.apache.kafka.connect.runtime.Herder;
import org.apache.kafka.connect.util.Callback; import org.apache.kafka.connect.util.Callback;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -33,13 +35,14 @@ import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class ConnectClusterStateImplTest { public class ConnectClusterStateImplTest {
protected static final String KAFKA_CLUSTER_ID = "franzwashere"; protected static final String KAFKA_CLUSTER_ID = "franzwashere";
@ -49,7 +52,7 @@ public class ConnectClusterStateImplTest {
protected long herderRequestTimeoutMs = TimeUnit.SECONDS.toMillis(10); protected long herderRequestTimeoutMs = TimeUnit.SECONDS.toMillis(10);
protected Collection<String> expectedConnectors; protected Collection<String> expectedConnectors;
@Before @BeforeEach
public void setUp() { public void setUp() {
expectedConnectors = Arrays.asList("sink1", "source1", "source2"); expectedConnectors = Arrays.asList("sink1", "source1", "source2");
connectClusterState = new ConnectClusterStateImpl( connectClusterState = new ConnectClusterStateImpl(
@ -86,11 +89,9 @@ public class ConnectClusterStateImplTest {
Map<String, String> actualConfig = connectClusterState.connectorConfig(connName); Map<String, String> actualConfig = connectClusterState.connectorConfig(connName);
assertEquals(expectedConfig, actualConfig); assertEquals(expectedConfig, actualConfig);
assertNotSame( assertNotSame(expectedConfig,
"Config should be copied in order to avoid mutation by REST extensions", actualConfig,
expectedConfig, "Config should be copied in order to avoid mutation by REST extensions");
actualConfig
);
} }
@Test @Test

View File

@ -17,10 +17,12 @@
package org.apache.kafka.connect.runtime.isolation; package org.apache.kafka.connect.runtime.isolation;
import org.apache.kafka.connect.sink.SinkConnector; import org.apache.kafka.connect.sink.SinkConnector;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
@ -28,12 +30,13 @@ import java.util.Collections;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import static org.junit.Assert.assertSame; import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class DelegatingClassLoaderTest { public class DelegatingClassLoaderTest {
public PluginClassLoader parent; public PluginClassLoader parent;
@ -55,7 +58,7 @@ public class DelegatingClassLoaderTest {
} }
} }
@Before @BeforeEach
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public void setUp() { public void setUp() {
parent = mock(PluginClassLoader.class); parent = mock(PluginClassLoader.class);

View File

@ -26,16 +26,16 @@ import org.apache.kafka.connect.storage.Converter;
import org.apache.kafka.connect.storage.HeaderConverter; import org.apache.kafka.connect.storage.HeaderConverter;
import org.apache.kafka.connect.transforms.Transformation; import org.apache.kafka.connect.transforms.Transformation;
import org.apache.kafka.connect.transforms.predicates.Predicate; import org.apache.kafka.connect.transforms.predicates.Predicate;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import java.net.URL; import java.net.URL;
import java.nio.file.Paths; import java.nio.file.Paths;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -48,7 +48,7 @@ public class PluginDescTest {
private PluginClassLoader pluginLoader; private PluginClassLoader pluginLoader;
private PluginClassLoader otherPluginLoader; private PluginClassLoader otherPluginLoader;
@Before @BeforeEach
public void setUp() throws Exception { public void setUp() throws Exception {
// Fairly simple use case, thus no need to create a random directory here yet. // Fairly simple use case, thus no need to create a random directory here yet.
URL location = Paths.get("/tmp").toUri().toURL(); URL location = Paths.get("/tmp").toUri().toURL();
@ -285,8 +285,8 @@ public class PluginDescTest {
otherPluginLoader otherPluginLoader
); );
assertTrue("Different plugin loaders should have an ordering", assertTrue(configProviderDescPluginPath.compareTo(configProviderDescOtherPluginLoader) != 0,
configProviderDescPluginPath.compareTo(configProviderDescOtherPluginLoader) != 0); "Different plugin loaders should have an ordering");
PluginDesc<Converter> jsonConverterPlugin = new PluginDesc<>( PluginDesc<Converter> jsonConverterPlugin = new PluginDesc<>(
@ -339,6 +339,6 @@ public class PluginDescTest {
} }
private static void assertNewer(PluginDesc<?> older, PluginDesc<?> newer) { private static void assertNewer(PluginDesc<?> older, PluginDesc<?> newer) {
assertTrue(newer + " should be newer than " + older, older.compareTo(newer) < 0); assertTrue(older.compareTo(newer) < 0, newer + " should be newer than " + older);
} }
} }

View File

@ -17,161 +17,141 @@
package org.apache.kafka.connect.runtime.isolation; package org.apache.kafka.connect.runtime.isolation;
import org.junit.BeforeClass; import java.io.File;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
@RunWith(Parameterized.class)
public class PluginScannerTest { public class PluginScannerTest {
private enum ScannerType { Reflection, ServiceLoader } private enum ScannerType { Reflection, ServiceLoader }
@Rule @TempDir
public TemporaryFolder pluginDir = new TemporaryFolder(); File pluginDir;
private final PluginScanner scanner; private Map<ScannerType, PluginScanner> scannerMap;
@Parameterized.Parameters static Stream<PluginScanner> parameters() {
public static Collection<Object[]> parameters() { return Stream.of(new ReflectionScanner(), new ServiceLoaderScanner());
List<Object[]> values = new ArrayList<>();
for (ScannerType type : ScannerType.values()) {
values.add(new Object[]{type});
}
return values;
} }
public PluginScannerTest(ScannerType scannerType) { @BeforeAll
switch (scannerType) {
case Reflection:
this.scanner = new ReflectionScanner();
break;
case ServiceLoader:
this.scanner = new ServiceLoaderScanner();
break;
default:
throw new IllegalArgumentException("Unknown type " + scannerType);
}
}
@BeforeClass
public static void setUp() { public static void setUp() {
// Work around a circular-dependency in TestPlugins. // Work around a circular-dependency in TestPlugins.
TestPlugins.pluginPath(); TestPlugins.pluginPath();
} }
@Test @ParameterizedTest
public void testScanningEmptyPluginPath() { @MethodSource("parameters")
PluginScanResult result = scan( public void testScanningEmptyPluginPath(PluginScanner scanner) {
Collections.emptySet() PluginScanResult result = scan(scanner, Collections.emptySet());
);
assertTrue(result.isEmpty()); assertTrue(result.isEmpty());
} }
@Test @ParameterizedTest
public void testScanningPluginClasses() { @MethodSource("parameters")
PluginScanResult result = scan( public void testScanningPluginClasses(PluginScanner scanner) {
TestPlugins.pluginPath() PluginScanResult result = scan(scanner, TestPlugins.pluginPath());
);
Set<String> classes = new HashSet<>(); Set<String> classes = new HashSet<>();
result.forEach(pluginDesc -> classes.add(pluginDesc.className())); result.forEach(pluginDesc -> classes.add(pluginDesc.className()));
Set<String> expectedClasses = new HashSet<>(TestPlugins.pluginClasses()); Set<String> expectedClasses = new HashSet<>(TestPlugins.pluginClasses());
assertEquals(expectedClasses, classes); assertEquals(expectedClasses, classes);
} }
@Test @ParameterizedTest
public void testScanningInvalidUberJar() throws Exception { @MethodSource("parameters")
pluginDir.newFile("invalid.jar"); public void testScanningInvalidUberJar(PluginScanner scanner) throws Exception {
File newFile = new File(pluginDir, "invalid.jar");
PluginScanResult result = scan( newFile.createNewFile();
Collections.singleton(pluginDir.getRoot().toPath().toAbsolutePath()) PluginScanResult result = scan(scanner, Collections.singleton(pluginDir.toPath()));
);
assertTrue(result.isEmpty()); assertTrue(result.isEmpty());
} }
@Test @ParameterizedTest
public void testScanningPluginDirContainsInvalidJarsOnly() throws Exception { @MethodSource("parameters")
pluginDir.newFolder("my-plugin"); public void testScanningPluginDirContainsInvalidJarsOnly(PluginScanner scanner) throws Exception {
pluginDir.newFile("my-plugin/invalid.jar"); File newFile = new File(pluginDir, "my-plugin");
newFile.mkdir();
newFile = new File(newFile, "invalid.jar");
newFile.createNewFile();
PluginScanResult result = scan( PluginScanResult result = scan(scanner, Collections.singleton(pluginDir.toPath()));
Collections.singleton(pluginDir.getRoot().toPath().toAbsolutePath())
);
assertTrue(result.isEmpty()); assertTrue(result.isEmpty());
} }
@Test @ParameterizedTest
public void testScanningNoPlugins() { @MethodSource("parameters")
PluginScanResult result = scan( public void testScanningNoPlugins(PluginScanner scanner) {
Collections.singleton(pluginDir.getRoot().toPath().toAbsolutePath()) PluginScanResult result = scan(scanner, Collections.singleton(pluginDir.toPath()));
);
assertTrue(result.isEmpty()); assertTrue(result.isEmpty());
} }
@Test @ParameterizedTest
public void testScanningPluginDirEmpty() throws Exception { @MethodSource("parameters")
pluginDir.newFolder("my-plugin"); public void testScanningPluginDirEmpty(PluginScanner scanner) {
File newFile = new File(pluginDir, "my-plugin");
newFile.mkdir();
PluginScanResult result = scan( PluginScanResult result = scan(scanner, Collections.singleton(pluginDir.toPath()));
Collections.singleton(pluginDir.getRoot().toPath().toAbsolutePath())
);
assertTrue(result.isEmpty()); assertTrue(result.isEmpty());
} }
@Test @ParameterizedTest
public void testScanningMixOfValidAndInvalidPlugins() throws Exception { @MethodSource("parameters")
pluginDir.newFile("invalid.jar"); public void testScanningMixOfValidAndInvalidPlugins(PluginScanner scanner) throws Exception {
pluginDir.newFolder("my-plugin"); new File(pluginDir, "invalid.jar").createNewFile();
pluginDir.newFile("my-plugin/invalid.jar"); File newFile = new File(pluginDir, "my-plugin");
Path pluginPath = this.pluginDir.getRoot().toPath(); newFile.mkdir();
newFile = new File(newFile, "invalid.jar");
newFile.createNewFile();
Path pluginPath = this.pluginDir.toPath();
for (Path source : TestPlugins.pluginPath()) { for (Path source : TestPlugins.pluginPath()) {
Files.copy(source, pluginPath.resolve(source.getFileName())); Files.copy(source, pluginPath.resolve(source.getFileName()));
} }
PluginScanResult result = scan( PluginScanResult result = scan(scanner, Collections.singleton(pluginDir.toPath()));
Collections.singleton(pluginDir.getRoot().toPath().toAbsolutePath())
);
Set<String> classes = new HashSet<>(); Set<String> classes = new HashSet<>();
result.forEach(pluginDesc -> classes.add(pluginDesc.className())); result.forEach(pluginDesc -> classes.add(pluginDesc.className()));
Set<String> expectedClasses = new HashSet<>(TestPlugins.pluginClasses()); Set<String> expectedClasses = new HashSet<>(TestPlugins.pluginClasses());
assertEquals(expectedClasses, classes); assertEquals(expectedClasses, classes);
} }
@Test @ParameterizedTest
public void testNonVersionedPluginHasUndefinedVersion() { @MethodSource("parameters")
PluginScanResult unversionedPluginsResult = scan(TestPlugins.pluginPath(TestPlugins.TestPlugin.SAMPLING_HEADER_CONVERTER)); public void testNonVersionedPluginHasUndefinedVersion(PluginScanner scanner) {
PluginScanResult unversionedPluginsResult = scan(scanner,
TestPlugins.pluginPath(TestPlugins.TestPlugin.SAMPLING_HEADER_CONVERTER));
assertFalse(unversionedPluginsResult.isEmpty()); assertFalse(unversionedPluginsResult.isEmpty());
unversionedPluginsResult.forEach(pluginDesc -> assertEquals(PluginDesc.UNDEFINED_VERSION, pluginDesc.version())); unversionedPluginsResult.forEach(pluginDesc -> assertEquals(PluginDesc.UNDEFINED_VERSION, pluginDesc.version()));
} }
@Test @ParameterizedTest
public void testVersionedPluginsHasVersion() { @MethodSource("parameters")
PluginScanResult versionedPluginResult = scan(TestPlugins.pluginPath(TestPlugins.TestPlugin.READ_VERSION_FROM_RESOURCE_V1)); public void testVersionedPluginsHasVersion(PluginScanner scanner) {
PluginScanResult versionedPluginResult = scan(scanner,
TestPlugins.pluginPath(TestPlugins.TestPlugin.READ_VERSION_FROM_RESOURCE_V1));
assertFalse(versionedPluginResult.isEmpty()); assertFalse(versionedPluginResult.isEmpty());
versionedPluginResult.forEach(pluginDesc -> assertEquals("1.0.0", pluginDesc.version())); versionedPluginResult.forEach(pluginDesc -> assertEquals("1.0.0", pluginDesc.version()));
} }
private PluginScanResult scan(Set<Path> pluginLocations) { private PluginScanResult scan(PluginScanner scanner, Set<Path> pluginLocations) {
ClassLoaderFactory factory = new ClassLoaderFactory(); ClassLoaderFactory factory = new ClassLoaderFactory();
Set<PluginSource> pluginSources = PluginUtils.pluginSources(pluginLocations, PluginScannerTest.class.getClassLoader(), factory); Set<PluginSource> pluginSources = PluginUtils.pluginSources(pluginLocations, PluginScannerTest.class.getClassLoader(), factory);
return scanner.discoverPlugins(pluginSources); return scanner.discoverPlugins(pluginSources);
} }
} }

View File

@ -28,10 +28,9 @@ import org.apache.kafka.connect.storage.HeaderConverter;
import org.apache.kafka.connect.tools.MockSinkConnector; import org.apache.kafka.connect.tools.MockSinkConnector;
import org.apache.kafka.connect.tools.MockSourceConnector; import org.apache.kafka.connect.tools.MockSourceConnector;
import org.apache.kafka.connect.transforms.Transformation; import org.apache.kafka.connect.transforms.Transformation;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.io.TempDir;
import org.junit.rules.TemporaryFolder;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@ -46,18 +45,21 @@ import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
public class PluginUtilsTest { public class PluginUtilsTest {
@Rule @TempDir
public TemporaryFolder rootDir = new TemporaryFolder(); Path rootDir;
private Path pluginPath; private Path pluginPath;
@Before @BeforeEach
public void setUp() throws Exception { public void setUp() throws Exception {
pluginPath = rootDir.newFolder("plugins").toPath().toRealPath(); pluginPath = rootDir.resolve("plugins");
Files.createDirectories(pluginPath);
pluginPath = pluginPath.toRealPath();
} }
@Test @Test
@ -190,10 +192,8 @@ public class PluginUtilsTest {
); );
// Classes in the API should never be loaded in isolation. // Classes in the API should never be loaded in isolation.
for (String clazz : apiClasses) { for (String clazz : apiClasses) {
assertFalse( assertFalse(PluginUtils.shouldLoadInIsolation(clazz),
clazz + " from 'api' is loaded in isolation but should not be", clazz + " from 'api' is loaded in isolation but should not be");
PluginUtils.shouldLoadInIsolation(clazz)
);
} }
} }
@ -221,10 +221,8 @@ public class PluginUtilsTest {
"org.apache.kafka.connect.util." "org.apache.kafka.connect.util."
); );
for (String clazz : runtimeClasses) { for (String clazz : runtimeClasses) {
assertFalse( assertFalse(PluginUtils.shouldLoadInIsolation(clazz),
clazz + " from 'runtime' is loaded in isolation but should not be", clazz + " from 'runtime' is loaded in isolation but should not be");
PluginUtils.shouldLoadInIsolation(clazz)
);
} }
} }
@ -250,10 +248,8 @@ public class PluginUtilsTest {
"org.apache.kafka.connect.storage.SimpleHeaderConverter" "org.apache.kafka.connect.storage.SimpleHeaderConverter"
); );
for (String clazz : jsonConverterClasses) { for (String clazz : jsonConverterClasses) {
assertTrue( assertTrue(PluginUtils.shouldLoadInIsolation(clazz),
clazz + " from 'runtime' is not loaded in isolation but should be", clazz + " from 'runtime' is not loaded in isolation but should be");
PluginUtils.shouldLoadInIsolation(clazz)
);
} }
} }
@ -305,10 +301,8 @@ public class PluginUtilsTest {
"org.apache.kafka.connect.transforms.predicates.TopicNameMatches" "org.apache.kafka.connect.transforms.predicates.TopicNameMatches"
); );
for (String clazz : transformsClasses) { for (String clazz : transformsClasses) {
assertTrue( assertTrue(PluginUtils.shouldLoadInIsolation(clazz),
clazz + " from 'transforms' is not loaded in isolation but should be", clazz + " from 'transforms' is not loaded in isolation but should be");
PluginUtils.shouldLoadInIsolation(clazz)
);
} }
} }
@ -324,10 +318,8 @@ public class PluginUtilsTest {
"org.apache.kafka.connect.json.JsonSerializer" "org.apache.kafka.connect.json.JsonSerializer"
); );
for (String clazz : jsonConverterClasses) { for (String clazz : jsonConverterClasses) {
assertTrue( assertTrue(PluginUtils.shouldLoadInIsolation(clazz),
clazz + " from 'json' is not loaded in isolation but should be", clazz + " from 'json' is not loaded in isolation but should be");
PluginUtils.shouldLoadInIsolation(clazz)
);
} }
} }
@ -341,10 +333,8 @@ public class PluginUtilsTest {
"org.apache.kafka.connect.file.FileStreamSourceTask" "org.apache.kafka.connect.file.FileStreamSourceTask"
); );
for (String clazz : jsonConverterClasses) { for (String clazz : jsonConverterClasses) {
assertTrue( assertTrue(PluginUtils.shouldLoadInIsolation(clazz),
clazz + " from 'file' is not loaded in isolation but should be", clazz + " from 'file' is not loaded in isolation but should be");
PluginUtils.shouldLoadInIsolation(clazz)
);
} }
} }
@ -356,10 +346,8 @@ public class PluginUtilsTest {
//"org.apache.kafka.connect.rest.basic.auth.extension.PropertyFileLoginModule" TODO fix? //"org.apache.kafka.connect.rest.basic.auth.extension.PropertyFileLoginModule" TODO fix?
); );
for (String clazz : basicAuthExtensionClasses) { for (String clazz : basicAuthExtensionClasses) {
assertTrue( assertTrue(PluginUtils.shouldLoadInIsolation(clazz),
clazz + " from 'basic-auth-extension' is not loaded in isolation but should be", clazz + " from 'basic-auth-extension' is not loaded in isolation but should be");
PluginUtils.shouldLoadInIsolation(clazz)
);
} }
} }
@ -457,7 +445,9 @@ public class PluginUtilsTest {
public void testPluginUrlsWithAbsoluteSymlink() throws Exception { public void testPluginUrlsWithAbsoluteSymlink() throws Exception {
createBasicDirectoryLayout(); createBasicDirectoryLayout();
Path anotherPath = rootDir.newFolder("moreplugins").toPath().toRealPath(); Path anotherPath = rootDir.resolve("moreplugins");
Files.createDirectories(anotherPath);
anotherPath = anotherPath.toRealPath();
Files.createDirectories(anotherPath.resolve("connectorB-deps")); Files.createDirectories(anotherPath.resolve("connectorB-deps"));
Files.createSymbolicLink( Files.createSymbolicLink(
pluginPath.resolve("connectorB/deps/symlink"), pluginPath.resolve("connectorB/deps/symlink"),
@ -474,7 +464,9 @@ public class PluginUtilsTest {
public void testPluginUrlsWithRelativeSymlinkBackwards() throws Exception { public void testPluginUrlsWithRelativeSymlinkBackwards() throws Exception {
createBasicDirectoryLayout(); createBasicDirectoryLayout();
Path anotherPath = rootDir.newFolder("moreplugins").toPath().toRealPath(); Path anotherPath = rootDir.resolve("moreplugins");
Files.createDirectories(anotherPath);
anotherPath = anotherPath.toRealPath();
Files.createDirectories(anotherPath.resolve("connectorB-deps")); Files.createDirectories(anotherPath.resolve("connectorB-deps"));
Files.createSymbolicLink( Files.createSymbolicLink(
pluginPath.resolve("connectorB/deps/symlink"), pluginPath.resolve("connectorB/deps/symlink"),

View File

@ -54,8 +54,8 @@ import org.apache.kafka.connect.storage.ConverterConfig;
import org.apache.kafka.connect.storage.ConverterType; import org.apache.kafka.connect.storage.ConverterType;
import org.apache.kafka.connect.storage.HeaderConverter; import org.apache.kafka.connect.storage.HeaderConverter;
import org.apache.kafka.connect.storage.SimpleHeaderConverter; import org.apache.kafka.connect.storage.SimpleHeaderConverter;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -64,13 +64,13 @@ import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertSame; import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertInstanceOf;
public class PluginsTest { public class PluginsTest {
@ -85,7 +85,7 @@ public class PluginsTest {
private PluginScanResult empty; private PluginScanResult empty;
private String missingPluginClass; private String missingPluginClass;
@Before @BeforeEach
public void setup() { public void setup() {
Map<String, String> pluginProps = new HashMap<>(); Map<String, String> pluginProps = new HashMap<>();
@ -183,10 +183,10 @@ public class PluginsTest {
config, config,
ConnectRestExtension.class); ConnectRestExtension.class);
assertNotNull(connectRestExtensions); assertNotNull(connectRestExtensions);
assertEquals("One Rest Extension expected", 1, connectRestExtensions.size()); assertEquals(1, connectRestExtensions.size(), "One Rest Extension expected");
assertNotNull(connectRestExtensions.get(0)); assertNotNull(connectRestExtensions.get(0));
assertTrue("Should be instance of TestConnectRestExtension", assertTrue(connectRestExtensions.get(0) instanceof TestConnectRestExtension,
connectRestExtensions.get(0) instanceof TestConnectRestExtension); "Should be instance of TestConnectRestExtension");
assertNotNull(((TestConnectRestExtension) connectRestExtensions.get(0)).configs); assertNotNull(((TestConnectRestExtension) connectRestExtensions.get(0)).configs);
assertEquals(config.originals(), assertEquals(config.originals(),
((TestConnectRestExtension) connectRestExtensions.get(0)).configs); ((TestConnectRestExtension) connectRestExtensions.get(0)).configs);
@ -482,7 +482,7 @@ public class PluginsTest {
.stream() .stream()
.filter(pluginDesc -> ByteArrayConverter.class.equals(pluginDesc.pluginClass())) .filter(pluginDesc -> ByteArrayConverter.class.equals(pluginDesc.pluginClass()))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
assertFalse("Could not find superclass of " + TestPlugin.SUBCLASS_OF_CLASSPATH_CONVERTER + " as plugin", converters.isEmpty()); assertFalse(converters.isEmpty(), "Could not find superclass of " + TestPlugin.SUBCLASS_OF_CLASSPATH_CONVERTER + " as plugin");
for (PluginDesc<Converter> byteArrayConverter : converters) { for (PluginDesc<Converter> byteArrayConverter : converters) {
assertEquals("classpath", byteArrayConverter.location()); assertEquals("classpath", byteArrayConverter.location());
} }
@ -494,7 +494,7 @@ public class PluginsTest {
.stream() .stream()
.filter(pluginDesc -> AllConnectorClientConfigOverridePolicy.class.equals(pluginDesc.pluginClass())) .filter(pluginDesc -> AllConnectorClientConfigOverridePolicy.class.equals(pluginDesc.pluginClass()))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
assertFalse("Could not find superclass of " + TestPlugin.SUBCLASS_OF_CLASSPATH_OVERRIDE_POLICY + " as plugin", overridePolicies.isEmpty()); assertFalse(overridePolicies.isEmpty(), "Could not find superclass of " + TestPlugin.SUBCLASS_OF_CLASSPATH_OVERRIDE_POLICY + " as plugin");
for (PluginDesc<ConnectorClientConfigOverridePolicy> allOverridePolicy : overridePolicies) { for (PluginDesc<ConnectorClientConfigOverridePolicy> allOverridePolicy : overridePolicies) {
assertEquals("classpath", allOverridePolicy.location()); assertEquals("classpath", allOverridePolicy.location());
} }
@ -620,10 +620,10 @@ public class PluginsTest {
); );
plugins = new Plugins(pluginProps, parent, new ClassLoaderFactory()); plugins = new Plugins(pluginProps, parent, new ClassLoaderFactory());
assertTrue("Should find plugin in plugin classloader", assertTrue(plugins.converters().stream().anyMatch(desc -> desc.loader() instanceof PluginClassLoader),
plugins.converters().stream().anyMatch(desc -> desc.loader() instanceof PluginClassLoader)); "Should find plugin in plugin classloader");
assertTrue("Should find plugin in parent classloader", assertTrue(plugins.converters().stream().anyMatch(desc -> parent.equals(desc.loader())),
plugins.converters().stream().anyMatch(desc -> parent.equals(desc.loader()))); "Should find plugin in parent classloader");
Converter converter = plugins.newPlugin( Converter converter = plugins.newPlugin(
className, className,

View File

@ -17,7 +17,6 @@
package org.apache.kafka.connect.runtime.isolation; package org.apache.kafka.connect.runtime.isolation;
import static org.junit.Assert.fail;
import java.lang.management.LockInfo; import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
@ -45,36 +44,35 @@ import org.apache.kafka.common.config.ConfigDef;
import org.apache.kafka.common.config.ConfigDef.Importance; import org.apache.kafka.common.config.ConfigDef.Importance;
import org.apache.kafka.common.config.ConfigDef.Type; import org.apache.kafka.common.config.ConfigDef.Type;
import org.apache.kafka.connect.runtime.WorkerConfig; import org.apache.kafka.connect.runtime.WorkerConfig;
import org.junit.After; import org.junit.jupiter.api.Test;
import org.junit.Before; import org.junit.jupiter.api.AfterEach;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.TestInfo;
import org.junit.rules.TestName; import org.junit.jupiter.api.Timeout;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static org.junit.jupiter.api.Assertions.fail;
public class SynchronizationTest { public class SynchronizationTest {
public static final Logger log = LoggerFactory.getLogger(SynchronizationTest.class); public static final Logger log = LoggerFactory.getLogger(SynchronizationTest.class);
@Rule
public final TestName testName = new TestName();
private String threadPrefix; private String threadPrefix;
private Plugins plugins; private Plugins plugins;
private ThreadPoolExecutor exec; private ThreadPoolExecutor exec;
private Breakpoint<String> dclBreakpoint; private Breakpoint<String> dclBreakpoint;
private Breakpoint<String> pclBreakpoint; private Breakpoint<String> pclBreakpoint;
@Before @BeforeEach
public void setup() { public void setup(TestInfo testInfo) {
Map<String, String> pluginProps = Collections.singletonMap( Map<String, String> pluginProps = Collections.singletonMap(
WorkerConfig.PLUGIN_PATH_CONFIG, WorkerConfig.PLUGIN_PATH_CONFIG,
TestPlugins.pluginPathJoined() TestPlugins.pluginPathJoined()
); );
threadPrefix = SynchronizationTest.class.getSimpleName() threadPrefix = SynchronizationTest.class.getSimpleName()
+ "." + testName.getMethodName() + "-"; + "." + testInfo.getDisplayName() + "-";
dclBreakpoint = new Breakpoint<>(); dclBreakpoint = new Breakpoint<>();
pclBreakpoint = new Breakpoint<>(); pclBreakpoint = new Breakpoint<>();
plugins = new Plugins(pluginProps, Plugins.class.getClassLoader(), new SynchronizedClassLoaderFactory()); plugins = new Plugins(pluginProps, Plugins.class.getClassLoader(), new SynchronizedClassLoaderFactory());
@ -89,7 +87,7 @@ public class SynchronizationTest {
} }
@After @AfterEach
public void tearDown() throws InterruptedException { public void tearDown() throws InterruptedException {
dclBreakpoint.clear(); dclBreakpoint.clear();
pclBreakpoint.clear(); pclBreakpoint.clear();
@ -113,7 +111,6 @@ public class SynchronizationTest {
public synchronized void set(Predicate<T> predicate) { public synchronized void set(Predicate<T> predicate) {
clear(); clear();
this.predicate = predicate; this.predicate = predicate;
// As soon as the barrier is tripped, the barrier will be reset for the next round.
barrier = new CyclicBarrier(2); barrier = new CyclicBarrier(2);
} }
@ -206,7 +203,6 @@ public class SynchronizationTest {
private final Breakpoint<String> pclBreakpoint; private final Breakpoint<String> pclBreakpoint;
public SynchronizedPluginClassLoader( public SynchronizedPluginClassLoader(
URL pluginLocation, URL[] urls, ClassLoader parent, Breakpoint<String> pclBreakpoint URL pluginLocation, URL[] urls, ClassLoader parent, Breakpoint<String> pclBreakpoint
) { ) {
@ -221,8 +217,9 @@ public class SynchronizationTest {
} }
} }
@Test
@Timeout(15)
// If the test times out, then there's a deadlock in the test but not necessarily the code // If the test times out, then there's a deadlock in the test but not necessarily the code
@Test(timeout = 15000L)
public void testSimultaneousUpwardAndDownwardDelegating() throws Exception { public void testSimultaneousUpwardAndDownwardDelegating() throws Exception {
String t1Class = TestPlugins.TestPlugin.SAMPLING_CONVERTER.className(); String t1Class = TestPlugins.TestPlugin.SAMPLING_CONVERTER.className();
// Grab a reference to the target PluginClassLoader before activating breakpoints // Grab a reference to the target PluginClassLoader before activating breakpoints
@ -300,8 +297,9 @@ public class SynchronizationTest {
} }
// If the test times out, then there's a deadlock in the test but not necessarily the code // If the test times out, then there's a deadlock in the test but not necessarily the code
@Test(timeout = 15000L) @Test
// Ensure the PluginClassLoader is parallel capable and not synchronized on its monitor lock // Ensure the PluginClassLoader is parallel capable and not synchronized on its monitor lock
@Timeout(15)
public void testPluginClassLoaderDoesntHoldMonitorLock() public void testPluginClassLoaderDoesntHoldMonitorLock()
throws InterruptedException, TimeoutException, BrokenBarrierException { throws InterruptedException, TimeoutException, BrokenBarrierException {
String t1Class = TestPlugins.TestPlugin.SAMPLING_CONVERTER.className(); String t1Class = TestPlugins.TestPlugin.SAMPLING_CONVERTER.className();

View File

@ -35,13 +35,14 @@ import org.apache.kafka.connect.rest.ConnectRestExtension;
import org.apache.kafka.connect.runtime.Herder; import org.apache.kafka.connect.runtime.Herder;
import org.apache.kafka.connect.runtime.isolation.Plugins; import org.apache.kafka.connect.runtime.isolation.Plugins;
import org.apache.kafka.connect.runtime.rest.entities.LoggerLevel; import org.apache.kafka.connect.runtime.rest.entities.LoggerLevel;
import org.junit.After; import org.junit.jupiter.api.Test;
import org.junit.Assert; import org.junit.jupiter.api.AfterEach;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
@ -56,15 +57,17 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.Assert.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class ConnectRestServerTest { public class ConnectRestServerTest {
@Mock private RestClient restClient; @Mock private RestClient restClient;
@ -76,12 +79,12 @@ public class ConnectRestServerTest {
protected static final String KAFKA_CLUSTER_ID = "Xbafgnagvar"; protected static final String KAFKA_CLUSTER_ID = "Xbafgnagvar";
@Before @BeforeEach
public void setUp() { public void setUp() {
httpClient = HttpClients.createMinimal(); httpClient = HttpClients.createMinimal();
} }
@After @AfterEach
public void tearDown() throws IOException { public void tearDown() throws IOException {
for (CloseableHttpResponse response: responses) { for (CloseableHttpResponse response: responses) {
response.close(); response.close();
@ -117,7 +120,7 @@ public class ConnectRestServerTest {
configMap.put(RestServerConfig.LISTENERS_CONFIG, "http://localhost:8080,https://localhost:8443"); configMap.put(RestServerConfig.LISTENERS_CONFIG, "http://localhost:8080,https://localhost:8443");
server = new ConnectRestServer(null, restClient, configMap); server = new ConnectRestServer(null, restClient, configMap);
Assert.assertEquals("http://localhost:8080/", server.advertisedUrl().toString()); assertEquals("http://localhost:8080/", server.advertisedUrl().toString());
server.stop(); server.stop();
// Advertised URI from listeners with protocol // Advertised URI from listeners with protocol
@ -126,7 +129,7 @@ public class ConnectRestServerTest {
configMap.put(RestServerConfig.REST_ADVERTISED_LISTENER_CONFIG, "https"); configMap.put(RestServerConfig.REST_ADVERTISED_LISTENER_CONFIG, "https");
server = new ConnectRestServer(null, restClient, configMap); server = new ConnectRestServer(null, restClient, configMap);
Assert.assertEquals("https://localhost:8443/", server.advertisedUrl().toString()); assertEquals("https://localhost:8443/", server.advertisedUrl().toString());
server.stop(); server.stop();
// Advertised URI from listeners with only SSL available // Advertised URI from listeners with only SSL available
@ -134,7 +137,7 @@ public class ConnectRestServerTest {
configMap.put(RestServerConfig.LISTENERS_CONFIG, "https://localhost:8443"); configMap.put(RestServerConfig.LISTENERS_CONFIG, "https://localhost:8443");
server = new ConnectRestServer(null, restClient, configMap); server = new ConnectRestServer(null, restClient, configMap);
Assert.assertEquals("https://localhost:8443/", server.advertisedUrl().toString()); assertEquals("https://localhost:8443/", server.advertisedUrl().toString());
server.stop(); server.stop();
// Listener is overridden by advertised values // Listener is overridden by advertised values
@ -145,7 +148,7 @@ public class ConnectRestServerTest {
configMap.put(RestServerConfig.REST_ADVERTISED_PORT_CONFIG, "10000"); configMap.put(RestServerConfig.REST_ADVERTISED_PORT_CONFIG, "10000");
server = new ConnectRestServer(null, restClient, configMap); server = new ConnectRestServer(null, restClient, configMap);
Assert.assertEquals("http://somehost:10000/", server.advertisedUrl().toString()); assertEquals("http://somehost:10000/", server.advertisedUrl().toString());
server.stop(); server.stop();
// correct listener is chosen when https listener is configured before http listener and advertised listener is http // correct listener is chosen when https listener is configured before http listener and advertised listener is http
@ -154,7 +157,7 @@ public class ConnectRestServerTest {
configMap.put(RestServerConfig.REST_ADVERTISED_LISTENER_CONFIG, "http"); configMap.put(RestServerConfig.REST_ADVERTISED_LISTENER_CONFIG, "http");
server = new ConnectRestServer(null, restClient, configMap); server = new ConnectRestServer(null, restClient, configMap);
Assert.assertEquals("http://plaintext-localhost:4761/", server.advertisedUrl().toString()); assertEquals("http://plaintext-localhost:4761/", server.advertisedUrl().toString());
server.stop(); server.stop();
} }
@ -173,10 +176,10 @@ public class ConnectRestServerTest {
HttpOptions request = new HttpOptions("/connectors"); HttpOptions request = new HttpOptions("/connectors");
request.addHeader("Content-Type", MediaType.WILDCARD); request.addHeader("Content-Type", MediaType.WILDCARD);
HttpResponse response = executeRequest(server.advertisedUrl(), request); HttpResponse response = executeRequest(server.advertisedUrl(), request);
Assert.assertEquals(MediaType.TEXT_PLAIN, response.getEntity().getContentType().getValue()); assertEquals(MediaType.TEXT_PLAIN, response.getEntity().getContentType().getValue());
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
response.getEntity().writeTo(baos); response.getEntity().writeTo(baos);
Assert.assertArrayEquals( assertArrayEquals(
request.getAllowedMethods(response).toArray(), request.getAllowedMethods(response).toArray(),
new String(baos.toByteArray(), StandardCharsets.UTF_8).split(", ") new String(baos.toByteArray(), StandardCharsets.UTF_8).split(", ")
); );
@ -203,10 +206,10 @@ public class ConnectRestServerTest {
request.addHeader("Origin", origin); request.addHeader("Origin", origin);
HttpResponse response = executeRequest(serverUrl, request); HttpResponse response = executeRequest(serverUrl, request);
Assert.assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
if (expectedHeader != null) { if (expectedHeader != null) {
Assert.assertEquals(expectedHeader, assertEquals(expectedHeader,
response.getFirstHeader("Access-Control-Allow-Origin").getValue()); response.getFirstHeader("Access-Control-Allow-Origin").getValue());
} }
@ -215,13 +218,13 @@ public class ConnectRestServerTest {
request.addHeader("Origin", origin); request.addHeader("Origin", origin);
request.addHeader("Access-Control-Request-Method", method); request.addHeader("Access-Control-Request-Method", method);
response = executeRequest(serverUrl, request); response = executeRequest(serverUrl, request);
Assert.assertEquals(404, response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode());
if (expectedHeader != null) { if (expectedHeader != null) {
Assert.assertEquals(expectedHeader, assertEquals(expectedHeader,
response.getFirstHeader("Access-Control-Allow-Origin").getValue()); response.getFirstHeader("Access-Control-Allow-Origin").getValue());
} }
if (method != null) { if (method != null) {
Assert.assertEquals(method, assertEquals(method,
response.getFirstHeader("Access-Control-Allow-Methods").getValue()); response.getFirstHeader("Access-Control-Allow-Methods").getValue());
} }
} }
@ -242,7 +245,7 @@ public class ConnectRestServerTest {
HttpRequest request = new HttpGet("/connectors"); HttpRequest request = new HttpGet("/connectors");
HttpResponse response = executeRequest(server.advertisedUrl(), request); HttpResponse response = executeRequest(server.advertisedUrl(), request);
Assert.assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
} }
@Test @Test
@ -304,7 +307,7 @@ public class ConnectRestServerTest {
HttpRequest request = new HttpGet("/admin/loggers"); HttpRequest request = new HttpGet("/admin/loggers");
HttpResponse response = executeRequest(server.advertisedUrl(), request); HttpResponse response = executeRequest(server.advertisedUrl(), request);
Assert.assertEquals(404, response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode());
} }
@Test @Test
@ -324,7 +327,7 @@ public class ConnectRestServerTest {
HttpRequest request = new HttpGet("/admin/loggers"); HttpRequest request = new HttpGet("/admin/loggers");
HttpResponse response = executeRequest(server.advertisedUrl(), request); HttpResponse response = executeRequest(server.advertisedUrl(), request);
Assert.assertEquals(404, response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode());
} }
@Test @Test
@ -386,12 +389,12 @@ public class ConnectRestServerTest {
server.initializeResources(herder); server.initializeResources(herder);
HttpRequest request = new HttpGet("/connectors"); HttpRequest request = new HttpGet("/connectors");
HttpResponse response = executeRequest(server.advertisedUrl(), request); HttpResponse response = executeRequest(server.advertisedUrl(), request);
Assert.assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
if (!headerConfig.isEmpty()) { if (!headerConfig.isEmpty()) {
expectedHeaders.forEach((k, v) -> expectedHeaders.forEach((k, v) ->
Assert.assertEquals(response.getFirstHeader(k).getValue(), v)); assertEquals(response.getFirstHeader(k).getValue(), v));
} else { } else {
Assert.assertNull(response.getFirstHeader("X-Frame-Options")); assertNull(response.getFirstHeader("X-Frame-Options"));
} }
} }
@ -399,7 +402,7 @@ public class ConnectRestServerTest {
HttpRequest request = new HttpGet(endpoint); HttpRequest request = new HttpGet(endpoint);
HttpResponse response = executeRequest(serverUrl, request); HttpResponse response = executeRequest(serverUrl, request);
Assert.assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
return new BasicResponseHandler().handleResponse(response); return new BasicResponseHandler().handleResponse(response);
} }
@ -410,7 +413,7 @@ public class ConnectRestServerTest {
request.setEntity(entity); request.setEntity(entity);
HttpResponse response = executeRequest(serverUrl, request); HttpResponse response = executeRequest(serverUrl, request);
Assert.assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
return new BasicResponseHandler().handleResponse(response); return new BasicResponseHandler().handleResponse(response);
} }

View File

@ -21,10 +21,12 @@ import org.apache.kafka.connect.errors.ConnectException;
import org.apache.kafka.connect.runtime.distributed.Crypto; import org.apache.kafka.connect.runtime.distributed.Crypto;
import org.apache.kafka.connect.runtime.rest.errors.BadRequestException; import org.apache.kafka.connect.runtime.rest.errors.BadRequestException;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Request;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import javax.crypto.Mac; import javax.crypto.Mac;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
@ -34,18 +36,19 @@ import javax.ws.rs.core.HttpHeaders;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Base64; import java.util.Base64;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class InternalRequestSignatureTest { public class InternalRequestSignatureTest {
private static final byte[] REQUEST_BODY = private static final byte[] REQUEST_BODY =
@ -123,16 +126,12 @@ public class InternalRequestSignatureTest {
InternalRequestSignature.addToRequest(crypto, KEY, REQUEST_BODY, SIGNATURE_ALGORITHM, request); InternalRequestSignature.addToRequest(crypto, KEY, REQUEST_BODY, SIGNATURE_ALGORITHM, request);
assertEquals( assertEquals(ENCODED_SIGNATURE,
"Request should have valid base 64-encoded signature added as header", signatureCapture.getValue(),
ENCODED_SIGNATURE, "Request should have valid base 64-encoded signature added as header");
signatureCapture.getValue() assertEquals(SIGNATURE_ALGORITHM,
); signatureAlgorithmCapture.getValue(),
assertEquals( "Request should have provided signature algorithm added as header");
"Request should have provided signature algorithm added as header",
SIGNATURE_ALGORITHM,
signatureAlgorithmCapture.getValue()
);
} }
@Test @Test

View File

@ -19,7 +19,6 @@ package org.apache.kafka.connect.runtime.rest;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.kafka.connect.runtime.rest.entities.ErrorMessage; import org.apache.kafka.connect.runtime.rest.entities.ErrorMessage;
@ -27,25 +26,23 @@ import org.apache.kafka.connect.runtime.rest.errors.ConnectRestException;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Request;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.experimental.runners.Enclosed; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.runner.RunWith; import org.junit.jupiter.params.provider.Arguments;
import org.junit.runners.Parameterized; import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.junit.MockitoRule;
import org.mockito.quality.Strictness; import org.mockito.quality.Strictness;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -61,18 +58,21 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(Enclosed.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class RestClientTest { public class RestClientTest {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final String MOCK_URL = "http://localhost:1234/api/endpoint"; private static final String MOCK_URL = "http://localhost:1234/api/endpoint";
private static final String TEST_METHOD = "GET"; private static final String TEST_METHOD = "GET";
private static final TestDTO TEST_DTO = new TestDTO("requestBodyData"); private static final TestDTO TEST_DTO = new TestDTO("requestBodyData");
private static final TypeReference<TestDTO> TEST_TYPE = new TypeReference<TestDTO>() { private static final TypeReference<TestDTO> TEST_TYPE = new TypeReference<TestDTO>() { };
};
private static final SecretKey MOCK_SECRET_KEY = getMockSecretKey(); private static final SecretKey MOCK_SECRET_KEY = getMockSecretKey();
private static final String TEST_SIGNATURE_ALGORITHM = "HmacSHA1"; private static final String TEST_SIGNATURE_ALGORITHM = "HmacSHA1";
@Mock
private HttpClient httpClient;
private static void assertIsInternalServerError(ConnectRestException e) { private static void assertIsInternalServerError(ConnectRestException e) {
assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e.statusCode()); assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e.statusCode());
assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e.errorCode()); assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e.errorCode());
@ -80,7 +80,7 @@ public class RestClientTest {
private static SecretKey getMockSecretKey() { private static SecretKey getMockSecretKey() {
SecretKey mockKey = mock(SecretKey.class); SecretKey mockKey = mock(SecretKey.class);
when(mockKey.getFormat()).thenReturn("RAW"); // supported format by when(mockKey.getFormat()).thenReturn("RAW");
when(mockKey.getEncoded()).thenReturn("SomeKey".getBytes(StandardCharsets.UTF_8)); when(mockKey.getEncoded()).thenReturn("SomeKey".getBytes(StandardCharsets.UTF_8));
return mockKey; return mockKey;
} }
@ -105,26 +105,12 @@ public class RestClientTest {
); );
} }
private static Stream<Arguments> requestExceptions() {
@RunWith(Parameterized.class) return Stream.of(
public static class RequestFailureParameterizedTest { Arguments.of(new InterruptedException()),
Arguments.of(new ExecutionException(null)),
@Rule Arguments.of(new TimeoutException())
public MockitoRule initRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); );
@Mock
private HttpClient httpClient;
@Parameterized.Parameter
public Throwable requestException;
@Parameterized.Parameters
public static Collection<Object[]> requestExceptions() {
return Arrays.asList(new Object[][]{
{new InterruptedException()},
{new ExecutionException(null)},
{new TimeoutException()}
});
} }
private static Request buildThrowingMockRequest(Throwable t) throws ExecutionException, InterruptedException, TimeoutException { private static Request buildThrowingMockRequest(Throwable t) throws ExecutionException, InterruptedException, TimeoutException {
@ -134,8 +120,9 @@ public class RestClientTest {
return req; return req;
} }
@Test @ParameterizedTest
public void testFailureDuringRequestCausesInternalServerError() throws Exception { @MethodSource("requestExceptions")
public void testFailureDuringRequestCausesInternalServerError(Throwable requestException) throws Exception {
Request request = buildThrowingMockRequest(requestException); Request request = buildThrowingMockRequest(requestException);
when(httpClient.newRequest(anyString())).thenReturn(request); when(httpClient.newRequest(anyString())).thenReturn(request);
ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest( ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest(
@ -144,66 +131,58 @@ public class RestClientTest {
assertIsInternalServerError(e); assertIsInternalServerError(e);
assertEquals(requestException, e.getCause()); assertEquals(requestException, e.getCause());
} }
}
@Test
@RunWith(MockitoJUnitRunner.StrictStubs.class) public void testNullUrl() {
public static class Tests { RestClient client = spy(new RestClient(null));
@Mock assertThrows(NullPointerException.class, () -> {
private HttpClient httpClient; client.httpRequest(
null,
private static String toJsonString(Object obj) { TEST_METHOD,
try { null,
return OBJECT_MAPPER.writeValueAsString(obj); TEST_DTO,
} catch (JsonProcessingException e) { TEST_TYPE,
throw new RuntimeException(e); MOCK_SECRET_KEY,
} TEST_SIGNATURE_ALGORITHM
} );
});
private void setupHttpClient(int responseCode, String responseJsonString) throws Exception {
Request req = mock(Request.class);
ContentResponse resp = mock(ContentResponse.class);
when(resp.getStatus()).thenReturn(responseCode);
when(resp.getContentAsString()).thenReturn(responseJsonString);
when(req.send()).thenReturn(resp);
when(req.header(anyString(), anyString())).thenReturn(req);
when(httpClient.newRequest(anyString())).thenReturn(req);
} }
@Test @Test
public void testNullUrl() throws Exception { public void testNullMethod() {
int statusCode = Response.Status.OK.getStatusCode(); RestClient client = spy(new RestClient(null));
setupHttpClient(statusCode, toJsonString(TEST_DTO)); assertThrows(NullPointerException.class, () -> client.httpRequest(
MOCK_URL,
assertThrows(NullPointerException.class, () -> httpRequest( null,
httpClient, null, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM null,
TEST_DTO,
TEST_TYPE,
MOCK_SECRET_KEY,
TEST_SIGNATURE_ALGORITHM
)); ));
} }
@Test @Test
public void testNullMethod() throws Exception { public void testNullResponseType() {
int statusCode = Response.Status.OK.getStatusCode(); RestClient client = spy(new RestClient(null));
setupHttpClient(statusCode, toJsonString(TEST_DTO)); assertThrows(NullPointerException.class, () -> client.httpRequest(
MOCK_URL,
assertThrows(NullPointerException.class, () -> httpRequest( TEST_METHOD,
httpClient, MOCK_URL, null, TEST_TYPE, TEST_SIGNATURE_ALGORITHM null,
)); TEST_DTO,
} null,
MOCK_SECRET_KEY,
@Test TEST_SIGNATURE_ALGORITHM
public void testNullResponseType() throws Exception {
int statusCode = Response.Status.OK.getStatusCode();
setupHttpClient(statusCode, toJsonString(TEST_DTO));
assertThrows(NullPointerException.class, () -> httpRequest(
httpClient, MOCK_URL, TEST_METHOD, null, TEST_SIGNATURE_ALGORITHM
)); ));
} }
@Test @Test
public void testSuccess() throws Exception { public void testSuccess() throws Exception {
int statusCode = Response.Status.OK.getStatusCode(); int statusCode = Response.Status.OK.getStatusCode();
setupHttpClient(statusCode, toJsonString(TEST_DTO)); Request req = mock(Request.class);
ContentResponse resp = mock(ContentResponse.class);
when(resp.getContentAsString()).thenReturn(toJsonString(TEST_DTO));
setupHttpClient(statusCode, req, resp);
RestClient.HttpResponse<TestDTO> httpResp = httpRequest( RestClient.HttpResponse<TestDTO> httpResp = httpRequest(
httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM
@ -215,7 +194,9 @@ public class RestClientTest {
@Test @Test
public void testNoContent() throws Exception { public void testNoContent() throws Exception {
int statusCode = Response.Status.NO_CONTENT.getStatusCode(); int statusCode = Response.Status.NO_CONTENT.getStatusCode();
setupHttpClient(statusCode, null); Request req = mock(Request.class);
ContentResponse resp = mock(ContentResponse.class);
setupHttpClient(statusCode, req, resp);
RestClient.HttpResponse<TestDTO> httpResp = httpRequest( RestClient.HttpResponse<TestDTO> httpResp = httpRequest(
httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM
@ -228,7 +209,10 @@ public class RestClientTest {
public void testStatusCodeAndErrorMessagePreserved() throws Exception { public void testStatusCodeAndErrorMessagePreserved() throws Exception {
int statusCode = Response.Status.CONFLICT.getStatusCode(); int statusCode = Response.Status.CONFLICT.getStatusCode();
ErrorMessage errorMsg = new ErrorMessage(Response.Status.GONE.getStatusCode(), "Some Error Message"); ErrorMessage errorMsg = new ErrorMessage(Response.Status.GONE.getStatusCode(), "Some Error Message");
setupHttpClient(statusCode, toJsonString(errorMsg)); Request req = mock(Request.class);
ContentResponse resp = mock(ContentResponse.class);
when(resp.getContentAsString()).thenReturn(toJsonString(errorMsg));
setupHttpClient(statusCode, req, resp);
ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest( ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest(
httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM
@ -241,7 +225,10 @@ public class RestClientTest {
@Test @Test
public void testNonEmptyResponseWithVoidResponseType() throws Exception { public void testNonEmptyResponseWithVoidResponseType() throws Exception {
int statusCode = Response.Status.OK.getStatusCode(); int statusCode = Response.Status.OK.getStatusCode();
setupHttpClient(statusCode, toJsonString(TEST_DTO)); Request req = mock(Request.class);
ContentResponse resp = mock(ContentResponse.class);
when(resp.getContentAsString()).thenReturn(toJsonString(TEST_DTO));
setupHttpClient(statusCode, req, resp);
TypeReference<Void> voidResponse = new TypeReference<Void>() { }; TypeReference<Void> voidResponse = new TypeReference<Void>() { };
RestClient.HttpResponse<Void> httpResp = httpRequest( RestClient.HttpResponse<Void> httpResp = httpRequest(
@ -253,10 +240,11 @@ public class RestClientTest {
@Test @Test
public void testUnexpectedHttpResponseCausesInternalServerError() throws Exception { public void testUnexpectedHttpResponseCausesInternalServerError() throws Exception {
int statusCode = Response.Status.NOT_MODIFIED.getStatusCode(); // never thrown explicitly - int statusCode = Response.Status.NOT_MODIFIED.getStatusCode();
// should be treated as an unexpected error and translated into 500 INTERNAL_SERVER_ERROR Request req = mock(Request.class);
ContentResponse resp = mock(ContentResponse.class);
setupHttpClient(statusCode, null); setupHttpClient(statusCode, req, resp);
ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest( ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest(
httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM
)); ));
@ -274,9 +262,7 @@ public class RestClientTest {
} }
@Test @Test
public void testRequestSignatureFailureCausesInternalServerError() throws Exception { public void testRequestSignatureFailureCausesInternalServerError() {
setupHttpClient(0, null);
String invalidRequestSignatureAlgorithm = "Foo"; String invalidRequestSignatureAlgorithm = "Foo";
ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest( ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest(
httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, invalidRequestSignatureAlgorithm httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, invalidRequestSignatureAlgorithm
@ -286,8 +272,9 @@ public class RestClientTest {
@Test @Test
public void testIOExceptionCausesInternalServerError() throws Exception { public void testIOExceptionCausesInternalServerError() throws Exception {
String invalidJsonString = "Invalid"; Request req = mock(Request.class);
setupHttpClient(201, invalidJsonString); ContentResponse resp = mock(ContentResponse.class);
setupHttpClient(201, req, resp);
ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest( ConnectRestException e = assertThrows(ConnectRestException.class, () -> httpRequest(
httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM
@ -297,17 +284,24 @@ public class RestClientTest {
@Test @Test
public void testUseSslConfigsOnlyWhenNecessary() throws Exception { public void testUseSslConfigsOnlyWhenNecessary() throws Exception {
// See KAFKA-14816; we want to make sure that even if the worker is configured with invalid SSL properties,
// REST requests only fail if we try to contact a URL using HTTPS (but not HTTP)
int statusCode = Response.Status.OK.getStatusCode(); int statusCode = Response.Status.OK.getStatusCode();
setupHttpClient(statusCode, toJsonString(TEST_DTO)); Request req = mock(Request.class);
ContentResponse resp = mock(ContentResponse.class);
when(resp.getContentAsString()).thenReturn(toJsonString(TEST_DTO));
setupHttpClient(statusCode, req, resp);
assertDoesNotThrow(() -> httpRequest( assertDoesNotThrow(() -> httpRequest(
httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM httpClient, MOCK_URL, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM
)); ));
String httpsUrl = "https://localhost:1234/api/endpoint"; String httpsUrl = "https://localhost:1234/api/endpoint";
assertThrows(RuntimeException.class, () -> httpRequest( RestClient client = spy(new RestClient(null));
httpClient, httpsUrl, TEST_METHOD, TEST_TYPE, TEST_SIGNATURE_ALGORITHM assertThrows(RuntimeException.class, () -> client.httpRequest(
httpsUrl,
TEST_METHOD,
null,
TEST_DTO,
TEST_TYPE,
MOCK_SECRET_KEY,
TEST_SIGNATURE_ALGORITHM
)); ));
} }
@ -324,8 +318,17 @@ public class RestClientTest {
assertInstanceOf(InterruptedException.class, e.getCause()); assertInstanceOf(InterruptedException.class, e.getCause());
assertTrue(Thread.interrupted()); assertTrue(Thread.interrupted());
} }
private void setupHttpClient(int responseCode, Request req, ContentResponse resp) throws Exception {
when(resp.getStatus()).thenReturn(responseCode);
when(req.send()).thenReturn(resp);
when(req.header(anyString(), anyString())).thenReturn(req);
when(httpClient.newRequest(anyString())).thenReturn(req);
} }
private String toJsonString(Object obj) {
return assertDoesNotThrow(() -> OBJECT_MAPPER.writeValueAsString(obj));
}
private static class TestDTO { private static class TestDTO {
private final String content; private final String content;

View File

@ -18,7 +18,7 @@ package org.apache.kafka.connect.runtime.rest;
import org.apache.kafka.common.config.ConfigException; import org.apache.kafka.common.config.ConfigException;
import org.apache.kafka.common.config.internals.BrokerSecurityConfigs; import org.apache.kafka.common.config.internals.BrokerSecurityConfigs;
import org.junit.Test; import org.junit.jupiter.api.Test;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -27,10 +27,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import static org.apache.kafka.connect.runtime.rest.RestServerConfig.LISTENERS_DEFAULT; import static org.apache.kafka.connect.runtime.rest.RestServerConfig.LISTENERS_DEFAULT;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
public class RestServerConfigTest { public class RestServerConfigTest {
@ -106,7 +106,7 @@ public class RestServerConfigTest {
// no value set for "admin.listeners" // no value set for "admin.listeners"
RestServerConfig config = RestServerConfig.forPublic(null, props); RestServerConfig config = RestServerConfig.forPublic(null, props);
assertNull("Default value should be null.", config.adminListeners()); assertNull(config.adminListeners(), "Default value should be null.");
props.put(RestServerConfig.ADMIN_LISTENERS_CONFIG, ""); props.put(RestServerConfig.ADMIN_LISTENERS_CONFIG, "");
config = RestServerConfig.forPublic(null, props); config = RestServerConfig.forPublic(null, props);

View File

@ -16,13 +16,13 @@
*/ */
package org.apache.kafka.connect.runtime.rest.entities; package org.apache.kafka.connect.runtime.rest.entities;
import org.junit.Test; import org.junit.jupiter.api.Test;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class ConnectorOffsetsTest { public class ConnectorOffsetsTest {

View File

@ -16,11 +16,11 @@
*/ */
package org.apache.kafka.connect.runtime.rest.entities; package org.apache.kafka.connect.runtime.rest.entities;
import org.junit.Test; import org.junit.jupiter.api.Test;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
public class ConnectorTypeTest { public class ConnectorTypeTest {

View File

@ -17,12 +17,12 @@
package org.apache.kafka.connect.runtime.rest.entities; package org.apache.kafka.connect.runtime.rest.entities;
import org.apache.kafka.connect.runtime.TargetState; import org.apache.kafka.connect.runtime.TargetState;
import org.junit.Test; import org.junit.jupiter.api.Test;
import java.util.Collections; import java.util.Collections;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
public class CreateConnectorRequestTest { public class CreateConnectorRequestTest {

View File

@ -17,7 +17,7 @@
package org.apache.kafka.connect.runtime.rest.entities; package org.apache.kafka.connect.runtime.rest.entities;
import org.apache.kafka.connect.runtime.isolation.PluginDesc; import org.apache.kafka.connect.runtime.isolation.PluginDesc;
import org.junit.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;

View File

@ -59,11 +59,13 @@ import org.apache.kafka.connect.transforms.TimestampConverter;
import org.apache.kafka.connect.transforms.predicates.HasHeaderKey; import org.apache.kafka.connect.transforms.predicates.HasHeaderKey;
import org.apache.kafka.connect.transforms.predicates.RecordIsTombstone; import org.apache.kafka.connect.transforms.predicates.RecordIsTombstone;
import org.apache.kafka.connect.util.Callback; import org.apache.kafka.connect.util.Callback;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
import java.net.URL; import java.net.URL;
@ -83,10 +85,10 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
@ -97,7 +99,8 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class ConnectorPluginsResourceTest { public class ConnectorPluginsResourceTest {
private static final Map<String, String> PROPS; private static final Map<String, String> PROPS;
@ -201,7 +204,7 @@ public class ConnectorPluginsResourceTest {
private final Plugins plugins = mock(Plugins.class); private final Plugins plugins = mock(Plugins.class);
private ConnectorPluginsResource connectorPluginsResource; private ConnectorPluginsResource connectorPluginsResource;
@Before @BeforeEach
public void setUp() throws Exception { public void setUp() throws Exception {
doReturn(plugins).when(herder).plugins(); doReturn(plugins).when(herder).plugins();
doReturn(SINK_CONNECTOR_PLUGINS).when(plugins).sinkConnectors(); doReturn(SINK_CONNECTOR_PLUGINS).when(plugins).sinkConnectors();

View File

@ -42,14 +42,15 @@ import org.apache.kafka.connect.runtime.rest.entities.TaskInfo;
import org.apache.kafka.connect.runtime.rest.errors.ConnectRestException; import org.apache.kafka.connect.runtime.rest.errors.ConnectRestException;
import org.apache.kafka.connect.util.Callback; import org.apache.kafka.connect.util.Callback;
import org.apache.kafka.connect.util.ConnectorTaskId; import org.apache.kafka.connect.util.ConnectorTaskId;
import org.junit.After; import org.junit.jupiter.api.Test;
import org.junit.Assert; import org.junit.jupiter.api.AfterEach;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Stubber; import org.mockito.stubbing.Stubber;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
@ -69,9 +70,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
@ -83,7 +84,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ConnectorsResourceTest { public class ConnectorsResourceTest {
// Note trailing / and that we do *not* use LEADER_URL to construct our reference values. This checks that we handle // Note trailing / and that we do *not* use LEADER_URL to construct our reference values. This checks that we handle
@ -166,18 +168,15 @@ public class ConnectorsResourceTest {
@Mock @Mock
private RestServerConfig serverConfig; private RestServerConfig serverConfig;
@Before @BeforeEach
public void setUp() throws NoSuchMethodException { public void setUp() throws NoSuchMethodException {
when(serverConfig.topicTrackingEnabled()).thenReturn(true); when(serverConfig.topicTrackingEnabled()).thenReturn(true);
when(serverConfig.topicTrackingResetEnabled()).thenReturn(true); when(serverConfig.topicTrackingResetEnabled()).thenReturn(true);
connectorsResource = new ConnectorsResource(herder, serverConfig, restClient, REQUEST_TIMEOUT); connectorsResource = new ConnectorsResource(herder, serverConfig, restClient, REQUEST_TIMEOUT);
forward = mock(UriInfo.class); forward = mock(UriInfo.class);
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<>();
queryParams.putSingle("forward", "true");
when(forward.getQueryParameters()).thenReturn(queryParams);
} }
@After @AfterEach
public void teardown() { public void teardown() {
verifyNoMoreInteractions(herder); verifyNoMoreInteractions(herder);
} }
@ -188,6 +187,9 @@ public class ConnectorsResourceTest {
@Test @Test
public void testListConnectors() { public void testListConnectors() {
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<>();
queryParams.putSingle("forward", "true");
when(forward.getQueryParameters()).thenReturn(queryParams);
when(herder.connectors()).thenReturn(Arrays.asList(CONNECTOR2_NAME, CONNECTOR_NAME)); when(herder.connectors()).thenReturn(Arrays.asList(CONNECTOR2_NAME, CONNECTOR_NAME));
Collection<String> connectors = (Collection<String>) connectorsResource.listConnectors(forward, NULL_HEADERS).getEntity(); Collection<String> connectors = (Collection<String>) connectorsResource.listConnectors(forward, NULL_HEADERS).getEntity();
@ -539,7 +541,7 @@ public class ConnectorsResourceTest {
String rspLocation = connectorsResource.createConnector(FORWARD, NULL_HEADERS, body).getLocation().toString(); String rspLocation = connectorsResource.createConnector(FORWARD, NULL_HEADERS, body).getLocation().toString();
String decoded = new URI(rspLocation).getPath(); String decoded = new URI(rspLocation).getPath();
Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded);
} }
@Test @Test
@ -554,7 +556,7 @@ public class ConnectorsResourceTest {
String rspLocation = connectorsResource.createConnector(FORWARD, NULL_HEADERS, body).getLocation().toString(); String rspLocation = connectorsResource.createConnector(FORWARD, NULL_HEADERS, body).getLocation().toString();
String decoded = new URI(rspLocation).getPath(); String decoded = new URI(rspLocation).getPath();
Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded);
} }
@Test @Test
@ -567,7 +569,7 @@ public class ConnectorsResourceTest {
String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, NULL_HEADERS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, NULL_HEADERS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString();
String decoded = new URI(rspLocation).getPath(); String decoded = new URI(rspLocation).getPath();
Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded);
} }
@Test @Test
@ -580,7 +582,7 @@ public class ConnectorsResourceTest {
String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, NULL_HEADERS, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, NULL_HEADERS, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString();
String decoded = new URI(rspLocation).getPath(); String decoded = new URI(rspLocation).getPath();
Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded);
} }
@Test @Test

View File

@ -23,12 +23,14 @@ import org.apache.kafka.connect.runtime.rest.InternalRequestSignature;
import org.apache.kafka.connect.runtime.rest.RestClient; import org.apache.kafka.connect.runtime.rest.RestClient;
import org.apache.kafka.connect.runtime.rest.RestServer; import org.apache.kafka.connect.runtime.rest.RestServer;
import org.apache.kafka.connect.util.Callback; import org.apache.kafka.connect.util.Callback;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Stubber; import org.mockito.stubbing.Stubber;
import javax.crypto.Mac; import javax.crypto.Mac;
@ -41,8 +43,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq; import static org.mockito.Mockito.eq;
@ -50,7 +52,8 @@ import static org.mockito.Mockito.isNull;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class InternalConnectResourceTest { public class InternalConnectResourceTest {
private static final Boolean FORWARD = true; private static final Boolean FORWARD = true;
@ -73,7 +76,7 @@ public class InternalConnectResourceTest {
private InternalConnectResource internalResource; private InternalConnectResource internalResource;
@Before @BeforeEach
public void setup() { public void setup() {
internalResource = new InternalConnectResource(herder, restClient, () -> RestServer.DEFAULT_REST_REQUEST_TIMEOUT_MS); internalResource = new InternalConnectResource(herder, restClient, () -> RestServer.DEFAULT_REST_REQUEST_TIMEOUT_MS);
internalResource.uriInfo = uriInfo; internalResource.uriInfo = uriInfo;

View File

@ -21,11 +21,13 @@ import org.apache.kafka.connect.errors.NotFoundException;
import org.apache.kafka.connect.runtime.Herder; import org.apache.kafka.connect.runtime.Herder;
import org.apache.kafka.connect.runtime.rest.entities.LoggerLevel; import org.apache.kafka.connect.runtime.rest.entities.LoggerLevel;
import org.apache.kafka.connect.runtime.rest.errors.BadRequestException; import org.apache.kafka.connect.runtime.rest.errors.BadRequestException;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.slf4j.event.Level; import org.slf4j.event.Level;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@ -33,13 +35,14 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class LoggingResourceTest { public class LoggingResourceTest {
private LoggingResource loggingResource; private LoggingResource loggingResource;
@ -47,7 +50,7 @@ public class LoggingResourceTest {
@Mock @Mock
private Herder herder; private Herder herder;
@Before @BeforeEach
public void setup() { public void setup() {
loggingResource = new LoggingResource(herder); loggingResource = new LoggingResource(herder);
} }

View File

@ -20,23 +20,26 @@ import org.apache.kafka.clients.admin.MockAdminClient;
import org.apache.kafka.common.utils.AppInfoParser; import org.apache.kafka.common.utils.AppInfoParser;
import org.apache.kafka.connect.runtime.Herder; import org.apache.kafka.connect.runtime.Herder;
import org.apache.kafka.connect.runtime.rest.entities.ServerInfo; import org.apache.kafka.connect.runtime.rest.entities.ServerInfo;
import org.junit.Before; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
public class RootResourceTest { public class RootResourceTest {
@Mock private Herder herder; @Mock private Herder herder;
private RootResource rootResource; private RootResource rootResource;
@Before @BeforeEach
public void setUp() { public void setUp() {
rootResource = new RootResource(herder); rootResource = new RootResource(herder);
} }

View File

@ -19,13 +19,17 @@ package org.apache.kafka.connect.runtime.rest.util;
import org.apache.kafka.common.config.SslConfigs; import org.apache.kafka.common.config.SslConfigs;
import org.apache.kafka.connect.runtime.rest.RestServerConfig; import org.apache.kafka.connect.runtime.rest.RestServerConfig;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class SSLUtilsTest { public class SSLUtilsTest {
@Test @Test
@ -37,8 +41,8 @@ public class SSLUtilsTest {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("exists", "value"); map.put("exists", "value");
Assert.assertEquals(SSLUtils.getOrDefault(map, existingKey, defaultValue), value); assertEquals(SSLUtils.getOrDefault(map, existingKey, defaultValue), value);
Assert.assertEquals(SSLUtils.getOrDefault(map, missingKey, defaultValue), defaultValue); assertEquals(SSLUtils.getOrDefault(map, missingKey, defaultValue), defaultValue);
} }
@Test @Test
@ -64,19 +68,19 @@ public class SSLUtilsTest {
RestServerConfig config = RestServerConfig.forPublic(null, configMap); RestServerConfig config = RestServerConfig.forPublic(null, configMap);
SslContextFactory.Server ssl = SSLUtils.createServerSideSslContextFactory(config); SslContextFactory.Server ssl = SSLUtils.createServerSideSslContextFactory(config);
Assert.assertEquals("file:///path/to/keystore", ssl.getKeyStorePath()); assertEquals("file:///path/to/keystore", ssl.getKeyStorePath());
Assert.assertEquals("file:///path/to/truststore", ssl.getTrustStorePath()); assertEquals("file:///path/to/truststore", ssl.getTrustStorePath());
Assert.assertEquals("SunJSSE", ssl.getProvider()); assertEquals("SunJSSE", ssl.getProvider());
Assert.assertArrayEquals(new String[] {"SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5"}, ssl.getIncludeCipherSuites()); assertArrayEquals(new String[] {"SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5"}, ssl.getIncludeCipherSuites());
Assert.assertEquals("SHA1PRNG", ssl.getSecureRandomAlgorithm()); assertEquals("SHA1PRNG", ssl.getSecureRandomAlgorithm());
Assert.assertTrue(ssl.getNeedClientAuth()); assertTrue(ssl.getNeedClientAuth());
Assert.assertFalse(ssl.getWantClientAuth()); assertFalse(ssl.getWantClientAuth());
Assert.assertEquals("JKS", ssl.getKeyStoreType()); assertEquals("JKS", ssl.getKeyStoreType());
Assert.assertEquals("JKS", ssl.getTrustStoreType()); assertEquals("JKS", ssl.getTrustStoreType());
Assert.assertEquals("TLS", ssl.getProtocol()); assertEquals("TLS", ssl.getProtocol());
Assert.assertArrayEquals(new String[] {"TLSv1.2", "TLSv1.1", "TLSv1"}, ssl.getIncludeProtocols()); assertArrayEquals(new String[] {"TLSv1.2", "TLSv1.1", "TLSv1"}, ssl.getIncludeProtocols());
Assert.assertEquals("SunX509", ssl.getKeyManagerFactoryAlgorithm()); assertEquals("SunX509", ssl.getKeyManagerFactoryAlgorithm());
Assert.assertEquals("PKIX", ssl.getTrustManagerFactoryAlgorithm()); assertEquals("PKIX", ssl.getTrustManagerFactoryAlgorithm());
} }
@Test @Test
@ -102,17 +106,17 @@ public class SSLUtilsTest {
RestServerConfig config = RestServerConfig.forPublic(null, configMap); RestServerConfig config = RestServerConfig.forPublic(null, configMap);
SslContextFactory.Client ssl = SSLUtils.createClientSideSslContextFactory(config); SslContextFactory.Client ssl = SSLUtils.createClientSideSslContextFactory(config);
Assert.assertEquals("file:///path/to/keystore", ssl.getKeyStorePath()); assertEquals("file:///path/to/keystore", ssl.getKeyStorePath());
Assert.assertEquals("file:///path/to/truststore", ssl.getTrustStorePath()); assertEquals("file:///path/to/truststore", ssl.getTrustStorePath());
Assert.assertEquals("SunJSSE", ssl.getProvider()); assertEquals("SunJSSE", ssl.getProvider());
Assert.assertArrayEquals(new String[] {"SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5"}, ssl.getIncludeCipherSuites()); assertArrayEquals(new String[] {"SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5"}, ssl.getIncludeCipherSuites());
Assert.assertEquals("SHA1PRNG", ssl.getSecureRandomAlgorithm()); assertEquals("SHA1PRNG", ssl.getSecureRandomAlgorithm());
Assert.assertEquals("JKS", ssl.getKeyStoreType()); assertEquals("JKS", ssl.getKeyStoreType());
Assert.assertEquals("JKS", ssl.getTrustStoreType()); assertEquals("JKS", ssl.getTrustStoreType());
Assert.assertEquals("TLS", ssl.getProtocol()); assertEquals("TLS", ssl.getProtocol());
Assert.assertArrayEquals(new String[] {"TLSv1.2", "TLSv1.1", "TLSv1"}, ssl.getIncludeProtocols()); assertArrayEquals(new String[] {"TLSv1.2", "TLSv1.1", "TLSv1"}, ssl.getIncludeProtocols());
Assert.assertEquals("SunX509", ssl.getKeyManagerFactoryAlgorithm()); assertEquals("SunX509", ssl.getKeyManagerFactoryAlgorithm());
Assert.assertEquals("PKIX", ssl.getTrustManagerFactoryAlgorithm()); assertEquals("PKIX", ssl.getTrustManagerFactoryAlgorithm());
} }
@Test @Test
@ -130,14 +134,14 @@ public class SSLUtilsTest {
RestServerConfig config = RestServerConfig.forPublic(null, configMap); RestServerConfig config = RestServerConfig.forPublic(null, configMap);
SslContextFactory.Server ssl = SSLUtils.createServerSideSslContextFactory(config); SslContextFactory.Server ssl = SSLUtils.createServerSideSslContextFactory(config);
Assert.assertEquals(SslConfigs.DEFAULT_SSL_KEYSTORE_TYPE, ssl.getKeyStoreType()); assertEquals(SslConfigs.DEFAULT_SSL_KEYSTORE_TYPE, ssl.getKeyStoreType());
Assert.assertEquals(SslConfigs.DEFAULT_SSL_TRUSTSTORE_TYPE, ssl.getTrustStoreType()); assertEquals(SslConfigs.DEFAULT_SSL_TRUSTSTORE_TYPE, ssl.getTrustStoreType());
Assert.assertEquals(SslConfigs.DEFAULT_SSL_PROTOCOL, ssl.getProtocol()); assertEquals(SslConfigs.DEFAULT_SSL_PROTOCOL, ssl.getProtocol());
Assert.assertArrayEquals(Arrays.asList(SslConfigs.DEFAULT_SSL_ENABLED_PROTOCOLS.split("\\s*,\\s*")).toArray(), ssl.getIncludeProtocols()); assertArrayEquals(Arrays.asList(SslConfigs.DEFAULT_SSL_ENABLED_PROTOCOLS.split("\\s*,\\s*")).toArray(), ssl.getIncludeProtocols());
Assert.assertEquals(SslConfigs.DEFAULT_SSL_KEYMANGER_ALGORITHM, ssl.getKeyManagerFactoryAlgorithm()); assertEquals(SslConfigs.DEFAULT_SSL_KEYMANGER_ALGORITHM, ssl.getKeyManagerFactoryAlgorithm());
Assert.assertEquals(SslConfigs.DEFAULT_SSL_TRUSTMANAGER_ALGORITHM, ssl.getTrustManagerFactoryAlgorithm()); assertEquals(SslConfigs.DEFAULT_SSL_TRUSTMANAGER_ALGORITHM, ssl.getTrustManagerFactoryAlgorithm());
Assert.assertFalse(ssl.getNeedClientAuth()); assertFalse(ssl.getNeedClientAuth());
Assert.assertFalse(ssl.getWantClientAuth()); assertFalse(ssl.getWantClientAuth());
} }
@Test @Test
@ -155,11 +159,11 @@ public class SSLUtilsTest {
RestServerConfig config = RestServerConfig.forPublic(null, configMap); RestServerConfig config = RestServerConfig.forPublic(null, configMap);
SslContextFactory.Client ssl = SSLUtils.createClientSideSslContextFactory(config); SslContextFactory.Client ssl = SSLUtils.createClientSideSslContextFactory(config);
Assert.assertEquals(SslConfigs.DEFAULT_SSL_KEYSTORE_TYPE, ssl.getKeyStoreType()); assertEquals(SslConfigs.DEFAULT_SSL_KEYSTORE_TYPE, ssl.getKeyStoreType());
Assert.assertEquals(SslConfigs.DEFAULT_SSL_TRUSTSTORE_TYPE, ssl.getTrustStoreType()); assertEquals(SslConfigs.DEFAULT_SSL_TRUSTSTORE_TYPE, ssl.getTrustStoreType());
Assert.assertEquals(SslConfigs.DEFAULT_SSL_PROTOCOL, ssl.getProtocol()); assertEquals(SslConfigs.DEFAULT_SSL_PROTOCOL, ssl.getProtocol());
Assert.assertArrayEquals(Arrays.asList(SslConfigs.DEFAULT_SSL_ENABLED_PROTOCOLS.split("\\s*,\\s*")).toArray(), ssl.getIncludeProtocols()); assertArrayEquals(Arrays.asList(SslConfigs.DEFAULT_SSL_ENABLED_PROTOCOLS.split("\\s*,\\s*")).toArray(), ssl.getIncludeProtocols());
Assert.assertEquals(SslConfigs.DEFAULT_SSL_KEYMANGER_ALGORITHM, ssl.getKeyManagerFactoryAlgorithm()); assertEquals(SslConfigs.DEFAULT_SSL_KEYMANGER_ALGORITHM, ssl.getKeyManagerFactoryAlgorithm());
Assert.assertEquals(SslConfigs.DEFAULT_SSL_TRUSTMANAGER_ALGORITHM, ssl.getTrustManagerFactoryAlgorithm()); assertEquals(SslConfigs.DEFAULT_SSL_TRUSTMANAGER_ALGORITHM, ssl.getTrustManagerFactoryAlgorithm());
} }
} }

View File

@ -20,13 +20,13 @@ import org.apache.kafka.common.config.ConfigDef;
import org.apache.kafka.common.config.SslConfigs; import org.apache.kafka.common.config.SslConfigs;
import org.apache.kafka.common.config.types.Password; import org.apache.kafka.common.config.types.Password;
import org.apache.kafka.connect.runtime.WorkerConfig; import org.apache.kafka.connect.runtime.WorkerConfig;
import org.junit.Test; import org.junit.jupiter.api.Test;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class StandaloneConfigTest { public class StandaloneConfigTest {

View File

@ -60,13 +60,14 @@ import org.apache.kafka.connect.storage.StatusBackingStore;
import org.apache.kafka.connect.util.Callback; import org.apache.kafka.connect.util.Callback;
import org.apache.kafka.connect.util.ConnectorTaskId; import org.apache.kafka.connect.util.ConnectorTaskId;
import org.apache.kafka.connect.util.FutureCallback; import org.apache.kafka.connect.util.FutureCallback;
import org.junit.After; import org.junit.jupiter.api.Test;
import org.junit.Before; import org.junit.jupiter.api.AfterEach;
import org.junit.Test; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -87,11 +88,10 @@ import static java.util.Collections.singletonMap;
import static org.apache.kafka.connect.runtime.TopicCreationConfig.DEFAULT_TOPIC_CREATION_PREFIX; import static org.apache.kafka.connect.runtime.TopicCreationConfig.DEFAULT_TOPIC_CREATION_PREFIX;
import static org.apache.kafka.connect.runtime.TopicCreationConfig.PARTITIONS_CONFIG; import static org.apache.kafka.connect.runtime.TopicCreationConfig.PARTITIONS_CONFIG;
import static org.apache.kafka.connect.runtime.TopicCreationConfig.REPLICATION_FACTOR_CONFIG; import static org.apache.kafka.connect.runtime.TopicCreationConfig.REPLICATION_FACTOR_CONFIG;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
@ -110,7 +110,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings; import static org.mockito.Mockito.withSettings;
@RunWith(MockitoJUnitRunner.StrictStubs.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS)
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class StandaloneHerderTest { public class StandaloneHerderTest {
private static final String CONNECTOR_NAME = "test"; private static final String CONNECTOR_NAME = "test";
@ -141,17 +142,17 @@ public class StandaloneHerderTest {
private final SampleConnectorClientConfigOverridePolicy private final SampleConnectorClientConfigOverridePolicy
noneConnectorClientConfigOverridePolicy = new SampleConnectorClientConfigOverridePolicy(); noneConnectorClientConfigOverridePolicy = new SampleConnectorClientConfigOverridePolicy();
@Before public void initialize(boolean mockTransform) {
public void setup() throws ExecutionException, InterruptedException {
herder = mock(StandaloneHerder.class, withSettings() herder = mock(StandaloneHerder.class, withSettings()
.useConstructor(worker, WORKER_ID, KAFKA_CLUSTER_ID, statusBackingStore, new MemoryConfigBackingStore(transformer), noneConnectorClientConfigOverridePolicy, new MockTime()) .useConstructor(worker, WORKER_ID, KAFKA_CLUSTER_ID, statusBackingStore, new MemoryConfigBackingStore(transformer), noneConnectorClientConfigOverridePolicy, new MockTime())
.defaultAnswer(CALLS_REAL_METHODS)); .defaultAnswer(CALLS_REAL_METHODS));
createCallback = new FutureCallback<>(); createCallback = new FutureCallback<>();
final ArgumentCaptor<Map<String, String>> configCapture = ArgumentCaptor.forClass(Map.class); final ArgumentCaptor<Map<String, String>> configCapture = ArgumentCaptor.forClass(Map.class);
if (mockTransform)
when(transformer.transform(eq(CONNECTOR_NAME), configCapture.capture())).thenAnswer(invocation -> configCapture.getValue()); when(transformer.transform(eq(CONNECTOR_NAME), configCapture.capture())).thenAnswer(invocation -> configCapture.getValue());
} }
@After @AfterEach
public void tearDown() { public void tearDown() {
verifyNoMoreInteractions(worker, statusBackingStore); verifyNoMoreInteractions(worker, statusBackingStore);
herder.stop(); herder.stop();
@ -159,6 +160,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testCreateSourceConnector() throws Exception { public void testCreateSourceConnector() throws Exception {
initialize(true);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
Map<String, String> config = connectorConfig(SourceSink.SOURCE); Map<String, String> config = connectorConfig(SourceSink.SOURCE);
@ -171,6 +173,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testCreateConnectorFailedValidation() { public void testCreateConnectorFailedValidation() {
initialize(false);
// Basic validation should be performed and return an error, but should still evaluate the connector's config // Basic validation should be performed and return an error, but should still evaluate the connector's config
Map<String, String> config = connectorConfig(SourceSink.SOURCE); Map<String, String> config = connectorConfig(SourceSink.SOURCE);
@ -201,6 +204,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testCreateConnectorAlreadyExists() throws Throwable { public void testCreateConnectorAlreadyExists() throws Throwable {
initialize(true);
// First addition should succeed // First addition should succeed
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
@ -224,6 +228,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testCreateSinkConnector() throws Exception { public void testCreateSinkConnector() throws Exception {
initialize(true);
expectAdd(SourceSink.SINK); expectAdd(SourceSink.SINK);
Map<String, String> config = connectorConfig(SourceSink.SINK); Map<String, String> config = connectorConfig(SourceSink.SINK);
@ -236,6 +241,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testCreateConnectorWithStoppedInitialState() throws Exception { public void testCreateConnectorWithStoppedInitialState() throws Exception {
initialize(true);
Map<String, String> config = connectorConfig(SourceSink.SINK); Map<String, String> config = connectorConfig(SourceSink.SINK);
expectConfigValidation(SourceSink.SINK, config); expectConfigValidation(SourceSink.SINK, config);
@ -256,6 +262,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testDestroyConnector() throws Exception { public void testDestroyConnector() throws Exception {
initialize(true);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
Map<String, String> config = connectorConfig(SourceSink.SOURCE); Map<String, String> config = connectorConfig(SourceSink.SOURCE);
@ -279,16 +286,17 @@ public class StandaloneHerderTest {
FutureCallback<Herder.Created<ConnectorInfo>> failedDeleteCallback = new FutureCallback<>(); FutureCallback<Herder.Created<ConnectorInfo>> failedDeleteCallback = new FutureCallback<>();
herder.deleteConnectorConfig(CONNECTOR_NAME, failedDeleteCallback); herder.deleteConnectorConfig(CONNECTOR_NAME, failedDeleteCallback);
ExecutionException e = assertThrows( ExecutionException e = assertThrows(
"Should have thrown NotFoundException",
ExecutionException.class, ExecutionException.class,
() -> failedDeleteCallback.get(WAIT_TIME_MS, TimeUnit.MILLISECONDS) () -> failedDeleteCallback.get(WAIT_TIME_MS, TimeUnit.MILLISECONDS),
"Should have thrown NotFoundException"
); );
assertInstanceOf(NotFoundException.class, e.getCause()); assertInstanceOf(NotFoundException.class, e.getCause());
} }
@Test @Test
public void testRestartConnectorSameTaskConfigs() throws Exception { public void testRestartConnectorSameTaskConfigs() throws Exception {
expectAdd(SourceSink.SOURCE); initialize(true);
expectAdd(SourceSink.SOURCE, false);
Map<String, String> config = connectorConfig(SourceSink.SOURCE); Map<String, String> config = connectorConfig(SourceSink.SOURCE);
expectConfigValidation(SourceSink.SOURCE, config); expectConfigValidation(SourceSink.SOURCE, config);
@ -313,6 +321,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testRestartConnectorNewTaskConfigs() throws Exception { public void testRestartConnectorNewTaskConfigs() throws Exception {
initialize(true);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
Map<String, String> config = connectorConfig(SourceSink.SOURCE); Map<String, String> config = connectorConfig(SourceSink.SOURCE);
@ -344,6 +353,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testRestartConnectorFailureOnStart() throws Exception { public void testRestartConnectorFailureOnStart() throws Exception {
initialize(true);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
Map<String, String> config = connectorConfig(SourceSink.SOURCE); Map<String, String> config = connectorConfig(SourceSink.SOURCE);
@ -360,16 +370,13 @@ public class StandaloneHerderTest {
FutureCallback<Void> restartCallback = new FutureCallback<>(); FutureCallback<Void> restartCallback = new FutureCallback<>();
mockStartConnector(config, null, TargetState.STARTED, exception); mockStartConnector(config, null, TargetState.STARTED, exception);
herder.restartConnector(CONNECTOR_NAME, restartCallback); herder.restartConnector(CONNECTOR_NAME, restartCallback);
try { ExecutionException e = assertThrows(ExecutionException.class, () -> restartCallback.get(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
restartCallback.get(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
fail();
} catch (ExecutionException e) {
assertEquals(exception, e.getCause()); assertEquals(exception, e.getCause());
} }
}
@Test @Test
public void testRestartTask() throws Exception { public void testRestartTask() throws Exception {
initialize(true);
ConnectorTaskId taskId = new ConnectorTaskId(CONNECTOR_NAME, 0); ConnectorTaskId taskId = new ConnectorTaskId(CONNECTOR_NAME, 0);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
@ -407,6 +414,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testRestartTaskFailureOnStart() throws Exception { public void testRestartTaskFailureOnStart() throws Exception {
initialize(true);
ConnectorTaskId taskId = new ConnectorTaskId(CONNECTOR_NAME, 0); ConnectorTaskId taskId = new ConnectorTaskId(CONNECTOR_NAME, 0);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
@ -436,16 +444,13 @@ public class StandaloneHerderTest {
FutureCallback<Void> cb = new FutureCallback<>(); FutureCallback<Void> cb = new FutureCallback<>();
herder.restartTask(taskId, cb); herder.restartTask(taskId, cb);
verify(worker).stopAndAwaitTask(taskId); verify(worker).stopAndAwaitTask(taskId);
try { ExecutionException exception = assertThrows(ExecutionException.class, () -> cb.get(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
cb.get(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
fail("Expected restart callback to raise an exception");
} catch (ExecutionException exception) {
assertEquals(ConnectException.class, exception.getCause().getClass()); assertEquals(ConnectException.class, exception.getCause().getClass());
} }
}
@Test @Test
public void testRestartConnectorAndTasksUnknownConnector() { public void testRestartConnectorAndTasksUnknownConnector() {
initialize(false);
FutureCallback<ConnectorStateInfo> restartCallback = new FutureCallback<>(); FutureCallback<ConnectorStateInfo> restartCallback = new FutureCallback<>();
RestartRequest restartRequest = new RestartRequest("UnknownConnector", false, true); RestartRequest restartRequest = new RestartRequest("UnknownConnector", false, true);
herder.restartConnectorAndTasks(restartRequest, restartCallback); herder.restartConnectorAndTasks(restartRequest, restartCallback);
@ -455,6 +460,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testRestartConnectorAndTasksNoStatus() throws Exception { public void testRestartConnectorAndTasksNoStatus() throws Exception {
initialize(true);
RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true); RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true);
doReturn(Optional.empty()).when(herder).buildRestartPlan(restartRequest); doReturn(Optional.empty()).when(herder).buildRestartPlan(restartRequest);
@ -476,6 +482,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testRestartConnectorAndTasksNoRestarts() throws Exception { public void testRestartConnectorAndTasksNoRestarts() throws Exception {
initialize(true);
RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true); RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true);
RestartPlan restartPlan = mock(RestartPlan.class); RestartPlan restartPlan = mock(RestartPlan.class);
ConnectorStateInfo connectorStateInfo = mock(ConnectorStateInfo.class); ConnectorStateInfo connectorStateInfo = mock(ConnectorStateInfo.class);
@ -500,6 +507,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testRestartConnectorAndTasksOnlyConnector() throws Exception { public void testRestartConnectorAndTasksOnlyConnector() throws Exception {
initialize(true);
RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true); RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true);
RestartPlan restartPlan = mock(RestartPlan.class); RestartPlan restartPlan = mock(RestartPlan.class);
ConnectorStateInfo connectorStateInfo = mock(ConnectorStateInfo.class); ConnectorStateInfo connectorStateInfo = mock(ConnectorStateInfo.class);
@ -508,7 +516,7 @@ public class StandaloneHerderTest {
when(restartPlan.restartConnectorStateInfo()).thenReturn(connectorStateInfo); when(restartPlan.restartConnectorStateInfo()).thenReturn(connectorStateInfo);
doReturn(Optional.of(restartPlan)).when(herder).buildRestartPlan(restartRequest); doReturn(Optional.of(restartPlan)).when(herder).buildRestartPlan(restartRequest);
expectAdd(SourceSink.SINK); expectAdd(SourceSink.SINK, false);
Map<String, String> connectorConfig = connectorConfig(SourceSink.SINK); Map<String, String> connectorConfig = connectorConfig(SourceSink.SINK);
expectConfigValidation(SourceSink.SINK, connectorConfig); expectConfigValidation(SourceSink.SINK, connectorConfig);
@ -530,6 +538,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testRestartConnectorAndTasksOnlyTasks() throws Exception { public void testRestartConnectorAndTasksOnlyTasks() throws Exception {
initialize(true);
ConnectorTaskId taskId = new ConnectorTaskId(CONNECTOR_NAME, 0); ConnectorTaskId taskId = new ConnectorTaskId(CONNECTOR_NAME, 0);
RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true); RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true);
RestartPlan restartPlan = mock(RestartPlan.class); RestartPlan restartPlan = mock(RestartPlan.class);
@ -580,6 +589,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testRestartConnectorAndTasksBoth() throws Exception { public void testRestartConnectorAndTasksBoth() throws Exception {
initialize(true);
ConnectorTaskId taskId = new ConnectorTaskId(CONNECTOR_NAME, 0); ConnectorTaskId taskId = new ConnectorTaskId(CONNECTOR_NAME, 0);
RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true); RestartRequest restartRequest = new RestartRequest(CONNECTOR_NAME, false, true);
RestartPlan restartPlan = mock(RestartPlan.class); RestartPlan restartPlan = mock(RestartPlan.class);
@ -594,7 +604,7 @@ public class StandaloneHerderTest {
ArgumentCaptor<TaskStatus> taskStatus = ArgumentCaptor.forClass(TaskStatus.class); ArgumentCaptor<TaskStatus> taskStatus = ArgumentCaptor.forClass(TaskStatus.class);
expectAdd(SourceSink.SINK); expectAdd(SourceSink.SINK, false);
Map<String, String> connectorConfig = connectorConfig(SourceSink.SINK); Map<String, String> connectorConfig = connectorConfig(SourceSink.SINK);
expectConfigValidation(SourceSink.SINK, connectorConfig); expectConfigValidation(SourceSink.SINK, connectorConfig);
@ -636,6 +646,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testCreateAndStop() throws Exception { public void testCreateAndStop() throws Exception {
initialize(true);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
Map<String, String> connectorConfig = connectorConfig(SourceSink.SOURCE); Map<String, String> connectorConfig = connectorConfig(SourceSink.SOURCE);
@ -657,6 +668,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testAccessors() throws Exception { public void testAccessors() throws Exception {
initialize(true);
Map<String, String> connConfig = connectorConfig(SourceSink.SOURCE); Map<String, String> connConfig = connectorConfig(SourceSink.SOURCE);
System.out.println(connConfig); System.out.println(connConfig);
@ -713,6 +725,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testPutConnectorConfig() throws Exception { public void testPutConnectorConfig() throws Exception {
initialize(true);
Map<String, String> connConfig = connectorConfig(SourceSink.SOURCE); Map<String, String> connConfig = connectorConfig(SourceSink.SOURCE);
Map<String, String> newConnConfig = new HashMap<>(connConfig); Map<String, String> newConnConfig = new HashMap<>(connConfig);
newConnConfig.put("foo", "bar"); newConnConfig.put("foo", "bar");
@ -720,7 +733,7 @@ public class StandaloneHerderTest {
Callback<Map<String, String>> connectorConfigCb = mock(Callback.class); Callback<Map<String, String>> connectorConfigCb = mock(Callback.class);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE, false);
expectConfigValidation(SourceSink.SOURCE, connConfig, newConnConfig); expectConfigValidation(SourceSink.SOURCE, connConfig, newConnConfig);
// Should get first config // Should get first config
@ -764,6 +777,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testPatchConnectorConfigNotFound() { public void testPatchConnectorConfigNotFound() {
initialize(false);
Map<String, String> connConfigPatch = new HashMap<>(); Map<String, String> connConfigPatch = new HashMap<>();
connConfigPatch.put("foo1", "baz1"); connConfigPatch.put("foo1", "baz1");
@ -777,6 +791,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testPatchConnectorConfig() throws ExecutionException, InterruptedException, TimeoutException { public void testPatchConnectorConfig() throws ExecutionException, InterruptedException, TimeoutException {
initialize(true);
// Create the connector. // Create the connector.
Map<String, String> originalConnConfig = connectorConfig(SourceSink.SOURCE); Map<String, String> originalConnConfig = connectorConfig(SourceSink.SOURCE);
originalConnConfig.put("foo0", "unaffected"); originalConnConfig.put("foo0", "unaffected");
@ -794,15 +809,15 @@ public class StandaloneHerderTest {
patchedConnConfig.remove("foo2"); patchedConnConfig.remove("foo2");
patchedConnConfig.put("foo3", "added"); patchedConnConfig.put("foo3", "added");
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE, false, false, false);
expectConfigValidation(SourceSink.SOURCE, originalConnConfig, patchedConnConfig); expectConfigValidation(SourceSink.SOURCE, originalConnConfig, patchedConnConfig);
expectConnectorStartingWithoutTasks(originalConnConfig, SourceSink.SOURCE); expectConnectorStartingWithoutTasks(originalConnConfig, true);
herder.putConnectorConfig(CONNECTOR_NAME, originalConnConfig, false, createCallback); herder.putConnectorConfig(CONNECTOR_NAME, originalConnConfig, false, createCallback);
createCallback.get(1000L, TimeUnit.SECONDS); createCallback.get(1000L, TimeUnit.SECONDS);
expectConnectorStartingWithoutTasks(patchedConnConfig, SourceSink.SOURCE); expectConnectorStartingWithoutTasks(patchedConnConfig, false);
FutureCallback<Herder.Created<ConnectorInfo>> patchCallback = new FutureCallback<>(); FutureCallback<Herder.Created<ConnectorInfo>> patchCallback = new FutureCallback<>();
herder.patchConnectorConfig(CONNECTOR_NAME, connConfigPatch, patchCallback); herder.patchConnectorConfig(CONNECTOR_NAME, connConfigPatch, patchCallback);
@ -818,23 +833,24 @@ public class StandaloneHerderTest {
assertEquals(patchedConnConfig, returnedConfig2); assertEquals(patchedConnConfig, returnedConfig2);
} }
private void expectConnectorStartingWithoutTasks(Map<String, String> config, SourceSink sourceSink) { private void expectConnectorStartingWithoutTasks(Map<String, String> config, boolean mockStop) {
if (mockStop) {
doNothing().when(worker).stopAndAwaitConnector(CONNECTOR_NAME); doNothing().when(worker).stopAndAwaitConnector(CONNECTOR_NAME);
}
final ArgumentCaptor<Callback<TargetState>> onStart = ArgumentCaptor.forClass(Callback.class); final ArgumentCaptor<Callback<TargetState>> onStart = ArgumentCaptor.forClass(Callback.class);
doAnswer(invocation -> { doAnswer(invocation -> {
onStart.getValue().onCompletion(null, TargetState.STARTED); onStart.getValue().onCompletion(null, TargetState.STARTED);
return true; return true;
}).when(worker).startConnector(eq(CONNECTOR_NAME), any(Map.class), any(), }).when(worker).startConnector(eq(CONNECTOR_NAME), any(Map.class), any(),
eq(herder), eq(TargetState.STARTED), onStart.capture()); eq(herder), eq(TargetState.STARTED), onStart.capture());
ConnectorConfig connConfig = sourceSink == SourceSink.SOURCE ? ConnectorConfig connConfig = new SourceConnectorConfig(plugins, config, true);
new SourceConnectorConfig(plugins, config, true) :
new SinkConnectorConfig(plugins, config);
when(worker.connectorTaskConfigs(CONNECTOR_NAME, connConfig)) when(worker.connectorTaskConfigs(CONNECTOR_NAME, connConfig))
.thenReturn(emptyList()); .thenReturn(emptyList());
} }
@Test @Test
public void testPutTaskConfigs() { public void testPutTaskConfigs() {
initialize(false);
Callback<Void> cb = mock(Callback.class); Callback<Void> cb = mock(Callback.class);
assertThrows(UnsupportedOperationException.class, () -> herder.putTaskConfigs(CONNECTOR_NAME, assertThrows(UnsupportedOperationException.class, () -> herder.putTaskConfigs(CONNECTOR_NAME,
@ -843,6 +859,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testCorruptConfig() { public void testCorruptConfig() {
initialize(false);
Map<String, String> config = new HashMap<>(); Map<String, String> config = new HashMap<>();
config.put(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME); config.put(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME);
config.put(ConnectorConfig.CONNECTOR_CLASS_CONFIG, BogusSinkConnector.class.getName()); config.put(ConnectorConfig.CONNECTOR_CLASS_CONFIG, BogusSinkConnector.class.getName());
@ -869,9 +886,9 @@ public class StandaloneHerderTest {
herder.putConnectorConfig(CONNECTOR_NAME, config, true, createCallback); herder.putConnectorConfig(CONNECTOR_NAME, config, true, createCallback);
ExecutionException e = assertThrows( ExecutionException e = assertThrows(
"Should have failed to configure connector",
ExecutionException.class, ExecutionException.class,
() -> createCallback.get(WAIT_TIME_MS, TimeUnit.MILLISECONDS) () -> createCallback.get(WAIT_TIME_MS, TimeUnit.MILLISECONDS),
"Should have failed to configure connector"
); );
assertNotNull(e.getCause()); assertNotNull(e.getCause());
Throwable cause = e.getCause(); Throwable cause = e.getCause();
@ -887,6 +904,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testTargetStates() throws Exception { public void testTargetStates() throws Exception {
initialize(true);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
Map<String, String> connectorConfig = connectorConfig(SourceSink.SOURCE); Map<String, String> connectorConfig = connectorConfig(SourceSink.SOURCE);
@ -922,6 +940,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testModifyConnectorOffsetsUnknownConnector() { public void testModifyConnectorOffsetsUnknownConnector() {
initialize(false);
FutureCallback<Message> alterOffsetsCallback = new FutureCallback<>(); FutureCallback<Message> alterOffsetsCallback = new FutureCallback<>();
herder.alterConnectorOffsets("unknown-connector", herder.alterConnectorOffsets("unknown-connector",
Collections.singletonMap(Collections.singletonMap("partitionKey", "partitionValue"), Collections.singletonMap("offsetKey", "offsetValue")), Collections.singletonMap(Collections.singletonMap("partitionKey", "partitionValue"), Collections.singletonMap("offsetKey", "offsetValue")),
@ -937,6 +956,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testModifyConnectorOffsetsConnectorNotInStoppedState() { public void testModifyConnectorOffsetsConnectorNotInStoppedState() {
initialize(false);
Map<String, String> connectorConfig = connectorConfig(SourceSink.SOURCE); Map<String, String> connectorConfig = connectorConfig(SourceSink.SOURCE);
herder.configState = new ClusterConfigState( herder.configState = new ClusterConfigState(
@ -968,6 +988,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testAlterConnectorOffsets() throws Exception { public void testAlterConnectorOffsets() throws Exception {
initialize(false);
ArgumentCaptor<Callback<Message>> workerCallbackCapture = ArgumentCaptor.forClass(Callback.class); ArgumentCaptor<Callback<Message>> workerCallbackCapture = ArgumentCaptor.forClass(Callback.class);
Message msg = new Message("The offsets for this connector have been altered successfully"); Message msg = new Message("The offsets for this connector have been altered successfully");
doAnswer(invocation -> { doAnswer(invocation -> {
@ -999,6 +1020,7 @@ public class StandaloneHerderTest {
@Test @Test
public void testResetConnectorOffsets() throws Exception { public void testResetConnectorOffsets() throws Exception {
initialize(false);
ArgumentCaptor<Callback<Message>> workerCallbackCapture = ArgumentCaptor.forClass(Callback.class); ArgumentCaptor<Callback<Message>> workerCallbackCapture = ArgumentCaptor.forClass(Callback.class);
Message msg = new Message("The offsets for this connector have been reset successfully"); Message msg = new Message("The offsets for this connector have been reset successfully");
@ -1027,8 +1049,9 @@ public class StandaloneHerderTest {
assertEquals(msg, resetOffsetsCallback.get(1000, TimeUnit.MILLISECONDS)); assertEquals(msg, resetOffsetsCallback.get(1000, TimeUnit.MILLISECONDS));
} }
@Test() @Test
public void testRequestTaskReconfigurationDoesNotDeadlock() throws Exception { public void testRequestTaskReconfigurationDoesNotDeadlock() throws Exception {
initialize(true);
expectAdd(SourceSink.SOURCE); expectAdd(SourceSink.SOURCE);
// Start the connector // Start the connector
@ -1076,12 +1099,25 @@ public class StandaloneHerderTest {
} }
private void expectAdd(SourceSink sourceSink) { private void expectAdd(SourceSink sourceSink) {
expectAdd(sourceSink, true);
}
private void expectAdd(SourceSink sourceSink, boolean mockStartConnector) {
expectAdd(sourceSink, mockStartConnector, true, true);
}
private void expectAdd(SourceSink sourceSink,
boolean mockStartConnector,
boolean mockConnectorTaskConfigs,
boolean mockStartSourceTask) {
Map<String, String> connectorProps = connectorConfig(sourceSink); Map<String, String> connectorProps = connectorConfig(sourceSink);
ConnectorConfig connConfig = sourceSink == SourceSink.SOURCE ? ConnectorConfig connConfig = sourceSink == SourceSink.SOURCE ?
new SourceConnectorConfig(plugins, connectorProps, true) : new SourceConnectorConfig(plugins, connectorProps, true) :
new SinkConnectorConfig(plugins, connectorProps); new SinkConnectorConfig(plugins, connectorProps);
if (mockStartConnector) {
mockStartConnector(connectorProps, TargetState.STARTED, TargetState.STARTED, null); mockStartConnector(connectorProps, TargetState.STARTED, TargetState.STARTED, null);
}
when(worker.isRunning(CONNECTOR_NAME)).thenReturn(true); when(worker.isRunning(CONNECTOR_NAME)).thenReturn(true);
if (sourceSink == SourceSink.SOURCE) { if (sourceSink == SourceSink.SOURCE) {
when(worker.isTopicCreationEnabled()).thenReturn(true); when(worker.isTopicCreationEnabled()).thenReturn(true);
@ -1092,8 +1128,9 @@ public class StandaloneHerderTest {
Map<String, String> connectorConfig = connectorConfig(sourceSink); Map<String, String> connectorConfig = connectorConfig(sourceSink);
Map<String, String> generatedTaskProps = taskConfig(sourceSink); Map<String, String> generatedTaskProps = taskConfig(sourceSink);
when(worker.connectorTaskConfigs(CONNECTOR_NAME, connConfig)) if (mockConnectorTaskConfigs) {
.thenReturn(singletonList(generatedTaskProps)); when(worker.connectorTaskConfigs(CONNECTOR_NAME, connConfig)).thenReturn(singletonList(generatedTaskProps));
}
ClusterConfigState configState = new ClusterConfigState( ClusterConfigState configState = new ClusterConfigState(
-1, -1,
@ -1108,9 +1145,12 @@ public class StandaloneHerderTest {
new HashSet<>(), new HashSet<>(),
new HashSet<>(), new HashSet<>(),
transformer); transformer);
if (sourceSink.equals(SourceSink.SOURCE)) {
if (sourceSink.equals(SourceSink.SOURCE) && mockStartSourceTask) {
when(worker.startSourceTask(new ConnectorTaskId(CONNECTOR_NAME, 0), configState, connectorConfig(sourceSink), generatedTaskProps, herder, TargetState.STARTED)).thenReturn(true); when(worker.startSourceTask(new ConnectorTaskId(CONNECTOR_NAME, 0), configState, connectorConfig(sourceSink), generatedTaskProps, herder, TargetState.STARTED)).thenReturn(true);
} else { }
if (sourceSink.equals(SourceSink.SINK)) {
when(worker.startSinkTask(new ConnectorTaskId(CONNECTOR_NAME, 0), configState, connectorConfig(sourceSink), generatedTaskProps, herder, TargetState.STARTED)).thenReturn(true); when(worker.startSinkTask(new ConnectorTaskId(CONNECTOR_NAME, 0), configState, connectorConfig(sourceSink), generatedTaskProps, herder, TargetState.STARTED)).thenReturn(true);
} }