/** * Copyright 2015 Confluent Inc. * * Licensed 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 io.confluent.kafkarest.integration; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.List; import java.util.Properties; import javax.ws.rs.core.GenericType; import javax.ws.rs.core.Response; import io.confluent.kafkarest.Errors; import io.confluent.kafkarest.Versions; import io.confluent.kafkarest.entities.BrokerList; import io.confluent.kafkarest.entities.Partition; import io.confluent.kafkarest.entities.PartitionReplica; import io.confluent.kafkarest.entities.Topic; import scala.collection.JavaConversions; import static io.confluent.kafkarest.TestUtils.assertErrorResponse; import static io.confluent.kafkarest.TestUtils.assertOKResponse; import static io.confluent.kafkarest.TestUtils.tryReadEntityOrLog; import static org.junit.Assert.assertEquals; /** * Tests metadata access against a real cluster. This isn't exhaustive since the unit tests cover * corner cases; rather it verifies the basic functionality works against a real cluster. */ public class MetadataAPITest extends ClusterTestHarness { private static final String topic1Name = "topic1"; private static final List<Partition> topic1Partitions = Arrays.asList( new Partition(0, 0, Arrays.asList( new PartitionReplica(0, true, true), new PartitionReplica(1, false, false) )) ); private static final Topic topic1 = new Topic(topic1Name, new Properties(), topic1Partitions); private static final String topic2Name = "topic2"; private static final List<Partition> topic2Partitions = Arrays.asList( new Partition(0, 0, Arrays.asList( new PartitionReplica(0, true, true), new PartitionReplica(1, false, false) )), new Partition(1, 1, Arrays.asList( new PartitionReplica(0, false, true), new PartitionReplica(1, true, true) )) ); private static final Properties topic2Configs; private static final Topic topic2; static { topic2Configs = new Properties(); topic2Configs.setProperty("cleanup.policy", "delete"); topic2 = new Topic(topic2Name, topic2Configs, topic2Partitions); } private static final int numReplicas = 2; public MetadataAPITest() { super(2, false); } @Before @Override public void setUp() throws Exception { super.setUp(); kafka.utils.TestUtils.createTopic(zkUtils, topic1Name, topic1Partitions.size(), numReplicas, JavaConversions.asScalaBuffer(this.servers), new Properties()); kafka.utils.TestUtils.createTopic(zkUtils, topic2Name, topic2Partitions.size(), numReplicas, JavaConversions.asScalaBuffer(this.servers), topic2Configs); } @Test public void testBrokers() throws InterruptedException { // Listing Response response = request("/brokers").get(); assertOKResponse(response, Versions.KAFKA_MOST_SPECIFIC_DEFAULT); final BrokerList brokers = tryReadEntityOrLog(response, BrokerList.class); assertEquals(new BrokerList(Arrays.asList(0, 1)), brokers); } /* This should work, but due to the lack of timeouts in ZkClient, if ZK is down some calls * will just block forever, see https://issues.apache.org/jira/browse/KAFKA-1907. We should * reenable this once we can apply timeouts to ZK operations. */ /* @Test public void testZkFailure() throws InterruptedException { // Kill ZK so the request will generate an error. zookeeper.shutdown(); // Since this is handled via an ExceptionMapper, testing one endpoint is good enough Response response = request("/brokers").get(); assertErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, response, Errors.ZOOKEEPER_ERROR_ERROR_CODE, Errors.ZOOKEEPER_ERROR_MESSAGE, Versions.KAFKA_MOST_SPECIFIC_DEFAULT); } */ @Test public void testTopicsList() throws InterruptedException { // Listing Response response = request("/topics").get(); assertOKResponse(response, Versions.KAFKA_MOST_SPECIFIC_DEFAULT); final List<String> topicsResponse = tryReadEntityOrLog(response, new GenericType<List<String>>() { }); assertEquals( Arrays.asList(topic1Name, topic2Name), topicsResponse); // Get topic Response response1 = request("/topics/{topic}", "topic", topic1Name).get(); assertOKResponse(response, Versions.KAFKA_MOST_SPECIFIC_DEFAULT); final Topic topic1Response = tryReadEntityOrLog(response1, Topic.class); // Just verify some basic properties because the exact values can vary based on replica // assignment, leader election assertEquals(topic1.getName(), topic1Response.getName()); assertEquals(topic1.getConfigs(), topic1Response.getConfigs()); assertEquals(topic1Partitions.size(), topic1Response.getPartitions().size()); assertEquals(numReplicas, topic1Response.getPartitions().get(0).getReplicas().size()); // Get invalid topic final Response invalidResponse = request("/topics/{topic}", "topic", "topicdoesntexist").get(); assertErrorResponse(Response.Status.NOT_FOUND, invalidResponse, Errors.TOPIC_NOT_FOUND_ERROR_CODE, Errors.TOPIC_NOT_FOUND_MESSAGE, Versions.KAFKA_MOST_SPECIFIC_DEFAULT); } @Test public void testPartitionsList() throws InterruptedException { // Listing Response response = request("/topics/" + topic1Name + "/partitions").get(); assertOKResponse(response, Versions.KAFKA_MOST_SPECIFIC_DEFAULT); final List<Partition> partitions1Response = tryReadEntityOrLog(response, new GenericType<List<Partition>>() { }); // Just verify some basic properties because the exact values can vary based on replica // assignment, leader election assertEquals(topic1Partitions.size(), partitions1Response.size()); assertEquals(numReplicas, partitions1Response.get(0).getReplicas().size()); response = request("/topics/" + topic2Name + "/partitions").get(); assertOKResponse(response, Versions.KAFKA_MOST_SPECIFIC_DEFAULT); final List<Partition> partitions2Response = tryReadEntityOrLog(response, new GenericType<List<Partition>>() { }); assertEquals(topic2Partitions.size(), partitions2Response.size()); assertEquals(numReplicas, partitions2Response.get(0).getReplicas().size()); assertEquals(numReplicas, partitions2Response.get(1).getReplicas().size()); // Get single partition response = request("/topics/" + topic1Name + "/partitions/0").get(); assertOKResponse(response, Versions.KAFKA_MOST_SPECIFIC_DEFAULT); final Partition getPartitionResponse = tryReadEntityOrLog(response, Partition.class); assertEquals(0, getPartitionResponse.getPartition()); assertEquals(numReplicas, getPartitionResponse.getReplicas().size()); // Get invalid partition final Response invalidResponse = request("/topics/topic1/partitions/1000").get(); assertErrorResponse(Response.Status.NOT_FOUND, invalidResponse, Errors.PARTITION_NOT_FOUND_ERROR_CODE, Errors.PARTITION_NOT_FOUND_MESSAGE, Versions.KAFKA_MOST_SPECIFIC_DEFAULT); } }