BatchedFixedIntervalInvocationGateTest.java
/*
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2026, QOS.ch. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v2.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
package ch.qos.logback.core.util;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
* Tests for {@link BatchedFixedIntervalInvocationGate}. Time is always injected
* via {@link BatchedFixedIntervalInvocationGate#isTooSoon(long)}; wall-clock
* time is not used.
*/
public class BatchedFixedIntervalInvocationGateTest {
private static final Duration LULL = Duration.buildByMilliseconds(100);
@Test
public void allowsBatchSizeSuccessiveCallsThenLulls() {
int batchSize = 3;
BatchedFixedIntervalInvocationGate gate = new BatchedFixedIntervalInvocationGate(batchSize, LULL);
long t = 1_000L;
for (int i = 0; i < batchSize; i++) {
assertFalse(gate.isTooSoon(t), "call " + i + " within batch should proceed");
}
// batch exhausted ��� lull until t + LULL
assertTrue(gate.isTooSoon(t));
assertTrue(gate.isTooSoon(t + LULL.getMilliseconds() - 1));
// after lull, a new batch of N is available
long afterLull = t + LULL.getMilliseconds();
for (int i = 0; i < batchSize; i++) {
assertFalse(gate.isTooSoon(afterLull), "call " + i + " after lull should proceed");
}
assertTrue(gate.isTooSoon(afterLull));
}
@Test
public void batchSizeOneMatchesFixedIntervalGateShape() {
BatchedFixedIntervalInvocationGate gate = new BatchedFixedIntervalInvocationGate(1, LULL);
long t = 200L;
assertFalse(gate.isTooSoon(t));
assertTrue(gate.isTooSoon(t));
assertTrue(gate.isTooSoon(t + LULL.getMilliseconds() - 1));
assertFalse(gate.isTooSoon(t + LULL.getMilliseconds()));
}
@Test
public void timeUnavailableAlwaysAllows() {
BatchedFixedIntervalInvocationGate gate = new BatchedFixedIntervalInvocationGate(2,
Duration.buildByMilliseconds(10));
assertFalse(gate.isTooSoon(InvocationGate.TIME_UNAVAILABLE));
assertFalse(gate.isTooSoon(-1));
}
@Test
public void timeAdvancesWithinOpenBatchStillAllowsUntilBatchExhausted() {
int batchSize = 4;
BatchedFixedIntervalInvocationGate gate = new BatchedFixedIntervalInvocationGate(batchSize, LULL);
// Inject increasing timestamps while still inside the batch; all should proceed.
assertFalse(gate.isTooSoon(10L));
assertFalse(gate.isTooSoon(11L));
assertFalse(gate.isTooSoon(50L));
assertFalse(gate.isTooSoon(99L));
// 5th call starts lull at 99 + LULL
assertTrue(gate.isTooSoon(99L));
assertTrue(gate.isTooSoon(99L + LULL.getMilliseconds() - 1));
assertFalse(gate.isTooSoon(99L + LULL.getMilliseconds()));
}
@Test
public void multipleBatchesWithInjectedTime() {
int batchSize = 2;
Duration lull = Duration.buildByMilliseconds(20);
BatchedFixedIntervalInvocationGate gate = new BatchedFixedIntervalInvocationGate(batchSize, lull);
long t = 0L;
// batch 1
assertFalse(gate.isTooSoon(t));
assertFalse(gate.isTooSoon(t));
assertTrue(gate.isTooSoon(t));
t = lull.getMilliseconds(); // end of first lull
// batch 2
assertFalse(gate.isTooSoon(t));
assertFalse(gate.isTooSoon(t + 5));
assertTrue(gate.isTooSoon(t + 5));
t = t + 5 + lull.getMilliseconds(); // end of second lull
assertFalse(gate.isTooSoon(t));
}
@Test
public void invalidBatchSizeRejected() {
assertThrows(IllegalArgumentException.class, () -> new BatchedFixedIntervalInvocationGate(0, LULL));
assertThrows(IllegalArgumentException.class, () -> new BatchedFixedIntervalInvocationGate(-1, LULL));
}
@Test
public void nullIncrementRejected() {
assertThrows(IllegalArgumentException.class, () -> new BatchedFixedIntervalInvocationGate(2, null));
}
@Test
public void defaultConstructorIsUsableWithInjectedTime() {
BatchedFixedIntervalInvocationGate gate = new BatchedFixedIntervalInvocationGate();
long t = 1L;
assertFalse(gate.isTooSoon(t));
// remaining DEFAULT_BATCH_SIZE - 1 still open at same t
for (int i = 1; i < BatchedFixedIntervalInvocationGate.DEFAULT_BATCH_SIZE; i++) {
assertFalse(gate.isTooSoon(t));
}
assertTrue(gate.isTooSoon(t));
}
}