/* * 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.client.logging; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.kaaproject.kaa.client.channel.KaaChannelManager; import org.kaaproject.kaa.client.channel.LogTransport; import org.kaaproject.kaa.client.channel.failover.FailoverManager; import org.kaaproject.kaa.client.context.ExecutorContext; import org.kaaproject.kaa.client.logging.future.RecordFuture; import org.kaaproject.kaa.common.endpoint.gen.LogDeliveryErrorCode; import org.kaaproject.kaa.common.endpoint.gen.LogDeliveryStatus; import org.kaaproject.kaa.common.endpoint.gen.LogSyncRequest; import org.kaaproject.kaa.common.endpoint.gen.LogSyncResponse; import org.kaaproject.kaa.common.endpoint.gen.SyncResponseResultType; import org.kaaproject.kaa.schema.base.Log; import org.mockito.Mockito; import org.springframework.test.util.ReflectionTestUtils; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class DefaultLogCollectorTest { private static ExecutorContext executorContext; private static ScheduledExecutorService executor; @BeforeClass public static void beforeSuite() { executorContext = Mockito.mock(ExecutorContext.class); executor = Executors.newSingleThreadScheduledExecutor(); Mockito.when(executorContext.getApiExecutor()).thenReturn(new AbstractExecutorService() { @Override public void execute(Runnable command) { command.run(); } @Override public List<Runnable> shutdownNow() { // TODO Auto-generated method stub return null; } @Override public void shutdown() { // TODO Auto-generated method stub } @Override public boolean isTerminated() { // TODO Auto-generated method stub return false; } @Override public boolean isShutdown() { // TODO Auto-generated method stub return false; } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { // TODO Auto-generated method stub return false; } }); Mockito.when(executorContext.getCallbackExecutor()).thenReturn(executor); Mockito.when(executorContext.getScheduledExecutor()).thenReturn(executor); } @AfterClass public static void afterSuite() { executor.shutdown(); } @Test public void testDefaultUploadConfiguration() { KaaChannelManager channelManager = Mockito.mock(KaaChannelManager.class); FailoverManager failoverManager = Mockito.mock(FailoverManager.class); LogTransport transport = Mockito.mock(LogTransport.class); AbstractLogCollector logCollector = new DefaultLogCollector(transport, executorContext, channelManager, failoverManager); DefaultLogUploadStrategy strategy = new DefaultLogUploadStrategy(); strategy.setCountThreshold(5); logCollector.setStrategy(strategy); Log record = new Log(); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); verify(transport, times(0)).sync(); logCollector.addLogRecord(record); verify(transport, Mockito.timeout(1000).times(1)).sync(); } @Test public void testStorageStatusAffect() { KaaChannelManager channelManager = Mockito.mock(KaaChannelManager.class); FailoverManager failoverManager = Mockito.mock(FailoverManager.class); LogTransport transport = Mockito.mock(LogTransport.class); AbstractLogCollector logCollector = new DefaultLogCollector(transport, executorContext, channelManager, failoverManager); LogStorage storage = Mockito.mock(LogStorage.class); logCollector.setStorage(storage); Log record = new Log(); Mockito.when(storage.addLogRecord(Mockito.any(LogRecord.class))).thenReturn(new BucketInfo(1, 1)); Mockito.when(storage.getStatus()).thenReturn(new LogStorageStatus() { @Override public long getRecordCount() { return 1; } @Override public long getConsumedVolume() { return 1; } }); logCollector.addLogRecord(record); verify(transport, times(0)).sync(); Mockito.when(storage.getStatus()).thenReturn(new LogStorageStatus() { @Override public long getRecordCount() { return 1; } @Override public long getConsumedVolume() { return 1024 * 1024; } }); logCollector.addLogRecord(record); verify(transport, Mockito.timeout(1000).times(1)).sync(); } @Test public void testLogUploadRequestAndSuccessResponse() throws Exception { KaaChannelManager channelManager = Mockito.mock(KaaChannelManager.class); FailoverManager failoverManager = Mockito.mock(FailoverManager.class); LogDeliveryListener deliveryListener = Mockito.mock(LogDeliveryListener.class); LogTransport transport = Mockito.mock(LogTransport.class); AbstractLogCollector logCollector = new DefaultLogCollector(transport, executorContext, channelManager, failoverManager); DefaultLogUploadStrategy strategy = Mockito.spy(new DefaultLogUploadStrategy()); logCollector.setStrategy(strategy); LogStorage storage = Mockito.mock(LogStorage.class); logCollector.setStorage(storage); Log record = new Log(); Mockito.when(storage.addLogRecord(Mockito.any(LogRecord.class))).thenReturn(new BucketInfo(1, 1)); Mockito.when(storage.getStatus()).thenReturn(new LogStorageStatus() { @Override public long getRecordCount() { return 1; } @Override public long getConsumedVolume() { return 1; } }); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); Mockito.when(storage.getStatus()).thenReturn(new LogStorageStatus() { @Override public long getRecordCount() { return 1; } @Override public long getConsumedVolume() { return 1024 * 1024; } }); logCollector.addLogRecord(record); Mockito.when(storage.getNextBucket()).thenReturn( new LogBucket(1, Arrays.asList(new LogRecord(record), new LogRecord(record), new LogRecord(record)))); LogSyncRequest request1 = new LogSyncRequest(); logCollector.fillSyncRequest(request1); Assert.assertEquals(3, request1.getLogEntries().size()); LogSyncResponse uploadResponse = new LogSyncResponse(); LogDeliveryStatus status = new LogDeliveryStatus(request1.getRequestId(), SyncResponseResultType.SUCCESS, null); uploadResponse.setDeliveryStatuses(Collections.singletonList(status)); logCollector.setLogDeliveryListener(deliveryListener); logCollector.onLogResponse(uploadResponse); verify(deliveryListener, Mockito.timeout(1000)).onLogDeliverySuccess(Mockito.any(BucketInfo.class)); verify(transport, Mockito.timeout(1000).times(2)).sync(); } @Test public void testLogUploadAndFailureResponse() throws IOException, InterruptedException { KaaChannelManager channelManager = Mockito.mock(KaaChannelManager.class); FailoverManager failoverManager = Mockito.mock(FailoverManager.class); LogDeliveryListener deliveryListener = Mockito.mock(LogDeliveryListener.class); LogTransport transport = Mockito.mock(LogTransport.class); AbstractLogCollector logCollector = new DefaultLogCollector(transport, executorContext, channelManager, failoverManager); DefaultLogUploadStrategy strategy = Mockito.spy(new DefaultLogUploadStrategy()); strategy.setRetryPeriod(0); logCollector.setStrategy(strategy); LogStorage storage = Mockito.mock(LogStorage.class); logCollector.setStorage(storage); Log record = new Log(); Mockito.when(storage.addLogRecord(Mockito.any(LogRecord.class))).thenReturn(new BucketInfo(1, 1)); Mockito.when(storage.getStatus()).thenReturn(new LogStorageStatus() { @Override public long getRecordCount() { return 1; } @Override public long getConsumedVolume() { return 1; } }); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); Mockito.when(storage.addLogRecord(Mockito.any(LogRecord.class))).thenReturn(new BucketInfo(1, 1)); Mockito.when(storage.getStatus()).thenReturn(new LogStorageStatus() { @Override public long getRecordCount() { return 1; } @Override public long getConsumedVolume() { return 1024 * 1024; } }); logCollector.addLogRecord(record); Mockito.when(storage.getNextBucket()).thenReturn( new LogBucket(1, Arrays.asList(new LogRecord(record), new LogRecord(record), new LogRecord(record)))); LogSyncRequest request1 = new LogSyncRequest(); logCollector.fillSyncRequest(request1); Assert.assertEquals(3, request1.getLogEntries().size()); LogSyncResponse uploadResponse = new LogSyncResponse(); LogDeliveryStatus status = new LogDeliveryStatus(request1.getRequestId(), SyncResponseResultType.FAILURE, LogDeliveryErrorCode.NO_APPENDERS_CONFIGURED); uploadResponse.setDeliveryStatuses(Collections.singletonList(status)); logCollector.setLogDeliveryListener(deliveryListener); logCollector.onLogResponse(uploadResponse); LogFailoverCommand controller = (LogFailoverCommand) ReflectionTestUtils.getField(logCollector, "controller"); verify(deliveryListener, Mockito.timeout(1000)).onLogDeliveryFailure(Mockito.any(BucketInfo.class)); verify(strategy, Mockito.timeout(1000)).onFailure(controller, LogDeliveryErrorCode.NO_APPENDERS_CONFIGURED); verify(transport, Mockito.timeout(1000).times(2)).sync(); reset(transport); Thread.sleep(1000); verify(transport, never()).sync(); } @Test public void testTimeout() throws Exception { int timeout = 2; // in seconds KaaChannelManager channelManager = Mockito.mock(KaaChannelManager.class); FailoverManager failoverManager = Mockito.mock(FailoverManager.class); LogTransport transport = Mockito.mock(LogTransport.class); LogDeliveryListener deliveryListener = Mockito.mock(LogDeliveryListener.class); AbstractLogCollector logCollector = new DefaultLogCollector(transport, executorContext, channelManager, failoverManager); DefaultLogUploadStrategy tmp = new DefaultLogUploadStrategy(); tmp.setTimeout(timeout); LogUploadStrategy strategy = Mockito.spy(tmp); logCollector.setLogDeliveryListener(deliveryListener); logCollector.setStrategy(strategy); Log record = new Log(); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); logCollector.addLogRecord(record); Mockito.verify(strategy, Mockito.times(0)).onTimeout(Mockito.any(LogFailoverCommand.class)); LogSyncRequest request1 = Mockito.mock(LogSyncRequest.class); logCollector.fillSyncRequest(request1); Thread.sleep(timeout / 2 * 1000); Mockito.verify(strategy, Mockito.times(0)).onTimeout(Mockito.any(LogFailoverCommand.class)); Thread.sleep(timeout / 2 * 1000); logCollector.addLogRecord(record); verify(deliveryListener, Mockito.timeout(1000)).onLogDeliveryTimeout(Mockito.any(BucketInfo.class)); Mockito.verify(strategy, Mockito.timeout(1000).times(1)).onTimeout(Mockito.any(LogFailoverCommand.class)); } @Test public void testBucketFuture() throws Exception { int defaultId = 42; int logCount = 5; KaaChannelManager channelManager = Mockito.mock(KaaChannelManager.class); FailoverManager failoverManager = Mockito.mock(FailoverManager.class); LogTransport transport = Mockito.mock(LogTransport.class); LogStorage storage = Mockito.mock(LogStorage.class); AbstractLogCollector logCollector = new DefaultLogCollector(transport, executorContext, channelManager, failoverManager); logCollector.setStorage(storage); Mockito.when(storage.getStatus()).thenReturn(new LogStorageStatus() { @Override public long getRecordCount() { return 1; } @Override public long getConsumedVolume() { return 1; } }); DefaultLogUploadStrategy strategy = new DefaultLogUploadStrategy() { @Override public LogUploadStrategyDecision isUploadNeeded(LogStorageStatus status) { return LogUploadStrategyDecision.UPLOAD; } }; logCollector.setStrategy(strategy); LogSyncResponse response = new LogSyncResponse(); List<LogDeliveryStatus> statuses = new ArrayList<>(); LogDeliveryStatus status = new LogDeliveryStatus(defaultId, SyncResponseResultType.SUCCESS, null); statuses.add(status); response.setDeliveryStatuses(statuses); BucketInfo bucketInfo = new BucketInfo(status.getRequestId(), logCount); Mockito.when(storage.addLogRecord(Mockito.any(LogRecord.class))).thenReturn(bucketInfo); List<LogRecord> logRecords = new ArrayList<>(); logRecords.add(new LogRecord()); LogBucket logBlock = new LogBucket(defaultId, logRecords); Mockito.when(storage.getNextBucket()).thenReturn(logBlock); List<RecordFuture> deliveryFutures = new LinkedList<RecordFuture>(); for (int i = 0; i < logCount; ++i) { deliveryFutures.add(logCollector.addLogRecord(new Log())); } LogSyncRequest request = new LogSyncRequest(); logCollector.fillSyncRequest(request); logCollector.onLogResponse(response); for (RecordFuture future : deliveryFutures) { Assert.assertEquals(defaultId, future.get().getBucketInfo().getBucketId()); } } @Test public void testMaxParallelUpload() throws Exception { testMaxParallelUploadHelper(0); testMaxParallelUploadHelper(3); testMaxParallelUploadHelper(5); } private void testMaxParallelUploadHelper(int maxParallelUpload) throws Exception { KaaChannelManager channelManager = Mockito.mock(KaaChannelManager.class); FailoverManager failoverManager = Mockito.mock(FailoverManager.class); LogTransport transport = Mockito.mock(LogTransport.class); AbstractLogCollector logCollector = new DefaultLogCollector(transport, executorContext, channelManager, failoverManager); DefaultLogUploadStrategy strategy = Mockito.spy(new DefaultLogUploadStrategy()); strategy.setMaxParallelUploads(maxParallelUpload); logCollector.setStrategy(strategy); LogSyncRequest request = Mockito.spy(new LogSyncRequest()); List<LogDeliveryStatus> statuses = new ArrayList<>(); for (int i = 0; i < maxParallelUpload; i++) { logCollector.addLogRecord(new Log()); logCollector.fillSyncRequest(request); statuses.add(new LogDeliveryStatus(request.getRequestId(), SyncResponseResultType.SUCCESS, null)); } logCollector.addLogRecord(new Log()); logCollector.fillSyncRequest(request); Mockito.verify(request, Mockito.times(maxParallelUpload)).setRequestId(Mockito.any(Integer.class)); if (statuses.isEmpty() && maxParallelUpload == 0) { return; } LogSyncResponse response = new LogSyncResponse(statuses); logCollector.onLogResponse(response); Mockito.reset(request); logCollector.fillSyncRequest(request); Mockito.verify(request, Mockito.times(1)).setRequestId(Mockito.any(Integer.class)); } @Test public void testMaxParallelUploadWithSyncAll() throws Exception { testMaxParallelUploadSyncHelper(0); testMaxParallelUploadSyncHelper(3); testMaxParallelUploadSyncHelper(5); } private void testMaxParallelUploadSyncHelper(int maxParallelUpload) throws Exception { KaaChannelManager channelManager = Mockito.mock(KaaChannelManager.class); FailoverManager failoverManager = Mockito.mock(FailoverManager.class); LogTransport transport = Mockito.mock(LogTransport.class); AbstractLogCollector logCollector = new DefaultLogCollector(transport, executorContext, channelManager, failoverManager); DefaultLogUploadStrategy strategy = new DefaultLogUploadStrategy() { @Override public LogUploadStrategyDecision isUploadNeeded(LogStorageStatus status) { return LogUploadStrategyDecision.UPLOAD; } }; strategy.setMaxParallelUploads(maxParallelUpload); logCollector.setStrategy(strategy); LogSyncRequest request = new LogSyncRequest(); List<LogDeliveryStatus> statuses = new ArrayList<>(); for (int i = 0; i < maxParallelUpload; i++) { logCollector.addLogRecord(new Log()); logCollector.fillSyncRequest(request); } LogSyncResponse response = new LogSyncResponse(statuses); logCollector.onLogResponse(response); Mockito.verify(transport, Mockito.times(maxParallelUpload)).sync(); } }