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 .Mockito .mock ;
26
28
import static org .mockito .Mockito .when ;
27
29
@@ -45,6 +47,54 @@ void setup() {
45
47
when (mockedContext .getControllerConfiguration ()).thenReturn (controllerConfiguration );
46
48
}
47
49
50
+ @ Test
51
+ void noMatchWhenNoMatchingController () {
52
+ var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
53
+ var actual =
54
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
55
+ actual
56
+ .getMetadata ()
57
+ .getManagedFields ()
58
+ .removeIf (managedFieldsEntry -> managedFieldsEntry .getManager ().equals ("controller" ));
59
+
60
+ assertThat (matcher .matches (actual , desired , mockedContext )).isFalse ();
61
+ }
62
+
63
+ @ Test
64
+ void exceptionWhenDuplicateController () {
65
+ var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
66
+ var actual =
67
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
68
+ actual .getMetadata ().getManagedFields ().stream ()
69
+ .filter (managedFieldsEntry -> managedFieldsEntry .getManager ().equals ("controller" ))
70
+ .findFirst ()
71
+ .ifPresent (
72
+ managedFieldsEntry -> actual .getMetadata ().getManagedFields ().add (managedFieldsEntry ));
73
+
74
+ assertThatThrownBy (() -> matcher .matches (actual , desired , mockedContext ))
75
+ .isInstanceOf (OperatorException .class )
76
+ .hasMessage (
77
+ "More than one field manager exists with name: controller in resource: Deployment with"
78
+ + " name: test" );
79
+ }
80
+
81
+ @ Test
82
+ void matchWithSensitiveResource () {
83
+ var desired = loadResource ("secret-desired.yaml" , Secret .class );
84
+ var actual = loadResource ("secret.yaml" , Secret .class );
85
+
86
+ assertThat (matcher .matches (actual , desired , mockedContext )).isTrue ();
87
+ }
88
+
89
+ @ Test
90
+ void noMatchWithSensitiveResource () {
91
+ var desired = loadResource ("secret-desired.yaml" , Secret .class );
92
+ var actual = loadResource ("secret.yaml" , Secret .class );
93
+ actual .getData ().put ("key1" , "dmFsMg==" );
94
+
95
+ assertThat (matcher .matches (actual , desired , mockedContext )).isFalse ();
96
+ }
97
+
48
98
@ Test
49
99
void checksIfAddsNotAddedByController () {
50
100
var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
@@ -54,7 +104,40 @@ void checksIfAddsNotAddedByController() {
54
104
assertThat (matcher .matches (actual , desired , mockedContext )).isTrue ();
55
105
}
56
106
57
- // In the example the owner reference in a list is referenced by "k:", while all the fields are
107
+ @ Test
108
+ void throwExceptionWhenManagedListEntryNotFound () {
109
+ var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
110
+ var actual =
111
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
112
+ final var container = actual .getSpec ().getTemplate ().getSpec ().getContainers ().get (0 );
113
+ container .setName ("foobar" );
114
+
115
+ assertThatThrownBy (() -> matcher .matches (actual , desired , mockedContext ))
116
+ .isInstanceOf (IllegalStateException .class )
117
+ .hasMessage (
118
+ "Cannot find list element for key: {\" name\" :\" nginx\" } in map: [[image,"
119
+ + " imagePullPolicy, name, ports, resources, terminationMessagePath,"
120
+ + " terminationMessagePolicy]]" );
121
+ }
122
+
123
+ @ Test
124
+ void throwExceptionWhenDuplicateManagedListEntryFound () {
125
+ var desired = loadResource ("nginx-deployment.yaml" , Deployment .class );
126
+ var actual =
127
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
128
+ final var container = actual .getSpec ().getTemplate ().getSpec ().getContainers ().get (0 );
129
+ actual .getSpec ().getTemplate ().getSpec ().getContainers ().add (container );
130
+
131
+ assertThatThrownBy (() -> matcher .matches (actual , desired , mockedContext ))
132
+ .isInstanceOf (IllegalStateException .class )
133
+ .hasMessage (
134
+ "More targets found in list element for key: {\" name\" :\" nginx\" } in map: [[image,"
135
+ + " imagePullPolicy, name, ports, resources, terminationMessagePath,"
136
+ + " terminationMessagePolicy], [image, imagePullPolicy, name, ports, resources,"
137
+ + " terminationMessagePath, terminationMessagePolicy]]" );
138
+ }
139
+
140
+ // in the example the owner reference in a list is referenced by "k:", while all the fields are
58
141
// managed but not listed
59
142
@ Test
60
143
void emptyListElementMatchesAllFields () {
@@ -115,6 +198,14 @@ void addedLabelInDesiredMakesMatchFail() {
115
198
assertThat (matcher .matches (actualConfigMap , desiredConfigMap , mockedContext )).isFalse ();
116
199
}
117
200
201
+ @ Test
202
+ void withFinalizer () {
203
+ var desired = loadResource ("secret-with-finalizer-desired.yaml" , Secret .class );
204
+ var actual = loadResource ("secret-with-finalizer.yaml" , Secret .class );
205
+
206
+ assertThat (matcher .matches (actual , desired , mockedContext )).isTrue ();
207
+ }
208
+
118
209
@ ParameterizedTest
119
210
@ ValueSource (
120
211
strings = {
@@ -161,6 +252,23 @@ void testSanitizeState_statefulSetWithResources_withMismatch() {
161
252
assertThat (matcher .matches (actualStatefulSet , desiredStatefulSet , mockedContext )).isFalse ();
162
253
}
163
254
255
+ @ Test
256
+ void testSanitizeState_statefulSet_withResourceTypeMismatch () {
257
+ var desiredReplicaSet = loadResource ("sample-rs-resources-desired.yaml" , ReplicaSet .class );
258
+ var actualStatefulSet = loadResource ("sample-sts-resources.yaml" , StatefulSet .class );
259
+
260
+ assertThat (matcher .matches (actualStatefulSet , desiredReplicaSet , mockedContext )).isFalse ();
261
+ }
262
+
263
+ @ Test
264
+ void testSanitizeState_deployment_withResourceTypeMismatch () {
265
+ var desiredReplicaSet = loadResource ("sample-rs-resources-desired.yaml" , ReplicaSet .class );
266
+ var actualDeployment =
267
+ loadResource ("deployment-with-managed-fields-additional-controller.yaml" , Deployment .class );
268
+
269
+ assertThat (matcher .matches (actualDeployment , desiredReplicaSet , mockedContext )).isFalse ();
270
+ }
271
+
164
272
@ Test
165
273
void testSanitizeState_replicaSetWithResources () {
166
274
var desiredReplicaSet = loadResource ("sample-rs-resources-desired.yaml" , ReplicaSet .class );
@@ -178,6 +286,14 @@ void testSanitizeState_replicaSetWithResources_withMismatch() {
178
286
assertThat (matcher .matches (actualReplicaSet , desiredReplicaSet , mockedContext )).isFalse ();
179
287
}
180
288
289
+ @ Test
290
+ void testSanitizeState_replicaSet_withResourceTypeMismatch () {
291
+ var desiredDaemonSet = loadResource ("sample-ds-resources-desired.yaml" , DaemonSet .class );
292
+ var actualReplicaSet = loadResource ("sample-rs-resources.yaml" , ReplicaSet .class );
293
+
294
+ assertThat (matcher .matches (actualReplicaSet , desiredDaemonSet , mockedContext )).isFalse ();
295
+ }
296
+
181
297
@ Test
182
298
void testSanitizeState_daemonSetWithResources () {
183
299
var desiredDaemonSet = loadResource ("sample-ds-resources-desired.yaml" , DaemonSet .class );
@@ -194,6 +310,14 @@ void testSanitizeState_daemonSetWithResources_withMismatch() {
194
310
assertThat (matcher .matches (actualDaemonSet , desiredDaemonSet , mockedContext )).isFalse ();
195
311
}
196
312
313
+ @ Test
314
+ void testSanitizeState_daemonSet_withResourceTypeMismatch () {
315
+ var desiredReplicaSet = loadResource ("sample-rs-resources-desired.yaml" , ReplicaSet .class );
316
+ var actualDaemonSet = loadResource ("sample-ds-resources.yaml" , DaemonSet .class );
317
+
318
+ assertThat (matcher .matches (actualDaemonSet , desiredReplicaSet , mockedContext )).isFalse ();
319
+ }
320
+
197
321
@ ParameterizedTest
198
322
@ ValueSource (booleans = {true , false })
199
323
void testCustomMatcher_returnsExpectedMatchBasedOnReadOnlyLabel (boolean readOnly ) {
@@ -209,16 +333,22 @@ void testCustomMatcher_returnsExpectedMatchBasedOnReadOnlyLabel(boolean readOnly
209
333
}
210
334
211
335
@ Test
212
- @ SuppressWarnings ("unchecked" )
213
- void testSortMapWithNestedMap () {
214
- var nestedMap = new HashMap <String , Object >();
215
- nestedMap .put ("z" , 26 );
216
- nestedMap .put ("y" , 25 );
336
+ void keepOnlyManagedFields_withInvalidManagedFieldsKey () {
337
+ assertThatThrownBy (
338
+ () ->
339
+ SSABasedGenericKubernetesResourceMatcher .keepOnlyManagedFields (
340
+ Map .of (),
341
+ Map .of (),
342
+ Map .of ("invalid" , 1 ),
343
+ mockedContext .getClient ().getKubernetesSerialization ())) //
344
+ .isInstanceOf (IllegalStateException .class ) //
345
+ .hasMessage ("Key: invalid has no prefix: f:" );
346
+ }
217
347
218
- var unsortedMap = new HashMap < String , Object >();
219
- unsortedMap . put ( "b" , nestedMap );
220
- unsortedMap . put ( "a" , 1 );
221
- unsortedMap . put ( "c" , 2 );
348
+ @ Test
349
+ @ SuppressWarnings ( "unchecked" )
350
+ void testSortMap () {
351
+ final var unsortedMap = Map . of ( "b" , Map . of ( "z" , 26 , "y" , 25 ), "a" , List . of ( "w" , "v" ), "c" , 2 );
222
352
223
353
var sortedMap = SSABasedGenericKubernetesResourceMatcher .sortMap (unsortedMap );
224
354
assertThat (sortedMap .keySet ()).containsExactly ("a" , "b" , "c" );
@@ -229,18 +359,11 @@ void testSortMapWithNestedMap() {
229
359
230
360
@ Test
231
361
@ SuppressWarnings ("unchecked" )
232
- void sortListItemsTest () {
233
- var nestedMap1 = new HashMap <String , Object >();
234
- nestedMap1 .put ("z" , 26 );
235
- nestedMap1 .put ("y" , 25 );
236
-
237
- var nestedMap2 = new HashMap <String , Object >();
238
- nestedMap2 .put ("b" , 26 );
239
- nestedMap2 .put ("c" , 25 );
240
- nestedMap2 .put ("a" , 24 );
241
-
242
- var unsortedListItems = List .<Object >of (1 , nestedMap1 , nestedMap2 );
243
- var sortedListItems = SSABasedGenericKubernetesResourceMatcher .sortListItems (unsortedListItems );
362
+ void testSortListItems () {
363
+ final var unsortedList =
364
+ List .of (1 , Map .of ("z" , 26 , "y" , 25 ), Map .of ("b" , 26 , "c" , 25 , "a" , 24 ), List .of ("w" , "v" ));
365
+
366
+ var sortedListItems = SSABasedGenericKubernetesResourceMatcher .sortListItems (unsortedList );
244
367
assertThat (sortedListItems ).element (0 ).isEqualTo (1 );
245
368
246
369
var sortedNestedMap1 = (Map <String , Object >) sortedListItems .get (1 );
@@ -252,7 +375,7 @@ void sortListItemsTest() {
252
375
253
376
private static <R > R loadResource (String fileName , Class <R > clazz ) {
254
377
return ReconcilerUtils .loadYaml (
255
- clazz , SSABasedGenericKubernetesResourceMatcherTest .class , fileName );
378
+ clazz , SSABasedGenericKubernetesResourceMatcherTest .class , fileName );
256
379
}
257
380
258
381
private static class ReadOnlyAwareMatcher <T extends HasMetadata >
0 commit comments