/*
* Copyright 2011-2014 Proofpoint, 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 com.proofpoint.event.collector.combiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.proofpoint.event.collector.ServerConfig;
import com.proofpoint.testing.SerialScheduledExecutorService;
import org.mockito.stubbing.Stubber;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
public class TestScheduledCombiner
{
private static final int CHECK_DELAY_MILLIS = (int) MINUTES.toMillis(10);
private static final int PER_TYPE_CHECK_DELAY_MILLIS = (int) SECONDS.toMillis(10);
private static final int PER_TYPE_ITERATIONS_PER_CHECK = CHECK_DELAY_MILLIS / PER_TYPE_CHECK_DELAY_MILLIS;
private static final String EVENT_TYPE_A = "eventA";
private static final String EVENT_TYPE_B = "eventB";
private static final String EVENT_TYPE_C = "eventC";
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "objectCombiner is null")
public void testConstructorNullObjectCombiner()
{
ScheduledExecutorService executor = new SerialScheduledExecutorService();
new ScheduledCombiner(null, executor, executor, executor, createServerConfig());
}
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "executorService is null")
public void testConstructorNullExecutorService()
{
ScheduledExecutorService executor = new SerialScheduledExecutorService();
new ScheduledCombiner(mock(StoredObjectCombiner.class), null, executor, executor, createServerConfig());
}
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "highPriorityExecutorService is null")
public void testConstructorNullHighPriorityExecutorService()
{
ScheduledExecutorService executor = new SerialScheduledExecutorService();
new ScheduledCombiner(mock(StoredObjectCombiner.class), executor, null, executor, createServerConfig().setCombinerHighPriorityEventTypes(ImmutableSet.of("EventA")));
}
@Test
public void testConstructorNullHighPriorityExecutorServiceWithoutAny()
{
ScheduledExecutorService executor = new SerialScheduledExecutorService();
new ScheduledCombiner(mock(StoredObjectCombiner.class), executor, null, executor, createServerConfig());
}
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "lowPriorityExecutorService is null")
public void testConstructorNullLowPriorityExecutorService()
{
ScheduledExecutorService executor = new SerialScheduledExecutorService();
new ScheduledCombiner(mock(StoredObjectCombiner.class), executor, executor, null, new ServerConfig().setCombinerLowPriorityEventTypes(ImmutableSet.of("EventA")));
}
@Test
public void testConstructorNullLowPriorityExecutorServiceWithoutAny()
{
ScheduledExecutorService executor = new SerialScheduledExecutorService();
new ScheduledCombiner(mock(StoredObjectCombiner.class), executor, executor, null, createServerConfig());
}
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "config is null")
public void testConstructorNullConfig()
{
ScheduledExecutorService executor = new SerialScheduledExecutorService();
new ScheduledCombiner(mock(StoredObjectCombiner.class), executor, executor, executor, null);
}
@Test
public void testScheduleFrequency()
throws IOException
{
SerialScheduledExecutorService executorService = new SerialScheduledExecutorService();
StoredObjectCombiner storedObjectCombiner = createStoredObjectCombiner(ImmutableList.of(EVENT_TYPE_A), ImmutableList.of(EVENT_TYPE_A, EVENT_TYPE_B), ImmutableList.of(EVENT_TYPE_A, EVENT_TYPE_B, EVENT_TYPE_C));
ScheduledCombiner scheduledCombiner = new ScheduledCombiner(storedObjectCombiner, executorService, executorService, executorService, createServerConfig());
scheduledCombiner.start();
// Initial delay to check for new event types is 0, frequency is CHECK_DELAY_MILLIS.
// Initial delay to check for events of a given type is 0, delay between
// iterations is PER_TYPE_CHECK_DELAY_MILLIS.
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_A);
for (int i = 1; i < PER_TYPE_ITERATIONS_PER_CHECK; ++i) {
executorService.elapseTime(PER_TYPE_CHECK_DELAY_MILLIS - 1, MILLISECONDS);
verify(storedObjectCombiner, times(i)).combineObjects(EVENT_TYPE_A);
verify(storedObjectCombiner, never()).combineObjects(EVENT_TYPE_B);
executorService.elapseTime(1, MILLISECONDS);
verify(storedObjectCombiner, times(i + 1)).combineObjects(EVENT_TYPE_A);
verify(storedObjectCombiner, never()).combineObjects(EVENT_TYPE_B);
}
executorService.elapseTime(PER_TYPE_CHECK_DELAY_MILLIS - 1, MILLISECONDS);
verify(storedObjectCombiner, times(PER_TYPE_ITERATIONS_PER_CHECK)).combineObjects(EVENT_TYPE_A);
executorService.elapseTime(1, MILLISECONDS);
verify(storedObjectCombiner, times(PER_TYPE_ITERATIONS_PER_CHECK + 1)).combineObjects(EVENT_TYPE_A);
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_B);
verify(storedObjectCombiner, never()).combineObjects(EVENT_TYPE_C);
scheduledCombiner.destroy();
}
@Test
public void testScheduleFrequencyWhenDisabled()
throws IOException
{
SerialScheduledExecutorService executorService = new SerialScheduledExecutorService();
StoredObjectCombiner storedObjectCombiner = createStoredObjectCombiner();
ScheduledCombiner scheduledCombiner = new ScheduledCombiner(storedObjectCombiner, executorService, executorService, executorService, createServerConfig().setCombinerEnabled(false));
scheduledCombiner.start();
executorService.elapseTime(CHECK_DELAY_MILLIS * 10, MILLISECONDS);
verifyZeroInteractions(storedObjectCombiner);
scheduledCombiner.destroy();
}
@Test
public void testScheduleAgainAfterException()
throws IOException
{
SerialScheduledExecutorService executorService = new SerialScheduledExecutorService();
StoredObjectCombiner storedObjectCombiner = mock(StoredObjectCombiner.class);
ScheduledCombiner scheduledCombiner = new ScheduledCombiner(storedObjectCombiner, executorService, executorService, executorService, createServerConfig());
doReturn(ImmutableList.of())
.doThrow(new RuntimeException())
.doReturn(ImmutableList.of(EVENT_TYPE_A))
.when(storedObjectCombiner).listEventTypes();
scheduledCombiner.start();
executorService.elapseTime(CHECK_DELAY_MILLIS, MILLISECONDS);
verify(storedObjectCombiner, never()).combineObjects(any(String.class));
executorService.elapseTime(CHECK_DELAY_MILLIS, MILLISECONDS);
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_A);
scheduledCombiner.destroy();
}
@Test
public void testScheduleTypeAfterException()
{
SerialScheduledExecutorService executorService = new SerialScheduledExecutorService();
StoredObjectCombiner storedObjectCombiner = createStoredObjectCombiner(EVENT_TYPE_A);
ScheduledCombiner scheduledCombiner = new ScheduledCombiner(storedObjectCombiner, executorService, executorService, executorService, createServerConfig());
scheduledCombiner.start();
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_A);
doThrow(new RuntimeException())
.doNothing().when(storedObjectCombiner).combineObjects(any(String.class));
executorService.elapseTime(PER_TYPE_CHECK_DELAY_MILLIS, MILLISECONDS);
verify(storedObjectCombiner, times(2)).combineObjects(EVENT_TYPE_A);
executorService.elapseTime(PER_TYPE_CHECK_DELAY_MILLIS, MILLISECONDS);
verify(storedObjectCombiner, times(3)).combineObjects(EVENT_TYPE_A);
}
@Test
void testScheduleUsingCorrectExecutor()
{
SerialScheduledExecutorService highPriorityExecutorService = new SerialScheduledExecutorService();
SerialScheduledExecutorService lowPriorityExecutorService = new SerialScheduledExecutorService();
SerialScheduledExecutorService normalPriorityExecutorService = new SerialScheduledExecutorService();
StoredObjectCombiner storedObjectCombiner = createStoredObjectCombiner(EVENT_TYPE_A, EVENT_TYPE_B, EVENT_TYPE_C);
ScheduledCombiner scheduledCombiner = new ScheduledCombiner(
storedObjectCombiner,
normalPriorityExecutorService,
highPriorityExecutorService,
lowPriorityExecutorService,
createServerConfig()
.setCombinerHighPriorityEventTypes(ImmutableSet.of(EVENT_TYPE_A))
.setCombinerLowPriorityEventTypes(ImmutableSet.of(EVENT_TYPE_C)));
scheduledCombiner.start();
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_A);
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_B);
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_C);
highPriorityExecutorService.elapseTime(PER_TYPE_CHECK_DELAY_MILLIS, MILLISECONDS);
verify(storedObjectCombiner, times(2)).combineObjects(EVENT_TYPE_A);
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_B);
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_C);
normalPriorityExecutorService.elapseTime(PER_TYPE_CHECK_DELAY_MILLIS, MILLISECONDS);
verify(storedObjectCombiner, times(2)).combineObjects(EVENT_TYPE_A);
verify(storedObjectCombiner, times(2)).combineObjects(EVENT_TYPE_B);
verify(storedObjectCombiner, times(1)).combineObjects(EVENT_TYPE_C);
lowPriorityExecutorService.elapseTime(PER_TYPE_CHECK_DELAY_MILLIS, MILLISECONDS);
verify(storedObjectCombiner, times(2)).combineObjects(EVENT_TYPE_A);
verify(storedObjectCombiner, times(2)).combineObjects(EVENT_TYPE_B);
verify(storedObjectCombiner, times(2)).combineObjects(EVENT_TYPE_C);
}
private StoredObjectCombiner createStoredObjectCombiner()
{
StoredObjectCombiner result = mock(StoredObjectCombiner.class);
doReturn(ImmutableList.of()).when(result).listEventTypes();
return result;
}
private StoredObjectCombiner createStoredObjectCombiner(List<String>... eventTypeLists)
{
StoredObjectCombiner result = mock(StoredObjectCombiner.class);
if (eventTypeLists.length > 0) {
Stubber stubber = doReturn(ImmutableList.copyOf(eventTypeLists[0]));
for (int i = 1; i < eventTypeLists.length; ++i) {
stubber = stubber.doReturn(eventTypeLists[i]);
}
stubber.when(result).listEventTypes();
}
return result;
}
private StoredObjectCombiner createStoredObjectCombiner(String... eventTypes)
{
StoredObjectCombiner result = mock(StoredObjectCombiner.class);
doReturn(ImmutableList.copyOf(eventTypes)).when(result).listEventTypes();
return result;
}
private ServerConfig createServerConfig()
{
return new ServerConfig().setCombinerEnabled(true);
}
}