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