Skip to content

Commit 115e44d

Browse files
committed
retry tests, fixes
1 parent 4511728 commit 115e44d

File tree

3 files changed

+73
-12
lines changed

3 files changed

+73
-12
lines changed

operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/DefaultEventHandler.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,13 @@ void eventProcessingFinished(
108108
unsetUnderExecution(executionScope.getCustomResourceUid());
109109

110110
if (retry != null && postExecutionControl.exceptionDuringExecution()) {
111-
handleRetryOnException(executionScope, postExecutionControl);
111+
handleRetryOnException(executionScope);
112112
return;
113-
} else if (retry != null) {
114-
handleSuccessfulExecutionRegardingRetry(executionScope);
115113
}
116114

115+
if (retry != null) {
116+
markSuccessfulExecutionRegardingRetry(executionScope);
117+
}
117118
if (containsCustomResourceDeletedEvent(executionScope.getEvents())) {
118119
cleanupAfterDeletedEvent(executionScope.getCustomResourceUid());
119120
} else {
@@ -130,25 +131,24 @@ void eventProcessingFinished(
130131
* events (received meanwhile retry is in place or already in buffer) instantly or always wait
131132
* according to the retry timing if there was an exception.
132133
*/
133-
private void handleRetryOnException(
134-
ExecutionScope executionScope, PostExecutionControl postExecutionControl) {
134+
private void handleRetryOnException(ExecutionScope executionScope) {
135135
RetryExecution execution = getOrInitRetryExecution(executionScope);
136136
boolean newEventsExists = eventBuffer.newEventsExists(executionScope.getCustomResourceUid());
137137
eventBuffer.putBackEvents(executionScope.getCustomResourceUid(), executionScope.getEvents());
138138

139-
Optional<Long> nextDelay = execution.nextDelay();
140139
if (newEventsExists) {
141140
executeBufferedEvents(executionScope.getCustomResourceUid());
142141
return;
143142
}
143+
Optional<Long> nextDelay = execution.nextDelay();
144144
nextDelay.ifPresent(
145145
delay ->
146146
defaultEventSourceManager
147147
.getRetryTimerEventSource()
148148
.scheduleOnce(executionScope.getCustomResource(), delay));
149149
}
150150

151-
private void handleSuccessfulExecutionRegardingRetry(ExecutionScope executionScope) {
151+
private void markSuccessfulExecutionRegardingRetry(ExecutionScope executionScope) {
152152
retryState.remove(executionScope.getCustomResourceUid());
153153
defaultEventSourceManager
154154
.getRetryTimerEventSource()

operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventBuffer.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ public void addEvent(Event event) {
1414
}
1515

1616
public boolean newEventsExists(String resourceId) {
17-
return !events.get(resourceId).isEmpty();
17+
return events.get(resourceId) != null && !events.get(resourceId).isEmpty();
1818
}
1919

2020
public void putBackEvents(String resourceUid, List<Event> oldEvents) {
21-
events.get(resourceUid).addAll(0, oldEvents);
21+
List<Event> crEvents =
22+
events.computeIfAbsent(resourceUid, (id) -> new ArrayList<>(oldEvents.size()));
23+
crEvents.addAll(0, oldEvents);
2224
}
2325

2426
public boolean containsEvents(String customResourceId) {

operator-framework/src/test/java/io/javaoperatorsdk/operator/processing/DefaultEventHandlerTest.java

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
import io.javaoperatorsdk.operator.processing.event.Event;
1010
import io.javaoperatorsdk.operator.processing.event.internal.CustomResourceEvent;
1111
import io.javaoperatorsdk.operator.processing.event.internal.TimerEvent;
12+
import io.javaoperatorsdk.operator.processing.event.internal.TimerEventSource;
13+
import io.javaoperatorsdk.operator.processing.retry.GenericRetry;
1214
import io.javaoperatorsdk.operator.sample.simple.TestCustomResource;
15+
import java.util.Arrays;
1316
import java.util.List;
1417
import java.util.UUID;
1518
import org.junit.jupiter.api.BeforeEach;
@@ -23,14 +26,26 @@ class DefaultEventHandlerTest {
2326
public static final int SEPARATE_EXECUTION_TIMEOUT = 450;
2427
private EventDispatcher eventDispatcherMock = mock(EventDispatcher.class);
2528
private CustomResourceCache customResourceCache = new CustomResourceCache();
26-
private DefaultEventHandler defaultEventHandler =
27-
new DefaultEventHandler(customResourceCache, eventDispatcherMock, "Test", null);
2829
private DefaultEventSourceManager defaultEventSourceManagerMock =
2930
mock(DefaultEventSourceManager.class);
31+
private TimerEventSource retryTimerEventSourceMock = mock(TimerEventSource.class);
32+
33+
private DefaultEventHandler defaultEventHandler =
34+
new DefaultEventHandler(customResourceCache, eventDispatcherMock, "Test", null);
35+
36+
private DefaultEventHandler defaultEventHandlerWithRetry =
37+
new DefaultEventHandler(
38+
customResourceCache,
39+
eventDispatcherMock,
40+
"Test",
41+
GenericRetry.defaultLimitedExponentialRetry());
3042

3143
@BeforeEach
3244
public void setup() {
45+
when(defaultEventSourceManagerMock.getRetryTimerEventSource())
46+
.thenReturn(retryTimerEventSourceMock);
3347
defaultEventHandler.setDefaultEventSourceManager(defaultEventSourceManagerMock);
48+
defaultEventHandlerWithRetry.setDefaultEventSourceManager(defaultEventSourceManagerMock);
3449
}
3550

3651
@Test
@@ -85,13 +100,57 @@ public void cleanUpAfterDeleteEvent() {
85100
String uid = customResource.getMetadata().getUid();
86101

87102
defaultEventHandler.handleEvent(event);
88-
// todo awaitility?
103+
89104
waitMinimalTime();
90105

91106
verify(defaultEventSourceManagerMock, times(1)).cleanup(uid);
92107
assertThat(customResourceCache.getLatestResource(uid)).isNotPresent();
93108
}
94109

110+
@Test
111+
public void schedulesAnEventRetryOnException() {
112+
Event event = prepareCREvent();
113+
TestCustomResource customResource = testCustomResource();
114+
115+
ExecutionScope executionScope = new ExecutionScope(Arrays.asList(event), customResource);
116+
PostExecutionControl postExecutionControl =
117+
PostExecutionControl.exceptionDuringExecution(new RuntimeException("test"));
118+
119+
defaultEventHandlerWithRetry.eventProcessingFinished(executionScope, postExecutionControl);
120+
121+
verify(retryTimerEventSourceMock, times(1))
122+
.scheduleOnce(eq(customResource), eq(GenericRetry.DEFAULT_INITIAL_INTERVAL));
123+
}
124+
125+
@Test
126+
public void executesTheControllerInstantlyAfterErrorIfEventsBuffered() {
127+
Event event = prepareCREvent();
128+
TestCustomResource customResource = testCustomResource();
129+
customResource.getMetadata().setUid(event.getRelatedCustomResourceUid());
130+
ExecutionScope executionScope = new ExecutionScope(Arrays.asList(event), customResource);
131+
PostExecutionControl postExecutionControl =
132+
PostExecutionControl.exceptionDuringExecution(new RuntimeException("test"));
133+
134+
// start processing an event
135+
defaultEventHandlerWithRetry.handleEvent(event);
136+
// buffer an another event
137+
defaultEventHandlerWithRetry.handleEvent(event);
138+
verify(eventDispatcherMock, timeout(SEPARATE_EXECUTION_TIMEOUT).times(1))
139+
.handleExecution(any());
140+
141+
defaultEventHandlerWithRetry.eventProcessingFinished(executionScope, postExecutionControl);
142+
143+
ArgumentCaptor<ExecutionScope> executionScopeArgumentCaptor =
144+
ArgumentCaptor.forClass(ExecutionScope.class);
145+
verify(eventDispatcherMock, timeout(SEPARATE_EXECUTION_TIMEOUT).times(2))
146+
.handleExecution(executionScopeArgumentCaptor.capture());
147+
List<ExecutionScope> allValues = executionScopeArgumentCaptor.getAllValues();
148+
assertThat(allValues).hasSize(2);
149+
assertThat(allValues.get(1).getEvents()).hasSize(2);
150+
verify(retryTimerEventSourceMock, never())
151+
.scheduleOnce(eq(customResource), eq(GenericRetry.DEFAULT_INITIAL_INTERVAL));
152+
}
153+
95154
private void waitMinimalTime() {
96155
try {
97156
Thread.sleep(50);

0 commit comments

Comments
 (0)