Skip to content

Commit 646f396

Browse files
lburgazzolimetacosm
authored andcommitted
fix: improve unit testing of TimerEventSource #293
1 parent 1a6ad39 commit 646f396

File tree

1 file changed

+64
-39
lines changed

1 file changed

+64
-39
lines changed

Diff for: operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/internal/TimerEventSourceTest.java

+64-39
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,35 @@
33
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID;
44
import static org.assertj.core.api.Assertions.assertThat;
55
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
6-
import static org.mockito.Mockito.any;
7-
import static org.mockito.Mockito.mock;
8-
import static org.mockito.Mockito.never;
9-
import static org.mockito.Mockito.timeout;
10-
import static org.mockito.Mockito.times;
11-
import static org.mockito.Mockito.verify;
126

137
import io.fabric8.kubernetes.client.CustomResource;
148
import io.javaoperatorsdk.operator.TestUtils;
159
import io.javaoperatorsdk.operator.processing.KubernetesResourceUtils;
10+
import io.javaoperatorsdk.operator.processing.event.Event;
1611
import io.javaoperatorsdk.operator.processing.event.EventHandler;
1712
import java.io.IOException;
1813
import java.util.List;
14+
import java.util.concurrent.CopyOnWriteArrayList;
15+
import java.util.concurrent.TimeUnit;
16+
import org.awaitility.Awaitility;
17+
import org.awaitility.core.ConditionFactory;
18+
import org.awaitility.core.ThrowingRunnable;
1919
import org.junit.jupiter.api.BeforeEach;
20-
import org.junit.jupiter.api.Disabled;
2120
import org.junit.jupiter.api.Test;
22-
import org.mockito.ArgumentCaptor;
2321

