|
19 | 19 |
|
20 | 20 | package org.elasticsearch.threadpool; |
21 | 21 |
|
22 | | -import org.apache.logging.log4j.Level; |
23 | | -import org.apache.logging.log4j.LogManager; |
24 | | -import org.apache.logging.log4j.Logger; |
25 | | -import org.apache.logging.log4j.core.LogEvent; |
26 | | -import org.elasticsearch.common.logging.Loggers; |
| 22 | +import org.elasticsearch.common.SuppressForbidden; |
27 | 23 | import org.elasticsearch.common.settings.Settings; |
28 | 24 | import org.elasticsearch.common.unit.TimeValue; |
29 | 25 | import org.elasticsearch.common.util.concurrent.AbstractRunnable; |
30 | 26 | import org.elasticsearch.common.util.concurrent.EsExecutors; |
31 | 27 | import org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor; |
32 | 28 | import org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor; |
33 | 29 | import org.elasticsearch.test.ESTestCase; |
34 | | -import org.elasticsearch.test.MockLogAppender; |
35 | 30 | import org.junit.After; |
36 | 31 | import org.junit.Before; |
37 | 32 |
|
38 | 33 | import java.util.Optional; |
39 | 34 | import java.util.concurrent.CountDownLatch; |
| 35 | +import java.util.concurrent.ExecutionException; |
40 | 36 | import java.util.concurrent.ExecutorService; |
| 37 | +import java.util.concurrent.ScheduledFuture; |
41 | 38 | import java.util.concurrent.ScheduledThreadPoolExecutor; |
42 | 39 | import java.util.concurrent.TimeUnit; |
43 | 40 | import java.util.concurrent.atomic.AtomicReference; |
| 41 | +import java.util.function.BiFunction; |
44 | 42 | import java.util.function.Consumer; |
45 | 43 |
|
46 | 44 | import static org.hamcrest.Matchers.containsString; |
47 | | -import static org.hamcrest.Matchers.equalTo; |
48 | 45 | import static org.hamcrest.Matchers.hasToString; |
49 | 46 | import static org.hamcrest.Matchers.instanceOf; |
50 | 47 |
|
@@ -260,6 +257,50 @@ public void testExecutionExceptionOnScheduler() throws InterruptedException { |
260 | 257 | } |
261 | 258 | } |
262 | 259 |
|
| 260 | + @SuppressForbidden(reason = "this tests that the deprecated method still works") |
| 261 | + public void testDeprecatedSchedule() throws ExecutionException, InterruptedException { |
| 262 | + verifyDeprecatedSchedule(((threadPool, runnable) |
| 263 | + -> threadPool.schedule(TimeValue.timeValueMillis(randomInt(10)), ThreadPool.Names.SAME, runnable))); |
| 264 | + } |
| 265 | + |
| 266 | + public void testThreadPoolScheduleDeprecated() throws ExecutionException, InterruptedException { |
| 267 | + verifyDeprecatedSchedule(((threadPool, runnable) |
| 268 | + -> threadPool.scheduleDeprecated(TimeValue.timeValueMillis(randomInt(10)), ThreadPool.Names.SAME, runnable))); |
| 269 | + } |
| 270 | + |
| 271 | + private void verifyDeprecatedSchedule(BiFunction<ThreadPool, |
| 272 | + Runnable, ScheduledFuture<?>> scheduleFunction) throws InterruptedException, ExecutionException { |
| 273 | + Thread.UncaughtExceptionHandler originalHandler = Thread.getDefaultUncaughtExceptionHandler(); |
| 274 | + CountDownLatch missingExceptions = new CountDownLatch(1); |
| 275 | + Thread.setDefaultUncaughtExceptionHandler((t, e) -> { |
| 276 | + missingExceptions.countDown(); |
| 277 | + }); |
| 278 | + try { |
| 279 | + ThreadPool threadPool = new TestThreadPool("test"); |
| 280 | + CountDownLatch missingExecutions = new CountDownLatch(1); |
| 281 | + try { |
| 282 | + scheduleFunction.apply(threadPool, missingExecutions::countDown) |
| 283 | + .get(); |
| 284 | + assertEquals(0, missingExecutions.getCount()); |
| 285 | + |
| 286 | + ExecutionException exception = expectThrows(ExecutionException.class, |
| 287 | + "schedule(...).get() must throw exception from runnable", |
| 288 | + () -> scheduleFunction.apply(threadPool, |
| 289 | + () -> { |
| 290 | + throw new IllegalArgumentException("FAIL"); |
| 291 | + } |
| 292 | + ).get()); |
| 293 | + |
| 294 | + assertEquals(IllegalArgumentException.class, exception.getCause().getClass()); |
| 295 | + assertTrue(missingExceptions.await(30, TimeUnit.SECONDS)); |
| 296 | + } finally { |
| 297 | + ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS); |
| 298 | + } |
| 299 | + } finally { |
| 300 | + Thread.setDefaultUncaughtExceptionHandler(originalHandler); |
| 301 | + } |
| 302 | + } |
| 303 | + |
263 | 304 | private Runnable delayMillis(Runnable r, int ms) { |
264 | 305 | return () -> { |
265 | 306 | try { |
@@ -369,60 +410,26 @@ private void runExecutionTest( |
369 | 410 |
|
370 | 411 | final CountDownLatch supplierLatch = new CountDownLatch(1); |
371 | 412 |
|
372 | | - Runnable job = () -> { |
373 | | - try { |
374 | | - runnable.run(); |
375 | | - } finally { |
376 | | - supplierLatch.countDown(); |
377 | | - } |
378 | | - }; |
379 | | - |
380 | | - // snoop on logging to also handle the cases where exceptions are simply logged in Scheduler. |
381 | | - final Logger schedulerLogger = LogManager.getLogger(Scheduler.SafeScheduledThreadPoolExecutor.class); |
382 | | - final MockLogAppender appender = new MockLogAppender(); |
383 | | - appender.addExpectation( |
384 | | - new MockLogAppender.LoggingExpectation() { |
385 | | - @Override |
386 | | - public void match(LogEvent event) { |
387 | | - if (event.getLevel() == Level.WARN) { |
388 | | - assertThat("no other warnings than those expected", |
389 | | - event.getMessage().getFormattedMessage(), |
390 | | - equalTo("uncaught exception in scheduled thread [" + Thread.currentThread().getName() + "]")); |
391 | | - assertTrue(expectThrowable); |
392 | | - assertNotNull(event.getThrown()); |
393 | | - assertTrue("only one message allowed", throwableReference.compareAndSet(null, event.getThrown())); |
394 | | - uncaughtExceptionHandlerLatch.countDown(); |
395 | | - } |
396 | | - } |
397 | | - |
398 | | - @Override |
399 | | - public void assertMatched() { |
| 413 | + try { |
| 414 | + runner.accept(() -> { |
| 415 | + try { |
| 416 | + runnable.run(); |
| 417 | + } finally { |
| 418 | + supplierLatch.countDown(); |
400 | 419 | } |
401 | 420 | }); |
| 421 | + } catch (Throwable t) { |
| 422 | + consumer.accept(Optional.of(t)); |
| 423 | + return; |
| 424 | + } |
402 | 425 |
|
403 | | - appender.start(); |
404 | | - Loggers.addAppender(schedulerLogger, appender); |
405 | | - try { |
406 | | - try { |
407 | | - runner.accept(job); |
408 | | - } catch (Throwable t) { |
409 | | - consumer.accept(Optional.of(t)); |
410 | | - return; |
411 | | - } |
412 | | - |
413 | | - supplierLatch.await(); |
| 426 | + supplierLatch.await(); |
414 | 427 |
|
415 | | - if (expectThrowable) { |
416 | | - uncaughtExceptionHandlerLatch.await(); |
417 | | - } |
418 | | - } finally { |
419 | | - Loggers.removeAppender(schedulerLogger, appender); |
420 | | - appender.stop(); |
| 428 | + if (expectThrowable) { |
| 429 | + uncaughtExceptionHandlerLatch.await(); |
421 | 430 | } |
422 | 431 |
|
423 | 432 | consumer.accept(Optional.ofNullable(throwableReference.get())); |
424 | | - } catch (IllegalAccessException e) { |
425 | | - throw new RuntimeException(e); |
426 | 433 | } finally { |
427 | 434 | Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler); |
428 | 435 | } |
|
0 commit comments