/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.apereo.portal.events.aggr;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.google.common.base.Function;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import javax.naming.CompositeName;
import org.apache.commons.lang.mutable.MutableInt;
import org.apache.commons.lang.mutable.MutableObject;
import org.apereo.portal.concurrency.CallableWithoutResult;
import org.apereo.portal.concurrency.FunctionWithoutResult;
import org.apereo.portal.events.aggr.dao.DateDimensionDao;
import org.apereo.portal.events.aggr.dao.TimeDimensionDao;
import org.apereo.portal.events.aggr.groups.AggregatedGroupLookupDao;
import org.apereo.portal.events.aggr.groups.AggregatedGroupMapping;
import org.apereo.portal.groups.ICompositeGroupService;
import org.apereo.portal.groups.IEntityGroup;
import org.apereo.portal.test.BaseAggrEventsJpaDaoTest;
import org.apereo.portal.utils.Tuple;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalTime;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
/**
*/
public abstract class JpaBaseAggregationDaoTest<
T extends BaseAggregationImpl<K, D>,
K extends BaseAggregationKey,
D extends BaseGroupedAggregationDiscriminator>
extends BaseAggrEventsJpaDaoTest {
@Autowired protected TimeDimensionDao timeDimensionDao;
@Autowired protected DateDimensionDao dateDimensionDao;
@Autowired protected AggregatedGroupLookupDao aggregatedGroupLookupDao;
@Autowired protected ICompositeGroupService compositeGroupService;
@Autowired protected AggregationIntervalHelper aggregationIntervalHelper;
/** @return The private aggregation DAO to use */
protected abstract BaseAggregationPrivateDao<T, K> getAggregationDao();
/**
* Populate some data in the aggregation, use the Random source if needed for the population (it
* will be consistent across test runs)
*/
protected abstract void updateAggregation(
AggregationIntervalInfo intervalInfo, T aggregation, Random r);
/** Create an aggregation key */
protected abstract K createAggregationKey(
AggregationIntervalInfo intervalInfo, AggregatedGroupMapping aggregatedGroup);
/** Create an aggregation key */
protected abstract K createAggregationKey(
AggregationInterval interval, AggregatedGroupMapping aggregatedGroup);
/** Create a list of aggregations for use in the lifecycle test */
protected abstract Map<K, T> createAggregations(
AggregationIntervalInfo intervalInfo, AggregatedGroupMapping aggregatedGroup);
@Test
public final void testBaseAggregationLifecycle() throws Exception {
final IEntityGroup entityGroupA = mock(IEntityGroup.class);
when(entityGroupA.getServiceName()).thenReturn(new CompositeName("local"));
when(entityGroupA.getName()).thenReturn("Group A");
when(compositeGroupService.findGroup("local.0")).thenReturn(entityGroupA);
final IEntityGroup entityGroupB = mock(IEntityGroup.class);
when(entityGroupB.getServiceName()).thenReturn(new CompositeName("local"));
when(entityGroupB.getName()).thenReturn("Group B");
when(compositeGroupService.findGroup("local.1")).thenReturn(entityGroupB);
final DateTime instant =
new DateTime(1326734644000l, DateTimeZone.UTC); //just a random time
//Create required date and time dimensions
populateDateTimeDimensions(instant.minusHours(2), instant.plusHours(2), null);
//Create aggregations
final Map<K, T> createdAggrs =
this.executeInTransaction(
new Callable<Map<K, T>>() {
@Override
public Map<K, T> call() throws Exception {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
final AggregationIntervalInfo fiveMinuteInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.FIVE_MINUTE, instant);
final AggregationIntervalInfo hourInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.HOUR, instant);
final Map<K, T> fiveMinGroupA =
createAggregations(fiveMinuteInfo, groupA);
final Map<K, T> fiveMinGroupB =
createAggregations(fiveMinuteInfo, groupB);
final Map<K, T> hourGroupA = createAggregations(hourInfo, groupA);
final Map<K, T> aggrs = new HashMap<K, T>(fiveMinGroupA);
aggrs.putAll(fiveMinGroupB);
aggrs.putAll(hourGroupA);
return aggrs;
}
});
//Verify aggregations were created
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregationIntervalInfo fiveMinuteInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.FIVE_MINUTE, instant);
final AggregationIntervalInfo hourInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.HOUR, instant);
final Map<K, T> fiveMinGroup =
getAggregationDao()
.getAggregationsForInterval(
fiveMinuteInfo.getDateDimension(),
fiveMinuteInfo.getTimeDimension(),
fiveMinuteInfo.getAggregationInterval());
final Map<K, T> hourGroup =
getAggregationDao()
.getAggregationsForInterval(
hourInfo.getDateDimension(),
hourInfo.getTimeDimension(),
hourInfo.getAggregationInterval());
final Map<K, T> foundAggrs = new HashMap<K, T>(fiveMinGroup);
foundAggrs.putAll(hourGroup);
assertEquals(
"Aggregations not created as expected", createdAggrs, foundAggrs);
}
});
//Update Aggregations
final Map<K, T> updatedAggrs =
this.executeInTransaction(
new Callable<Map<K, T>>() {
@Override
public Map<K, T> call() throws Exception {
final Random r = new Random(0);
final AggregationIntervalInfo fiveMinuteInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.FIVE_MINUTE, instant);
final AggregationIntervalInfo hourInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.HOUR, instant);
final Map<K, T> fiveMinGroup =
getAggregationDao()
.getAggregationsForInterval(
fiveMinuteInfo.getDateDimension(),
fiveMinuteInfo.getTimeDimension(),
fiveMinuteInfo.getAggregationInterval());
final Map<K, T> hourGroup =
getAggregationDao()
.getAggregationsForInterval(
hourInfo.getDateDimension(),
hourInfo.getTimeDimension(),
hourInfo.getAggregationInterval());
final Map<K, T> updatedAggrs = new HashMap<K, T>();
for (final Entry<K, T> aggrEntry : fiveMinGroup.entrySet()) {
final T aggr = aggrEntry.getValue();
updateAggregation(fiveMinuteInfo, aggr, r);
getAggregationDao().updateAggregation(aggr);
updatedAggrs.put(aggrEntry.getKey(), aggr);
}
for (final Entry<K, T> aggrEntry : hourGroup.entrySet()) {
final T aggr = aggrEntry.getValue();
updateAggregation(hourInfo, aggr, r);
getAggregationDao().updateAggregation(aggr);
updatedAggrs.put(aggrEntry.getKey(), aggr);
}
return updatedAggrs;
}
});
//Verify aggregations were updated
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregationIntervalInfo fiveMinuteInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.FIVE_MINUTE, instant);
final AggregationIntervalInfo hourInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.HOUR, instant);
final Map<K, T> fiveMinGroup =
getAggregationDao()
.getAggregationsForInterval(
fiveMinuteInfo.getDateDimension(),
fiveMinuteInfo.getTimeDimension(),
fiveMinuteInfo.getAggregationInterval());
final Map<K, T> hourGroup =
getAggregationDao()
.getAggregationsForInterval(
hourInfo.getDateDimension(),
hourInfo.getTimeDimension(),
hourInfo.getAggregationInterval());
final Map<K, T> foundAggrs = new HashMap<K, T>(fiveMinGroup);
foundAggrs.putAll(hourGroup);
assertEquals(
"Aggregations not updated as expected", updatedAggrs, foundAggrs);
}
});
//Complete intervals
final Map<K, T> completeAggrs =
this.executeInTransaction(
new Callable<Map<K, T>>() {
@Override
public Map<K, T> call() throws Exception {
final AggregationIntervalInfo fiveMinuteInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.FIVE_MINUTE, instant);
final AggregationIntervalInfo hourInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.HOUR, instant);
final Map<K, T> fiveMinGroup =
getAggregationDao()
.getAggregationsForInterval(
fiveMinuteInfo.getDateDimension(),
fiveMinuteInfo.getTimeDimension(),
fiveMinuteInfo.getAggregationInterval());
final Map<K, T> hourGroup =
getAggregationDao()
.getAggregationsForInterval(
hourInfo.getDateDimension(),
hourInfo.getTimeDimension(),
hourInfo.getAggregationInterval());
final Map<K, T> completeAggrs = new HashMap<K, T>();
for (final Entry<K, T> aggrEntry : fiveMinGroup.entrySet()) {
final T aggr = aggrEntry.getValue();
aggr.intervalComplete(5);
getAggregationDao().updateAggregation(aggr);
completeAggrs.put(aggrEntry.getKey(), aggr);
}
for (final Entry<K, T> aggrEntry : hourGroup.entrySet()) {
final T aggr = aggrEntry.getValue();
aggr.intervalComplete(60);
getAggregationDao().updateAggregation(aggr);
completeAggrs.put(aggrEntry.getKey(), aggr);
}
return completeAggrs;
}
});
//Verify aggregations were completed
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregationIntervalInfo fiveMinuteInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.FIVE_MINUTE, instant);
final AggregationIntervalInfo hourInfo =
aggregationIntervalHelper.getIntervalInfo(
AggregationInterval.HOUR, instant);
final Map<K, T> fiveMinGroup =
getAggregationDao()
.getAggregationsForInterval(
fiveMinuteInfo.getDateDimension(),
fiveMinuteInfo.getTimeDimension(),
fiveMinuteInfo.getAggregationInterval());
final Map<K, T> hourGroup =
getAggregationDao()
.getAggregationsForInterval(
hourInfo.getDateDimension(),
hourInfo.getTimeDimension(),
hourInfo.getAggregationInterval());
final Map<K, T> foundAggrs = new HashMap<K, T>(fiveMinGroup);
foundAggrs.putAll(hourGroup);
assertEquals(
"Aggregations not completed as expected",
completeAggrs,
foundAggrs);
}
});
}
@Test
public final void testBaseAggregationRangeQuery() throws Exception {
final IEntityGroup entityGroupA = mock(IEntityGroup.class);
when(entityGroupA.getServiceName()).thenReturn(new CompositeName("local"));
when(entityGroupA.getName()).thenReturn("Group A");
when(compositeGroupService.findGroup("local.0")).thenReturn(entityGroupA);
final IEntityGroup entityGroupB = mock(IEntityGroup.class);
when(entityGroupB.getServiceName()).thenReturn(new CompositeName("local"));
when(entityGroupB.getName()).thenReturn("Group B");
when(compositeGroupService.findGroup("local.1")).thenReturn(entityGroupB);
final MutableInt aggrs = new MutableInt();
//Create 2 days of login aggregates ... every 5 minutes
final DateTime start =
new DateTime(1326734644000l, DateTimeZone.UTC).minuteOfDay().roundFloorCopy();
final DateTime end = start.plusDays(2);
final AggregationInterval interval = AggregationInterval.FIVE_MINUTE;
final MutableObject startObj = new MutableObject();
final MutableObject endObj = new MutableObject();
this.executeInTransaction(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final Random r = new Random(0);
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
populateDateTimeDimensions(
start,
end,
new FunctionWithoutResult<Tuple<DateDimension, TimeDimension>>() {
@Override
protected void applyWithoutResult(
Tuple<DateDimension, TimeDimension> input) {
final TimeDimension td = input.second;
final DateDimension dd = input.first;
final DateTime instant =
td.getTime().toDateTime(dd.getDate());
if (startObj.getValue() == null) {
startObj.setValue(instant);
}
endObj.setValue(instant);
if (instant.equals(interval.determineStart(instant))) {
final AggregationIntervalInfo intervalInfo =
aggregationIntervalHelper.getIntervalInfo(
interval, instant);
final T baseAggregationA =
getAggregationDao()
.createAggregation(
createAggregationKey(
intervalInfo, groupA));
final T baseAggregationB =
getAggregationDao()
.createAggregation(
createAggregationKey(
intervalInfo, groupB));
for (int u = 0; u < r.nextInt(50); u++) {
updateAggregation(
intervalInfo, baseAggregationA, r);
updateAggregation(
intervalInfo, baseAggregationB, r);
}
baseAggregationA.intervalComplete(5);
baseAggregationB.intervalComplete(5);
getAggregationDao().updateAggregation(baseAggregationA);
getAggregationDao().updateAggregation(baseAggregationB);
aggrs.add(2);
}
}
});
}
});
//Verify all aggrs created
assertEquals(1152, aggrs.intValue());
//Find aggrs for one day
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
final DateTime queryStart = start.toDateMidnight().toDateTime();
final DateTime queryEnd = queryStart.plusDays(1).minusSeconds(1);
final List<T> baseAggregations =
getAggregationDao()
.getAggregations(
queryStart,
queryEnd,
createAggregationKey(interval, groupA),
groupB);
assertEquals(158, baseAggregations.size());
}
});
//Find aggrs for second day
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
final DateTime queryStart =
start.toDateMidnight().minusDays(1).toDateTime();
final DateTime queryEnd = queryStart.plusDays(2).minusSeconds(1);
final List<T> baseAggregations =
getAggregationDao()
.getAggregations(
queryStart,
queryEnd,
createAggregationKey(interval, groupA),
groupB);
assertEquals(158, baseAggregations.size());
}
});
//Find all aggrs
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
final List<T> baseAggregations =
getAggregationDao()
.getAggregations(
start,
end.plusDays(1),
createAggregationKey(interval, groupA),
groupB);
assertEquals(1152, baseAggregations.size());
}
});
//Find first days worth
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
final List<T> baseAggregations =
getAggregationDao()
.getAggregations(
start,
end,
createAggregationKey(interval, groupA),
groupB);
assertEquals(1152, baseAggregations.size());
}
});
//Find second days worth
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
final List<T> baseAggregations =
getAggregationDao()
.getAggregations(
start.plusDays(1),
end.plusDays(1),
createAggregationKey(interval, groupA),
groupB);
assertEquals(576, baseAggregations.size());
}
});
//Find first 12 hours worth
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
final List<T> baseAggregations =
getAggregationDao()
.getAggregations(
start,
start.plusHours(12),
createAggregationKey(interval, groupA),
groupB);
assertEquals(288, baseAggregations.size());
}
});
//Find middle 24 hours worth
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
final List<T> baseAggregations =
getAggregationDao()
.getAggregations(
start.plusHours(12),
end.plusHours(12),
createAggregationKey(interval, groupA),
groupB);
assertEquals(864, baseAggregations.size());
}
});
//Find middle 24 hours worth for one group
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final List<T> baseAggregations =
getAggregationDao()
.getAggregations(
start.plusHours(12),
end.plusHours(12),
createAggregationKey(interval, groupA));
assertEquals(432, baseAggregations.size());
}
});
//Find last 12 hours worth
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
final List<T> baseAggregations =
getAggregationDao()
.getAggregations(
start.plusHours(36),
end.plusDays(1),
createAggregationKey(interval, groupA),
groupB);
assertEquals(288, baseAggregations.size());
}
});
//TODO Query for intervals that are stored
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final Set<AggregatedGroupMapping> aggregatedGroupMappings =
getAggregationDao().getAggregatedGroupMappings();
assertEquals(2, aggregatedGroupMappings.size());
final Set<AggregationInterval> aggregationIntervals =
getAggregationDao().getAggregationIntervals();
assertEquals(1, aggregationIntervals.size());
}
});
}
@Test
public final void testModifyingClosedAggregationRangeQuery() throws Exception {
final IEntityGroup entityGroupA = mock(IEntityGroup.class);
when(entityGroupA.getServiceName()).thenReturn(new CompositeName("local"));
when(entityGroupA.getName()).thenReturn("Group A");
when(compositeGroupService.findGroup("local.0")).thenReturn(entityGroupA);
final MutableInt aggrs = new MutableInt();
//Create 10 minutes of aggregations
final DateTime start =
new DateTime(1326734644000l, DateTimeZone.UTC).minuteOfDay().roundFloorCopy();
final DateTime end = start.plusMinutes(10);
final AggregationInterval interval = AggregationInterval.FIVE_MINUTE;
final MutableObject startObj = new MutableObject();
final MutableObject endObj = new MutableObject();
this.executeInTransaction(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final Random r = new Random(0);
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
populateDateTimeDimensions(
start,
end,
new FunctionWithoutResult<Tuple<DateDimension, TimeDimension>>() {
@Override
protected void applyWithoutResult(
Tuple<DateDimension, TimeDimension> input) {
final TimeDimension td = input.second;
final DateDimension dd = input.first;
final DateTime instant =
td.getTime().toDateTime(dd.getDate());
if (startObj.getValue() == null) {
startObj.setValue(instant);
}
endObj.setValue(instant);
if (instant.equals(interval.determineStart(instant))) {
final AggregationIntervalInfo intervalInfo =
aggregationIntervalHelper.getIntervalInfo(
interval, instant);
final T baseAggregationA =
getAggregationDao()
.createAggregation(
createAggregationKey(
intervalInfo, groupA));
for (int u = 0; u < r.nextInt(50); u++) {
updateAggregation(
intervalInfo, baseAggregationA, r);
}
baseAggregationA.intervalComplete(5);
getAggregationDao().updateAggregation(baseAggregationA);
aggrs.add(1);
}
}
});
}
});
//Verify all aggrs created
assertEquals(2, aggrs.intValue());
//Find unclosed 1 aggr
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final Random r = new Random(0);
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final K key = createAggregationKey(interval, groupA);
final List<T> aggregations =
getAggregationDao()
.getAggregations(start.minusDays(1), end.plusDays(1), key);
assertEquals(2, aggregations.size());
for (final T baseAggregationImpl : aggregations) {
final DateTime instant = baseAggregationImpl.getDateTime();
final AggregationIntervalInfo intervalInfo =
aggregationIntervalHelper.getIntervalInfo(interval, instant);
updateAggregation(intervalInfo, baseAggregationImpl, r);
//TODO verify unchanged
}
}
});
}
@Test
public final void testUnclosedBaseAggregationRangeQuery() throws Exception {
final IEntityGroup entityGroupA = mock(IEntityGroup.class);
when(entityGroupA.getServiceName()).thenReturn(new CompositeName("local"));
when(entityGroupA.getName()).thenReturn("Group A");
when(compositeGroupService.findGroup("local.0")).thenReturn(entityGroupA);
final IEntityGroup entityGroupB = mock(IEntityGroup.class);
when(entityGroupB.getServiceName()).thenReturn(new CompositeName("local"));
when(entityGroupB.getName()).thenReturn("Group B");
when(compositeGroupService.findGroup("local.1")).thenReturn(entityGroupB);
final MutableInt aggrs = new MutableInt();
//Create 10 minutes of aggregations
final DateTime start =
new DateTime(1326734644000l, DateTimeZone.UTC).minuteOfDay().roundFloorCopy();
final DateTime end = start.plusMinutes(10);
final AggregationInterval interval = AggregationInterval.FIVE_MINUTE;
final MutableObject startObj = new MutableObject();
final MutableObject endObj = new MutableObject();
this.executeInTransaction(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final Random r = new Random(0);
final AggregatedGroupMapping groupA =
aggregatedGroupLookupDao.getGroupMapping("local.0");
final AggregatedGroupMapping groupB =
aggregatedGroupLookupDao.getGroupMapping("local.1");
populateDateTimeDimensions(
start,
end,
new FunctionWithoutResult<Tuple<DateDimension, TimeDimension>>() {
@Override
protected void applyWithoutResult(
Tuple<DateDimension, TimeDimension> input) {
final TimeDimension td = input.second;
final DateDimension dd = input.first;
final DateTime instant =
td.getTime().toDateTime(dd.getDate());
if (startObj.getValue() == null) {
startObj.setValue(instant);
}
endObj.setValue(instant);
if (instant.equals(interval.determineStart(instant))) {
final AggregationIntervalInfo intervalInfo =
aggregationIntervalHelper.getIntervalInfo(
interval, instant);
final T baseAggregationA =
getAggregationDao()
.createAggregation(
createAggregationKey(
intervalInfo, groupA));
final T baseAggregationB =
getAggregationDao()
.createAggregation(
createAggregationKey(
intervalInfo, groupB));
for (int u = 0; u < r.nextInt(50); u++) {
updateAggregation(
intervalInfo, baseAggregationA, r);
updateAggregation(
intervalInfo, baseAggregationB, r);
}
if (aggrs.intValue() % 4 == 0) {
baseAggregationA.intervalComplete(5);
}
baseAggregationB.intervalComplete(5);
getAggregationDao().updateAggregation(baseAggregationA);
getAggregationDao().updateAggregation(baseAggregationB);
aggrs.add(2);
}
}
});
}
});
//Verify all aggrs created
assertEquals(4, aggrs.intValue());
//Find unclosed 1 aggr
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final Collection<T> baseAggregations =
getAggregationDao()
.getUnclosedAggregations(
start.minusDays(1), end.plusDays(1), interval);
assertEquals(1, baseAggregations.size());
for (final T baseAggregationImpl : baseAggregations) {
baseAggregationImpl.intervalComplete(5);
getAggregationDao().updateAggregation(baseAggregationImpl);
}
}
});
//Find unclosed 0 aggr
this.execute(
new CallableWithoutResult() {
@Override
protected void callWithoutResult() {
final Collection<T> baseAggregations =
getAggregationDao()
.getUnclosedAggregations(
start.minusDays(1), end.plusDays(1), interval);
assertEquals(0, baseAggregations.size());
}
});
}
/** Populate date & time dimensions in an interval range executing a callback for each pair */
public final <RT> List<RT> populateDateTimeDimensions(
final DateTime start,
final DateTime end,
final Function<Tuple<DateDimension, TimeDimension>, RT> newDimensionHandler) {
return this.executeInTransaction(
new Callable<List<RT>>() {
@Override
public List<RT> call() throws Exception {
final List<RT> results = new LinkedList<RT>();
final SortedMap<LocalTime, TimeDimension> times =
new TreeMap<LocalTime, TimeDimension>();
final SortedMap<DateMidnight, DateDimension> dates =
new TreeMap<DateMidnight, DateDimension>();
DateTime nextDateTime = start.minuteOfDay().roundFloorCopy();
while (nextDateTime.isBefore(end)) {
//get/create TimeDimension
final LocalTime localTime = nextDateTime.toLocalTime();
TimeDimension td = times.get(localTime);
if (td == null) {
td = timeDimensionDao.createTimeDimension(localTime);
times.put(localTime, td);
}
//get/create DateDimension
final DateMidnight dateMidnight = nextDateTime.toDateMidnight();
DateDimension dd = dates.get(dateMidnight);
if (dd == null) {
dd = dateDimensionDao.createDateDimension(dateMidnight, 0, null);
dates.put(dateMidnight, dd);
}
//Let callback do work
if (newDimensionHandler != null) {
final RT result =
newDimensionHandler.apply(
new Tuple<DateDimension, TimeDimension>(dd, td));
if (result != null) {
results.add(result);
}
}
nextDateTime = nextDateTime.plusMinutes(1);
}
return results;
}
});
}
}