/*
* Copyright 2014-2016 CyberVision, 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 org.kaaproject.kaa.server.appenders.flume.appender;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import org.apache.flume.Event;
import org.apache.flume.EventDeliveryException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.kaaproject.kaa.common.avro.AvroByteArrayConverter;
import org.kaaproject.kaa.common.dto.EndpointProfileDataDto;
import org.kaaproject.kaa.common.dto.logs.LogAppenderDto;
import org.kaaproject.kaa.server.appenders.flume.appender.client.FlumeClientManager;
import org.kaaproject.kaa.server.appenders.flume.appender.client.async.AppendBatchAsyncResultPojo;
import org.kaaproject.kaa.server.appenders.flume.config.gen.FlumeConfig;
import org.kaaproject.kaa.server.appenders.flume.config.gen.FlumeEventFormat;
import org.kaaproject.kaa.server.appenders.flume.config.gen.FlumeNode;
import org.kaaproject.kaa.server.appenders.flume.config.gen.FlumeNodes;
import org.kaaproject.kaa.server.common.log.shared.appender.LogDeliveryCallback;
import org.kaaproject.kaa.server.common.log.shared.appender.LogEvent;
import org.kaaproject.kaa.server.common.log.shared.appender.data.BaseLogEventPack;
import org.kaaproject.kaa.server.common.log.shared.avro.gen.RecordHeader;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.util.ReflectionTestUtils;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FlumeLogAppenderTest {
private static final Logger LOG = LoggerFactory.getLogger(FlumeLogAppenderTest.class);
private static final String APPLICATION_ID = "application_id";
private static final String APPENDER_ID = "appender_id";
private static final String APPENDER_NAME = "appender_name";
private FlumeLogAppender appender;
private FlumeEventBuilder flumeEventBuilder;
private FlumeClientManager<?> flumeClientManager;
private ExecutorService executor;
private ExecutorService callbackExecutor;
@Before
public void before() throws Exception {
appender = new FlumeLogAppender();
appender.setName(APPENDER_NAME);
appender.setAppenderId(APPENDER_ID);
flumeEventBuilder = mock(FlumeEventBuilder.class);
flumeClientManager = mock(FlumeClientManager.class);
executor = Executors.newFixedThreadPool(1);
callbackExecutor = Executors.newFixedThreadPool(1);
ReflectionTestUtils.setField(appender, "flumeEventBuilder", flumeEventBuilder);
ReflectionTestUtils.setField(appender, "flumeClientManager", flumeClientManager);
ReflectionTestUtils.setField(appender, "executor", executor);
ReflectionTestUtils.setField(appender, "callbackExecutor", callbackExecutor);
}
@Test
public void initTest() throws IOException {
LOG.debug("Init test for appender name: {}, id: {}", appender.getName(), appender.getAppenderId());
LogAppenderDto logAppender = new LogAppenderDto();
logAppender.setApplicationId(APPLICATION_ID);
logAppender.setId(APPENDER_ID);
FlumeNodes nodes = FlumeNodes.newBuilder()
.setFlumeNodes(Arrays.asList(new FlumeNode("localhost", 12121), new FlumeNode("localhost", 12122)))
.build();
FlumeConfig flumeConfig = FlumeConfig.newBuilder().setFlumeEventFormat(FlumeEventFormat.RECORDS_CONTAINER)
.setHostsBalancing(nodes).setExecutorThreadPoolSize(2).setCallbackThreadPoolSize(2)
.setClientsThreadPoolSize(2).setIncludeClientProfile(false).setIncludeServerProfile(false).build();
AvroByteArrayConverter<FlumeConfig> converter = new AvroByteArrayConverter<>(FlumeConfig.class);
byte[] rawConfiguration = converter.toByteArray(flumeConfig);
logAppender.setRawConfiguration(rawConfiguration);
appender.init(logAppender);
}
@Test
public void appendWithExceptionTest() throws EventDeliveryException, InterruptedException {
BaseLogEventPack eventPack = generateLogEventPack();
Mockito.when(
flumeEventBuilder.generateEvents(Mockito.any(BaseLogEventPack.class), Mockito.any(RecordHeader.class),
Mockito.anyString())).thenReturn(Collections.singletonList(Mockito.mock(Event.class)));
doThrow(new EventDeliveryException()).when(flumeClientManager).sendEventsToFlumeAsync(Mockito.anyList());
TestLogDeliveryCallback callback = new TestLogDeliveryCallback();
appender.doAppend(eventPack, callback);
Thread.sleep(3000);
Assert.assertTrue(callback.connectionError);
}
@Test
public void appendTest() throws EventDeliveryException, InterruptedException {
BaseLogEventPack eventPack = generateLogEventPack();
ListeningExecutorService rpcES = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
Mockito.when(
flumeEventBuilder.generateEvents(Mockito.any(BaseLogEventPack.class), Mockito.any(RecordHeader.class),
Mockito.anyString())).thenReturn(Collections.singletonList(Mockito.mock(Event.class)));
Mockito.when(flumeClientManager.sendEventsToFlumeAsync(Mockito.anyList()))
.thenReturn(rpcES.submit(new Callable<AppendBatchAsyncResultPojo>() {
public AppendBatchAsyncResultPojo call() throws Exception {
return new AppendBatchAsyncResultPojo(true,
Collections.singletonList(Mockito.mock(Event.class)));
}
}));
TestLogDeliveryCallback callback = new TestLogDeliveryCallback();
appender.doAppend(eventPack, callback);
Thread.sleep(3000);
Assert.assertTrue(callback.success);
}
@Test
public void appendWhenClosedTest() {
appender.close();
BaseLogEventPack eventPack = generateLogEventPack();
TestLogDeliveryCallback callback = new TestLogDeliveryCallback();
appender.doAppend(eventPack, callback);
Assert.assertTrue(callback.internallError);
}
@Test
public void appendWithEmptyClientManagerTest() throws EventDeliveryException {
BaseLogEventPack eventPack = generateLogEventPack();
ReflectionTestUtils.setField(appender, "flumeClientManager", null);
TestLogDeliveryCallback callback = new TestLogDeliveryCallback();
appender.doAppend(eventPack, callback);
Assert.assertTrue(callback.internallError);
}
private BaseLogEventPack generateLogEventPack() {
EndpointProfileDataDto profileDto = new EndpointProfileDataDto("1", UUID.randomUUID().toString(), 1, "", 1, "");
List<LogEvent> events = Collections.emptyList();
return new BaseLogEventPack(profileDto, System.currentTimeMillis(), 2, events);
}
private static class TestLogDeliveryCallback implements LogDeliveryCallback {
private volatile boolean success;
private volatile boolean internallError;
private volatile boolean connectionError;
private volatile boolean remoteError;
@Override
public void onSuccess() {
success = true;
}
@Override
public void onInternalError() {
internallError = true;
}
@Override
public void onConnectionError() {
connectionError = true;
}
@Override
public void onRemoteError() {
remoteError = true;
}
}
}