Skip to content

Commit cc08d4d

Browse files
committed
wip
Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
1 parent cf7ed55 commit cc08d4d

1 file changed

Lines changed: 125 additions & 7 deletions

File tree

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java

Lines changed: 125 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,28 @@ void filtersOnDeleteEvents() {
168168
verify(eventHandlerMock, never()).handleEvent(any());
169169
}
170170

171+
@Test
172+
void deletePropagatesEventWhenTempCacheReturnsDeleteEvent() {
173+
var resource = testDeployment();
174+
when(temporaryResourceCache.onDeleteEvent(resource, false))
175+
.thenReturn(
176+
Optional.of(new GenericResourceEvent(ResourceAction.DELETED, resource, null, false)));
177+
178+
informerEventSource.onDelete(resource, false);
179+
180+
verify(eventHandlerMock, times(1)).handleEvent(any());
181+
}
182+
183+
@Test
184+
void deleteDoesNotPropagateWhenTempCacheReturnsEmpty() {
185+
var resource = testDeployment();
186+
when(temporaryResourceCache.onDeleteEvent(resource, false)).thenReturn(Optional.empty());
187+
188+
informerEventSource.onDelete(resource, false);
189+
190+
verify(eventHandlerMock, never()).handleEvent(any());
191+
}
192+
171193
@RepeatedTest(REPEAT_COUNT)
172194
void handlesPrevResourceVersionForUpdate() {
173195
withRealTemporaryResourceCache();
@@ -187,13 +209,7 @@ void handlesPrevResourceVersionForUpdate() {
187209
void handlesPrevResourceVersionForUpdateInCaseOfException() {
188210
withRealTemporaryResourceCache();
189211

190-
CountDownLatch latch =
191-
EventFilterTestUtils.sendForEventFilteringUpdate(
192-
informerEventSource,
193-
testDeployment(),
194-
r -> {
195-
throw new KubernetesClientException("fake");
196-
});
212+
CountDownLatch latch = sendForExceptionThrowingUpdate();
197213
informerEventSource.onUpdate(
198214
deploymentWithResourceVersion(1), deploymentWithResourceVersion(2));
199215
latch.countDown();
@@ -202,6 +218,99 @@ void handlesPrevResourceVersionForUpdateInCaseOfException() {
202218
expectNoActiveUpdates();
203219
}
204220

221+
@RepeatedTest(REPEAT_COUNT)
222+
void failedUpdate_withNoEventsDuringWindow_propagatesNothing() {
223+
// No event arrives between start and the thrown exception. doneEventFilterModify
224+
// sees an empty filter window with no own writes — summary must be empty.
225+
withRealTemporaryResourceCache();
226+
227+
CountDownLatch latch = sendForExceptionThrowingUpdate();
228+
latch.countDown();
229+
230+
assertNoEventProduced();
231+
expectNoActiveUpdates();
232+
assertThat(temporaryResourceCache.getResources()).isEmpty();
233+
}
234+
235+
@RepeatedTest(REPEAT_COUNT)
236+
void failedUpdate_withMultipleEventsDuringWindow_synthesizesSummary() {
237+
// Multiple foreign updates arrive while we are about to fail. Since no own write
238+
// happened, every related event is foreign and must be folded into one summary
239+
// event spanning first.previous → last.resource.
240+
withRealTemporaryResourceCache();
241+
242+
CountDownLatch latch = sendForExceptionThrowingUpdate();
243+
informerEventSource.onUpdate(
244+
deploymentWithResourceVersion(1), deploymentWithResourceVersion(2));
245+
informerEventSource.onUpdate(
246+
deploymentWithResourceVersion(2), deploymentWithResourceVersion(3));
247+
latch.countDown();
248+
249+
expectHandleAddEvent(3, 1);
250+
expectNoActiveUpdates();
251+
}
252+
253+
@RepeatedTest(REPEAT_COUNT)
254+
void failedUpdate_withDeleteEventDuringWindow_propagatesDelete() {
255+
// delete arrives during the (failing) filter window — must surface as DELETE.
256+
withRealTemporaryResourceCache();
257+
258+
CountDownLatch latch = sendForExceptionThrowingUpdate();
259+
informerEventSource.onDelete(deploymentWithResourceVersion(2), false);
260+
latch.countDown();
261+
262+
expectHandleDeleteEvent(2);
263+
expectNoActiveUpdates();
264+
}
265+
266+
@RepeatedTest(REPEAT_COUNT)
267+
void failedUpdate_withUpdateThenDelete_propagatesDelete() {
268+
// Update followed by delete inside a failing filter window: last event is DELETE,
269+
// so the summary must surface the delete (not a synthesized update).
270+
withRealTemporaryResourceCache();
271+
272+
CountDownLatch latch = sendForExceptionThrowingUpdate();
273+
informerEventSource.onUpdate(
274+
deploymentWithResourceVersion(1), deploymentWithResourceVersion(2));
275+
informerEventSource.onDelete(deploymentWithResourceVersion(3), false);
276+
latch.countDown();
277+
278+
expectHandleDeleteEvent(3);
279+
expectNoActiveUpdates();
280+
}
281+
282+
@RepeatedTest(REPEAT_COUNT)
283+
void failedUpdate_doesNotPopulateTempCache() {
284+
// putResource is only called from handleRecentResourceUpdate, which never runs
285+
// when updateMethod throws. The temp cache must therefore stay empty.
286+
withRealTemporaryResourceCache();
287+
288+
CountDownLatch latch = sendForExceptionThrowingUpdate();
289+
informerEventSource.onUpdate(
290+
deploymentWithResourceVersion(1), deploymentWithResourceVersion(2));
291+
latch.countDown();
292+
293+
expectHandleAddEvent(2, 1);
294+
expectNoActiveUpdates();
295+
assertThat(temporaryResourceCache.getResources()).isEmpty();
296+
}
297+
298+
@RepeatedTest(REPEAT_COUNT)
299+
void eventReceivedAfterFailedUpdate_isPropagatedNormally() {
300+
// After the exception unwinds and the filter window is fully closed, subsequent
301+
// events must propagate via the regular non-filtered path.
302+
withRealTemporaryResourceCache();
303+
304+
CountDownLatch latch = sendForExceptionThrowingUpdate();
305+
latch.countDown();
306+
expectNoActiveUpdates();
307+
308+
informerEventSource.onUpdate(
309+
deploymentWithResourceVersion(1), deploymentWithResourceVersion(2));
310+
311+
expectHandleAddEvent(2, 1);
312+
}
313+
205314
@RepeatedTest(REPEAT_COUNT)
206315
void handlesPrevResourceVersionForUpdateInCaseOfMultipleUpdates() {
207316
withRealTemporaryResourceCache();
@@ -597,6 +706,15 @@ private CountDownLatch sendForEventFilteringUpdate(Deployment deployment, int re
597706
informerEventSource, deployment, r -> withResourceVersion(deployment, resourceVersion));
598707
}
599708

709+
private CountDownLatch sendForExceptionThrowingUpdate() {
710+
return EventFilterTestUtils.sendForEventFilteringUpdate(
711+
informerEventSource,
712+
testDeployment(),
713+
r -> {
714+
throw new KubernetesClientException("fake");
715+
});
716+
}
717+
600718
private void withRealTemporaryResourceCache() {
601719
var mes = mock(ManagedInformerEventSource.class);
602720
var mim = mock(InformerManager.class);

0 commit comments

Comments
 (0)