@@ -56,6 +56,7 @@ public class FileSettingsServiceTests extends ESTestCase {
56
56
private Environment env ;
57
57
private ClusterService clusterService ;
58
58
private FileSettingsService fileSettingsService ;
59
+ private ReservedClusterStateService controller ;
59
60
private ThreadPool threadpool ;
60
61
61
62
@ Before
@@ -86,10 +87,7 @@ public void setUp() throws Exception {
86
87
87
88
ClusterSettings clusterSettings = new ClusterSettings (Settings .EMPTY , ClusterSettings .BUILT_IN_CLUSTER_SETTINGS );
88
89
89
- ReservedClusterStateService controller = new ReservedClusterStateService (
90
- clusterService ,
91
- List .of (new ReservedClusterSettingsAction (clusterSettings ))
92
- );
90
+ controller = new ReservedClusterStateService (clusterService , List .of (new ReservedClusterSettingsAction (clusterSettings )));
93
91
94
92
fileSettingsService = new FileSettingsService (clusterService , controller , env );
95
93
}
@@ -217,4 +215,93 @@ public void testInitialFile() throws Exception {
217
215
service .stop ();
218
216
service .close ();
219
217
}
218
+
219
+ @ SuppressWarnings ("unchecked" )
220
+ public void testStopWorksInMiddleOfProcessing () throws Exception {
221
+ var spiedController = spy (controller );
222
+ var fsService = new FileSettingsService (clusterService , spiedController , env );
223
+
224
+ FileSettingsService service = spy (fsService );
225
+ CountDownLatch processFileLatch = new CountDownLatch (1 );
226
+ CountDownLatch deadThreadLatch = new CountDownLatch (1 );
227
+
228
+ doAnswer ((Answer <Void >) invocation -> {
229
+ processFileLatch .countDown ();
230
+ new Thread (() -> {
231
+ // Simulate a thread that never comes back and decrements the
232
+ // countdown latch in FileSettingsService.processFileSettings
233
+ try {
234
+ deadThreadLatch .await ();
235
+ } catch (InterruptedException e ) {
236
+ throw new RuntimeException (e );
237
+ }
238
+ }).start ();
239
+ return null ;
240
+ }).when (spiedController ).process (any (String .class ), any (XContentParser .class ), any (Consumer .class ));
241
+
242
+ service .start ();
243
+ assertTrue (service .watching ());
244
+
245
+ Files .createDirectories (service .operatorSettingsDir ());
246
+
247
+ // Make some fake settings file to cause the file settings service to process it
248
+ Files .write (service .operatorSettingsFile (), "{}" .getBytes (StandardCharsets .UTF_8 ));
249
+
250
+ // we need to wait a bit, on MacOS it may take up to 10 seconds for the Java watcher service to notice the file,
251
+ // on Linux is instantaneous. Windows is instantaneous too.
252
+ processFileLatch .await (30 , TimeUnit .SECONDS );
253
+
254
+ // Stopping the service should interrupt the watcher thread, we should be able to stop
255
+ service .stop ();
256
+ assertFalse (service .watching ());
257
+ service .close ();
258
+ // let the deadlocked thread end, so we can cleanly exit the test
259
+ deadThreadLatch .countDown ();
260
+ }
261
+
262
+ @ SuppressWarnings ("unchecked" )
263
+ public void testStopWorksIfProcessingDidntReturnYet () throws Exception {
264
+ var spiedController = spy (controller );
265
+ var fsService = new FileSettingsService (clusterService , spiedController , env );
266
+
267
+ FileSettingsService service = spy (fsService );
268
+ CountDownLatch processFileLatch = new CountDownLatch (1 );
269
+ CountDownLatch deadThreadLatch = new CountDownLatch (1 );
270
+
271
+ doAnswer ((Answer <Void >) invocation -> {
272
+ processFileLatch .countDown ();
273
+ // allow the other thread to continue, but hold on a bit to avoid
274
+ // setting the count-down latch in the main watcher loop.
275
+ Thread .sleep (1_000 );
276
+ new Thread (() -> {
277
+ // Simulate a thread that never comes back and decrements the
278
+ // countdown latch in FileSettingsService.processFileSettings
279
+ try {
280
+ deadThreadLatch .await ();
281
+ } catch (InterruptedException e ) {
282
+ throw new RuntimeException (e );
283
+ }
284
+ }).start ();
285
+ return null ;
286
+ }).when (spiedController ).process (any (String .class ), any (XContentParser .class ), any (Consumer .class ));
287
+
288
+ service .start ();
289
+ assertTrue (service .watching ());
290
+
291
+ Files .createDirectories (service .operatorSettingsDir ());
292
+
293
+ // Make some fake settings file to cause the file settings service to process it
294
+ Files .write (service .operatorSettingsFile (), "{}" .getBytes (StandardCharsets .UTF_8 ));
295
+
296
+ // we need to wait a bit, on MacOS it may take up to 10 seconds for the Java watcher service to notice the file,
297
+ // on Linux is instantaneous. Windows is instantaneous too.
298
+ processFileLatch .await (30 , TimeUnit .SECONDS );
299
+
300
+ // Stopping the service should interrupt the watcher thread, we should be able to stop
301
+ service .stop ();
302
+ assertFalse (service .watching ());
303
+ service .close ();
304
+ // let the deadlocked thread end, so we can cleanly exit the test
305
+ deadThreadLatch .countDown ();
306
+ }
220
307
}
0 commit comments