/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.storm.kafka;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.curator.test.TestingServer;
import org.apache.storm.Config;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import kafka.javaapi.consumer.SimpleConsumer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.when;
public class ZkCoordinatorTest {
@Mock
private DynamicBrokersReader reader;
@Mock
private DynamicPartitionConnections dynamicPartitionConnections;
private KafkaTestBroker broker = new KafkaTestBroker();
private TestingServer server;
private Map<String, Object> stormConf = new HashMap<>();
private SpoutConfig spoutConfig;
private ZkState state;
private SimpleConsumer simpleConsumer;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
server = new TestingServer();
String connectionString = server.getConnectString();
ZkHosts hosts = new ZkHosts(connectionString);
hosts.refreshFreqSecs = 1;
spoutConfig = new SpoutConfig(hosts, "topic", "/test", "id");
Map<String, Object> conf = buildZookeeperConfig(server);
state = new ZkState(conf);
simpleConsumer = new SimpleConsumer("localhost", broker.getPort(), 60000, 1024, "testClient");
when(dynamicPartitionConnections.register(any(Broker.class), any(String.class), anyInt()))
.thenReturn(simpleConsumer);
}
private Map<String, Object> buildZookeeperConfig(TestingServer aServer) {
Map<String, Object> conf = new HashMap<>();
conf.put(Config.TRANSACTIONAL_ZOOKEEPER_PORT, aServer.getPort());
conf.put(Config.TRANSACTIONAL_ZOOKEEPER_SERVERS, Arrays.asList("localhost"));
conf.put(Config.STORM_ZOOKEEPER_SESSION_TIMEOUT, 20000);
conf.put(Config.STORM_ZOOKEEPER_CONNECTION_TIMEOUT, 20000);
conf.put(Config.STORM_ZOOKEEPER_RETRY_TIMES, 3);
conf.put(Config.STORM_ZOOKEEPER_RETRY_INTERVAL, 30);
return conf;
}
@After
public void shutdown() throws Exception {
simpleConsumer.close();
broker.shutdown();
server.close();
}
@Test
public void testOnePartitionPerTask() throws Exception {
int totalTasks = 64;
int partitionsPerTask = 1;
List<ZkCoordinator> coordinatorList = buildCoordinators(totalTasks / partitionsPerTask);
when(reader.getBrokerInfo())
.thenReturn(TestUtils.buildPartitionInfoList(TestUtils.buildPartitionInfo(totalTasks)));
for (ZkCoordinator coordinator : coordinatorList) {
List<PartitionManager> myManagedPartitions = coordinator.getMyManagedPartitions();
assertEquals(partitionsPerTask, myManagedPartitions.size());
assertEquals(coordinator.getTaskIndex(), myManagedPartitions.get(0).getPartition().partition);
}
}
@Test
public void testPartitionsChange() throws Exception {
final int totalTasks = 64;
int partitionsPerTask = 2;
List<ZkCoordinator> coordinatorList = buildCoordinators(totalTasks / partitionsPerTask);
when(reader.getBrokerInfo())
.thenReturn(TestUtils.buildPartitionInfoList(
TestUtils.buildPartitionInfo(totalTasks, 9092)));
List<List<PartitionManager>> partitionManagersBeforeRefresh =
getPartitionManagers(coordinatorList);
waitForRefresh();
when(reader.getBrokerInfo())
.thenReturn(TestUtils.buildPartitionInfoList(
TestUtils.buildPartitionInfo(totalTasks, 9093)));
List<List<PartitionManager>> partitionManagersAfterRefresh =
getPartitionManagers(coordinatorList);
assertEquals(partitionManagersAfterRefresh.size(), partitionManagersAfterRefresh.size());
Iterator<List<PartitionManager>> iterator = partitionManagersAfterRefresh.iterator();
for (List<PartitionManager> partitionManagersBefore : partitionManagersBeforeRefresh) {
List<PartitionManager> partitionManagersAfter = iterator.next();
assertPartitionsAreDifferent(partitionManagersBefore,
partitionManagersAfter,
partitionsPerTask);
}
}
private void assertPartitionsAreDifferent(List<PartitionManager> partitionManagersBefore,
List<PartitionManager> partitionManagersAfter,
int partitionsPerTask) {
assertEquals(partitionsPerTask, partitionManagersBefore.size());
assertEquals(partitionManagersBefore.size(), partitionManagersAfter.size());
for (int i = 0; i < partitionsPerTask; i++) {
assertNotEquals(partitionManagersBefore.get(i).getPartition(),
partitionManagersAfter.get(i).getPartition());
}
}
private List<List<PartitionManager>> getPartitionManagers(List<ZkCoordinator> coordinatorList) {
List<List<PartitionManager>> partitions = new ArrayList<>();
for (ZkCoordinator coordinator : coordinatorList) {
partitions.add(coordinator.getMyManagedPartitions());
}
return partitions;
}
private void waitForRefresh() throws InterruptedException {
Thread.sleep(((ZkHosts) spoutConfig.hosts).refreshFreqSecs * 1000 + 1);
}
private List<ZkCoordinator> buildCoordinators(int totalTasks) {
List<ZkCoordinator> coordinatorList = new ArrayList<ZkCoordinator>();
for (int i = 0; i < totalTasks; i++) {
ZkCoordinator coordinator =
new ZkCoordinator(dynamicPartitionConnections,
stormConf,
spoutConfig,
state,
i,
totalTasks,
"test-id",
reader);
coordinatorList.add(coordinator);
}
return coordinatorList;
}
}