/** * Copyright 2015, Xiaomi. * All rights reserved. * Author: yongxing@xiaomi.com */ package com.xiaomi.infra.galaxy.talos.consumer; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.xiaomi.infra.galaxy.talos.thrift.ConsumerService; import com.xiaomi.infra.galaxy.talos.thrift.ErrorCode; import com.xiaomi.infra.galaxy.talos.thrift.GalaxyTalosException; import com.xiaomi.infra.galaxy.talos.thrift.LockPartitionRequest; import com.xiaomi.infra.galaxy.talos.thrift.LockPartitionResponse; import com.xiaomi.infra.galaxy.talos.thrift.Message; import com.xiaomi.infra.galaxy.talos.thrift.MessageAndOffset; import com.xiaomi.infra.galaxy.talos.thrift.QueryOffsetRequest; import com.xiaomi.infra.galaxy.talos.thrift.QueryOffsetResponse; import com.xiaomi.infra.galaxy.talos.thrift.TopicTalosResourceName; import com.xiaomi.infra.galaxy.talos.thrift.UnlockPartitionRequest; import com.xiaomi.infra.galaxy.talos.thrift.UpdateOffsetRequest; import com.xiaomi.infra.galaxy.talos.thrift.UpdateOffsetResponse; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.when; public class PartitionFetcherTest { private static final Logger LOG = LoggerFactory.getLogger(PartitionFetcherTest.class); private static final String topicName = "MyTopic"; private static final String resourceName = "12345#MyTopic#34595fkdiso456i390"; private static final int partitionId = 7; private static final String consumerGroup = "MyConsumerGroup"; private static final String workerId = "workerId"; private static List<MessageAndOffset> messageAndOffsetList; private static List<MessageAndOffset> messageAndOffsetList2; private static ConsumerService.Iface consumerClientMock; private static SimpleConsumer simpleConsumerMock; private static MessageReader messageReaderMock; private static PartitionFetcher partitionFetcher; @Before public void setUp() throws Exception { messageAndOffsetList = new ArrayList<MessageAndOffset>(); messageAndOffsetList2 = new ArrayList<MessageAndOffset>(); MessageAndOffset messageAndOffset1 = new MessageAndOffset(new Message( ByteBuffer.wrap("message1".getBytes())), 1); MessageAndOffset messageAndOffset2 = new MessageAndOffset(new Message( ByteBuffer.wrap("message2".getBytes())), 2); MessageAndOffset messageAndOffset3 = new MessageAndOffset(new Message( ByteBuffer.wrap("message3".getBytes())), 3); messageAndOffsetList.add(messageAndOffset1); messageAndOffsetList.add(messageAndOffset2); messageAndOffsetList.add(messageAndOffset3); MessageAndOffset messageAndOffset4 = new MessageAndOffset(new Message( ByteBuffer.wrap("message4".getBytes())), 4); MessageAndOffset messageAndOffset5 = new MessageAndOffset(new Message( ByteBuffer.wrap("message5".getBytes())), 5); messageAndOffsetList2.add(messageAndOffset4); messageAndOffsetList2.add(messageAndOffset5); consumerClientMock = Mockito.mock(ConsumerService.Iface.class); simpleConsumerMock = Mockito.mock(SimpleConsumer.class); messageReaderMock = Mockito.mock(MessageReader.class); partitionFetcher = new PartitionFetcher(consumerGroup, topicName, new TopicTalosResourceName(resourceName), partitionId, workerId, consumerClientMock, simpleConsumerMock, messageReaderMock); // mock value for simpleConsumerMock and consumerClientMock when(simpleConsumerMock.fetchMessage(anyLong())) .thenReturn(messageAndOffsetList).thenReturn(messageAndOffsetList2); UpdateOffsetResponse updateOffsetResponse = new UpdateOffsetResponse(true); when(consumerClientMock.updateOffset(any(UpdateOffsetRequest.class))) .thenReturn(updateOffsetResponse); doNothing().when(consumerClientMock) .unlockPartition(any(UnlockPartitionRequest.class)); List<Integer> successPartitionList = new ArrayList<Integer>(); successPartitionList.add(partitionId); LockPartitionResponse lockPartitionResponse = new LockPartitionResponse( successPartitionList, new ArrayList<Integer>()); when(consumerClientMock.lockPartition(any(LockPartitionRequest.class))) .thenReturn(lockPartitionResponse); QueryOffsetResponse queryOffsetResponse = new QueryOffsetResponse(0); when(consumerClientMock.queryOffset(any(QueryOffsetRequest.class))) .thenReturn(queryOffsetResponse); } @After public void tearDown() { partitionFetcher.shutDown(); } @Test public void testLockFailedFromLockedToUnlocked() throws Exception { doThrow(new GalaxyTalosException()).when(consumerClientMock) .lockPartition(any(LockPartitionRequest.class)); partitionFetcher.lock(); // sleep to wait stealing lock failed Thread.sleep(50); assertEquals(false, partitionFetcher.isServing()); } @Test public void testLockFailedWhenNullSuccessList() throws Exception { List<Integer> successPartitionList = new ArrayList<Integer>(); LockPartitionResponse lockPartitionResponse = new LockPartitionResponse( successPartitionList, new ArrayList<Integer>()); when(consumerClientMock.lockPartition(any(LockPartitionRequest.class))) .thenReturn(lockPartitionResponse); partitionFetcher.lock(); // sleep to wait lock Thread.sleep(50); assertEquals(false, partitionFetcher.isServing()); } @Test public void testLockFailedWhenGetStartOffset() throws Exception { doThrow(new GalaxyTalosException()).when(messageReaderMock) .initStartOffset(); partitionFetcher.lock(); Thread.sleep(50); assertEquals(false, partitionFetcher.isServing()); } @Test public void testGetMessageAndCommitOffset() throws Exception { partitionFetcher.lock(); assertEquals(true, partitionFetcher.isHoldingLock()); Thread.sleep(100); assertEquals(true, partitionFetcher.isHoldingLock()); partitionFetcher.unlock(); assertEquals(true, partitionFetcher.isHoldingLock()); Thread.sleep(50); assertEquals(false, partitionFetcher.isServing()); } // check log for: 1) call message 2/3 times; // 2) commit offset 5 even if getMultiple messages @Test public void testCallGetMessageMultipleTimesAndCommitOffset() throws Exception { partitionFetcher.lock(); assertEquals(true, partitionFetcher.isHoldingLock()); Thread.sleep(500); assertEquals(true, partitionFetcher.isHoldingLock()); partitionFetcher.unlock(); } @Test public void testPartitionNotServing() throws Exception { when(simpleConsumerMock.fetchMessage(anyLong())) .thenThrow(new GalaxyTalosException().setErrorCode( ErrorCode.PARTITION_NOT_SERVING)); partitionFetcher.lock(); Thread.sleep(500); } @Test public void testOffsetOutOfRange() throws Exception { when(simpleConsumerMock.fetchMessage(anyLong())) .thenThrow(new GalaxyTalosException().setErrorCode( ErrorCode.MESSAGE_OFFSET_OUT_OF_RANGE)); partitionFetcher.lock(); Thread.sleep(500); } @Test public void testLockLock() throws Exception { partitionFetcher.lock(); Thread.sleep(50); partitionFetcher.lock(); Thread.sleep(50); } @Test public void testUnlockUnlock() throws Exception { partitionFetcher.lock(); partitionFetcher.unlock(); Thread.sleep(50); partitionFetcher.unlock(); } @Test public void testUnlockLock() throws Exception { partitionFetcher.lock(); partitionFetcher.unlock(); partitionFetcher.lock(); } }