1
1
package io .javaoperatorsdk .operator .processing .dependent .kubernetes ;
2
2
3
- import java .util .HashMap ;
4
3
import java .util .List ;
5
4
import java .util .Map ;
6
5
11
10
12
11
import io .fabric8 .kubernetes .api .model .ConfigMap ;
13
12
import io .fabric8 .kubernetes .api .model .HasMetadata ;
13
+ import io .fabric8 .kubernetes .api .model .Secret ;
14
14
import io .fabric8 .kubernetes .api .model .apps .DaemonSet ;
15
15
import io .fabric8 .kubernetes .api .model .apps .Deployment ;
16
16
import io .fabric8 .kubernetes .api .model .apps .ReplicaSet ;
17
17
import io .fabric8 .kubernetes .api .model .apps .StatefulSet ;
18
18
import io .javaoperatorsdk .operator .MockKubernetesClient ;
19
+ import io .javaoperatorsdk .operator .OperatorException ;
19
20
import io .javaoperatorsdk .operator .ReconcilerUtils ;
20
21
import io .javaoperatorsdk .operator .api .config .ConfigurationService ;
21
22
import io .javaoperatorsdk .operator .api .config .ControllerConfiguration ;
22
23
import io .javaoperatorsdk .operator .api .reconciler .Context ;
23
24
24
25
import static org .assertj .core .api .Assertions .assertThat ;
26
+ import static org .assertj .core .api .Assertions .assertThatThrownBy ;
25
27
import static org .mockito .ArgumentMatchers .any ;
26
28
import static org .mockito .Mockito .mock ;
27
29
import static org .mockito .Mockito .when ;
@@ -47,6 +49,54 @@ void setup() {
47
49
when (mockedContext .getControllerConfiguration ()).thenReturn (controllerConfiguration );
48
50
}
49
51
52
+ @ Test
53
+ void noMatchWhenNoMatchingController () {
54
+ var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
55
+ var actual =
56
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
57
+ actual
58
+ .getMetadata ()
59
+ .getManagedFields ()
60
+ .removeIf (managedFieldsEntry -> managedFieldsEntry .getManager ().equals ("controller" ));
61
+
62
+ assertThat (matcher .matches (actual , desired , mockedContext )).isFalse ();
63
+ }
64
+
65
+ @ Test
66
+ void exceptionWhenDuplicateController () {
67
+ var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
68
+ var actual =
69
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
70
+ actual .getMetadata ().getManagedFields ().stream ()
71
+ .filter (managedFieldsEntry -> managedFieldsEntry .getManager ().equals ("controller" ))
72
+ .findFirst ()
73
+ .ifPresent (
74
+ managedFieldsEntry -> actual .getMetadata ().getManagedFields ().add (managedFieldsEntry ));
75
+
76
+ assertThatThrownBy (() -> matcher .matches (actual , desired , mockedContext ))
77
+ .isInstanceOf (OperatorException .class )
78
+ .hasMessage (
79
+ "More than one field manager exists with name: controller in resource: Deployment with"
80
+ + " name: test" );
81
+ }
82
+
83
+ @ Test
84
+ void matchWithSensitiveResource () {
85
+ var desired = loadResource ("secret-desired.yaml" , Secret .class );
86
+ var actual = loadResource ("secret.yaml" , Secret .class );
87
+
88
+ assertThat (matcher .matches (actual , desired , mockedContext )).isTrue ();
89
+ }
90
+
91
+ @ Test
92
+ void noMatchWithSensitiveResource () {
93
+ var desired = loadResource ("secret-desired.yaml" , Secret .class );
94
+ var actual = loadResource ("secret.yaml" , Secret .class );
95
+ actual .getData ().put ("key1" , "dmFsMg==" );
96
+
97
+ assertThat (matcher .matches (actual , desired , mockedContext )).isFalse ();
98
+ }
99
+
50
100
@ Test
51
101
void checksIfAddsNotAddedByController () {
52
102
var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
@@ -56,7 +106,40 @@ void checksIfAddsNotAddedByController() {
56
106
assertThat (matcher .matches (actual , desired , mockedContext )).isTrue ();
57
107
}
58
108
59
- // In the example the owner reference in a list is referenced by "k:", while all the fields are
109
+ @ Test
110
+ void throwExceptionWhenManagedListEntryNotFound () {
111
+ var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
112
+ var actual =
113
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
114
+ final var container = actual .getSpec ().getTemplate ().getSpec ().getContainers ().get (0 );
115
+ container .setName ("foobar" );
116
+
117
+ assertThatThrownBy (() -> matcher .matches (actual , desired , mockedContext ))
118
+ .isInstanceOf (IllegalStateException .class )
119
+ .hasMessage (
120
+ "Cannot find list element for key: {\" name\" :\" nginx\" } in map: [[image,"
121
+ + " imagePullPolicy, name, ports, resources, terminationMessagePath,"
122
+ + " terminationMessagePolicy]]" );
123
+ }
124
+
125
+ @ Test
126
+ void throwExceptionWhenDuplicateManagedListEntryFound () {
127
+ var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
128
+ var actual =
129
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
130
+ final var container = actual .getSpec ().getTemplate ().getSpec ().getContainers ().get (0 );
131
+ actual .getSpec ().getTemplate ().getSpec ().getContainers ().add (container );
132
+
133
+ assertThatThrownBy (() -> matcher .matches (actual , desired , mockedContext ))
134
+ .isInstanceOf (IllegalStateException .class )
135
+ .hasMessage (
136
+ "More targets found in list element for key: {\" name\" :\" nginx\" } in map: [[image,"
137
+ + " imagePullPolicy, name, ports, resources, terminationMessagePath,"
138
+ + " terminationMessagePolicy], [image, imagePullPolicy, name, ports, resources,"
139
+ + " terminationMessagePath, terminationMessagePolicy]]" );
140
+ }
141
+
142
+ // in the example the owner reference in a list is referenced by "k:", while all the fields are
60
143
// managed but not listed
61
144
@ Test
62
145
void emptyListElementMatchesAllFields () {
@@ -118,45 +201,11 @@ void addedLabelInDesiredMakesMatchFail() {
118
201
}
119
202
120
203
@ Test
121
- @ SuppressWarnings ("unchecked" )
122
- void sortListItemsTest () {
123
- var nestedMap1 = new HashMap <String , Object >();
124
- nestedMap1 .put ("z" , 26 );
125
- nestedMap1 .put ("y" , 25 );
126
-
127
- var nestedMap2 = new HashMap <String , Object >();
128
- nestedMap2 .put ("b" , 26 );
129
- nestedMap2 .put ("c" , 25 );
130
- nestedMap2 .put ("a" , 24 );
131
-
132
- var unsortedListItems = List .<Object >of (1 , nestedMap1 , nestedMap2 );
133
- var sortedListItems = matcher .sortListItems (unsortedListItems );
134
- assertThat (sortedListItems ).element (0 ).isEqualTo (1 );
135
-
136
- var sortedNestedMap1 = (Map <String , Object >) sortedListItems .get (1 );
137
- assertThat (sortedNestedMap1 .keySet ()).containsExactly ("y" , "z" );
204
+ void withFinalizer () {
205
+ var desired = loadResource ("secret-with-finalizer-desired.yaml" , Secret .class );
206
+ var actual = loadResource ("secret-with-finalizer.yaml" , Secret .class );
138
207
139
- var sortedNestedMap2 = (Map <String , Object >) sortedListItems .get (2 );
140
- assertThat (sortedNestedMap2 .keySet ()).containsExactly ("a" , "b" , "c" );
141
- }
142
-
143
- @ Test
144
- @ SuppressWarnings ("unchecked" )
145
- void testSortMapWithNestedMap () {
146
- var nestedMap = new HashMap <String , Object >();
147
- nestedMap .put ("z" , 26 );
148
- nestedMap .put ("y" , 25 );
149
-
150
- var unsortedMap = new HashMap <String , Object >();
151
- unsortedMap .put ("b" , nestedMap );
152
- unsortedMap .put ("a" , 1 );
153
- unsortedMap .put ("c" , 2 );
154
-
155
- var sortedMap = matcher .sortMap (unsortedMap );
156
- assertThat (sortedMap .keySet ()).containsExactly ("a" , "b" , "c" );
157
-
158
- var sortedNestedMap = (Map <String , Object >) sortedMap .get ("b" );
159
- assertThat (sortedNestedMap .keySet ()).containsExactly ("y" , "z" );
208
+ assertThat (matcher .matches (actual , desired , mockedContext )).isTrue ();
160
209
}
161
210
162
211
@ ParameterizedTest
@@ -205,6 +254,23 @@ void testSanitizeState_statefulSetWithResources_withMismatch() {
205
254
assertThat (matcher .matches (actualStatefulSet , desiredStatefulSet , mockedContext )).isFalse ();
206
255
}
207
256
257
+ @ Test
258
+ void testSanitizeState_statefulSet_withResourceTypeMismatch () {
259
+ var desiredReplicaSet = loadResource ("sample-rs-resources-desired.yaml" , ReplicaSet .class );
260
+ var actualStatefulSet = loadResource ("sample-sts-resources.yaml" , StatefulSet .class );
261
+
262
+ assertThat (matcher .matches (actualStatefulSet , desiredReplicaSet , mockedContext )).isFalse ();
263
+ }
264
+
265
+ @ Test
266
+ void testSanitizeState_deployment_withResourceTypeMismatch () {
267
+ var desiredReplicaSet = loadResource ("sample-rs-resources-desired.yaml" , ReplicaSet .class );
268
+ var actualDeployment =
269
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
270
+
271
+ assertThat (matcher .matches (actualDeployment , desiredReplicaSet , mockedContext )).isFalse ();
272
+ }
273
+
208
274
@ Test
209
275
void testSanitizeState_replicaSetWithResources () {
210
276
var desiredReplicaSet = loadResource ("sample-rs-resources-desired.yaml" , ReplicaSet .class );
@@ -222,6 +288,14 @@ void testSanitizeState_replicaSetWithResources_withMismatch() {
222
288
assertThat (matcher .matches (actualReplicaSet , desiredReplicaSet , mockedContext )).isFalse ();
223
289
}
224
290
291
+ @ Test
292
+ void testSanitizeState_replicaSet_withResourceTypeMismatch () {
293
+ var desiredDaemonSet = loadResource ("sample-ds-resources-desired.yaml" , DaemonSet .class );
294
+ var actualReplicaSet = loadResource ("sample-rs-resources.yaml" , ReplicaSet .class );
295
+
296
+ assertThat (matcher .matches (actualReplicaSet , desiredDaemonSet , mockedContext )).isFalse ();
297
+ }
298
+
225
299
@ Test
226
300
void testSanitizeState_daemonSetWithResources () {
227
301
var desiredDaemonSet = loadResource ("sample-ds-resources-desired.yaml" , DaemonSet .class );
@@ -238,6 +312,14 @@ void testSanitizeState_daemonSetWithResources_withMismatch() {
238
312
assertThat (matcher .matches (actualDaemonSet , desiredDaemonSet , mockedContext )).isFalse ();
239
313
}
240
314
315
+ @ Test
316
+ void testSanitizeState_daemonSet_withResourceTypeMismatch () {
317
+ var desiredReplicaSet = loadResource ("sample-rs-resources-desired.yaml" , ReplicaSet .class );
318
+ var actualDaemonSet = loadResource ("sample-ds-resources.yaml" , DaemonSet .class );
319
+
320
+ assertThat (matcher .matches (actualDaemonSet , desiredReplicaSet , mockedContext )).isFalse ();
321
+ }
322
+
241
323
@ ParameterizedTest
242
324
@ ValueSource (booleans = {true , false })
243
325
void testCustomMatcher_returnsExpectedMatchBasedOnReadOnlyLabel (boolean readOnly ) {
@@ -263,6 +345,52 @@ void testCustomMatcher_returnsExpectedMatchBasedOnReadOnlyLabel(boolean readOnly
263
345
.isEqualTo (readOnly );
264
346
}
265
347
348
+ @ Test
349
+ void keepOnlyManagedFields_withInvalidManagedFieldsKey () {
350
+ assertThatThrownBy (
351
+ () ->
352
+ SSABasedGenericKubernetesResourceMatcher .keepOnlyManagedFields (
353
+ Map .of (),
354
+ Map .of (),
355
+ Map .of ("invalid" , 1 ),
356
+ mockedContext .getClient ().getKubernetesSerialization ())) //
357
+ .isInstanceOf (IllegalStateException .class ) //
358
+ .hasMessage ("Key: invalid has no prefix: f:" );
359
+ }
360
+
361
+ @ Test
362
+ @ SuppressWarnings ("unchecked" )
363
+ void testSortMap () {
364
+ final var unsortedMap = Map .of ("b" , Map .of ("z" , 26 , "y" , 25 ), "a" , List .of ("w" , "v" ), "c" , 2 );
365
+
366
+ var sortedMap = SSABasedGenericKubernetesResourceMatcher .sortMap (unsortedMap );
367
+ assertThat (sortedMap .keySet ()).containsExactly ("a" , "b" , "c" );
368
+
369
+ var sortedNestedMap = (Map <String , Object >) sortedMap .get ("b" );
370
+ assertThat (sortedNestedMap .keySet ()).containsExactly ("y" , "z" );
371
+ }
372
+
373
+ @ Test
374
+ @ SuppressWarnings ("unchecked" )
375
+ void testSortListItems () {
376
+ final var unsortedList =
377
+ List .of (1 , Map .of ("z" , 26 , "y" , 25 ), Map .of ("b" , 26 , "c" , 25 , "a" , 24 ), List .of ("w" , "v" ));
378
+
379
+ var sortedListItems = SSABasedGenericKubernetesResourceMatcher .sortListItems (unsortedList );
380
+ assertThat (sortedListItems ).element (0 ).isEqualTo (1 );
381
+
382
+ var sortedNestedMap1 = (Map <String , Object >) sortedListItems .get (1 );
383
+ assertThat (sortedNestedMap1 .keySet ()).containsExactly ("y" , "z" );
384
+
385
+ var sortedNestedMap2 = (Map <String , Object >) sortedListItems .get (2 );
386
+ assertThat (sortedNestedMap2 .keySet ()).containsExactly ("a" , "b" , "c" );
387
+ }
388
+
389
+ private static <R > R loadResource (String fileName , Class <R > clazz ) {
390
+ return ReconcilerUtils .loadYaml (
391
+ clazz , SSABasedGenericKubernetesResourceMatcherTest .class , fileName );
392
+ }
393
+
266
394
private static class ConfigMapDR extends KubernetesDependentResource <ConfigMap , ConfigMap > {
267
395
public ConfigMapDR () {
268
396
super (ConfigMap .class );
@@ -285,9 +413,4 @@ protected boolean matches(
285
413
return actualMap .equals (desiredMap );
286
414
}
287
415
}
288
-
289
- private static <R > R loadResource (String fileName , Class <R > clazz ) {
290
- return ReconcilerUtils .loadYaml (
291
- clazz , SSABasedGenericKubernetesResourceMatcherTest .class , fileName );
292
- }
293
416
}
0 commit comments