@@ -32,7 +32,7 @@ class EventSchedulerTest {
32
32
@ SuppressWarnings ("unchecked" )
33
33
private EventDispatcher eventDispatcher = mock (EventDispatcher .class );
34
34
35
- private EventScheduler eventScheduler = new EventScheduler ( eventDispatcher , new GenericRetry (). setMaxAttempts ( MAX_RETRY_ATTEMPTS ). withLinearRetry () );
35
+ private EventScheduler eventScheduler = initScheduler ( true );
36
36
37
37
private List <EventProcessingDetail > eventProcessingList = Collections .synchronizedList (new ArrayList <>());
38
38
@@ -55,6 +55,7 @@ public void eventsAreNotExecutedConcurrentlyForSameResource() throws Interrupted
55
55
CustomResource resource1 = sampleResource ();
56
56
CustomResource resource2 = sampleResource ();
57
57
resource2 .getMetadata ().setResourceVersion ("2" );
58
+ resource2 .getMetadata ().setGeneration (2l );
58
59
59
60
eventScheduler .eventReceived (Watcher .Action .MODIFIED , resource1 );
60
61
eventScheduler .eventReceived (Watcher .Action .MODIFIED , resource2 );
@@ -70,14 +71,56 @@ public void eventsAreNotExecutedConcurrentlyForSameResource() throws Interrupted
70
71
"Start time of event 2 is after end time of event 1" );
71
72
}
72
73
74
+ @ Test
75
+ public void generationAwareSchedulingSkipsEventsWithoutIncreasedGeneration () {
76
+ normalDispatcherExecution ();
77
+ CustomResource resource1 = sampleResource ();
78
+ CustomResource resource2 = sampleResource ();
79
+ resource2 .getMetadata ().setResourceVersion ("2" );
80
+
81
+ eventScheduler .eventReceived (Watcher .Action .MODIFIED , resource1 );
82
+ eventScheduler .eventReceived (Watcher .Action .MODIFIED , resource2 );
83
+
84
+ waitTimeForExecution (2 );
85
+ assertThat (eventProcessingList ).hasSize (1 )
86
+ .matches (list ->
87
+ eventProcessingList .get (0 ).getCustomResource ().getMetadata ().getResourceVersion ().equals ("1" ));
88
+
89
+ }
90
+
91
+ @ Test
92
+ public void notGenerationAwareSchedulingProcessesAllEventsRegardlessOfGeneration () {
93
+ generationUnAwareScheduler ();
94
+ normalDispatcherExecution ();
95
+ CustomResource resource1 = sampleResource ();
96
+ CustomResource resource2 = sampleResource ();
97
+ resource2 .getMetadata ().setResourceVersion ("2" );
98
+
99
+ eventScheduler .eventReceived (Watcher .Action .MODIFIED , resource1 );
100
+ eventScheduler .eventReceived (Watcher .Action .MODIFIED , resource2 );
101
+
102
+ waitTimeForExecution (2 );
103
+ log .info ("Event processing details 1.: {}. 2: {}" , eventProcessingList .get (0 ), eventProcessingList .get (1 ));
104
+ assertThat (eventProcessingList ).hasSize (2 )
105
+ .matches (list -> eventProcessingList .get (0 ).getCustomResource ().getMetadata ().getResourceVersion ().equals ("1" ) &&
106
+ eventProcessingList .get (1 ).getCustomResource ().getMetadata ().getResourceVersion ().equals ("2" ),
107
+ "Events processed in correct order" )
108
+ .matches (list ->
109
+ eventProcessingList .get (0 ).getEndTime ().isBefore (eventProcessingList .get (1 ).startTime ),
110
+ "Start time of event 2 is after end time of event 1" );
111
+ }
112
+
113
+ // note that this is true for generation aware scheduling
73
114
@ Test
74
115
public void onlyLastEventIsScheduledIfMoreReceivedDuringAndExecution () {
75
116
normalDispatcherExecution ();
76
117
CustomResource resource1 = sampleResource ();
77
118
CustomResource resource2 = sampleResource ();
78
119
resource2 .getMetadata ().setResourceVersion ("2" );
120
+ resource2 .getMetadata ().setGeneration (2l );
79
121
CustomResource resource3 = sampleResource ();
80
122
resource3 .getMetadata ().setResourceVersion ("3" );
123
+ resource3 .getMetadata ().setGeneration (3l );
81
124
82
125
eventScheduler .eventReceived (Watcher .Action .MODIFIED , resource1 );
83
126
eventScheduler .eventReceived (Watcher .Action .MODIFIED , resource2 );
@@ -118,6 +161,7 @@ public void processesNewEventIfItIsReceivedAfterExecutionInError() {
118
161
CustomResource resource1 = sampleResource ();
119
162
CustomResource resource2 = sampleResource ();
120
163
resource2 .getMetadata ().setResourceVersion ("2" );
164
+ resource2 .getMetadata ().setGeneration (2l );
121
165
122
166
doAnswer (this ::exceptionInExecution ).when (eventDispatcher ).handleEvent (any (Watcher .Action .class ), eq (resource1 ));
123
167
doAnswer (this ::normalExecution ).when (eventDispatcher ).handleEvent (any (Watcher .Action .class ), eq (resource2 ));
@@ -140,7 +184,7 @@ public void processesNewEventIfItIsReceivedAfterExecutionInError() {
140
184
}
141
185
142
186
@ Test
143
- public void numberOfRetriesIsLimited () {
187
+ public void numberOfRetriesCanBeLimited () {
144
188
doAnswer (this ::exceptionInExecution ).when (eventDispatcher ).handleEvent (any (Watcher .Action .class ), any (CustomResource .class ));
145
189
146
190
eventScheduler .eventReceived (Watcher .Action .MODIFIED , sampleResource ());
@@ -166,6 +210,14 @@ private Object normalExecution(InvocationOnMock invocation) {
166
210
}
167
211
}
168
212
213
+ private void generationUnAwareScheduler () {
214
+ eventScheduler = initScheduler (false );
215
+ }
216
+
217
+ private EventScheduler initScheduler (boolean generationAware ) {
218
+ return new EventScheduler (eventDispatcher ,
219
+ new GenericRetry ().setMaxAttempts (MAX_RETRY_ATTEMPTS ).withLinearRetry (), generationAware );
220
+ }
169
221
170
222
private Object exceptionInExecution (InvocationOnMock invocation ) {
171
223
try {
@@ -203,7 +255,7 @@ CustomResource sampleResource() {
203
255
resource .setMetadata (new ObjectMetaBuilder ()
204
256
.withCreationTimestamp ("creationTimestamp" )
205
257
.withDeletionGracePeriodSeconds (10L )
206
- .withGeneration (10L )
258
+ .withGeneration (1L )
207
259
.withName ("name" )
208
260
.withNamespace ("namespace" )
209
261
.withResourceVersion ("1" )
0 commit comments