33import static io .javaoperatorsdk .operator .processing .KubernetesResourceUtils .getUID ;
44import static org .assertj .core .api .Assertions .assertThat ;
55import 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
137import io .fabric8 .kubernetes .client .CustomResource ;
148import io .javaoperatorsdk .operator .TestUtils ;
159import io .javaoperatorsdk .operator .processing .KubernetesResourceUtils ;
10+ import io .javaoperatorsdk .operator .processing .event .Event ;
1611import io .javaoperatorsdk .operator .processing .event .EventHandler ;
1712import java .io .IOException ;
1813import 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 ;
1919import org .junit .jupiter .api .BeforeEach ;
20- import org .junit .jupiter .api .Disabled ;
2120import 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" )
2522class 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