package com.rackspacecloud.blueflood.service;
import com.google.common.base.Ticker;
import com.rackspacecloud.blueflood.rollup.Granularity;
import com.rackspacecloud.blueflood.utils.Clock;
import org.joda.time.Instant;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
import static org.mockito.Mockito.when;
public class ShardStateManagerTest {
private final int TEST_SHARD = 0;
private final int TEST_SLOT = 0;
private final Granularity TEST_GRANULARITY = Granularity.MIN_5;
private List<Integer> managedShards = new ArrayList<Integer>() {{ add(TEST_SHARD); }};
private ShardStateManager.SlotStateManager slotStateManager;
private final Clock mockClock = Mockito.mock(Clock.class);
private final long lastIngestTime = 1235L;
@Before
public void setup() {
ShardStateManager shardStateManager = new ShardStateManager(managedShards, Ticker.systemTicker(), mockClock);
slotStateManager = shardStateManager.getSlotStateManager(TEST_SHARD, TEST_GRANULARITY);
when(mockClock.now()).thenReturn(new Instant(lastIngestTime));
}
@Test
public void testUpdateSlotsOnReadForSlotsNeverRolled() {
//during startup
//This tests -> if (stamp == null)
final long lastCollectionTime = System.currentTimeMillis();
final long activeSlotLastUpdatedTime = lastCollectionTime + 10; //to make it different from lastCollectionTime
List<SlotState> slotStates = new ArrayList<SlotState>() {{
add(createSlotState(TEST_GRANULARITY, UpdateStamp.State.Active, lastCollectionTime, activeSlotLastUpdatedTime));
}};
for (SlotState slotState: slotStates) {
slotStateManager.updateSlotOnRead(slotState);
}
Map<Integer, UpdateStamp> slotStamps = slotStateManager.getSlotStamps();
UpdateStamp updateStamp = slotStamps.get(TEST_SLOT);
assertEquals("Unexpected state", UpdateStamp.State.Active, updateStamp.getState());
assertEquals("Invalid last collection timestamp", lastCollectionTime, updateStamp.getTimestamp());
assertEquals("Last rollup time should not be set", 0, updateStamp.getLastRollupTimestamp());
assertEquals("Invalid last ingest timestamp", activeSlotLastUpdatedTime, updateStamp.getLastIngestTimestamp());
}
@Test
public void testUpdateSlotsOnReadForRolledSlots() {
//during startup
//This tests -> if (stamp.getTimestamp() == timestamp && state.equals(UpdateStamp.State.Rolled))
final long lastCollectionTime = System.currentTimeMillis() - 10 * 60 * 1000; //minus 10 mins
final long rolledSlotLastUpdatedTime = System.currentTimeMillis() - 5 * 60 * 1000; //minus 5 mins
final long activeSlotLastUpdatedTime = lastCollectionTime + 10; //to make it different from lastCollectionTime
//Both active and rolled states have same last collection timestamp
List<SlotState> slotStates = new ArrayList<SlotState>() {{
add(createSlotState(TEST_GRANULARITY, UpdateStamp.State.Active, lastCollectionTime, activeSlotLastUpdatedTime));
add(createSlotState(TEST_GRANULARITY, UpdateStamp.State.Rolled, lastCollectionTime, rolledSlotLastUpdatedTime));
}};
for (SlotState slotState: slotStates) {
slotStateManager.updateSlotOnRead(slotState);
}
Map<Integer, UpdateStamp> slotStamps = slotStateManager.getSlotStamps();
UpdateStamp updateStamp = slotStamps.get(TEST_SLOT);
assertEquals("Unexpected state", UpdateStamp.State.Rolled, updateStamp.getState());
assertEquals("Last collection timestamp is incorrect", lastCollectionTime, updateStamp.getTimestamp());
assertEquals("Last rollup timestamp is incorrect", rolledSlotLastUpdatedTime, updateStamp.getLastRollupTimestamp());
assertEquals("Last ingest timestamp is incorrect", activeSlotLastUpdatedTime, updateStamp.getLastIngestTimestamp());
}
@Test
public void testUpdateSlotsOnReadForRolledSlotsButGotDelayedMetrics() {
//during startup
//This tests -> if (state.equals(UpdateStamp.State.Rolled))
final long lastCollectionTime = System.currentTimeMillis() - 10 * 60 * 1000; //minus 10 mins
final long rolledSlotLastUpdatedTime = System.currentTimeMillis() - 5 * 60 * 1000; //minus 5 mins
final long delayedMetricCollectionTime = lastCollectionTime - 1; //it just has to be different than lastCollectionTime
final long activeSlotLastUpdatedTime = System.currentTimeMillis(); //means we ingested delayed metric recently
//Both active and rolled states have different last collection timestamp.
//The slot last update time is also different as we got a delayed metric later and "Active" got updated cos of that.
List<SlotState> slotStates = new ArrayList<SlotState>() {{
add(createSlotState(TEST_GRANULARITY, UpdateStamp.State.Active, delayedMetricCollectionTime, activeSlotLastUpdatedTime));
add(createSlotState(TEST_GRANULARITY, UpdateStamp.State.Rolled, lastCollectionTime, rolledSlotLastUpdatedTime));
}};
for (SlotState slotState: slotStates) {
slotStateManager.updateSlotOnRead(slotState);
}
Map<Integer, UpdateStamp> slotStamps = slotStateManager.getSlotStamps();
UpdateStamp updateStamp = slotStamps.get(TEST_SLOT);
assertEquals("Unexpected state", UpdateStamp.State.Active, updateStamp.getState());
assertEquals("Last collection timestamp is incorrect", delayedMetricCollectionTime, updateStamp.getTimestamp());
assertEquals("Last rollup timestamp is incorrect", rolledSlotLastUpdatedTime, updateStamp.getLastRollupTimestamp());
assertEquals("Last ingest timestamp is incorrect", activeSlotLastUpdatedTime, updateStamp.getLastIngestTimestamp());
}
private void establishCurrentState() {
final long existingCollectionTime = System.currentTimeMillis() - 60 * 1000; //minus 1 min
final long lastRolledCollectionTime = existingCollectionTime - 14 * 24 * 60 * 60 * 1000; //minus 14 days
final long rolledSlotLastUpdatedTime = lastRolledCollectionTime + 5 * 60 * 1000;
final long activeSlotLastUpdatedTime = existingCollectionTime + 10; //to make it different from lastCollectionTime
List<SlotState> slotStates = new ArrayList<SlotState>() {{
add(createSlotState(TEST_GRANULARITY, UpdateStamp.State.Active, existingCollectionTime, activeSlotLastUpdatedTime));
add(createSlotState(TEST_GRANULARITY, UpdateStamp.State.Rolled, lastRolledCollectionTime, rolledSlotLastUpdatedTime));
}};
//establishing state as active (with in-memory current state as Active)
for (SlotState slotState: slotStates) {
slotStateManager.updateSlotOnRead(slotState);
}
}
@Test
public void testUpdateSlotsOnReadWithIncomingActiveState() {
//updating existing in-memory map (current state: active, incoming: active state)
//This tests -> if (stamp.getTimestamp() != timestamp && state.equals(UpdateStamp.State.Active))
//This tests -> if (!(stamp.getState().equals(UpdateStamp.State.Active) && (stamp.getTimestamp() > timestamp || stamp.isDirty())))
establishCurrentState();
final long lastRollupTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getLastRollupTimestamp();
final long lastCollectionTime = System.currentTimeMillis();
final long lastUpdatedTime = System.currentTimeMillis();
SlotState newUpdateForActiveSlot = createSlotState(Granularity.MIN_5, UpdateStamp.State.Active, lastCollectionTime, lastUpdatedTime);
//new incoming slot state
slotStateManager.updateSlotOnRead(newUpdateForActiveSlot);
Map<Integer, UpdateStamp> slotStamps = slotStateManager.getSlotStamps();
UpdateStamp updateStamp = slotStamps.get(TEST_SLOT);
assertEquals("Unexpected state", UpdateStamp.State.Active, updateStamp.getState());
assertEquals("Last collection timestamp is incorrect", lastCollectionTime, updateStamp.getTimestamp());
assertEquals("Last rollup timestamp is incorrect", lastRollupTime, updateStamp.getLastRollupTimestamp());
assertEquals("Last ingest timestamp is incorrect", lastUpdatedTime, updateStamp.getLastIngestTimestamp());
}
@Test
public void testUpdateSlotsOnReadWithIncomingActiveStateButOlderData() {
//updating existing in-memory map (current state: active, incoming: active state but with old collection timestamp)
//This tests -> if (stamp.getTimestamp() != timestamp && state.equals(UpdateStamp.State.Active))
//This tests -> else part of if (!(stamp.getState().equals(UpdateStamp.State.Active) && (stamp.getTimestamp() > timestamp || stamp.isDirty())))
establishCurrentState();
final long lastRollupTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getLastRollupTimestamp();
final long existingLastCollectionTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getTimestamp();
final long existingLastIngestTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getLastIngestTimestamp();
long lastCollectionTime = existingLastCollectionTime - 60 * 1000; //minus 1 min
long lastUpdatedTime = System.currentTimeMillis();
SlotState newUpdateForActiveSlot = createSlotState(Granularity.MIN_5, UpdateStamp.State.Active, lastCollectionTime, lastUpdatedTime);
//new incoming slot state
slotStateManager.updateSlotOnRead(newUpdateForActiveSlot);
Map<Integer, UpdateStamp> slotStamps = slotStateManager.getSlotStamps();
UpdateStamp updateStamp = slotStamps.get(TEST_SLOT);
assertEquals("Unexpected state", UpdateStamp.State.Active, updateStamp.getState());
assertEquals("Last collection timestamp is incorrect", existingLastCollectionTime, updateStamp.getTimestamp());
assertEquals("Last rollup timestamp is incorrect", lastRollupTime, updateStamp.getLastRollupTimestamp());
assertEquals("Dirty flag is incorrect", true, updateStamp.isDirty());
assertEquals("Last ingest timestamp is incorrect", existingLastIngestTime, updateStamp.getLastIngestTimestamp());
}
@Test
public void testUpdateSlotsOnReadWithIncomingActiveStateButInMemoryDirtyData() {
//updating existing in-memory map (current state: active with dirty data, incoming: active state)
//This tests -> if (stamp.getTimestamp() != timestamp && state.equals(UpdateStamp.State.Active))
//This tests -> else part of if (!(stamp.getState().equals(UpdateStamp.State.Active) && (stamp.getTimestamp() > timestamp || stamp.isDirty())))
establishCurrentState();
final long lastRollupTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getLastRollupTimestamp();
final long existingLastCollectionTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getTimestamp();
final long existingLastIngestTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getLastIngestTimestamp();
slotStateManager.getSlotStamps().get(TEST_SLOT).setDirty(true);
long lastCollectionTime = existingLastCollectionTime + 60 * 1000; //not older data
long lastUpdatedTime = System.currentTimeMillis();
SlotState newUpdateForActiveSlot = createSlotState(Granularity.MIN_5, UpdateStamp.State.Active, lastCollectionTime, lastUpdatedTime);
//new incoming slot state
slotStateManager.updateSlotOnRead(newUpdateForActiveSlot);
Map<Integer, UpdateStamp> slotStamps = slotStateManager.getSlotStamps();
UpdateStamp updateStamp = slotStamps.get(TEST_SLOT);
assertEquals("Unexpected state", UpdateStamp.State.Active, updateStamp.getState());
assertEquals("Last collection timestamp is incorrect", existingLastCollectionTime, updateStamp.getTimestamp());
assertEquals("Last rollup timestamp is incorrect", lastRollupTime, updateStamp.getLastRollupTimestamp());
assertEquals("Dirty flag is incorrect", true, updateStamp.isDirty());
assertEquals("Last ingest timestamp is incorrect", existingLastIngestTime, updateStamp.getLastIngestTimestamp());
}
@Test
public void testUpdateSlotsOnReadIncomingRolledStateSameTimestamp() {
//updating existing in-memory map (current state:active, incoming: rolled state with same collection timestamp)
//This tests -> if (stamp.getTimestamp() == timestamp && state.equals(UpdateStamp.State.Rolled))
establishCurrentState();
final long existingLastCollectionTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getTimestamp();
final long existingLastIngestTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getLastIngestTimestamp();
final long newRolledSlotLastUpdatedTime = System.currentTimeMillis();
SlotState newUpdateForActiveSlot = createSlotState(Granularity.MIN_5, UpdateStamp.State.Rolled, existingLastCollectionTime, newRolledSlotLastUpdatedTime);
//new incoming slot state
slotStateManager.updateSlotOnRead(newUpdateForActiveSlot);
Map<Integer, UpdateStamp> slotStamps = slotStateManager.getSlotStamps();
UpdateStamp updateStamp = slotStamps.get(TEST_SLOT);
assertEquals("Unexpected state", UpdateStamp.State.Rolled, updateStamp.getState());
assertEquals("Last collection timestamp is incorrect", existingLastCollectionTime, updateStamp.getTimestamp());
assertEquals("Last rollup timestamp is incorrect", newRolledSlotLastUpdatedTime, updateStamp.getLastRollupTimestamp());
assertEquals("Last ingest timestamp is incorrect", existingLastIngestTime, updateStamp.getLastIngestTimestamp());
}
@Test
public void testUpdateSlotsOnReadIncomingRolledStateDifferentTimestamp() {
//updating existing in-memory map (current state: active, incoming: rolled state with different collection timestamp)
//This tests -> if (state.equals(UpdateStamp.State.Rolled))
establishCurrentState();
final long existingLastCollectionTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getTimestamp();
final long existingLastIngestTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getLastIngestTimestamp();
final long newLastRolledCollectionTime = existingLastCollectionTime - 1; //making it different from the collection time we already have in "Active"
final long newRolledSlotLastUpdatedTime = System.currentTimeMillis();
SlotState newUpdateForActiveSlot = createSlotState(Granularity.MIN_5, UpdateStamp.State.Rolled, newLastRolledCollectionTime, newRolledSlotLastUpdatedTime);
//new incoming slot state
slotStateManager.updateSlotOnRead(newUpdateForActiveSlot);
Map<Integer, UpdateStamp> slotStamps = slotStateManager.getSlotStamps();
UpdateStamp updateStamp = slotStamps.get(TEST_SLOT);
assertEquals("Unexpected state", UpdateStamp.State.Active, updateStamp.getState());
assertEquals("Last collection timestamp is incorrect", existingLastCollectionTime, updateStamp.getTimestamp());
assertEquals("Last rollup timestamp is incorrect", newRolledSlotLastUpdatedTime, updateStamp.getLastRollupTimestamp());
assertEquals("Last ingest timestamp is incorrect", existingLastIngestTime, updateStamp.getLastIngestTimestamp());
}
@Test
public void testUpdateSlotsOnReadIncomingOldRolledState() {
//updating existing in-memory map (current state: active, incoming: old rolled state;
//This tests -> if (state.equals(UpdateStamp.State.Rolled))
// a rolled up state gets marked as "active" because of incoming delayed metric before "rolled" state is saved in db.
// So rolled state from db will have old lastRolluptimestamp
establishCurrentState();
final long existingLastCollectionTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getTimestamp();
final long existingLastRollupTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getLastRollupTimestamp();
final long existingLastIngestTime = slotStateManager.getSlotStamps().get(TEST_SLOT).getLastIngestTimestamp();
final long oldLastRolledCollectionTime = existingLastCollectionTime - 1; //making it different from the collection time we already have in "Active"
final long oldRolledSlotLastUpdatedTime = System.currentTimeMillis() - 14 * 24 * 60 * 60 * 1000; //minus 14 days
SlotState newUpdateForActiveSlot = createSlotState(Granularity.MIN_5, UpdateStamp.State.Rolled, oldLastRolledCollectionTime, oldRolledSlotLastUpdatedTime);
//new incoming slot state
slotStateManager.updateSlotOnRead(newUpdateForActiveSlot);
Map<Integer, UpdateStamp> slotStamps = slotStateManager.getSlotStamps();
UpdateStamp updateStamp = slotStamps.get(TEST_SLOT);
assertEquals("Unexpected state", UpdateStamp.State.Active, updateStamp.getState());
assertEquals("Last collection timestamp is incorrect", existingLastCollectionTime, updateStamp.getTimestamp());
assertEquals("Last rollup timestamp is incorrect", existingLastRollupTime, updateStamp.getLastRollupTimestamp());
assertEquals("Last ingest timestamp is incorrect", existingLastIngestTime, updateStamp.getLastIngestTimestamp());
}
private SlotState createSlotState(Granularity granularity, UpdateStamp.State state, long lastCollectionTimeStamp, long lastUpdatedTimestamp) {
return new SlotState(granularity, TEST_SLOT, state).withTimestamp(lastCollectionTimeStamp).withLastUpdatedTimestamp(lastUpdatedTimestamp);
}
@Test
public void createOrUpdateCreatesWhenSlotNotPresent() {
// precondition
assertFalse(slotStateManager.getSlotStamps().containsKey(0));
// when
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
// then
assertTrue("The slot should be present in the map", slotStateManager.getSlotStamps().containsKey(0));
UpdateStamp stamp = slotStateManager.getSlotStamps().get(0);
assertTrue("The slot should be marked dirty", stamp.isDirty());
assertEquals("The timestamp should be set", 1234L, stamp.getTimestamp());
assertEquals("The state should be Active", UpdateStamp.State.Active, stamp.getState());
assertEquals("The last rollup timestamp should be uninitialized", 0, stamp.getLastRollupTimestamp());
assertEquals("Last ingest time should be set", lastIngestTime, stamp.getLastIngestTimestamp());
}
@Test
public void createOrUpdateUpdatesWhenSlotAlreadyPresent() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
UpdateStamp _stamp = slotStateManager.getSlotStamps().get(0);
_stamp.setDirty(false);
_stamp.setState(UpdateStamp.State.Rolled);
// precondition
assertEquals(1234L, _stamp.getTimestamp());
assertFalse(_stamp.isDirty());
assertEquals(UpdateStamp.State.Rolled, _stamp.getState());
assertEquals(0, _stamp.getLastRollupTimestamp());
assertEquals(lastIngestTime, _stamp.getLastIngestTimestamp());
// when
final long lastIngestTime2 = 1237L;
when(mockClock.now()).thenReturn(new Instant(lastIngestTime2));
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1236L);
// then
assertTrue("The slot should still be present in the map", slotStateManager.getSlotStamps().containsKey(0));
UpdateStamp stamp = slotStateManager.getSlotStamps().get(0);
assertEquals("The timestamp should have changed", 1236L, _stamp.getTimestamp());
assertTrue("The slot should be marked dirty", stamp.isDirty());
assertEquals("The state should be Active", UpdateStamp.State.Active, stamp.getState());
assertEquals("The last rollup timestamp should be uninitialized", 0, stamp.getLastRollupTimestamp());
assertEquals("Last ingest time should be set", lastIngestTime2, stamp.getLastIngestTimestamp());
}
@Test
public void getDirtySlotsWhenEmptyReturnsEmpty() {
// precondition
assertTrue(slotStateManager.getSlotStamps().isEmpty());
// when
Map dirtySlots = slotStateManager.getDirtySlotStampsAndMarkClean();
// then
assertNotNull(dirtySlots);
assertTrue("No slots should be included", dirtySlots.isEmpty());
}
@Test
public void getDirtySlotsWhenContainsOnlyCleanSlotsReturnsEmpty() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
UpdateStamp _stamp = slotStateManager.getSlotStamps().get(0);
_stamp.setDirty(false);
// when
Map dirtySlots = slotStateManager.getDirtySlotStampsAndMarkClean();
// then
assertNotNull(dirtySlots);
assertTrue("No slots should be included", dirtySlots.isEmpty());
}
@Test
public void getDirtySlotsWhenContainsOnlyDirtySlotsReturnsThoseSlotsAndMarksClean() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
slotStateManager.createOrUpdateForSlotAndMillisecond(1, 1234L);
// when
Map<Integer, UpdateStamp> dirtySlots = slotStateManager.getDirtySlotStampsAndMarkClean();
// then
assertNotNull(dirtySlots);
assertEquals("Both slots should be returned", 2, dirtySlots.size());
assertTrue("The first slot should be included", dirtySlots.containsKey(0));
UpdateStamp stamp = dirtySlots.get(0);
assertFalse("The first slot should be clean", stamp.isDirty());
assertTrue("The second slot should be included", dirtySlots.containsKey(1));
stamp = dirtySlots.get(1);
assertFalse("The second slot should be clean", stamp.isDirty());
}
@Test
public void getDirtySlotsWhenContainsCleanAndDirtySlotsReturnsOnlyDirtySlotsAndMarksClean() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
slotStateManager.getSlotStamps().get(0).setDirty(false);
slotStateManager.createOrUpdateForSlotAndMillisecond(1, 1234L);
// when
Map<Integer, UpdateStamp> dirtySlots = slotStateManager.getDirtySlotStampsAndMarkClean();
// then
assertNotNull(dirtySlots);
assertEquals("Only one slot should be returned", 1, dirtySlots.size());
assertFalse("Slot 0 should not be included", dirtySlots.containsKey(0));
assertFalse("Slot 0 should still be clean", slotStateManager.getSlotStamps().get(0).isDirty());
assertTrue("Slot 1 should be included", dirtySlots.containsKey(1));
assertFalse("Slot 1 should now be clean", dirtySlots.get(1).isDirty());
}
@Test
public void getAndSetStateGetsAndSetsState() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
// precondition
assertEquals(UpdateStamp.State.Active, slotStateManager.getSlotStamps().get(0).getState());
// when
UpdateStamp stamp = slotStateManager.getAndSetState(0, UpdateStamp.State.Rolled);
// then
assertNotNull(stamp);
assertSame("The stamp returned should be the same one for slot 0", slotStateManager.getSlotStamps().get(0), stamp);
assertEquals("The state should be changed to Rolled", UpdateStamp.State.Rolled, stamp.getState());
}
@Test
public void getAndSetStateDoesNotAffectUnspecifiedSlot() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
slotStateManager.createOrUpdateForSlotAndMillisecond(1, 1235L);
// precondition
assertEquals(UpdateStamp.State.Active, slotStateManager.getSlotStamps().get(0).getState());
assertEquals(UpdateStamp.State.Active, slotStateManager.getSlotStamps().get(1).getState());
// when
UpdateStamp stamp = slotStateManager.getAndSetState(0, UpdateStamp.State.Rolled);
// then
assertNotNull(stamp);
assertSame(slotStateManager.getSlotStamps().get(0), stamp);
assertEquals("Slot 0 should now be Rolled", UpdateStamp.State.Rolled, stamp.getState());
assertEquals("Slot 0 should still be Active", UpdateStamp.State.Active, slotStateManager.getSlotStamps().get(1).getState());
}
@Test(expected = NullPointerException.class)
public void getAndSetStateUninitializedSlotThrowsException() {
// precondition
assertEquals(0, slotStateManager.getSlotStamps().size());
// when
UpdateStamp stamp = slotStateManager.getAndSetState(0, UpdateStamp.State.Rolled);
// then
// the exception is thrown
}
@Test
public void getSlotsEligibleUninitializedReturnsEmpty() {
// precondition
assertEquals(0, slotStateManager.getSlotStamps().size());
// when
List<Integer> slots = slotStateManager.getSlotsEligibleForRollup(0, 0, 0, 3600000);
// then
assertNotNull(slots);
assertTrue("No slots should be returned", slots.isEmpty());
}
@Test
public void getSlotsEligibleDoesNotReturnRolledSlots() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
slotStateManager.getAndSetState(0, UpdateStamp.State.Rolled);
// when
List<Integer> slots = slotStateManager.getSlotsEligibleForRollup(0, 0, 0, 3600000);
// then
assertNotNull(slots);
assertTrue("No slots should be returned", slots.isEmpty());
}
@Test
public void getSlotsEligibleDoesNotReturnSlotsThatAreTooYoung() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
slotStateManager.getAndSetState(0, UpdateStamp.State.Active);
// when
List<Integer> slots = slotStateManager.getSlotsEligibleForRollup(1235L, 30000, 0, 3600000);
// then
assertNotNull(slots);
assertTrue("No slots should be returned", slots.isEmpty());
}
@Test
public void getSlotsEligibleDoesNotReturnSlotsThatWereRolledRecently() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
UpdateStamp stamp = slotStateManager.getSlotStamps().get(0);
stamp.setLastRollupTimestamp(2345L);
// when
List<Integer> slots = slotStateManager.getSlotsEligibleForRollup(2346L, 0, 70000, 3600000);
// then
assertNotNull(slots);
assertTrue("No slots should be returned", slots.isEmpty());
}
@Test
public void getSlotsEligibleReturnsSlotsThatWereRolledRecentlyButReadyForReroll() {
// given
when(mockClock.now()).thenReturn(new Instant(2234L)); //ingesting delayed metric after 1000ms (SHORT_DELAY_METRICS_ROLLUP_DELAY_MILLIS = 2000ms)
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
UpdateStamp stamp = slotStateManager.getSlotStamps().get(0);
stamp.setLastRollupTimestamp(2345L);
// when
List<Integer> slots = slotStateManager.getSlotsEligibleForRollup(3235L, 0, 2000, 3600000);
// then
assertNotNull(slots);
assertEquals("Only one slot should be returned", 1, slots.size());
assertEquals("Slot zero should be included", 0, slots.get(0).intValue());
}
@Test
public void getSlotsEligibleReturnsSlotsThatWereRolledAndGotMetricsWithLongerDelay() {
// given
when(mockClock.now()).thenReturn(new Instant(4234L)); //ingesting delayed metric after 3000ms (SHORT_DELAY_METRICS_ROLLUP_DELAY_MILLIS = 2000ms)
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
UpdateStamp stamp = slotStateManager.getSlotStamps().get(0);
stamp.setLastRollupTimestamp(2345L);
// when
List<Integer> slots = slotStateManager.getSlotsEligibleForRollup(4235L, 0, 2000, 1000);
// then
// then
assertNotNull(slots);
assertTrue("No slots should be returned", slots.isEmpty());
}
@Test
public void getSlotsEligibleReturnsSlotsThatWereRolledAndGotMetricsWithLongerDelayButReadyToReroll() {
// given
when(mockClock.now()).thenReturn(new Instant(4234L)); //ingesting delayed metric after 3000ms (SHORT_DELAY_METRICS_ROLLUP_DELAY_MILLIS = 2000ms)
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
UpdateStamp stamp = slotStateManager.getSlotStamps().get(0);
stamp.setLastRollupTimestamp(2345L);
// when
List<Integer> slots = slotStateManager.getSlotsEligibleForRollup(5235L, 0, 2000, 1000);
// then
assertNotNull(slots);
assertEquals("Only one slot should be returned", 1, slots.size());
assertEquals("Slot zero should be included", 0, slots.get(0).intValue());
}
@Test
public void getSlotsEligibleReturnsSlotsThatWereRolledAndGotMetricsWithRepeatedLongerDelayButReadyToReroll() {
// given
when(mockClock.now()).thenReturn(new Instant(4234L)); //ingesting delayed metric after 3000ms (SHORT_DELAY_METRICS_ROLLUP_DELAY_MILLIS = 2000ms)
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
UpdateStamp stamp = slotStateManager.getSlotStamps().get(0);
stamp.setLastRollupTimestamp(2345L);
//pre condition - 1
List<Integer> slots = slotStateManager.getSlotsEligibleForRollup(4235L, 0, 2000, 1000);
assertTrue("No slots should be returned", slots.isEmpty());
//pre condition - 2
when(mockClock.now()).thenReturn(new Instant(5234L)); //ingesting delayed metric after 4000ms, right before ROLLUP_WAIT(1000ms) elapses
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
List<Integer> slots1 = slotStateManager.getSlotsEligibleForRollup(5235L, 0, 2000, 1000);
assertTrue("No slots should be returned", slots1.isEmpty());
//when
List<Integer> slots2 = slotStateManager.getSlotsEligibleForRollup(6235L, 0, 2000, 1000);
// then
assertNotNull(slots);
assertEquals("Only one slot should be returned", 1, slots2.size());
assertEquals("Slot zero should be included", 0, slots2.get(0).intValue());
}
@Test
public void getSlotsEligibleReturnsSlotsThatWereNotRolled() {
// given
slotStateManager.createOrUpdateForSlotAndMillisecond(0, 1234L);
// when
List<Integer> slots = slotStateManager.getSlotsEligibleForRollup(2346L, 0, 1, 3600000);
// then
assertNotNull(slots);
assertEquals("Only one slot should be returned", 1, slots.size());
assertEquals("Slot zero should be included", 0, slots.get(0).intValue());
}
}