Search in sources :

Example 1 with ClusterConfigState

use of org.apache.kafka.connect.runtime.distributed.ClusterConfigState in project kafka by apache.

the class KafkaConfigBackingStoreTest method testPutConnectorConfig.

@Test
public void testPutConnectorConfig() throws Exception {
    expectConfigure();
    expectStart(Collections.EMPTY_LIST, Collections.EMPTY_MAP);
    expectConvertWriteAndRead(CONNECTOR_CONFIG_KEYS.get(0), KafkaConfigBackingStore.CONNECTOR_CONFIGURATION_V0, CONFIGS_SERIALIZED.get(0), "properties", SAMPLE_CONFIGS.get(0));
    configUpdateListener.onConnectorConfigUpdate(CONNECTOR_IDS.get(0));
    EasyMock.expectLastCall();
    expectConvertWriteAndRead(CONNECTOR_CONFIG_KEYS.get(1), KafkaConfigBackingStore.CONNECTOR_CONFIGURATION_V0, CONFIGS_SERIALIZED.get(1), "properties", SAMPLE_CONFIGS.get(1));
    configUpdateListener.onConnectorConfigUpdate(CONNECTOR_IDS.get(1));
    EasyMock.expectLastCall();
    // Config deletion
    expectConnectorRemoval(CONNECTOR_CONFIG_KEYS.get(1), TARGET_STATE_KEYS.get(1));
    configUpdateListener.onConnectorConfigRemove(CONNECTOR_IDS.get(1));
    EasyMock.expectLastCall();
    expectStop();
    PowerMock.replayAll();
    configStorage.setupAndCreateKafkaBasedLog(TOPIC, DEFAULT_DISTRIBUTED_CONFIG);
    configStorage.start();
    // Null before writing
    ClusterConfigState configState = configStorage.snapshot();
    assertEquals(-1, configState.offset());
    assertNull(configState.connectorConfig(CONNECTOR_IDS.get(0)));
    assertNull(configState.connectorConfig(CONNECTOR_IDS.get(1)));
    // Writing should block until it is written and read back from Kafka
    configStorage.putConnectorConfig(CONNECTOR_IDS.get(0), SAMPLE_CONFIGS.get(0));
    configState = configStorage.snapshot();
    assertEquals(1, configState.offset());
    assertEquals(SAMPLE_CONFIGS.get(0), configState.connectorConfig(CONNECTOR_IDS.get(0)));
    assertNull(configState.connectorConfig(CONNECTOR_IDS.get(1)));
    // Second should also block and all configs should still be available
    configStorage.putConnectorConfig(CONNECTOR_IDS.get(1), SAMPLE_CONFIGS.get(1));
    configState = configStorage.snapshot();
    assertEquals(2, configState.offset());
    assertEquals(SAMPLE_CONFIGS.get(0), configState.connectorConfig(CONNECTOR_IDS.get(0)));
    assertEquals(SAMPLE_CONFIGS.get(1), configState.connectorConfig(CONNECTOR_IDS.get(1)));
    // Deletion should remove the second one we added
    configStorage.removeConnectorConfig(CONNECTOR_IDS.get(1));
    configState = configStorage.snapshot();
    assertEquals(4, configState.offset());
    assertEquals(SAMPLE_CONFIGS.get(0), configState.connectorConfig(CONNECTOR_IDS.get(0)));
    assertNull(configState.connectorConfig(CONNECTOR_IDS.get(1)));
    assertNull(configState.targetState(CONNECTOR_IDS.get(1)));
    configStorage.stop();
    PowerMock.verifyAll();
}
Also used : ClusterConfigState(org.apache.kafka.connect.runtime.distributed.ClusterConfigState) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Example 2 with ClusterConfigState

use of org.apache.kafka.connect.runtime.distributed.ClusterConfigState in project kafka by apache.

the class KafkaConfigBackingStoreTest method testRestore.

@Test
public void testRestore() throws Exception {
    // Restoring data should notify only of the latest values after loading is complete. This also validates
    // that inconsistent state is ignored.
    expectConfigure();
    // Overwrite each type at least once to ensure we see the latest data after loading
    List<ConsumerRecord<String, byte[]>> existingRecords = Arrays.asList(new ConsumerRecord<>(TOPIC, 0, 0, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, CONNECTOR_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(0)), new ConsumerRecord<>(TOPIC, 0, 1, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TASK_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(1)), new ConsumerRecord<>(TOPIC, 0, 2, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TASK_CONFIG_KEYS.get(1), CONFIGS_SERIALIZED.get(2)), new ConsumerRecord<>(TOPIC, 0, 3, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, CONNECTOR_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(3)), new ConsumerRecord<>(TOPIC, 0, 4, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, COMMIT_TASKS_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(4)), // Connector after root update should make it through, task update shouldn't
    new ConsumerRecord<>(TOPIC, 0, 5, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, CONNECTOR_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(5)), new ConsumerRecord<>(TOPIC, 0, 6, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TASK_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(6)));
    LinkedHashMap<byte[], Struct> deserialized = new LinkedHashMap();
    deserialized.put(CONFIGS_SERIALIZED.get(0), CONNECTOR_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(1), TASK_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(2), TASK_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(3), CONNECTOR_CONFIG_STRUCTS.get(1));
    deserialized.put(CONFIGS_SERIALIZED.get(4), TASKS_COMMIT_STRUCT_TWO_TASK_CONNECTOR);
    deserialized.put(CONFIGS_SERIALIZED.get(5), CONNECTOR_CONFIG_STRUCTS.get(2));
    deserialized.put(CONFIGS_SERIALIZED.get(6), TASK_CONFIG_STRUCTS.get(1));
    logOffset = 7;
    expectStart(existingRecords, deserialized);
    // Shouldn't see any callbacks since this is during startup
    expectStop();
    PowerMock.replayAll();
    configStorage.setupAndCreateKafkaBasedLog(TOPIC, DEFAULT_DISTRIBUTED_CONFIG);
    configStorage.start();
    // Should see a single connector and its config should be the last one seen anywhere in the log
    ClusterConfigState configState = configStorage.snapshot();
    // Should always be next to be read, even if uncommitted
    assertEquals(7, configState.offset());
    assertEquals(Arrays.asList(CONNECTOR_IDS.get(0)), new ArrayList<>(configState.connectors()));
    assertEquals(TargetState.STARTED, configState.targetState(CONNECTOR_IDS.get(0)));
    // CONNECTOR_CONFIG_STRUCTS[2] -> SAMPLE_CONFIGS[2]
    assertEquals(SAMPLE_CONFIGS.get(2), configState.connectorConfig(CONNECTOR_IDS.get(0)));
    // Should see 2 tasks for that connector. Only config updates before the root key update should be reflected
    assertEquals(Arrays.asList(TASK_IDS.get(0), TASK_IDS.get(1)), configState.tasks(CONNECTOR_IDS.get(0)));
    // Both TASK_CONFIG_STRUCTS[0] -> SAMPLE_CONFIGS[0]
    assertEquals(SAMPLE_CONFIGS.get(0), configState.taskConfig(TASK_IDS.get(0)));
    assertEquals(SAMPLE_CONFIGS.get(0), configState.taskConfig(TASK_IDS.get(1)));
    assertEquals(Collections.EMPTY_SET, configState.inconsistentConnectors());
    configStorage.stop();
    PowerMock.verifyAll();
}
Also used : ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) ClusterConfigState(org.apache.kafka.connect.runtime.distributed.ClusterConfigState) LinkedHashMap(java.util.LinkedHashMap) Struct(org.apache.kafka.connect.data.Struct) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Example 3 with ClusterConfigState

use of org.apache.kafka.connect.runtime.distributed.ClusterConfigState in project kafka by apache.

the class KafkaConfigBackingStoreTest method testPutTaskConfigsDoesNotResolveAllInconsistencies.