24-
@Disabled("Currently very flaky, will fix in https://github.com/java-operator-sdk/java-operator-sdk/issues/293")
2522
class TimerEventSourceTest {
2623

2724
public static final int INITIAL_DELAY = 50;
2825
public static final int PERIOD = 50;
2926
public static final int TESTING_TIME_SLACK = 40;
3027

3128
private TimerEventSource timerEventSource;
32-
private EventHandler eventHandlerMock = mock(EventHandler.class);
29+
private CapturingEventHandler eventHandlerMock;
3330

3431
@BeforeEach
3532
public void setup() {
33+
eventHandlerMock = new CapturingEventHandler();
34+
3635
timerEventSource = new TimerEventSource();
3736
timerEventSource.setEventHandler(eventHandlerMock);
3837
timerEventSource.start();
@@ -41,73 +40,69 @@ public void setup() {
4140
@Test
4241
public void producesEventsPeriodically() {
4342
CustomResource customResource = TestUtils.testCustomResource();
44-
4543
timerEventSource.schedule(customResource, INITIAL_DELAY, PERIOD);
4644

47-
ArgumentCaptor<TimerEvent> argumentCaptor = ArgumentCaptor.forClass(TimerEvent.class);
48-
verify(eventHandlerMock, timeout(INITIAL_DELAY + PERIOD + TESTING_TIME_SLACK).times(2))
49-
.handleEvent(argumentCaptor.capture());
50-
List<TimerEvent> events = argumentCaptor.getAllValues();
51-
assertThat(events)
52-
.allMatch(e -> e.getRelatedCustomResourceUid().equals(getUID(customResource)));
53-
assertThat(events).allMatch(e -> e.getEventSource().equals(timerEventSource));
45+
untilAsserted(() -> {
46+
assertThat(eventHandlerMock.events)
47+
.hasSizeGreaterThan(2);
48+
assertThat(eventHandlerMock.events)
49+
.allMatch(e -> e.getRelatedCustomResourceUid().equals(getUID(customResource)));
50+
assertThat(eventHandlerMock.events)
51+
.allMatch(e -> e.getEventSource().equals(timerEventSource));
52+
});
5453
}
5554

5655
@Test
57-
public void deRegistersPeriodicalEventSources() throws InterruptedException {
56+
public void deRegistersPeriodicalEventSources() {
5857
CustomResource customResource = TestUtils.testCustomResource();
5958

6059
timerEventSource.schedule(customResource, INITIAL_DELAY, PERIOD);
61-
Thread.sleep(INITIAL_DELAY + PERIOD + TESTING_TIME_SLACK);
60+
untilAsserted(() -> assertThat(eventHandlerMock.events).hasSizeGreaterThan(1));
61+
6262
timerEventSource.eventSourceDeRegisteredForResource(getUID(customResource));
63-
Thread.sleep(PERIOD + TESTING_TIME_SLACK);
6463

65-
verify(eventHandlerMock, times(2)).handleEvent(any());
64+
int size = eventHandlerMock.events.size();
65+
untilAsserted(() -> assertThat(eventHandlerMock.events).hasSize(size));
6666
}
6767

6868
@Test
69-
public void schedulesOnce() throws InterruptedException {
69+
public void schedulesOnce() {
7070
CustomResource customResource = TestUtils.testCustomResource();
7171

7272
timerEventSource.scheduleOnce(customResource, PERIOD);
7373

74-
Thread.sleep(2 * PERIOD + TESTING_TIME_SLACK);
75-
verify(eventHandlerMock, times(1)).handleEvent(any());
74+
untilAsserted(() -> assertThat(eventHandlerMock.events).hasSize(1));
75+
untilAsserted(PERIOD * 2, 0, () -> assertThat(eventHandlerMock.events).hasSize(1));
7676
}
7777

7878
@Test
79-
public void canCancelOnce() throws InterruptedException {
79+
public void canCancelOnce() {
8080
CustomResource customResource = TestUtils.testCustomResource();
8181

8282
timerEventSource.scheduleOnce(customResource, PERIOD);
8383
timerEventSource.cancelOnceSchedule(KubernetesResourceUtils.getUID(customResource));
8484

85-
Thread.sleep(PERIOD + TESTING_TIME_SLACK);
86-
verify(eventHandlerMock, never()).handleEvent(any());
85+
untilAsserted(() -> assertThat(eventHandlerMock.events).isEmpty());
8786
}
8887

8988
@Test
90-
public void canRescheduleOnceEvent() throws InterruptedException {
89+
public void canRescheduleOnceEvent() {
9190
CustomResource customResource = TestUtils.testCustomResource();
9291

9392
timerEventSource.scheduleOnce(customResource, PERIOD);
9493
timerEventSource.scheduleOnce(customResource, 2 * PERIOD);
9594

96-
Thread.sleep(PERIOD + TESTING_TIME_SLACK);
97-
verify(eventHandlerMock, never()).handleEvent(any());
98-
Thread.sleep(PERIOD + TESTING_TIME_SLACK);
99-
verify(eventHandlerMock, times(1)).handleEvent(any());
95+
untilAsserted(PERIOD * 2, PERIOD, () -> assertThat(eventHandlerMock.events).hasSize(1));
10096
}
10197

10298
@Test
103-
public void deRegistersOnceEventSources() throws InterruptedException {
99+
public void deRegistersOnceEventSources() {
104100
CustomResource customResource = TestUtils.testCustomResource();
105101

106102
timerEventSource.scheduleOnce(customResource, PERIOD);
107103
timerEventSource.eventSourceDeRegisteredForResource(getUID(customResource));
108-
Thread.sleep(PERIOD + TESTING_TIME_SLACK);
109104

110-
verify(eventHandlerMock, never()).handleEvent(any());
105+
untilAsserted(() -> assertThat(eventHandlerMock.events).isEmpty());
111106
}
112107

113108
@Test
@@ -120,12 +115,42 @@ public void eventNotRegisteredIfStopped() throws IOException {
120115
}
121116

122117
@Test
123-
public void eventNotFiredIfStopped() throws InterruptedException, IOException {
118+
public void eventNotFiredIfStopped() throws IOException {
124119
timerEventSource.scheduleOnce(TestUtils.testCustomResource(), PERIOD);
125120
timerEventSource.close();
126121

127-
Thread.sleep(PERIOD + TESTING_TIME_SLACK);
122+
untilAsserted(() -> assertThat(eventHandlerMock.events).isEmpty());
123+
}
124+
125+
private void untilAsserted(ThrowingRunnable assertion) {
126+
untilAsserted(INITIAL_DELAY, PERIOD, assertion);
127+
}
128+
129+
private void untilAsserted(long initialDelay, long interval, ThrowingRunnable assertion) {
130+
long delay = INITIAL_DELAY;
131+
long period = PERIOD;
132+
133+
ConditionFactory cf = Awaitility.await();
134+
135+
if (initialDelay > 0) {
136+
delay = initialDelay;
137+
cf = cf.pollDelay(initialDelay, TimeUnit.MILLISECONDS);
138+
}
139+
if (interval > 0) {
140+
period = interval;
141+
cf = cf.pollInterval(interval, TimeUnit.MILLISECONDS);
142+
}
143+
144+
cf = cf.atMost(delay + (period * 3), TimeUnit.MILLISECONDS);
145+
cf.untilAsserted(assertion);
146+
}
147+
148+
private static class CapturingEventHandler implements EventHandler {
149+
private final List<Event> events = new CopyOnWriteArrayList<>();
128150

129-
verify(eventHandlerMock, never()).handleEvent(any());
151+
@Override
152+
public void handleEvent(Event event) {
153+
events.add(event);
154+
}
130155
}
131156
}

0 commit comments

Comments
 (0)