/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.kafka.streams.processor.internals;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.Node;
import org.apache.kafka.common.PartitionInfo;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.metrics.Metrics;
import org.apache.kafka.common.utils.MockTime;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.errors.StreamsException;
import org.apache.kafka.streams.kstream.KStreamBuilder;
import org.apache.kafka.streams.processor.StateStore;
import org.apache.kafka.test.TestUtils;
import org.junit.Before;
import org.junit.Test;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class GlobalStreamThreadTest {
private final KStreamBuilder builder = new KStreamBuilder();
private final MockConsumer<byte[], byte[]> mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
private final MockTime time = new MockTime();
private GlobalStreamThread globalStreamThread;
private StreamsConfig config;
@Before
public void before() {
builder.globalTable("foo", "bar");
final HashMap<String, Object> properties = new HashMap<>();
properties.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "blah");
properties.put(StreamsConfig.APPLICATION_ID_CONFIG, "blah");
config = new StreamsConfig(properties);
globalStreamThread = new GlobalStreamThread(builder.buildGlobalStateTopology(),
config,
mockConsumer,
new StateDirectory("appId", TestUtils.tempDirectory().getPath(), time),
new Metrics(),
new MockTime(),
"clientId");
}
@Test
public void shouldThrowStreamsExceptionOnStartupIfThereIsAStreamsException() throws Exception {
// should throw as the MockConsumer hasn't been configured and there are no
// partitions available
try {
globalStreamThread.start();
fail("Should have thrown StreamsException if start up failed");
} catch (StreamsException e) {
// ok
}
assertFalse(globalStreamThread.stillRunning());
}
@SuppressWarnings("unchecked")
@Test
public void shouldThrowStreamsExceptionOnStartupIfExceptionOccurred() throws Exception {
final MockConsumer<byte[], byte[]> mockConsumer = new MockConsumer(OffsetResetStrategy.EARLIEST) {
@Override
public List<PartitionInfo> partitionsFor(final String topic) {
throw new RuntimeException("KABOOM!");
}
};
globalStreamThread = new GlobalStreamThread(builder.buildGlobalStateTopology(),
config,
mockConsumer,
new StateDirectory("appId", TestUtils.tempDirectory().getPath(), time),
new Metrics(),
new MockTime(),
"clientId");
try {
globalStreamThread.start();
fail("Should have thrown StreamsException if start up failed");
} catch (StreamsException e) {
assertThat(e.getCause(), instanceOf(RuntimeException.class));
assertThat(e.getCause().getMessage(), equalTo("KABOOM!"));
}
assertFalse(globalStreamThread.stillRunning());
}
@Test
public void shouldBeRunningAfterSuccesulStart() throws Exception {
initializeConsumer();
globalStreamThread.start();
assertTrue(globalStreamThread.stillRunning());
}
@Test(timeout = 30000)
public void shouldStopRunningWhenClosedByUser() throws Exception {
initializeConsumer();
globalStreamThread.start();
globalStreamThread.close();
globalStreamThread.join();
}
@Test
public void shouldCloseStateStoresOnClose() throws Exception {
initializeConsumer();
globalStreamThread.start();
final StateStore globalStore = builder.globalStateStores().get("bar");
assertTrue(globalStore.isOpen());
globalStreamThread.close();
globalStreamThread.join();
assertFalse(globalStore.isOpen());
}
private void initializeConsumer() {
mockConsumer.updatePartitions("foo", Collections.singletonList(new PartitionInfo("foo",
0,
null,
new Node[0],
new Node[0])));
final TopicPartition topicPartition = new TopicPartition("foo", 0);
mockConsumer.updateBeginningOffsets(Collections.singletonMap(topicPartition, 0L));
mockConsumer.updateEndOffsets(Collections.singletonMap(topicPartition, 0L));
}
}