mirror of https://github.com/apache/kafka.git
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:
parent
3a3f9ce48e
commit
d5592d8fe6
|
@ -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";
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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"),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue