Skip to content

Commit b4b635e

Browse files
author
jmhofer
committed
Added tests against periodic scheduling. I hope the delays are stable
yet fast enough...
1 parent 788d431 commit b4b635e

File tree

1 file changed

+65
-18
lines changed

1 file changed

+65
-18
lines changed

rxjava-core/src/main/java/rx/concurrency/SwingScheduler.java

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,22 @@
2020
import java.awt.EventQueue;
2121
import java.awt.event.ActionEvent;
2222
import java.awt.event.ActionListener;
23-
import java.lang.reflect.InvocationTargetException;
2423
import java.util.concurrent.TimeUnit;
2524
import java.util.concurrent.atomic.AtomicReference;
2625

2726
import javax.swing.Timer;
2827

28+
import org.junit.Rule;
2929
import org.junit.Test;
30+
import org.junit.rules.ExpectedException;
3031
import org.mockito.InOrder;
3132

3233
import rx.Scheduler;
3334
import rx.Subscription;
3435
import rx.subscriptions.CompositeSubscription;
3536
import rx.subscriptions.Subscriptions;
3637
import rx.util.functions.Action0;
38+
import rx.util.functions.Func0;
3739
import rx.util.functions.Func2;
3840

3941
/**
@@ -110,7 +112,6 @@ public void call() {
110112

111113
@Override
112114
public <T> Subscription schedulePeriodically(T state, final Func2<Scheduler, T, Subscription> action, long initialDelay, long period, TimeUnit unit) {
113-
// FIXME test this!
114115
final AtomicReference<Timer> timer = new AtomicReference<Timer>();
115116

116117
final long delay = unit.toMillis(period);
@@ -119,20 +120,17 @@ public <T> Subscription schedulePeriodically(T state, final Func2<Scheduler, T,
119120
final CompositeSubscription subscriptions = new CompositeSubscription();
120121
final Func2<Scheduler, T, Subscription> initialAction = new Func2<Scheduler, T, Subscription>() {
121122
@Override
122-
public Subscription call(final Scheduler scheduler, final T state) {
123-
// call the action once initially
124-
subscriptions.add(action.call(scheduler, state));
125-
123+
public Subscription call(final Scheduler scheduler, final T state0) {
126124
// start timer for periodic execution, collect subscriptions
127125
timer.set(new Timer((int) delay, new ActionListener() {
128126
@Override
129127
public void actionPerformed(ActionEvent e) {
130-
subscriptions.add(action.call(scheduler, state));
128+
subscriptions.add(action.call(scheduler, state0));
131129
}
132130
}));
133131
timer.get().start();
134132

135-
return action.call(scheduler, state);
133+
return action.call(scheduler, state0);
136134
}
137135
};
138136
subscriptions.add(schedule(state, initialAction, initialDelay, unit));
@@ -141,22 +139,68 @@ public void actionPerformed(ActionEvent e) {
141139
@Override
142140
public void call() {
143141
// in addition to all the individual unsubscriptions, stop the timer on unsubscribing
144-
timer.get().stop();
142+
Timer maybeTimer = timer.get();
143+
if (maybeTimer != null) {
144+
maybeTimer.stop();
145+
}
145146
}
146147
}));
147148

148149
return subscriptions;
149150
}
150151

151152
private static void assertThatTheDelayIsValidForTheSwingTimer(long delay) {
152-
if (delay > Integer.MAX_VALUE) {
153-
throw new IllegalArgumentException(String.format("The swing timer only accepts delays up to %d milliseconds.", Integer.MAX_VALUE));
153+
if (delay < 0 || delay > Integer.MAX_VALUE) {
154+
throw new IllegalArgumentException(String.format("The swing timer only accepts non-negative delays up to %d milliseconds.", Integer.MAX_VALUE));
154155
}
155156
}
156157

157158
public static class UnitTest {
159+
@Rule
160+
public ExpectedException exception = ExpectedException.none();
161+
158162
@Test
159-
public void testNestedActions() throws InterruptedException, InvocationTargetException {
163+
public void testInvalidDelayValues() {
164+
final SwingScheduler scheduler = new SwingScheduler();
165+
final Action0 action = mock(Action0.class);
166+
167+
exception.expect(IllegalArgumentException.class);
168+
scheduler.schedulePeriodically(action, -1L, 100L, TimeUnit.SECONDS);
169+
170+
exception.expect(IllegalArgumentException.class);
171+
scheduler.schedulePeriodically(action, 100L, -1L, TimeUnit.SECONDS);
172+
173+
exception.expect(IllegalArgumentException.class);
174+
scheduler.schedulePeriodically(action, 1L + Integer.MAX_VALUE, 100L, TimeUnit.MILLISECONDS);
175+
176+
exception.expect(IllegalArgumentException.class);
177+
scheduler.schedulePeriodically(action, 100L, 1L + Integer.MAX_VALUE / 1000, TimeUnit.SECONDS);
178+
}
179+
180+
@Test
181+
public void testPeriodicScheduling() throws Exception {
182+
final SwingScheduler scheduler = new SwingScheduler();
183+
184+
final Action0 innerAction = mock(Action0.class);
185+
final Action0 unsubscribe = mock(Action0.class);
186+
final Func0<Subscription> action = new Func0<Subscription>() {
187+
@Override
188+
public Subscription call() {
189+
innerAction.call();
190+
return Subscriptions.create(unsubscribe);
191+
}
192+
};
193+
194+
Subscription sub = scheduler.schedulePeriodically(action, 20, 100, TimeUnit.MILLISECONDS);
195+
Thread.sleep(400);
196+
sub.unsubscribe();
197+
waitForEmptyEventQueue();
198+
verify(innerAction, times(4)).call();
199+
verify(unsubscribe, times(4)).call();
200+
}
201+
202+
@Test
203+
public void testNestedActions() throws Exception {
160204
final SwingScheduler scheduler = new SwingScheduler();
161205

162206
final Action0 firstStepStart = mock(Action0.class);
@@ -195,12 +239,7 @@ public void call() {
195239
InOrder inOrder = inOrder(firstStepStart, firstStepEnd, secondStepStart, secondStepEnd, thirdStepStart, thirdStepEnd);
196240

197241
scheduler.schedule(thirdAction);
198-
EventQueue.invokeAndWait(new Runnable() {
199-
@Override
200-
public void run() {
201-
// nothing to do, we're just waiting here for the event queue to be emptied
202-
}
203-
});
242+
waitForEmptyEventQueue();
204243

205244
inOrder.verify(thirdStepStart, times(1)).call();
206245
inOrder.verify(thirdStepEnd, times(1)).call();
@@ -210,5 +249,13 @@ public void run() {
210249
inOrder.verify(firstStepEnd, times(1)).call();
211250
}
212251

252+
private static void waitForEmptyEventQueue() throws Exception {
253+
EventQueue.invokeAndWait(new Runnable() {
254+
@Override
255+
public void run() {
256+
// nothing to do, we're just waiting here for the event queue to be emptied
257+
}
258+
});
259+
}
213260
}
214261
}

0 commit comments

Comments
 (0)