1515 */
1616package io .javaoperatorsdk .operator .api .reconciler ;
1717
18+ import java .util .List ;
19+ import java .util .Set ;
20+
21+ import org .junit .jupiter .api .BeforeEach ;
1822import org .junit .jupiter .api .Test ;
1923
2024import io .fabric8 .kubernetes .api .model .ConfigMap ;
25+ import io .fabric8 .kubernetes .api .model .HasMetadata ;
26+ import io .fabric8 .kubernetes .api .model .ObjectMetaBuilder ;
27+ import io .fabric8 .kubernetes .api .model .Pod ;
28+ import io .fabric8 .kubernetes .api .model .PodBuilder ;
2129import io .fabric8 .kubernetes .api .model .Secret ;
2230import io .javaoperatorsdk .operator .processing .Controller ;
2331import io .javaoperatorsdk .operator .processing .event .EventSourceManager ;
2432import io .javaoperatorsdk .operator .processing .event .NoEventSourceForClassException ;
33+ import io .javaoperatorsdk .operator .processing .event .ResourceID ;
34+ import io .javaoperatorsdk .operator .processing .event .source .EventSource ;
2535
2636import static org .assertj .core .api .Assertions .assertThat ;
2737import static org .mockito .ArgumentMatchers .any ;
3040
3141class DefaultContextTest {
3242
33- private final Secret primary = new Secret ();
34- private final Controller <Secret > mockController = mock ();
43+ private DefaultContext <?> context ;
44+ private Controller <HasMetadata > mockController ;
45+ private EventSourceManager <HasMetadata > mockManager ;
3546
36- private final DefaultContext <?> context =
37- new DefaultContext <>(null , mockController , primary , false , false );
47+ @ BeforeEach
48+ void setUp () {
49+ mockController = mock ();
50+ mockManager = mock ();
51+ when (mockController .getEventSourceManager ()).thenReturn (mockManager );
52+
53+ context = new DefaultContext <>(null , mockController , new Secret (), false , false );
54+ }
3855
3956 @ Test
40- @ SuppressWarnings ("unchecked" )
4157 void getSecondaryResourceReturnsEmptyOptionalOnNonActivatedDRType () {
42- var mockManager = mock (EventSourceManager .class );
43- when (mockController .getEventSourceManager ()).thenReturn (mockManager );
4458 when (mockController .workflowContainsDependentForType (ConfigMap .class )).thenReturn (true );
4559 when (mockManager .getEventSourceFor (any (), any ()))
4660 .thenThrow (new NoEventSourceForClassException (ConfigMap .class ));
@@ -56,4 +70,101 @@ void setRetryInfo() {
5670 assertThat (newContext ).isSameAs (context );
5771 assertThat (newContext .getRetryInfo ()).hasValue (retryInfo );
5872 }
73+
74+ @ Test
75+ void latestDistinctKeepsOnlyLatestResourceVersion () {
76+ // Create multiple resources with same name and namespace but different versions
77+ var pod1v1 = podWithNameAndVersion ("pod1" , "100" );
78+ var pod1v2 = podWithNameAndVersion ("pod1" , "200" );
79+ var pod1v3 = podWithNameAndVersion ("pod1" , "150" );
80+
81+ // Create a resource with different name
82+ var pod2v1 = podWithNameAndVersion ("pod2" , "100" );
83+
84+ // Create a resource with same name but different namespace
85+ var pod1OtherNsv1 = podWithNameAndVersion ("pod1" , "50" , "other" );
86+
87+ setUpEventSourceWith (pod1v1 , pod1v2 , pod1v3 , pod1OtherNsv1 , pod2v1 );
88+
89+ var result = context .getSecondaryResourcesAsStream (Pod .class , true ).toList ();
90+
91+ // Should have 3 resources: pod1 in default (latest version 200), pod2 in default, and pod1 in
92+ // other
93+ assertThat (result ).hasSize (3 );
94+
95+ // Find pod1 in default namespace - should have version 200
96+ final var pod1InDefault =
97+ result .stream ()
98+ .filter (r -> ResourceID .fromResource (r ).isSameResource ("pod1" , "default" ))
99+ .findFirst ()
100+ .orElseThrow ();
101+ assertThat (pod1InDefault .getMetadata ().getResourceVersion ()).isEqualTo ("200" );
102+
103+ // Find pod2 in default namespace - should exist
104+ HasMetadata pod2InDefault =
105+ result .stream ()
106+ .filter (r -> ResourceID .fromResource (r ).isSameResource ("pod2" , "default" ))
107+ .findFirst ()
108+ .orElseThrow ();
109+ assertThat (pod2InDefault .getMetadata ().getResourceVersion ()).isEqualTo ("100" );
110+
111+ // Find pod1 in other namespace - should exist
112+ HasMetadata pod1InOther =
113+ result .stream ()
114+ .filter (r -> ResourceID .fromResource (r ).isSameResource ("pod1" , "other" ))
115+ .findFirst ()
116+ .orElseThrow ();
117+ assertThat (pod1InOther .getMetadata ().getResourceVersion ()).isEqualTo ("50" );
118+ }
119+
120+ private void setUpEventSourceWith (Pod ... pods ) {
121+ EventSource <Pod , HasMetadata > mockEventSource = mock ();
122+ when (mockEventSource .getSecondaryResources (any ())).thenReturn (Set .of (pods ));
123+ when (mockManager .getEventSourcesFor (Pod .class )).thenReturn (List .of (mockEventSource ));
124+ }
125+
126+ private static Pod podWithNameAndVersion (
127+ String name , String resourceVersion , String ... namespace ) {
128+ final var ns = namespace != null && namespace .length > 0 ? namespace [0 ] : "default" ;
129+ return new PodBuilder ()
130+ .withMetadata (
131+ new ObjectMetaBuilder ()
132+ .withName (name )
133+ .withNamespace (ns )
134+ .withResourceVersion (resourceVersion )
135+ .build ())
136+ .build ();
137+ }
138+
139+ @ Test
140+ void latestDistinctHandlesEmptyStream () {
141+ var result = context .getSecondaryResourcesAsStream (Pod .class , true ).toList ();
142+
143+ assertThat (result ).isEmpty ();
144+ }
145+
146+ @ Test
147+ void latestDistinctHandlesSingleResource () {
148+ final var pod = podWithNameAndVersion ("pod1" , "100" );
149+ setUpEventSourceWith (pod );
150+
151+ var result = context .getSecondaryResourcesAsStream (Pod .class , true ).toList ();
152+
153+ assertThat (result ).hasSize (1 );
154+ assertThat (result ).contains (pod );
155+ }
156+
157+ @ Test
158+ void latestDistinctComparesNumericVersionsCorrectly () {
159+ // Test that version 1000 is greater than version 999 (not lexicographic)
160+ final var podV999 = podWithNameAndVersion ("pod1" , "999" );
161+ final var podV1000 = podWithNameAndVersion ("pod1" , "1000" );
162+ setUpEventSourceWith (podV999 , podV1000 );
163+
164+ var result = context .getSecondaryResourcesAsStream (Pod .class , true ).toList ();
165+
166+ assertThat (result ).hasSize (1 );
167+ HasMetadata resultPod = result .iterator ().next ();
168+ assertThat (resultPod .getMetadata ().getResourceVersion ()).isEqualTo ("1000" );
169+ }
59170}
0 commit comments