@Test
public void testPutTaskConfigsDoesNotResolveAllInconsistencies() throws Exception {
    // Test a case where a failure and compaction has left us in an inconsistent state when reading the log.
    // We start out by loading an initial configuration where we started to write a task update, and then
    // compaction cleaned up the earlier record.
    expectConfigure();
    List<ConsumerRecord<String, byte[]>> existingRecords = Arrays.asList(new ConsumerRecord<>(TOPIC, 0, 0, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, CONNECTOR_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(0)), //new ConsumerRecord<>(TOPIC, 0, 1, TASK_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(1)),
    new ConsumerRecord<>(TOPIC, 0, 2, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TASK_CONFIG_KEYS.get(1), CONFIGS_SERIALIZED.get(2)), new ConsumerRecord<>(TOPIC, 0, 4, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, COMMIT_TASKS_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(4)), new ConsumerRecord<>(TOPIC, 0, 5, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TASK_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(5)));
    LinkedHashMap<byte[], Struct> deserialized = new LinkedHashMap();
    deserialized.put(CONFIGS_SERIALIZED.get(0), CONNECTOR_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(2), TASK_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(4), TASKS_COMMIT_STRUCT_TWO_TASK_CONNECTOR);
    deserialized.put(CONFIGS_SERIALIZED.get(5), TASK_CONFIG_STRUCTS.get(1));
    logOffset = 6;
    expectStart(existingRecords, deserialized);
    // Successful attempt to write new task config
    expectReadToEnd(new LinkedHashMap<String, byte[]>());
    expectConvertWriteRead(TASK_CONFIG_KEYS.get(0), KafkaConfigBackingStore.TASK_CONFIGURATION_V0, CONFIGS_SERIALIZED.get(0), "properties", SAMPLE_CONFIGS.get(0));
    expectReadToEnd(new LinkedHashMap<String, byte[]>());
    expectConvertWriteRead(COMMIT_TASKS_CONFIG_KEYS.get(0), KafkaConfigBackingStore.CONNECTOR_TASKS_COMMIT_V0, CONFIGS_SERIALIZED.get(2), "tasks", // Updated to just 1 task
    1);
    // As soon as root is rewritten, we should see a callback notifying us that we reconfigured some tasks
    configUpdateListener.onTaskConfigUpdate(Arrays.asList(TASK_IDS.get(0)));
    EasyMock.expectLastCall();
    // Records to be read by consumer as it reads to the end of the log
    LinkedHashMap<String, byte[]> serializedConfigs = new LinkedHashMap<>();
    serializedConfigs.put(TASK_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(0));
    serializedConfigs.put(COMMIT_TASKS_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(2));
    expectReadToEnd(serializedConfigs);
    expectStop();
    PowerMock.replayAll();
    configStorage.setupAndCreateKafkaBasedLog(TOPIC, DEFAULT_DISTRIBUTED_CONFIG);
    configStorage.start();
    // After reading the log, it should have been in an inconsistent state
    ClusterConfigState configState = configStorage.snapshot();
    // Should always be next to be read, not last committed
    assertEquals(6, configState.offset());
    assertEquals(Arrays.asList(CONNECTOR_IDS.get(0)), new ArrayList<>(configState.connectors()));
    // Inconsistent data should leave us with no tasks listed for the connector and an entry in the inconsistent list
    assertEquals(Collections.EMPTY_LIST, configState.tasks(CONNECTOR_IDS.get(0)));
    // Both TASK_CONFIG_STRUCTS[0] -> SAMPLE_CONFIGS[0]
    assertNull(configState.taskConfig(TASK_IDS.get(0)));
    assertNull(configState.taskConfig(TASK_IDS.get(1)));
    assertEquals(Collections.singleton(CONNECTOR_IDS.get(0)), configState.inconsistentConnectors());
    // Next, issue a write that has everything that is needed and it should be accepted. Note that in this case
    // we are going to shrink the number of tasks to 1
    configStorage.putTaskConfigs("connector1", Collections.singletonList(SAMPLE_CONFIGS.get(0)));
    // Validate updated config
    configState = configStorage.snapshot();
    // This is only two more ahead of the last one because multiple calls fail, and so their configs are not written
    // to the topic. Only the last call with 1 task config + 1 commit actually gets written.
    assertEquals(8, configState.offset());
    assertEquals(Arrays.asList(CONNECTOR_IDS.get(0)), new ArrayList<>(configState.connectors()));
    assertEquals(Arrays.asList(TASK_IDS.get(0)), configState.tasks(CONNECTOR_IDS.get(0)));
    assertEquals(SAMPLE_CONFIGS.get(0), configState.taskConfig(TASK_IDS.get(0)));
    assertEquals(Collections.EMPTY_SET, configState.inconsistentConnectors());
    configStorage.stop();
    PowerMock.verifyAll();
}
Also used : ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) ClusterConfigState(org.apache.kafka.connect.runtime.distributed.ClusterConfigState) LinkedHashMap(java.util.LinkedHashMap) Struct(org.apache.kafka.connect.data.Struct) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Example 4 with ClusterConfigState

use of org.apache.kafka.connect.runtime.distributed.ClusterConfigState in project kafka by apache.

the class KafkaConfigBackingStoreTest method testRestoreConnectorDeletion.

