mirror of https://github.com/tasks/tasks
Limit notifications to five per second
parent
2073cd9df2
commit
2179fe748a
@ -0,0 +1,86 @@
|
||||
package org.tasks.notifications;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.tasks.Freeze.freezeAt;
|
||||
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.tasks.notifications.Throttle.Sleeper;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ThrottleTest {
|
||||
|
||||
private Sleeper sleeper;
|
||||
private Throttle throttle;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
sleeper = mock(Sleeper.class);
|
||||
throttle = new Throttle(3, sleeper);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
verifyNoMoreInteractions(sleeper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dontThrottle() {
|
||||
long now = currentTimeMillis();
|
||||
|
||||
runAt(now);
|
||||
runAt(now);
|
||||
runAt(now);
|
||||
runAt(now + 1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throttleForOneMillisecond() {
|
||||
long now = currentTimeMillis();
|
||||
|
||||
runAt(now);
|
||||
runAt(now);
|
||||
runAt(now);
|
||||
runAt(now + 999);
|
||||
|
||||
verify(sleeper).sleep(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throttleForOneSecond() {
|
||||
long now = currentTimeMillis();
|
||||
|
||||
runAt(now);
|
||||
runAt(now);
|
||||
runAt(now);
|
||||
runAt(now);
|
||||
|
||||
verify(sleeper).sleep(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throttleMultiple() {
|
||||
long now = currentTimeMillis();
|
||||
|
||||
runAt(now);
|
||||
runAt(now + 200);
|
||||
runAt(now + 600);
|
||||
runAt(now + 700);
|
||||
|
||||
verify(sleeper).sleep(300);
|
||||
|
||||
runAt(now + 750);
|
||||
|
||||
verify(sleeper).sleep(450);
|
||||
}
|
||||
|
||||
private void runAt(long millis) {
|
||||
freezeAt(millis).thawAfter(() -> throttle.run(() -> {}));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package org.tasks.notifications;
|
||||
|
||||
import static com.todoroo.andlib.utility.AndroidUtilities.assertNotMainThread;
|
||||
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
||||
|
||||
class Throttle {
|
||||
private final long[] throttle;
|
||||
private final Sleeper sleeper;
|
||||
private int oldest = 0;
|
||||
|
||||
Throttle(int ratePerSecond) {
|
||||
this(ratePerSecond, Throttle::sleep);
|
||||
}
|
||||
|
||||
Throttle(int ratePerSecond, Sleeper sleeper) {
|
||||
this.sleeper = sleeper;
|
||||
throttle = new long[ratePerSecond];
|
||||
}
|
||||
|
||||
private static void sleep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void run(Runnable runnable) {
|
||||
assertNotMainThread();
|
||||
long sleep = throttle[oldest] - (currentTimeMillis() - 1000);
|
||||
if (sleep > 0) {
|
||||
sleeper.sleep(sleep);
|
||||
}
|
||||
runnable.run();
|
||||
throttle[oldest] = currentTimeMillis();
|
||||
oldest = (oldest + 1) % throttle.length;
|
||||
}
|
||||
|
||||
public interface Sleeper {
|
||||
void sleep(long millis);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue