Skip to content

Commit 001c506

Browse files
committed
obsolete handling unit test
Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
1 parent 936eb74 commit 001c506

File tree

2 files changed

+51
-23
lines changed

2 files changed

+51
-23
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,6 @@ public void handleRecentResourceCreate(ResourceID resourceID, R resource) {
190190

191191
@Override
192192
public Optional<R> get(ResourceID resourceID) {
193-
// The order of these two lookups matters. If we queried the informer cache first,
194-
// a race condition could occur: we might not find the resource there yet, then
195-
// process an informer event that evicts the temporary resource cache entry. At that
196-
// point the resource would already be present in the informer cache, but we would
197-
// have missed it in both caches during this call.
198193
Optional<R> resource = temporaryResourceCache.getResourceFromCache(resourceID);
199194
var res = cache.get(resourceID);
200195
if (comparableResourceVersions

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

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
*/
1616
package io.javaoperatorsdk.operator.processing.event.source.informer;
1717

18+
import java.time.Duration;
1819
import java.util.Map;
20+
import java.util.concurrent.Executors;
1921
import java.util.concurrent.ScheduledExecutorService;
2022

2123
import org.junit.jupiter.api.BeforeEach;
@@ -29,6 +31,7 @@
2931
import io.javaoperatorsdk.operator.processing.event.source.informer.TemporaryResourceCache.EventHandling;
3032

3133
import static org.assertj.core.api.Assertions.assertThat;
34+
import static org.awaitility.Awaitility.await;
3235
import static org.junit.jupiter.api.Assertions.assertTrue;
3336
import static org.mockito.ArgumentMatchers.any;
3437
import static org.mockito.Mockito.mock;
@@ -37,18 +40,23 @@
3740
class TemporaryPrimaryResourceCacheTest {
3841

3942
public static final String RESOURCE_VERSION = "2";
43+
public static final int OBSOLETE_RESOURCE_CHECK_INTERVAL = 100;
4044

4145
private TemporaryResourceCache<ConfigMap> temporaryResourceCache;
4246
private volatile String latestSyncVersion;
47+
private ManagedInformerEventSource managedInformerEventSource =
48+
mock(ManagedInformerEventSource.class);
4349

4450
@BeforeEach
4551
void setup() {
46-
var mes = mock(ManagedInformerEventSource.class);
52+
latestSyncVersion = "1";
53+
managedInformerEventSource = mock(ManagedInformerEventSource.class);
4754
var mim = mock(InformerManager.class);
48-
when(mes.manager()).thenReturn(mim);
55+
when(managedInformerEventSource.manager()).thenReturn(mim);
4956
when(mim.lastSyncResourceVersion(any())).then(a -> latestSyncVersion);
5057
temporaryResourceCache =
51-
new TemporaryResourceCache<>(true, mock(ScheduledExecutorService.class), mes);
58+
new TemporaryResourceCache<>(
59+
true, mock(ScheduledExecutorService.class), managedInformerEventSource);
5260
}
5361

5462
@Test
@@ -57,7 +65,7 @@ void updateAddsTheResourceIntoCacheIfTheInformerHasThePreviousResourceVersion()
5765
var prevTestResource = testResource();
5866
prevTestResource.getMetadata().setResourceVersion("1");
5967

60-
putResource(testResource);
68+
temporaryResourceCache.putResource(testResource);
6169

6270
var cached = temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource));
6371
assertThat(cached).isPresent();
@@ -72,7 +80,7 @@ void updateNotAddsTheResourceIntoCacheIfLaterVersionKnown() {
7280
testResource.toBuilder().editMetadata().withResourceVersion("3").endMetadata().build(),
7381
null);
7482
latestSyncVersion = "3";
75-
putResource(testResource);
83+
temporaryResourceCache.putResource(testResource);
7684

7785
var cached = temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource));
7886
assertThat(cached).isNotPresent();
@@ -82,7 +90,7 @@ void updateNotAddsTheResourceIntoCacheIfLaterVersionKnown() {
8290
void addOperationAddsTheResourceIfInformerCacheStillEmpty() {
8391
var testResource = testResource();
8492

85-
putResource(testResource);
93+
temporaryResourceCache.putResource(testResource);
8694

8795
var cached = temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource));
8896
assertThat(cached).isPresent();
@@ -92,9 +100,9 @@ void addOperationAddsTheResourceIfInformerCacheStillEmpty() {
92100
void addOperationNotAddsTheResourceIfInformerCacheNotEmpty() {
93101
var testResource = testResource();
94102

95-
putResource(testResource);
103+
temporaryResourceCache.putResource(testResource);
96104

97-
putResource(
105+
temporaryResourceCache.putResource(
98106
new ConfigMapBuilder(testResource)
99107
.editMetadata()
100108
.withResourceVersion("1")
@@ -140,7 +148,7 @@ void eventReceivedDuringFiltering() {
140148

141149
temporaryResourceCache.startEventFilteringModify(ResourceID.fromResource(testResource));
142150

143-
putResource(testResource);
151+
temporaryResourceCache.putResource(testResource);
144152
assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource)))
145153
.isPresent();
146154

@@ -162,7 +170,7 @@ void newerEventDuringFiltering() {
162170

163171
temporaryResourceCache.startEventFilteringModify(ResourceID.fromResource(testResource));
164172

165-
putResource(testResource);
173+
temporaryResourceCache.putResource(testResource);
166174
assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource)))
167175
.isPresent();
168176

@@ -186,7 +194,7 @@ void eventAfterFiltering() {
186194

187195
temporaryResourceCache.startEventFilteringModify(ResourceID.fromResource(testResource));
188196

189-
putResource(testResource);
197+
temporaryResourceCache.putResource(testResource);
190198
assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource)))
191199
.isPresent();
192200

@@ -213,7 +221,7 @@ void putBeforeEvent() {
213221

214222
var nextResource = testResource();
215223
nextResource.getMetadata().setResourceVersion("3");
216-
putResource(nextResource);
224+
temporaryResourceCache.putResource(nextResource);
217225

218226
// the result is obsolete
219227
result = temporaryResourceCache.onAddOrUpdateEvent(ResourceAction.UPDATED, nextResource, null);
@@ -228,16 +236,18 @@ void putBeforeEventWithEventFiltering() {
228236
var result =
229237
temporaryResourceCache.onAddOrUpdateEvent(ResourceAction.ADDED, testResource, null);
230238
assertThat(result).isEqualTo(EventHandling.NEW);
239+
latestSyncVersion = RESOURCE_VERSION;
231240

232241
var nextResource = testResource();
233242
nextResource.getMetadata().setResourceVersion("3");
234243
var resourceId = ResourceID.fromResource(testResource);
235244

236245
temporaryResourceCache.startEventFilteringModify(resourceId);
237-
putResource(nextResource);
246+
temporaryResourceCache.putResource(nextResource);
238247
temporaryResourceCache.doneEventFilterModify(resourceId, "3");
239248

240249
// the result is obsolete
250+
latestSyncVersion = "3";
241251
result = temporaryResourceCache.onAddOrUpdateEvent(ResourceAction.UPDATED, nextResource, null);
242252
assertThat(result).isEqualTo(EventHandling.OBSOLETE);
243253
}
@@ -261,7 +271,7 @@ void putAfterEventWithEventFilteringNoPost() {
261271
ResourceAction.UPDATED, nextResource, testResource);
262272
// the result is deferred
263273
assertThat(result).isEqualTo(EventHandling.DEFER);
264-
putResource(nextResource);
274+
temporaryResourceCache.putResource(testResource);
265275
var postEvent = temporaryResourceCache.doneEventFilterModify(resourceId, "3");
266276

267277
// there is no post event because the done call claimed responsibility for rv 3
@@ -301,19 +311,42 @@ void rapidDeletion() {
301311
.build(),
302312
false);
303313
latestSyncVersion = "3";
304-
putResource(testResource);
314+
temporaryResourceCache.putResource(testResource);
305315

306316
assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource)))
307317
.isEmpty();
308318
}
309319

310-
private void putResource(ConfigMap testResource) {
311-
temporaryResourceCache.putResource(testResource);
320+
@Test
321+
void removalOfObsoleteResources() {
322+
this.temporaryResourceCache =
323+
new TemporaryResourceCache<>(
324+
true,
325+
OBSOLETE_RESOURCE_CHECK_INTERVAL,
326+
Executors.newScheduledThreadPool(1),
327+
managedInformerEventSource);
328+
var tr = testResource();
329+
this.temporaryResourceCache.putResource(tr);
330+
331+
await()
332+
.pollDelay(Duration.ofMillis(2 * OBSOLETE_RESOURCE_CHECK_INTERVAL))
333+
.untilAsserted(
334+
() ->
335+
assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(tr)))
336+
.isPresent());
337+
338+
latestSyncVersion = "3";
339+
340+
await()
341+
.untilAsserted(
342+
() ->
343+
assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(tr)))
344+
.isEmpty());
312345
}
313346

314347
private ConfigMap propagateTestResourceToCache() {
315348
var testResource = testResource();
316-
putResource(testResource);
349+
temporaryResourceCache.putResource(testResource);
317350
assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource)))
318351
.isPresent();
319352
return testResource;

0 commit comments

Comments
 (0)