@Test
public void testRestoreConnectorDeletion() throws Exception {
    // Restoring data should notify only of the latest values after loading is complete. This also validates
    // that inconsistent state is ignored.
    expectConfigure();
    // Overwrite each type at least once to ensure we see the latest data after loading
    List<ConsumerRecord<String, byte[]>> existingRecords = Arrays.asList(new ConsumerRecord<>(TOPIC, 0, 0, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, CONNECTOR_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(0)), new ConsumerRecord<>(TOPIC, 0, 1, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TASK_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(1)), new ConsumerRecord<>(TOPIC, 0, 2, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TASK_CONFIG_KEYS.get(1), CONFIGS_SERIALIZED.get(2)), new ConsumerRecord<>(TOPIC, 0, 3, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, CONNECTOR_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(3)), new ConsumerRecord<>(TOPIC, 0, 4, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TARGET_STATE_KEYS.get(0), CONFIGS_SERIALIZED.get(4)), new ConsumerRecord<>(TOPIC, 0, 5, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, COMMIT_TASKS_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(5)));
    LinkedHashMap<byte[], Struct> deserialized = new LinkedHashMap();
    deserialized.put(CONFIGS_SERIALIZED.get(0), CONNECTOR_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(1), TASK_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(2), TASK_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(3), null);
    deserialized.put(CONFIGS_SERIALIZED.get(4), null);
    deserialized.put(CONFIGS_SERIALIZED.get(5), TASKS_COMMIT_STRUCT_TWO_TASK_CONNECTOR);
    logOffset = 6;
    expectStart(existingRecords, deserialized);
    // Shouldn't see any callbacks since this is during startup
    expectStop();
    PowerMock.replayAll();
    configStorage.setupAndCreateKafkaBasedLog(TOPIC, DEFAULT_DISTRIBUTED_CONFIG);
    configStorage.start();
    // Should see a single connector and its config should be the last one seen anywhere in the log
    ClusterConfigState configState = configStorage.snapshot();
    // Should always be next to be read, even if uncommitted
    assertEquals(6, configState.offset());
    assertTrue(configState.connectors().isEmpty());
    configStorage.stop();
    PowerMock.verifyAll();
}
Also used : ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) ClusterConfigState(org.apache.kafka.connect.runtime.distributed.ClusterConfigState) LinkedHashMap(java.util.LinkedHashMap) Struct(org.apache.kafka.connect.data.Struct) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Example 5 with ClusterConfigState

use of org.apache.kafka.connect.runtime.distributed.ClusterConfigState in project kafka by apache.

the class KafkaConfigBackingStoreTest method testBackgroundUpdateTargetState.

@Test
public void testBackgroundUpdateTargetState() throws Exception {
    // verify that we handle target state changes correctly when they come up through the log
    expectConfigure();
    List<ConsumerRecord<String, byte[]>> existingRecords = Arrays.asList(new ConsumerRecord<>(TOPIC, 0, 0, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, CONNECTOR_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(0)), new ConsumerRecord<>(TOPIC, 0, 1, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TASK_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(1)), new ConsumerRecord<>(TOPIC, 0, 2, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, TASK_CONFIG_KEYS.get(1), CONFIGS_SERIALIZED.get(2)), new ConsumerRecord<>(TOPIC, 0, 3, 0L, TimestampType.CREATE_TIME, 0L, 0, 0, COMMIT_TASKS_CONFIG_KEYS.get(0), CONFIGS_SERIALIZED.get(3)));
    LinkedHashMap<byte[], Struct> deserialized = new LinkedHashMap();
    deserialized.put(CONFIGS_SERIALIZED.get(0), CONNECTOR_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(1), TASK_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(2), TASK_CONFIG_STRUCTS.get(0));
    deserialized.put(CONFIGS_SERIALIZED.get(3), TASKS_COMMIT_STRUCT_TWO_TASK_CONNECTOR);
    logOffset = 5;
    expectStart(existingRecords, deserialized);
    expectRead(TARGET_STATE_KEYS.get(0), CONFIGS_SERIALIZED.get(0), TARGET_STATE_PAUSED);
    configUpdateListener.onConnectorTargetStateChange(CONNECTOR_IDS.get(0));
    EasyMock.expectLastCall();
    expectStop();
    PowerMock.replayAll();
    configStorage.setupAndCreateKafkaBasedLog(TOPIC, DEFAULT_DISTRIBUTED_CONFIG);
    configStorage.start();
    // Should see a single connector with initial state paused
    ClusterConfigState configState = configStorage.snapshot();
    assertEquals(TargetState.STARTED, configState.targetState(CONNECTOR_IDS.get(0)));
    configStorage.refresh(0, TimeUnit.SECONDS);
    configStorage.stop();
    PowerMock.verifyAll();
}
Also used : ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) ClusterConfigState(org.apache.kafka.connect.runtime.distributed.ClusterConfigState) LinkedHashMap(java.util.LinkedHashMap) Struct(org.apache.kafka.connect.data.Struct) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Aggregations

ClusterConfigState (org.apache.kafka.connect.runtime.distributed.ClusterConfigState)11 Test (org.junit.Test)11 PrepareForTest (org.powermock.core.classloader.annotations.PrepareForTest)11 LinkedHashMap (java.util.LinkedHashMap)10 ConsumerRecord (org.apache.kafka.clients.consumer.ConsumerRecord)8 Struct (org.apache.kafka.connect.data.Struct)8 HashMap (java.util.HashMap)3 Map (java.util.Map)2